diff --git a/static/js/app/authSession.js b/static/js/app/authSession.js index ddbbb6b2..8cb024db 100644 --- a/static/js/app/authSession.js +++ b/static/js/app/authSession.js @@ -120,7 +120,7 @@ async function checkAuthentication() { } } await resolveHomeFolder(); - window.dispatchEvent(new Event('authenticationDone')); + window.dispatchEvent(new CustomEvent('authenticationDone')); } else { // No cached user data — must verify session from server console.log('No cached user data, fetching from server'); diff --git a/static/js/app/filesView.js b/static/js/app/filesView.js index 42ce1eea..ec2e96f9 100644 --- a/static/js/app/filesView.js +++ b/static/js/app/filesView.js @@ -52,7 +52,6 @@ async function getFolder( id) { async function rebuildBreadCrumb() { const app = window.app; - /** * Store the leaf (this is the current displayed folder) * @type {FolderInfo | null} @@ -71,7 +70,7 @@ async function rebuildBreadCrumb() { console.log(`fetching folder information for folder ${id}`); try { let folderInfo = await getFolder(id); - + // store the Leaf which is the current folder if (currentFolderInfo === null) { currentFolderInfo = folderInfo; @@ -97,7 +96,6 @@ async function rebuildBreadCrumb() { app.currentPath = id; } } - // store informations on the current folder app.currentFolderInfo = currentFolderInfo; } @@ -221,6 +219,32 @@ async function loadFiles(options = { insertHistory: true}) { } else { window.ui.renderFolders(folderList); window.ui.renderFiles(fileList); + + // check if a file was provided + if (window.app.viewFile) { + let fileFound = null; + + // lookup for the given fle + for( const file of fileList) { + if (file.id === window.app.viewFile) { + fileFound = file; + break; + } + } + + if (fileFound) { + console.log(`file ${window.app.viewFile} found, calling viewer`); + await window.inlineViewer.openFile(fileFound); + } + else { + // remove file + console.log(`file ${window.app.viewFile} not found`); + window.app.viewFile = null; + + // correct url/history as file is not found + window.updateHistory( false); + } + } } console.log(`Loaded ${folderList.length} folders and ${fileList.length} files`); diff --git a/static/js/app/main.js b/static/js/app/main.js index c2c123fa..99b27ae6 100644 --- a/static/js/app/main.js +++ b/static/js/app/main.js @@ -194,8 +194,9 @@ function setupActionsBarDelegation() { /** * @typedef {Object} OxiContext - * @property {string | null} path the uuid of the path * @property {string} section + * @property {string | null} path the uuid of the path + * @property {string | null} file the uuid of file inline view */ /** @@ -232,6 +233,10 @@ function deserializeHash() { if (hash_elements[1] == 'files' && hash_elements[2] == 'folder' && hash_elements[3] !== null) { hashContext.path = hash_elements[3]; + + if (hash_elements[4] == 'file' && hash_elements[5] !== null) { + hashContext.file = hash_elements[5]; + } } return hashContext; @@ -248,13 +253,18 @@ function updateHistory( insertHistory) { let historyData = { section: app.currentSection, id: app.currentFolder, + file: app.viewFile, }; + let historyUrl = `#/${app.currentSection}`; if (app.currentSection === 'files' && app.currentFolderInfo !== null) { historyData.id = app.currentFolder; historyUrl = historyUrl.concat('/folder/', app.currentFolderInfo.id); + if (window.app.viewFile) { + historyUrl = historyUrl.concat('/file/', window.app.viewFile); + } // update title document.title = `OxiCloud: ${app.currentFolderInfo.path}`; } @@ -374,6 +384,10 @@ function initApp() { console.log(`init: reusing folder from hash URL: ${hashContext.path}`); window.app.currentPath = hashContext.path; } + + if (hashContext.file !== null) { + window.app.viewFile = hashContext.file; + } window.loadFiles(); } @@ -722,3 +736,4 @@ window.updateStorageUsageDisplay = updateStorageUsageDisplay; // Initialize app when DOM is ready window.initApp = initApp; window.updateHistory = updateHistory; +window.deserializeHash = deserializeHash; diff --git a/static/js/app/state.js b/static/js/app/state.js index 696293e3..b815f0d3 100644 --- a/static/js/app/state.js +++ b/static/js/app/state.js @@ -25,7 +25,8 @@ window.app = { notificationShareUrl: null, userHomeFolderId: null, userHomeFolderName: null, - breadcrumbPath: [] // Array of {id, name} tracking folder navigation hierarchy + breadcrumbPath: [], // Array of {id, name} tracking folder navigation hierarchy + viewFile: null // current file in inline view }; window.appElements = { diff --git a/static/js/app/ui.js b/static/js/app/ui.js index 30fb5280..8a9e87b9 100644 --- a/static/js/app/ui.js +++ b/static/js/app/ui.js @@ -817,13 +817,26 @@ const ui = { const ext = (file.name || '').split('.').pop().toLowerCase(); const imageExts = ['jpg','jpeg','png','gif','svg','webp','bmp','ico','heic','heif','avif','tiff']; const isImage = (file.mime_type && file.mime_type.startsWith('image/')) || imageExts.includes(ext); - if (!isImage && window.wopiEditor && await window.wopiEditor.canEdit(file.name)) { - window.wopiEditor.openInModal(file.id, file.name, 'edit'); - return; + try { + if (!isImage && window.wopiEditor && await window.wopiEditor.canEdit(file.name)) { + await window.wopiEditor.openInModal(file.id, file.name, 'edit') + return; + } } + catch (e) { + console.warn(`WOPI Editor failed, falling bck to classic view `, e); + } + if (self.isViewableFile(file) || isImage) { - if (window.inlineViewer) window.inlineViewer.openFile(file); - else window.fileOps.downloadFile(file.id, file.name); + if (window.inlineViewer) { + window.inlineViewer.openFile(file); + // update history + window.app.viewFile = file.id; + window.updateHistory(false); + } + else { + window.fileOps.downloadFile(file.id, file.name); + } } else { window.fileOps.downloadFile(file.id, file.name); } diff --git a/static/js/app/uiFileTypes.js b/static/js/app/uiFileTypes.js index 51be84fc..e41920c9 100644 --- a/static/js/app/uiFileTypes.js +++ b/static/js/app/uiFileTypes.js @@ -4,6 +4,7 @@ */ const uiFileTypes = { + // TODO: 'd better to use a canViw() method in inlineViewer isViewableFile(file) { if (!file || !file.mime_type) return false; if (file.mime_type.startsWith('image/')) return true; diff --git a/static/js/features/files/inlineViewer.js b/static/js/features/files/inlineViewer.js index 8130ae89..cf4c00c8 100644 --- a/static/js/features/files/inlineViewer.js +++ b/static/js/features/files/inlineViewer.js @@ -514,7 +514,11 @@ class InlineViewer { URL.revokeObjectURL(this.currentBlobUrl); this.currentBlobUrl = null; } - + + // clear + window.app.viewFile = null; + window.updateHistory(false); + // Clear references this.currentFile = null; } diff --git a/static/js/features/files/wopiEditor.js b/static/js/features/files/wopiEditor.js index b752c714..bfb871b6 100644 --- a/static/js/features/files/wopiEditor.js +++ b/static/js/features/files/wopiEditor.js @@ -27,15 +27,9 @@ class WopiEditor { */ async openInModal(fileId, fileName, action) { action = action || 'edit'; - try { - var data = await this._getEditorUrlWithFallback(fileId, fileName, action); - this._showModal(data, fileName); - } catch (error) { - console.error('Failed to open WOPI editor:', error); - if (window.showNotification) { - window.showNotification('Could not open the document editor.', 'error'); - } - } + // Error is thrown, caller can handle a classic view as fallback + var data = await this._getEditorUrlWithFallback(fileId, fileName, action); + this._showModal(data, fileName); } /**