%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /www/varak.net/nextcloud.varak.net/apps_old/apps/viewer/js/
Upload File :
Create Path :
Current File : //www/varak.net/nextcloud.varak.net/apps_old/apps/viewer/js/viewer-main.mjs.map

{"version":3,"mappings":"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KAAK,OAAS,KAAK,MAAM,KAAK,cAAgB,KAAK,aAAeA,CAAW,IAI7E,KAAK,OAAS,KAAK,cACnB,KAAK,MAAQ,KAAK,aAEnB,CACD,EAKD,aAAc,CACb,KAAK,MAAM,kBAAmB,EAAI,CAClC,EAKD,cAAe,CACd,KAAK,MAAM,kBAAmB,EAAK,CACnC,EAKD,kBAAmB,CACd,KAAK,aACR,SAAS,eAAgB,EAEzB,KAAK,IAAI,kBAAmB,CAE7B,CACD,CACF,EC/MA/C,GAAA,CACA,kBACA,gBACA,OACA,OACA,WACA,EACA,WACA,YACA,sBACA,EACA,MACA,YACA,UACA,CACA,CACA,ilBChBAA,GAAA,CACA,oBACA,gBACA,OACA,OACA,WACA,EACA,WACA,YACA,sBACA,EACA,MACA,YACA,UACA,CACA,CACA,2iBChBAA,GAAA,CACA,sBACA,gBACA,OACA,OACA,WACA,EACA,WACA,YACA,sBACA,EACA,MACA,YACA,UACA,CACA,CACA,0lBChBAA,GAAA,CACA,0BACA,gBACA,OACA,OACA,WACA,EACA,WACA,YACA,sBACA,EACA,MACA,YACA,UACA,CACA,CACA,8lBChBAA,GAAA,CACA,kBACA,gBACA,OACA,OACA,WACA,EACA,WACA,YACA,sBACA,EACA,MACA,YACA,UACA,CACA,CACA,mpBC0LAkD,GAAA,IAAAC,EAAA,WAGA,oCAAAC,KAAA,4CACAC,GAAA,oGACAC,GAAA,6DAAAF,KAAA,iDAEApD,GAAA,CACA,cAEA,YACA,OAAAuD,GACA,SAAAC,GACA,MAAAC,GACA,WAAAC,GACA,eAAAC,GACA,eAAAL,GACA,aAAAD,GACA,QAAAH,GACA,OAAAU,EACA,EAEA,SACA,UAAAC,EAAA,CACA,SAAAA,EAAA,OAAAA,EAAA,MACA,CACA,EAEA,QAAAC,GAAAC,EAAA,EAEA,OACA,OAEA,kBACA,aACA,sCAGA,cACA,cACA,sBAGA,eACA,gBACA,eACA,oBACA,YACA,YACA,mBAGA,YACA,aACA,WAGA,yBACA,2BAGA,kBACA,kBACA,oBACA,YACA,gBACA,WACA,mBACA,KAAAC,EACA,aA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","names":["getSortingConfig","viewConfigs","getViewConfigs","key","asc","isPublicShare","url","generateUrl","axios","response","index","isFullscreenState","isMobileState","hideDownloadElmt","canDownload","CancelableRequest","request","controller","options","_sfc_main","File","fileInfo","mime","component","data","getDavPath","legacyFilesActionHandler","name","context","path","oldQuery","onClose","pushToHistory","fileid","params","dir","query","encodePath","getFileList","client","getDavNameSpaces","getDavProperties","genFileInfo","PreviewUrl","getPreviewIfAny","isWindows","process","splitWindowsRe","win32","win32SplitPath","filename","pathString","allParts","splitPathRe","posix","posixSplitPath","pathParseModule","Mime","parsePath","val","old","e","debounce","modalWrapper","modalContainer","parentHeight","parentWidth","heightRatio","widthRatio","NcModal","__vitePreload","n","NcActionLink","NcActionButton","Delete","Download","Error","Fullscreen","FullscreenExit","Pencil","file","isFullscreen","isMobile","davRemoteURL","davRootPath","loadState","element","logger","viewerRoot","el","fileList","currentIndex","isEndOfList","list","handler","subscribe","unsubscribe","overrideHandlerId","fileRequest","cancelRequestFile","cancelableRequest","getFileInfo","fileName","extractFilePaths","title","error","showError","alias","h","defaultThemeIsLight","group","mimes","folderRequest","cancelRequestFolder","dirPath","filteredFiles","a","b","sortCompare","prev","next","Vue","event","sidebar","node","currentFileId","emit","t","ViewerRoot","VideoControls","ViewerComponent"],"ignoreList":[1,2,10,12,13,14,15,16],"sources":["../src/services/FileSortingConfig.ts","../node_modules/@nextcloud/vue/dist/Mixins/isFullscreen.mjs","../node_modules/@nextcloud/vue/dist/Mixins/isMobile.mjs","../src/utils/canDownload.js","../src/utils/CancelableRequest.js","../src/components/Error.vue","../src/models/file.js","../src/services/LegacyFilesActionHandler.js","../src/services/FileList.ts","../src/mixins/PreviewUrl.js","../node_modules/path-parse/index.js","../src/mixins/Mime.js","../node_modules/vue-material-design-icons/Delete.vue","../node_modules/vue-material-design-icons/Download.vue","../node_modules/vue-material-design-icons/Fullscreen.vue","../node_modules/vue-material-design-icons/FullscreenExit.vue","../node_modules/vue-material-design-icons/Pencil.vue","../src/views/Viewer.vue","../src/main.js"],"sourcesContent":["/**\n * @copyright Copyright (c) 2023 Hamza Mahjoubi <hamza.mahjoubi221@proton.me>\n *\n * @author Hamza Mahjoubi <hamza.mahjoubi221@proton.me>\n *\n * @license AGPL-3.0-or-later\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\nimport axios from '@nextcloud/axios'\nimport { generateUrl } from '@nextcloud/router'\nimport { isPublicShare } from '@nextcloud/sharing/public'\n\n/**\n * @return {object}\n */\nexport default async function getSortingConfig() {\n\tconst viewConfigs = await getViewConfigs()\n\n\tif (!viewConfigs) {\n\t\treturn { key: 'basename', asc: true }\n\t}\n\n\tconst keyMap = { mtime: 'lastmod' }\n\tconst key = keyMap[viewConfigs.sorting_mode] || viewConfigs.sorting_mode || 'basename'\n\tconst asc = viewConfigs.sorting_direction === 'asc' || !viewConfigs.sorting_direction\n\n\treturn { key, asc }\n}\n\n/**\n * @return {object}\n */\nasync function getViewConfigs() {\n\tif (isPublicShare()) {\n\t\treturn null\n\t}\n\tconst url = generateUrl('apps/files/api/v1/views')\n\treturn await axios.get(url)\n\t\t.then((response) => {\n\t\t\treturn response.data.data?.files\n\t\t})\n\t\t.catch(() => {\n\t\t\treturn null\n\t\t})\n}\n","import { isFullscreenState } from \"../Composables/useIsFullscreen.mjs\";\nconst index = {\n  computed: {\n    /**\n     * @deprecated Is to be removed in v9.0.0 with Vue 3 migration.\n     *             Use `composables/useIsFullscreen` instead.\n     */\n    isFullscreen() {\n      return isFullscreenState.value;\n    }\n  }\n};\nexport {\n  index as default\n};\n","import { isMobileState } from \"../Composables/useIsMobile.mjs\";\nconst index = {\n  computed: {\n    /**\n     * @deprecated Is to be removed in v9.0.0 with Vue 3 migration.\n     *             Use `composables/useIsMobile` instead.\n     */\n    isMobile() {\n      return isMobileState.value;\n    }\n  }\n};\nexport {\n  index as default\n};\n","/**\n * @copyright Copyright (c) 2020 John Molakvoæ <skjnldsv@protonmail.com>\n *\n * @author John Molakvoæ <skjnldsv@protonmail.com>\n *\n * @license AGPL-3.0-or-later\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\nconst hideDownloadElmt = document.getElementById('hideDownload')\n// true = hidden download\nexport default () => !hideDownloadElmt || (hideDownloadElmt && hideDownloadElmt.value !== 'true')\n","/**\n * @copyright Copyright (c) 2019 Marco Ambrosini <marcoambrosini@pm.me>\n *\n * @author Marco Ambrosini <marcoambrosini@pm.me>\n * @author John Molakvoæ <skjnldsv@protonmail.com>\n * @author Louis Chemineau <louis@chmn.me>\n *\n * @license AGPL-3.0-or-later\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n/**\n * Creates a cancelable axios 'request object'.\n *\n * @param {Function} request the axios promise request\n * @return {object}\n */\nconst CancelableRequest = function(request) {\n\tconst controller = new AbortController()\n\n\t/**\n\t * Execute the request\n\t *\n\t * @param {string} url the url to send the request to\n\t * @param {object} [options] optional config for the request\n\t */\n\tconst fetch = async function(url, options) {\n\t\treturn request(\n\t\t\turl,\n\t\t\t{ ...options, signal: controller.signal },\n\t\t)\n\t}\n\treturn {\n\t\trequest: fetch,\n\t\tcancel: () => controller.abort(),\n\t}\n}\n\nexport default CancelableRequest\n","<!--\n - @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>\n -\n - @author John Molakvoæ <skjnldsv@protonmail.com>\n -\n - @license AGPL-3.0-or-later\n -\n - This program is free software: you can redistribute it and/or modify\n - it under the terms of the GNU Affero General Public License as\n - published by the Free Software Foundation, either version 3 of the\n - License, or (at your option) any later version.\n -\n - This program is distributed in the hope that it will be useful,\n - but WITHOUT ANY WARRANTY; without even the implied warranty of\n - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n - GNU Affero General Public License for more details.\n -\n - You should have received a copy of the GNU Affero General Public License\n - along with this program. If not, see <http://www.gnu.org/licenses/>.\n -\n -->\n\n<template>\n\t<div id=\"emptycontent\">\n\t\t<div class=\"icon-error\" />\n\t\t<h2>\n\t\t\t<slot>{{ t('viewer', 'Error loading {name}', { name }) }}</slot>\n\t\t</h2>\n\t</div>\n</template>\n\n<script>\nexport default {\n\tname: 'Error',\n\n\tprops: {\n\t\tname: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n#emptycontent {\n\tmargin: 0;\n\tpadding: 10% 5%;\n\tbackground-color: var(--color-main-background);\n}\n</style>\n","/**\n * @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>\n *\n * @author John Molakvoæ <skjnldsv@protonmail.com>\n *\n * @license AGPL-3.0-or-later\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n *\n */\nimport { getDavPath } from '../utils/fileUtils.ts'\n\n/**\n * @param {object} fileInfo a FileInfo object\n * @param {string} mime the file mime type\n * @param {object} component the component to render\n */\nexport default function(fileInfo, mime, component) {\n\tconst data = {\n\t\tmime,\n\t\tmodal: component,\n\t\tfailed: false,\n\t\tloaded: false,\n\t\tdavPath: getDavPath(fileInfo),\n\t\tsource: fileInfo.source ?? getDavPath(fileInfo),\n\t}\n\n\treturn Object.assign({}, fileInfo, data)\n}\n","/**\n * @copyright Copyright (c) 2020 Azul <azul@riseup.net>\n *\n * @author Azul <azul@riseup.net>\n *\n * @license AGPL-3.0-or-later\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\nimport { encodePath } from '@nextcloud/paths'\n\n/**\n * @param {string} name the file name\n * @param {object} context the file context\n */\nexport default function(name, context) {\n\t// replace potential leading double slashes\n\tconst path = `${context.dir}/${name}`.replace(/^\\/\\//, '/')\n\tconst oldQuery = location.search.replace(/^\\?/, '')\n\tconst onClose = () => OC.Util.History.pushState(oldQuery)\n\tif (!context.fileInfoModel && context.fileList) {\n\t\tcontext.fileInfoModel = context.fileList.getModelForFile(name)\n\t}\n\tif (context.fileInfoModel) {\n\t\tpushToHistory({ fileid: context.fileInfoModel.get('id') })\n\t}\n\tOCA.Viewer.open({ path, onPrev: pushToHistory, onNext: pushToHistory, onClose })\n}\n\n/**\n * @param {object} root destructuring object\n * @param {number} root.fileid the opened file ID\n */\nfunction pushToHistory({ fileid }) {\n\tconst params = OC.Util.History.parseUrlQuery()\n\tconst dir = params.dir\n\tdelete params.dir\n\tdelete params.fileid\n\tparams.openfile = fileid\n\tconst query = 'dir=' + encodePath(dir) + '&' + OC.buildQueryString(params)\n\tOC.Util.History.pushState(query)\n}\n","/**\n * @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>\n *\n * @author John Molakvoæ <skjnldsv@protonmail.com>\n *\n * @license AGPL-3.0-or-later\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\nimport { getDavNameSpaces, getDavProperties } from '@nextcloud/files'\nimport { client } from './WebdavClient'\nimport { genFileInfo, type FileInfo } from '../utils/fileUtils'\nimport type { FileStat, ResponseDataDetailed } from 'webdav'\n\n/**\n * Retrieve the files list\n * @param path\n * @param options\n */\nexport default async function(path: string, options = {}): Promise<FileInfo[]> {\n\tconst response = await client.getDirectoryContents(path, Object.assign({\n\t\tdata: `<?xml version=\"1.0\"?>\n\t\t\t<d:propfind ${getDavNameSpaces()}>\n\t\t\t\t<d:prop>\n\t\t\t\t\t<oc:tags />\n\t\t\t\t\t${getDavProperties()}\n\t\t\t\t</d:prop>\n\t\t\t</d:propfind>`,\n\t\tdetails: true,\n\t}, options)) as ResponseDataDetailed<FileStat[]>\n\n\treturn response.data.map(genFileInfo)\n}\n","/**\n * @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>\n *\n * @author John Molakvoæ <skjnldsv@protonmail.com>\n *\n * @license AGPL-3.0-or-later\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n *\n */\nimport { getPreviewIfAny } from '../utils/previewUtils.ts'\nimport { getDavPath } from '../utils/fileUtils.ts'\n\nexport default {\n\tcomputed: {\n\t\t/**\n\t\t * Link to the preview path if the file have a preview\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tpreviewPath() {\n\t\t\treturn this.getPreviewIfAny({\n\t\t\t\tfileid: this.fileid,\n\t\t\t\tfilename: this.filename,\n\t\t\t\tpreviewUrl: this.previewUrl,\n\t\t\t\thasPreview: this.hasPreview,\n\t\t\t\tdavPath: this.davPath,\n\t\t\t\tetag: this.$attrs.etag,\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Absolute dav remote path of the file\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tdavPath() {\n\t\t\treturn getDavPath({\n\t\t\t\tfilename: this.filename,\n\t\t\t\tbasename: this.basename,\n\t\t\t})\n\t\t},\n\t},\n\tmethods: {\n\t\t/**\n\t\t * Return the preview url if the file have an existing\n\t\t * preview or the absolute dav remote path if none.\n\t\t *\n\t\t * @param {object} data destructuring object\n\t\t * @param {string} data.fileid the file id\n\t\t * @param {string} [data.previewUrl] URL of the file preview\n\t\t * @param {boolean} data.hasPreview have the file an existing preview ?\n\t\t * @param {string} data.davPath the absolute dav path\n\t\t * @param {string} data.filename the file name\n\t\t * @param {string|null} data.etag the etag of the file\n\t\t * @return {string} the absolute url\n\t\t */\n\t\tgetPreviewIfAny(data) {\n\t\t\treturn getPreviewIfAny(data)\n\t\t},\n\t},\n}\n","'use strict';\n\nvar isWindows = process.platform === 'win32';\n\n// Regex to split a windows path into into [dir, root, basename, name, ext]\nvar splitWindowsRe =\n    /^(((?:[a-zA-Z]:|[\\\\\\/]{2}[^\\\\\\/]+[\\\\\\/]+[^\\\\\\/]+)?[\\\\\\/]?)(?:[^\\\\\\/]*[\\\\\\/])*)((\\.{1,2}|[^\\\\\\/]+?|)(\\.[^.\\/\\\\]*|))[\\\\\\/]*$/;\n\nvar win32 = {};\n\nfunction win32SplitPath(filename) {\n  return splitWindowsRe.exec(filename).slice(1);\n}\n\nwin32.parse = function(pathString) {\n  if (typeof pathString !== 'string') {\n    throw new TypeError(\n        \"Parameter 'pathString' must be a string, not \" + typeof pathString\n    );\n  }\n  var allParts = win32SplitPath(pathString);\n  if (!allParts || allParts.length !== 5) {\n    throw new TypeError(\"Invalid path '\" + pathString + \"'\");\n  }\n  return {\n    root: allParts[1],\n    dir: allParts[0] === allParts[1] ? allParts[0] : allParts[0].slice(0, -1),\n    base: allParts[2],\n    ext: allParts[4],\n    name: allParts[3]\n  };\n};\n\n\n\n// Split a filename into [dir, root, basename, name, ext], unix version\n// 'root' is just a slash, or nothing.\nvar splitPathRe =\n    /^((\\/?)(?:[^\\/]*\\/)*)((\\.{1,2}|[^\\/]+?|)(\\.[^.\\/]*|))[\\/]*$/;\nvar posix = {};\n\n\nfunction posixSplitPath(filename) {\n  return splitPathRe.exec(filename).slice(1);\n}\n\n\nposix.parse = function(pathString) {\n  if (typeof pathString !== 'string') {\n    throw new TypeError(\n        \"Parameter 'pathString' must be a string, not \" + typeof pathString\n    );\n  }\n  var allParts = posixSplitPath(pathString);\n  if (!allParts || allParts.length !== 5) {\n    throw new TypeError(\"Invalid path '\" + pathString + \"'\");\n  }\n  \n  return {\n    root: allParts[1],\n    dir: allParts[0].slice(0, -1),\n    base: allParts[2],\n    ext: allParts[4],\n    name: allParts[3],\n  };\n};\n\n\nif (isWindows)\n  module.exports = win32.parse;\nelse /* posix */\n  module.exports = posix.parse;\n\nmodule.exports.posix = posix.parse;\nmodule.exports.win32 = win32.parse;\n","/**\n * @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>\n *\n * @author John Molakvoæ <skjnldsv@protonmail.com>\n *\n * @license AGPL-3.0-or-later\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n *\n */\nimport debounce from 'debounce'\nimport PreviewUrl from '../mixins/PreviewUrl.js'\nimport parsePath from 'path-parse'\n\nexport default {\n\tinheritAttrs: false,\n\tmixins: [PreviewUrl],\n\tprops: {\n\t\t// Is the current component shown\n\t\tactive: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t\t// file name\n\t\tbasename: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\t\t// file path relative to user folder\n\t\tfilename: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\t\t// file source to fetch contents from\n\t\tsource: {\n\t\t\ttype: String,\n\t\t\tdefault: undefined,\n\t\t},\n\t\t// URL the file preview\n\t\tpreviewUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: undefined,\n\t\t},\n\t\t// should the standard core preview be used?\n\t\thasPreview: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t\t// unique file id\n\t\tfileid: {\n\t\t\ttype: [Number, String],\n\t\t\trequired: false,\n\t\t},\n\t\t// list of all the visible files\n\t\tfileList: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\t\t// file mime (aliased if specified in the model)\n\t\tmime: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\t\t// can the user swipe\n\t\tcanSwipe: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\t\t// is the content loaded?\n\t\t// synced with parent\n\t\tloaded: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t\t// is the sidebar currently opened ?\n\t\tisSidebarShown: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t\t// are we in fullscreen mode ?\n\t\tisFullScreen: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t\t// The file id of the peer live photo file\n\t\tmetadataFilesLivePhoto: {\n\t\t\ttype: Number,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\theight: null,\n\t\t\twidth: null,\n\t\t\tnaturalHeight: null,\n\t\t\tnaturalWidth: null,\n\t\t\tisLoaded: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tname() {\n\t\t\treturn parsePath(this.basename).name\n\t\t},\n\t\text() {\n\t\t\treturn parsePath(this.basename).ext\n\t\t},\n\t\tsrc() {\n\t\t\treturn this.source ?? this.davPath\n\t\t},\n\t},\n\n\twatch: {\n\t\tactive(val, old) {\n\t\t\t// the item was hidden before and is now the current view\n\t\t\tif (val === true && old === false) {\n\t\t\t\t// just in case the file was preloaded, let's warn the viewer\n\t\t\t\tif (this.isLoaded) {\n\t\t\t\t\tthis.doneLoading()\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t// update image size on sidebar toggle\n\t\tisSidebarShown() {\n\t\t\t// wait for transition to complete (100ms)\n\t\t\tsetTimeout(this.updateHeightWidth, 200)\n\t\t},\n\t},\n\n\tmounted() {\n\t\t// detect error and let the viewer know\n\t\tthis.$el.addEventListener('error', e => {\n\t\t\tconsole.error('Error loading', this.filename, e)\n\t\t\tthis.$emit('error', e)\n\t\t})\n\n\t\t// update image size on window resize\n\t\twindow.addEventListener('resize', debounce(() => {\n\t\t\tthis.updateHeightWidth()\n\t\t}, 100))\n\t},\n\n\tmethods: {\n\n\t\t/**\n\t\t * This is used to make the viewer know this file is complete or ready\n\t\t * ! you NEED to use it to make the viewer aware of the current loading state\n\t\t */\n\t\tdoneLoading() {\n\t\t\t// send the current state\n\t\t\tthis.$emit('update:loaded', true)\n\t\t\t// save the current state\n\t\t\tthis.isLoaded = true\n\t\t},\n\n\t\t/**\n\t\t * Updates the current height and width data\n\t\t * based on the viewer maximum size\n\t\t */\n\t\tupdateHeightWidth() {\n\t\t\tconst modalWrapper = this.$parent.$el.querySelector('.modal-wrapper')\n\t\t\tif (modalWrapper && this.naturalHeight > 0 && this.naturalWidth > 0) {\n\t\t\t\tconst modalContainer = modalWrapper.querySelector('.modal-container')\n\n\t\t\t\tconst parentHeight = modalContainer.clientHeight\n\t\t\t\tconst parentWidth = modalContainer.clientWidth\n\n\t\t\t\tconst heightRatio = parentHeight / this.naturalHeight\n\t\t\t\tconst widthRatio = parentWidth / this.naturalWidth\n\n\t\t\t\t// if the video height is capped by the parent height\n\t\t\t\t// AND the video is bigger than the parent\n\t\t\t\tif (heightRatio < widthRatio && heightRatio < 1) {\n\t\t\t\t\tthis.height = parentHeight\n\t\t\t\t\tthis.width = Math.round(this.naturalWidth / this.naturalHeight * parentHeight)\n\n\t\t\t\t// if the video width is capped by the parent width\n\t\t\t\t// AND the video is bigger than the parent\n\t\t\t\t} else if (heightRatio > widthRatio && widthRatio < 1) {\n\t\t\t\t\tthis.width = parentWidth\n\t\t\t\t\tthis.height = Math.round(this.naturalHeight / this.naturalWidth * parentWidth)\n\n\t\t\t\t// RESET\n\t\t\t\t} else {\n\t\t\t\t\tthis.height = this.naturalHeight\n\t\t\t\t\tthis.width = this.naturalWidth\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Enable the viewer swiping previous/next capability\n\t\t */\n\t\tenableSwipe() {\n\t\t\tthis.$emit('update:canSwipe', true)\n\t\t},\n\n\t\t/**\n\t\t * Disable the viewer swiping previous/next capability\n\t\t */\n\t\tdisableSwipe() {\n\t\t\tthis.$emit('update:canSwipe', false)\n\t\t},\n\n\t\t/**\n\t\t * Toggle the fullscreen on the current visible element\n\t\t */\n\t\ttoggleFullScreen() {\n\t\t\tif (this.isFullScreen) {\n\t\t\t\tdocument.exitFullscreen()\n\t\t\t} else {\n\t\t\t\tthis.$el.requestFullscreen()\n\t\t\t}\n\t\t},\n\t},\n}\n","<template>\n  <span v-bind=\"$attrs\"\n        :aria-hidden=\"title ? null : true\"\n        :aria-label=\"title\"\n        class=\"material-design-icon delete-icon\"\n        role=\"img\"\n        @click=\"$emit('click', $event)\">\n    <svg :fill=\"fillColor\"\n         class=\"material-design-icon__svg\"\n         :width=\"size\"\n         :height=\"size\"\n         viewBox=\"0 0 24 24\">\n      <path d=\"M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z\">\n        <title v-if=\"title\">{{ title }}</title>\n      </path>\n    </svg>\n  </span>\n</template>\n\n<script>\nexport default {\n  name: \"DeleteIcon\",\n  emits: ['click'],\n  props: {\n    title: {\n      type: String,\n    },\n    fillColor: {\n      type: String,\n      default: \"currentColor\"\n    },\n    size: {\n      type: Number,\n      default: 24\n    }\n  }\n}\n</script>","<template>\n  <span v-bind=\"$attrs\"\n        :aria-hidden=\"title ? null : true\"\n        :aria-label=\"title\"\n        class=\"material-design-icon download-icon\"\n        role=\"img\"\n        @click=\"$emit('click', $event)\">\n    <svg :fill=\"fillColor\"\n         class=\"material-design-icon__svg\"\n         :width=\"size\"\n         :height=\"size\"\n         viewBox=\"0 0 24 24\">\n      <path d=\"M5,20H19V18H5M19,9H15V3H9V9H5L12,16L19,9Z\">\n        <title v-if=\"title\">{{ title }}</title>\n      </path>\n    </svg>\n  </span>\n</template>\n\n<script>\nexport default {\n  name: \"DownloadIcon\",\n  emits: ['click'],\n  props: {\n    title: {\n      type: String,\n    },\n    fillColor: {\n      type: String,\n      default: \"currentColor\"\n    },\n    size: {\n      type: Number,\n      default: 24\n    }\n  }\n}\n</script>","<template>\n  <span v-bind=\"$attrs\"\n        :aria-hidden=\"title ? null : true\"\n        :aria-label=\"title\"\n        class=\"material-design-icon fullscreen-icon\"\n        role=\"img\"\n        @click=\"$emit('click', $event)\">\n    <svg :fill=\"fillColor\"\n         class=\"material-design-icon__svg\"\n         :width=\"size\"\n         :height=\"size\"\n         viewBox=\"0 0 24 24\">\n      <path d=\"M5,5H10V7H7V10H5V5M14,5H19V10H17V7H14V5M17,14H19V19H14V17H17V14M10,17V19H5V14H7V17H10Z\">\n        <title v-if=\"title\">{{ title }}</title>\n      </path>\n    </svg>\n  </span>\n</template>\n\n<script>\nexport default {\n  name: \"FullscreenIcon\",\n  emits: ['click'],\n  props: {\n    title: {\n      type: String,\n    },\n    fillColor: {\n      type: String,\n      default: \"currentColor\"\n    },\n    size: {\n      type: Number,\n      default: 24\n    }\n  }\n}\n</script>","<template>\n  <span v-bind=\"$attrs\"\n        :aria-hidden=\"title ? null : true\"\n        :aria-label=\"title\"\n        class=\"material-design-icon fullscreen-exit-icon\"\n        role=\"img\"\n        @click=\"$emit('click', $event)\">\n    <svg :fill=\"fillColor\"\n         class=\"material-design-icon__svg\"\n         :width=\"size\"\n         :height=\"size\"\n         viewBox=\"0 0 24 24\">\n      <path d=\"M14,14H19V16H16V19H14V14M5,14H10V19H8V16H5V14M8,5H10V10H5V8H8V5M19,8V10H14V5H16V8H19Z\">\n        <title v-if=\"title\">{{ title }}</title>\n      </path>\n    </svg>\n  </span>\n</template>\n\n<script>\nexport default {\n  name: \"FullscreenExitIcon\",\n  emits: ['click'],\n  props: {\n    title: {\n      type: String,\n    },\n    fillColor: {\n      type: String,\n      default: \"currentColor\"\n    },\n    size: {\n      type: Number,\n      default: 24\n    }\n  }\n}\n</script>","<template>\n  <span v-bind=\"$attrs\"\n        :aria-hidden=\"title ? null : true\"\n        :aria-label=\"title\"\n        class=\"material-design-icon pencil-icon\"\n        role=\"img\"\n        @click=\"$emit('click', $event)\">\n    <svg :fill=\"fillColor\"\n         class=\"material-design-icon__svg\"\n         :width=\"size\"\n         :height=\"size\"\n         viewBox=\"0 0 24 24\">\n      <path d=\"M20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18,2.9 17.35,2.9 16.96,3.29L15.12,5.12L18.87,8.87M3,17.25V21H6.75L17.81,9.93L14.06,6.18L3,17.25Z\">\n        <title v-if=\"title\">{{ title }}</title>\n      </path>\n    </svg>\n  </span>\n</template>\n\n<script>\nexport default {\n  name: \"PencilIcon\",\n  emits: ['click'],\n  props: {\n    title: {\n      type: String,\n    },\n    fillColor: {\n      type: String,\n      default: \"currentColor\"\n    },\n    size: {\n      type: Number,\n      default: 24\n    }\n  }\n}\n</script>","<!--\n - @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>\n - @copyright Copyright (c) 2020 Gary Kim <gary@garykim.dev>\n -\n - @author John Molakvoæ <skjnldsv@protonmail.com>\n -\n - @license AGPL-3.0-or-later\n -\n - This program is free software: you can redistribute it and/or modify\n - it under the terms of the GNU Affero General Public License as\n - published by the Free Software Foundation, either version 3 of the\n - License, or (at your option) any later version.\n -\n - This program is distributed in the hope that it will be useful,\n - but WITHOUT ANY WARRANTY; without even the implied warranty of\n - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n - GNU Affero General Public License for more details.\n -\n - You should have received a copy of the GNU Affero General Public License\n - along with this program. If not, see <http://www.gnu.org/licenses/>.\n -\n -->\n\n<template>\n\t<!-- Single-file rendering -->\n\t<div v-if=\"el\"\n\t\tid=\"viewer\"\n\t\t:data-handler=\"handlerId\">\n\t\t<component :is=\"currentFile.modal\"\n\t\t\tv-if=\"!currentFile.failed\"\n\t\t\t:key=\"currentFile | uniqueKey\"\n\t\t\tref=\"content\"\n\t\t\t:active=\"true\"\n\t\t\t:can-swipe=\"false\"\n\t\t\tv-bind=\"currentFile\"\n\t\t\t:file-list=\"[currentFile]\"\n\t\t\t:is-full-screen=\"false\"\n\t\t\t:loaded.sync=\"currentFile.loaded\"\n\t\t\t:is-sidebar-shown=\"false\"\n\t\t\tclass=\"viewer__file viewer__file--active\"\n\t\t\t@error=\"currentFailed\" />\n\t\t<Error v-else\n\t\t\t:name=\"currentFile.basename\" />\n\t</div>\n\n\t<!-- Modal view rendering -->\n\t<NcModal v-else-if=\"initiated || currentFile.modal\"\n\t\tid=\"viewer\"\n\t\t:additional-trap-elements=\"trapElements\"\n\t\t:class=\"modalClass\"\n\t\t:clear-view-delay=\"-1 /* disable fade-out because of accessibility reasons */\"\n\t\t:close-button-contained=\"false\"\n\t\t:dark=\"true\"\n\t\t:light-backdrop=\"lightBackdrop\"\n\t\t:data-handler=\"handlerId\"\n\t\t:enable-slideshow=\"hasPrevious || hasNext\"\n\t\t:slideshow-paused=\"editing\"\n\t\t:enable-swipe=\"canSwipe && !editing\"\n\t\t:has-next=\"hasNext\"\n\t\t:has-previous=\"hasPrevious\"\n\t\t:inline-actions=\"canEdit ? 1 : 0\"\n\t\t:spread-navigation=\"true\"\n\t\t:style=\"{ width: isSidebarShown ? `${sidebarPosition}px` : null }\"\n\t\t:name=\"currentFile.basename\"\n\t\t:view=\"currentFile.modal\"\n\t\tclass=\"viewer\"\n\t\tsize=\"full\"\n\t\t@close=\"close\"\n\t\t@previous=\"previous\"\n\t\t@next=\"next\">\n\t\t<!-- ACTIONS -->\n\t\t<template #actions>\n\t\t\t<!-- Inline items -->\n\t\t\t<NcActionButton v-if=\"canEdit\"\n\t\t\t\t:close-after-click=\"true\"\n\t\t\t\t@click=\"onEdit\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Pencil :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('viewer', 'Edit') }}\n\t\t\t</NcActionButton>\n\t\t\t<!-- Menu items -->\n\t\t\t<NcActionButton :close-after-click=\"true\"\n\t\t\t\t@click=\"toggleFullScreen\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Fullscreen v-if=\"!isFullscreenMode\" :size=\"20\" />\n\t\t\t\t\t<FullscreenExit v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ isFullscreenMode ? t('viewer', 'Exit full screen') : t('viewer', 'Full screen') }}\n\t\t\t</NcActionButton>\n\t\t\t<NcActionButton v-if=\"enableSidebar && Sidebar && sidebarOpenFilePath && !isSidebarShown\"\n\t\t\t\t:close-after-click=\"true\"\n\t\t\t\ticon=\"icon-menu-sidebar\"\n\t\t\t\t@click=\"showSidebar\">\n\t\t\t\t{{ t('viewer', 'Open sidebar') }}\n\t\t\t</NcActionButton>\n\t\t\t<NcActionLink v-if=\"canDownload\"\n\t\t\t\t:download=\"currentFile.basename\"\n\t\t\t\t:close-after-click=\"true\"\n\t\t\t\t:href=\"downloadPath\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Download :size=\"24\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('viewer', 'Download') }}\n\t\t\t</NcActionLink>\n\t\t\t<NcActionButton v-if=\"canDelete\"\n\t\t\t\t:close-after-click=\"true\"\n\t\t\t\t@click=\"onDelete\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Delete :size=\"22\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('viewer', 'Delete') }}\n\t\t\t</NcActionButton>\n\t\t</template>\n\n\t\t<div class=\"viewer__content\" :class=\"contentClass\" @click.self.exact=\"close\">\n\t\t\t<!-- COMPARE FILE -->\n\t\t\t<div v-if=\"comparisonFile && !comparisonFile.failed && showComparison\" class=\"viewer__file-wrapper\">\n\t\t\t\t<component :is=\"comparisonFile.modal\"\n\t\t\t\t\t:key=\"comparisonFile | uniqueKey\"\n\t\t\t\t\tref=\"comparison-content\"\n\t\t\t\t\tv-bind=\"comparisonFile\"\n\t\t\t\t\t:active=\"true\"\n\t\t\t\t\t:can-swipe=\"false\"\n\t\t\t\t\t:can-zoom=\"false\"\n\t\t\t\t\t:editing=\"false\"\n\t\t\t\t\t:is-full-screen=\"isFullscreen\"\n\t\t\t\t\t:is-sidebar-shown=\"isSidebarShown\"\n\t\t\t\t\t:loaded.sync=\"comparisonFile.loaded\"\n\t\t\t\t\tclass=\"viewer__file viewer__file--active\"\n\t\t\t\t\t@error=\"comparisonFailed\" />\n\t\t\t</div>\n\n\t\t\t<!-- PREVIOUS -->\n\t\t\t<div v-if=\"previousFile\"\n\t\t\t\t:key=\"previousFile | uniqueKey\"\n\t\t\t\tclass=\"viewer__file-wrapper viewer__file-wrapper--hidden\"\n\t\t\t\taria-hidden=\"true\"\n\t\t\t\tinert>\n\t\t\t\t<component :is=\"previousFile.modal\"\n\t\t\t\t\tv-if=\"!previousFile.failed\"\n\t\t\t\t\tref=\"previous-content\"\n\t\t\t\t\tv-bind=\"previousFile\"\n\t\t\t\t\t:file-list=\"fileList\"\n\t\t\t\t\tclass=\"viewer__file\"\n\t\t\t\t\t@error=\"previousFailed\" />\n\t\t\t\t<Error v-else\n\t\t\t\t\t:name=\"previousFile.basename\" />\n\t\t\t</div>\n\n\t\t\t<!-- CURRENT -->\n\t\t\t<div :key=\"currentFile | uniqueKey\" class=\"viewer__file-wrapper\">\n\t\t\t\t<component :is=\"currentFile.modal\"\n\t\t\t\t\tv-if=\"!currentFile.failed\"\n\t\t\t\t\tref=\"content\"\n\t\t\t\t\tv-bind=\"currentFile\"\n\t\t\t\t\t:active=\"true\"\n\t\t\t\t\t:can-swipe.sync=\"canSwipe\"\n\t\t\t\t\t:can-zoom=\"canZoom\"\n\t\t\t\t\t:editing.sync=\"editing\"\n\t\t\t\t\t:file-list=\"fileList\"\n\t\t\t\t\t:is-full-screen=\"isFullscreen\"\n\t\t\t\t\t:is-sidebar-shown=\"isSidebarShown\"\n\t\t\t\t\t:loaded.sync=\"currentFile.loaded\"\n\t\t\t\t\tclass=\"viewer__file viewer__file--active\"\n\t\t\t\t\t@error=\"currentFailed\" />\n\t\t\t\t<Error v-else\n\t\t\t\t\t:name=\"currentFile.basename\" />\n\t\t\t</div>\n\n\t\t\t<!-- NEXT -->\n\t\t\t<div v-if=\"nextFile\"\n\t\t\t\t:key=\"nextFile | uniqueKey\"\n\t\t\t\tclass=\"viewer__file-wrapper viewer__file-wrapper--hidden\"\n\t\t\t\taria-hidden=\"true\"\n\t\t\t\tinert>\n\t\t\t\t<component :is=\"nextFile.modal\"\n\t\t\t\t\tv-if=\"!nextFile.failed\"\n\t\t\t\t\tref=\"next-content\"\n\t\t\t\t\tv-bind=\"nextFile\"\n\t\t\t\t\t:file-list=\"fileList\"\n\t\t\t\t\tclass=\"viewer__file\"\n\t\t\t\t\t@error=\"nextFailed\" />\n\t\t\t\t<Error v-else\n\t\t\t\t\t:name=\"nextFile.basename\" />\n\t\t\t</div>\n\t\t</div>\n\t</NcModal>\n</template>\n\n<script>\nimport '@nextcloud/dialogs/style.css'\nimport Vue from 'vue'\n\nimport axios from '@nextcloud/axios'\nimport { showError } from '@nextcloud/dialogs'\nimport { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport { Node, davRemoteURL, davRootPath } from '@nextcloud/files'\nimport { loadState } from '@nextcloud/initial-state'\nimport getSortingConfig from '../services/FileSortingConfig.ts'\n\nimport isFullscreen from '@nextcloud/vue/dist/Mixins/isFullscreen.js'\nimport isMobile from '@nextcloud/vue/dist/Mixins/isMobile.js'\n\nimport { extractFilePaths, sortCompare } from '../utils/fileUtils.ts'\nimport canDownload from '../utils/canDownload.js'\nimport cancelableRequest from '../utils/CancelableRequest.js'\nimport Error from '../components/Error.vue'\nimport File from '../models/file.js'\nimport legacyFilesActionHandler from '../services/LegacyFilesActionHandler.js'\nimport getFileInfo from '../services/FileInfo.ts'\nimport getFileList from '../services/FileList.ts'\nimport Mime from '../mixins/Mime.js'\nimport logger from '../services/logger.js'\n\nimport Delete from 'vue-material-design-icons/Delete.vue'\nimport Download from 'vue-material-design-icons/Download.vue'\nimport Fullscreen from 'vue-material-design-icons/Fullscreen.vue'\nimport FullscreenExit from 'vue-material-design-icons/FullscreenExit.vue'\nimport Pencil from 'vue-material-design-icons/Pencil.vue'\n\n// Dynamic loading\nconst NcModal = () => import(\n\t/* webpackChunkName: 'components' */\n\t/* webpackPrefetch: true */\n\t'@nextcloud/vue/dist/Components/NcModal.js')\nconst NcActionLink = () => import(/* webpackChunkName: 'components' */'@nextcloud/vue/dist/Components/NcActionLink.js')\nconst NcActionButton = () => import(/* webpackChunkName: 'components' */'@nextcloud/vue/dist/Components/NcActionButton.js')\n\nexport default {\n\tname: 'Viewer',\n\n\tcomponents: {\n\t\tDelete,\n\t\tDownload,\n\t\tError,\n\t\tFullscreen,\n\t\tFullscreenExit,\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcModal,\n\t\tPencil,\n\t},\n\n\tfilters: {\n\t\tuniqueKey(file) {\n\t\t\treturn '' + file.fileid + file.source\n\t\t},\n\t},\n\n\tmixins: [isFullscreen, isMobile],\n\n\tdata() {\n\t\treturn {\n\t\t\t// Reactivity bindings\n\t\t\tViewer: OCA.Viewer,\n\t\t\tSidebar: null,\n\t\t\thandlers: OCA.Viewer.availableHandlers,\n\n\t\t\t// Viewer variables\n\t\t\tcomponents: {},\n\t\t\tmimeGroups: {},\n\t\t\tregisteredHandlers: {},\n\n\t\t\t// Files variables\n\t\t\tcurrentIndex: 0,\n\t\t\tpreviousFile: {},\n\t\t\tcurrentFile: {},\n\t\t\tcomparisonFile: null,\n\t\t\tnextFile: {},\n\t\t\tfileList: [],\n\t\t\tsortingConfig: null,\n\n\t\t\t// States\n\t\t\tisLoaded: false,\n\t\t\tinitiated: false,\n\t\t\tediting: false,\n\n\t\t\t// cancellable requests\n\t\t\tcancelRequestFile: () => {},\n\t\t\tcancelRequestFolder: () => {},\n\n\t\t\t// Flags\n\t\t\tsidebarPosition: 0,\n\t\t\tisSidebarShown: false,\n\t\t\tisFullscreenMode: false,\n\t\t\tcanSwipe: true,\n\t\t\tisStandalone: false,\n\t\t\ttheme: null,\n\t\t\tlightBackdrop: null,\n\t\t\troot: davRemoteURL,\n\t\t\thandlerId: '',\n\n\t\t\ttrapElements: [],\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tdownloadPath() {\n\t\t\treturn this.currentFile.source ?? this.currentFile.davPath\n\t\t},\n\t\thasPrevious() {\n\t\t\treturn this.fileList.length > 1\n\t\t\t\t&& (this.canLoop || !this.isStartOfList)\n\t\t},\n\t\thasNext() {\n\t\t\treturn this.fileList.length > 1\n\t\t\t\t&& (this.canLoop || !this.isEndOfList)\n\t\t},\n\t\tfile() {\n\t\t\treturn this.Viewer.file\n\t\t},\n\t\tfileInfo() {\n\t\t\treturn this.Viewer.fileInfo\n\t\t},\n\t\tcomparisonFileInfo() {\n\t\t\treturn this.Viewer.compareFileInfo\n\t\t},\n\t\tfiles() {\n\t\t\treturn this.Viewer.files\n\t\t},\n\t\tenableSidebar() {\n\t\t\treturn this.Viewer.enableSidebar\n\t\t},\n\t\tel() {\n\t\t\treturn this.Viewer.el\n\t\t},\n\t\tloadMore() {\n\t\t\treturn this.Viewer.loadMore\n\t\t},\n\t\tcanLoop() {\n\t\t\treturn this.Viewer.canLoop\n\t\t},\n\t\tcanZoom() {\n\t\t\treturn !this.Viewer.el\n\t\t},\n\t\tisStartOfList() {\n\t\t\treturn this.currentIndex === 0\n\t\t},\n\t\tisEndOfList() {\n\t\t\treturn this.currentIndex === this.fileList.length - 1\n\t\t},\n\n\t\tisImage() {\n\t\t\treturn ['image/jpeg', 'image/png', 'image/webp'].includes(this.currentFile?.mime)\n\t\t},\n\n\t\t/**\n\t\t * Returns the path to the current opened file in the sidebar.\n\t\t *\n\t\t * If the sidebar is available but closed an empty string is returned.\n\t\t * If the sidebar is not available null is returned.\n\t\t *\n\t\t * @return {string|null} the path to the current opened file in the\n\t\t *          sidebar, if any.\n\t\t */\n\t\tsidebarFile() {\n\t\t\treturn this.Sidebar && this.Sidebar.file\n\t\t},\n\t\tsidebarOpenFilePath() {\n\t\t\ttry {\n\t\t\t\tconst relativePath = this.currentFile?.davPath?.split(davRootPath)[1]\n\t\t\t\treturn relativePath?.split('/')?.map(decodeURIComponent)?.join('/')\n\t\t\t} catch (e) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Is the current user allowed to delete the file?\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tcanDelete() {\n\t\t\treturn this.currentFile?.permissions?.includes('D')\n\t\t},\n\n\t\t/**\n\t\t * Is the current user allowed to download the file in public mode?\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tcanDownload() {\n\t\t\treturn canDownload() && !this.comparisonFile\n\t\t},\n\n\t\t/**\n\t\t * Is the current user allowed to edit the file ?\n\t\t * https://github.com/nextcloud/server/blob/7718c9776c5903474b8f3cf958cdd18a53b2449e/apps/dav/lib/Connector/Sabre/Node.php#L357-L387\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tcanEdit() {\n\t\t\treturn !this.isMobile\n\t\t\t\t&& canDownload()\n\t\t\t\t&& this.currentFile?.permissions?.includes('W')\n\t\t\t\t&& this.isImage\n\t\t\t\t&& !this.comparisonFile\n\t\t\t\t&& (loadState('core', 'config', [])['enable_non-accessible_features'] ?? true)\n\t\t},\n\n\t\tmodalClass() {\n\t\t\treturn {\n\t\t\t\t'icon-loading': !this.currentFile.loaded && !this.currentFile.failed,\n\t\t\t\t'theme--undefined': this.theme === null,\n\t\t\t\t'theme--dark': this.theme === 'dark',\n\t\t\t\t'theme--light': this.theme === 'light',\n\t\t\t\t'theme--default': this.theme === 'default',\n\t\t\t\t'image--fullscreen': this.isImage && this.isFullscreenMode,\n\t\t\t}\n\t\t},\n\n\t\tshowComparison() {\n\t\t\treturn !this.isMobile\n\t\t},\n\n\t\tcontentClass() {\n\t\t\treturn {\n\t\t\t\t'viewer--split': this.comparisonFile,\n\t\t\t}\n\t\t},\n\n\t\tisSameFile() {\n\t\t\treturn (fileInfo = null, path = null) => {\n\t\t\t\tif (\n\t\t\t\t\tpath && path === this.currentFile.path\n\t\t\t\t\t&& !this.currentFile.source\n\t\t\t\t) {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\tfileInfo && fileInfo.fileid === this.currentFile.fileid\n\t\t\t\t\t&& fileInfo.mtime && fileInfo.mtime === this.currentFile.mtime\n\t\t\t\t\t&& fileInfo.source && fileInfo.source === this.currentFile.source\n\t\t\t\t) {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\n\t\t\t\treturn false\n\t\t\t}\n\t\t},\n\t},\n\n\twatch: {\n\t\tel(element) {\n\t\t\tlogger.info(element)\n\t\t\tthis.$nextTick(() => {\n\t\t\t\tconst viewerRoot = document.getElementById('viewer')\n\t\t\t\tif (element) {\n\t\t\t\t\tconst el = document.querySelector(element)\n\t\t\t\t\tif (el) {\n\t\t\t\t\t\tel.appendChild(viewerRoot)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Could not find element ', { element })\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tdocument.body.appendChild(viewerRoot)\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\tfile(path) {\n\t\t\t// we got a valid path! Load file...\n\t\t\tif (path && path.trim() !== '') {\n\t\t\t\tlogger.info('Opening viewer for file ', { path })\n\t\t\t\tthis.openFile(path, OCA.Viewer.overrideHandlerId)\n\t\t\t} else {\n\t\t\t\t// path is empty, we're closing!\n\t\t\t\tthis.cleanup()\n\t\t\t}\n\t\t},\n\n\t\tfileInfo(fileInfo) {\n\t\t\tif (fileInfo) {\n\t\t\t\tlogger.info('Opening viewer for fileInfo ', { fileInfo })\n\t\t\t\tthis.openFileInfo(fileInfo, OCA.Viewer.overrideHandlerId)\n\t\t\t} else {\n\t\t\t\t// object is undefined, we're closing!\n\t\t\t\tthis.cleanup()\n\t\t\t}\n\t\t},\n\n\t\tcomparisonFileInfo(fileInfo) {\n\t\t\tif (fileInfo) {\n\t\t\t\tlogger.info('Opening viewer for comparisonFileInfo ', { fileInfo })\n\t\t\t\tthis.compareFile(fileInfo)\n\t\t\t} else {\n\t\t\t\t// object is undefined, we're closing!\n\t\t\t\tthis.cleanup()\n\t\t\t}\n\t\t},\n\n\t\tfiles(fileList) {\n\t\t\t// the files list changed, let's update the current opened index\n\t\t\tconst currentIndex = fileList.findIndex(file => file.filename === this.currentFile.filename)\n\t\t\tif (currentIndex > -1) {\n\t\t\t\tthis.currentIndex = currentIndex\n\t\t\t\tlogger.debug('The files list changed, new current file index is ' + currentIndex)\n\t\t\t}\n\t\t\t// finally replace the fileList\n\t\t\tthis.fileList = fileList\n\t\t},\n\n\t\t// user reached the end of list\n\t\tasync isEndOfList(isEndOfList) {\n\t\t\tif (!isEndOfList) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// if we have a loadMore handler, let's fetch more files\n\t\t\tif (this.loadMore && typeof this.loadMore === 'function') {\n\t\t\t\tlogger.debug('Fetching additional files...')\n\t\t\t\tconst list = await this.loadMore()\n\n\t\t\t\tif (Array.isArray(list) && list.length > 0) {\n\t\t\t\t\tthis.fileList.push(...list)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t},\n\n\tbeforeMount() {\n\t\tthis.isStandalone = window.OCP?.Files === undefined && window.OCA?.Files?.fileActions === undefined\n\t\tif (this.isStandalone) {\n\t\t\tlogger.info('No Files app found, viewer is now in standalone mode', { ocp: window.OCP?.Files, oca: window.OCA?.Files?.fileActions })\n\t\t}\n\n\t\t// register on load\n\t\tdocument.addEventListener('DOMContentLoaded', () => {\n\t\t\t// register all primary components mimes\n\t\t\tthis.handlers.forEach(handler => {\n\t\t\t\tthis.registerHandler(handler)\n\t\t\t})\n\n\t\t\t// then register aliases. We need to have the components\n\t\t\t// first so we can bind the alias to them.\n\t\t\tthis.handlers.forEach(handler => {\n\t\t\t\tthis.registerHandlerAlias(handler)\n\t\t\t})\n\t\t\tthis.isLoaded = true\n\n\t\t\t// bind Sidebar if available\n\t\t\tif (OCA?.Files?.Sidebar) {\n\t\t\t\tthis.Sidebar = OCA.Files.Sidebar.state\n\t\t\t}\n\n\t\t\tlogger.info(`${this.handlers.length} viewer handlers registered`, { handlers: this.handlers })\n\t\t})\n\n\t\twindow.addEventListener('resize', this.onResize)\n\t},\n\n\tmounted() {\n\t\t// React to Files' Sidebar events.\n\t\tsubscribe('files:sidebar:opened', this.handleAppSidebarOpen)\n\t\tsubscribe('files:sidebar:closed', this.handleAppSidebarClose)\n\t\tsubscribe('files:node:updated', this.handleFileUpdated)\n\t\tsubscribe('viewer:trapElements:changed', this.handleTrapElementsChange)\n\t\twindow.addEventListener('keydown', this.keyboardDeleteFile)\n\t\twindow.addEventListener('keydown', this.keyboardDownloadFile)\n\t\twindow.addEventListener('keydown', this.keyboardEditFile)\n\t\tthis.addFullscreenEventListeners()\n\t},\n\n\tbeforeDestroy() {\n\t\twindow.removeEventListener('resize', this.onResize)\n\t},\n\n\tdestroyed() {\n\t\t// Unsubscribe to Files Sidebar events.\n\t\tunsubscribe('files:sidebar:opened', this.handleAppSidebarOpen)\n\t\tunsubscribe('files:sidebar:closed', this.handleAppSidebarClose)\n\t\tunsubscribe('viewer:trapElements:changed', this.handleTrapElementsChange)\n\t\twindow.removeEventListener('keydown', this.keyboardDeleteFile)\n\t\twindow.removeEventListener('keydown', this.keyboardDownloadFile)\n\t\twindow.removeEventListener('keydown', this.keyboardEditFile)\n\t\tthis.removeFullscreenEventListeners()\n\t},\n\n\tmethods: {\n\t\tasync beforeOpen() {\n\t\t\t// initial loading start\n\t\t\tthis.initiated = true\n\n\t\t\tif (OCA?.Files?.Sidebar?.setFullScreenMode) {\n\t\t\t\tOCA.Files.Sidebar.setFullScreenMode(true)\n\t\t\t}\n\t\t\tthis.sortingConfig = await getSortingConfig()\n\n\t\t\t// Load Roboto font for visual regression tests\n\t\t\tif (window.loadRoboto) {\n\t\t\t\tlogger.debug('⚠️ Loading roboto font for visual regression tests')\n\t\t\t\timport('@fontsource/roboto/index.css')\n\t\t\t\tdelete window.loadRoboto\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Open the view and display the clicked file\n\t\t *\n\t\t * @param {string} path the file path to open\n\t\t * @param {string|null} overrideHandlerId the ID of the handler with which to view the files, if any\n\t\t */\n\t\tasync openFile(path, overrideHandlerId = null) {\n\t\t\tawait this.beforeOpen()\n\n\t\t\t// cancel any previous request\n\t\t\tthis.cancelRequestFile()\n\n\t\t\t// do not open the same file again\n\t\t\tif (this.isSameFile(null, path)) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst { request: fileRequest, cancel: cancelRequestFile } = cancelableRequest(getFileInfo)\n\t\t\tthis.cancelRequestFile = cancelRequestFile\n\n\t\t\t// extract needed info from path\n\t\t\tconst [, fileName] = extractFilePaths(path)\n\n\t\t\t// prevent scrolling while opened\n\t\t\tif (!this.el) {\n\t\t\t\tdocument.body.style.overflow = 'hidden'\n\t\t\t\tdocument.documentElement.style.overflow = 'hidden'\n\t\t\t}\n\n\t\t\t// swap title with original one\n\t\t\tconst title = document.getElementsByTagName('head')[0].getElementsByTagName('title')[0]\n\t\t\tif (title && !title.dataset.old) {\n\t\t\t\ttitle.dataset.old = document.title\n\t\t\t\tthis.updateTitle(fileName)\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t// retrieve and store the file info\n\t\t\t\tconst fileInfo = await fileRequest(path)\n\t\t\t\tconsole.debug('File info for ' + path + ' fetched', fileInfo)\n\t\t\t\tawait this.openFileInfo(fileInfo, overrideHandlerId)\n\t\t\t} catch (error) {\n\t\t\t\tif (error?.response?.status === 404) {\n\t\t\t\t\tlogger.error('The file no longer exists, error: ', { error })\n\t\t\t\t\tshowError(t('viewer', 'This file no longer exists'))\n\t\t\t\t\tthis.close()\n\t\t\t\t} else {\n\t\t\t\t\tconsole.error('Could not open file ' + path, error)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Open the view and display the clicked file from a known file info object\n\t\t *\n\t\t * @param {object} fileInfo the file info object to open\n\t\t * @param {string|null} overrideHandlerId the ID of the handler with which to view the files, if any\n\t\t */\n\t\tasync openFileInfo(fileInfo, overrideHandlerId = null) {\n\t\t\tthis.beforeOpen()\n\t\t\t// cancel any previous request\n\t\t\tthis.cancelRequestFolder()\n\n\t\t\t// do not open the same file info again\n\t\t\tif (this.isSameFile(fileInfo)) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// get original mime and alias\n\t\t\tconst mime = fileInfo.mime\n\t\t\tconst alias = mime.split('/')[0]\n\n\t\t\tlet handler\n\t\t\t// Try provided handler, if any\n\t\t\tif (overrideHandlerId !== null) {\n\t\t\t\tconst overrideHandler = Object.values(this.registeredHandlers).find(h => h.id === overrideHandlerId)\n\t\t\t\thandler = overrideHandler ?? handler\n\t\t\t}\n\t\t\t// If no provided handler, or provided handler not found: try a supported handler with mime/mime-alias\n\t\t\tif (!handler) {\n\t\t\t\thandler = this.registeredHandlers[mime] ?? this.registeredHandlers[alias]\n\t\t\t}\n\n\t\t\t// if we don't have a handler for this mime, abort\n\t\t\tif (!handler) {\n\t\t\t\tlogger.error('The following file could not be displayed', { fileInfo })\n\t\t\t\tshowError(t('viewer', 'There is no plugin available to display this file type'))\n\t\t\t\tthis.close()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tthis.theme = handler.theme ?? 'dark'\n\t\t\tconst defaultThemeIsLight = window.getComputedStyle(document.body).getPropertyValue('--background-invert-if-dark') !== 'invert(100%)'\n\t\t\tthis.lightBackdrop = handler.theme === 'light' || (handler.theme === 'default' && defaultThemeIsLight)\n\t\t\tthis.handlerId = handler.id\n\n\t\t\t// check if part of a group, if so retrieve full files list\n\t\t\tconst group = this.mimeGroups[mime]\n\t\t\tif (this.files && this.files.length > 0) {\n\t\t\t\tlogger.debug('A files list have been provided. No folder content will be fetched.')\n\t\t\t\t// we won't sort files here, let's use the order the array has\n\t\t\t\tthis.fileList = this.files\n\n\t\t\t\t// store current position\n\t\t\t\tthis.currentIndex = this.fileList.findIndex(file => file.filename === fileInfo.filename)\n\t\t\t} else if (group && this.el === null) {\n\t\t\t\tconst mimes = this.mimeGroups[group]\n\t\t\t\t\t? this.mimeGroups[group]\n\t\t\t\t\t: [mime]\n\n\t\t\t\t// retrieve folder list\n\t\t\t\tconst { request: folderRequest, cancel: cancelRequestFolder } = cancelableRequest(getFileList)\n\t\t\t\tthis.cancelRequestFolder = cancelRequestFolder\n\t\t\t\tconst [dirPath] = extractFilePaths(fileInfo.filename)\n\t\t\t\tconst fileList = await folderRequest(dirPath)\n\n\t\t\t\t// filter out the unwanted mimes\n\t\t\t\tconst filteredFiles = fileList.filter(file => file.mime && mimes.indexOf(file.mime) !== -1)\n\n\t\t\t\t// sort like the files list\n\t\t\t\t// TODO: implement global sorting API\n\t\t\t\t// https://github.com/nextcloud/server/blob/a83b79c5f8ab20ed9b4d751167417a65fa3c42b8/apps/files/lib/Controller/ApiController.php#L247\n\t\t\t\tthis.fileList = filteredFiles.sort((a, b) => sortCompare(a, b, this.sortingConfig.key, this.sortingConfig.asc))\n\n\t\t\t\t// store current position\n\t\t\t\tthis.currentIndex = this.fileList.findIndex(file => file.filename === fileInfo.filename)\n\t\t\t} else {\n\t\t\t\tthis.currentIndex = 0\n\t\t\t\tthis.fileList = [fileInfo]\n\t\t\t}\n\n\t\t\t// get saved fileInfo\n\t\t\tfileInfo = this.fileList[this.currentIndex]\n\n\t\t\t// show file\n\t\t\tthis.currentFile = new File(fileInfo, mime, handler.component)\n\t\t\tthis.comparisonFile = null\n\t\t\tthis.updatePreviousNext()\n\n\t\t\t// if sidebar was opened before, let's update the file\n\t\t\tthis.changeSidebar()\n\t\t},\n\n\t\t/**\n\t\t * Open the view and display the file from the file list\n\t\t *\n\t\t * @param {object} fileInfo the opened file info\n\t\t */\n\t\topenFileFromList(fileInfo) {\n\t\t\t// override mimetype if existing alias\n\t\t\tconst mime = fileInfo.mime\n\t\t\tthis.currentFile = new File(fileInfo, mime, this.components[mime])\n\t\t\tthis.changeSidebar()\n\t\t\tthis.updatePreviousNext()\n\t\t},\n\n\t\tasync compareFile(fileInfo) {\n\t\t\tthis.comparisonFile = new File(fileInfo, fileInfo.mime, this.components[fileInfo.mime])\n\t\t},\n\n\t\t/**\n\t\t * Show sidebar if available and a file is already opened\n\t\t */\n\t\tchangeSidebar() {\n\t\t\tif (this.sidebarFile) {\n\t\t\t\tthis.showSidebar()\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Update the previous and next file components\n\t\t */\n\t\tupdatePreviousNext() {\n\t\t\tconst prev = this.fileList[this.currentIndex - 1]\n\t\t\tconst next = this.fileList[this.currentIndex + 1]\n\n\t\t\tif (prev) {\n\t\t\t\tconst mime = prev.mime\n\t\t\t\tif (this.components[mime]) {\n\t\t\t\t\tthis.previousFile = new File(prev, mime, this.components[mime])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// RESET\n\t\t\t\tthis.previousFile = null\n\t\t\t}\n\n\t\t\tif (next) {\n\t\t\t\tconst mime = next.mime\n\t\t\t\tif (this.components[mime]) {\n\t\t\t\t\tthis.nextFile = new File(next, mime, this.components[mime])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// RESET\n\t\t\t\tthis.nextFile = null\n\t\t\t}\n\n\t\t},\n\n\t\tupdateTitle(fileName) {\n\t\t\tdocument.title = `${fileName} - ${OCA.Theming?.name ?? oc_defaults.name}`\n\t\t},\n\n\t\t/**\n\t\t * Registering possible new handers\n\t\t *\n\t\t * @param {object} handler the handler to register\n\t\t * @param {string} handler.id unique handler identifier\n\t\t * @param {Array} handler.mimes list of valid mimes compatible with the handler\n\t\t * @param {object} handler.component a vuejs component to render when a file matching the mime list is opened\n\t\t * @param {string} [handler.group] a group name to be associated with for the slideshow\n\t\t */\n\t\tregisterHandler(handler) {\n\t\t\t// checking if handler is not already registered\n\t\t\tif (handler.id && Object.values(this.registeredHandlers).findIndex((h) => h.id === handler.id) > -1) {\n\t\t\t\tlogger.error('The following handler is already registered', { handler })\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// checking valid handler id\n\t\t\tif (!handler.id || handler.id.trim() === '' || typeof handler.id !== 'string') {\n\t\t\t\tlogger.error('The following handler doesn\\'t have a valid id', { handler })\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// checking if no valid mimes data but alias. If so, skipping...\n\t\t\tif (!(handler.mimes && Array.isArray(handler.mimes)) && handler.mimesAliases) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Nothing available to process! Failure\n\t\t\tif (!(handler.mimes && Array.isArray(handler.mimes)) && !handler.mimesAliases) {\n\t\t\t\tlogger.error('The following handler doesn\\'t have a valid mime array', { handler })\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// checking valid handler component data\n\t\t\tif ((!handler.component || (typeof handler.component !== 'object' && typeof handler.component !== 'function'))) {\n\t\t\t\tlogger.error('The following handler doesn\\'t have a valid component', { handler })\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// force apply mixin\n\t\t\thandler.component.mixins = [...handler?.component?.mixins ?? [], Mime]\n\n\t\t\t// parsing mimes registration\n\t\t\tif (handler.mimes) {\n\t\t\t\thandler.mimes.forEach(mime => {\n\t\t\t\t\t// checking valid mime\n\t\t\t\t\tif (this.components[mime]) {\n\t\t\t\t\t\tlogger.error('The following mime is already registered', { mime, handler })\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\t// register file action and groups\n\t\t\t\t\tthis.registerLegacyAction({ mime, group: handler.group })\n\t\t\t\t\t// register groups\n\t\t\t\t\tthis.registerGroups({ mime, group: handler.group })\n\n\t\t\t\t\t// register mime's component\n\t\t\t\t\tthis.components[mime] = handler.component\n\t\t\t\t\tVue.component(handler.component.name, handler.component)\n\n\t\t\t\t\t// set the handler as registered\n\t\t\t\t\tthis.registeredHandlers[mime] = handler\n\t\t\t\t})\n\t\t\t}\n\t\t},\n\n\t\tregisterHandlerAlias(handler) {\n\t\t\t// parsing aliases registration\n\t\t\tif (handler.mimesAliases) {\n\t\t\t\tObject.keys(handler.mimesAliases).forEach(mime => {\n\n\t\t\t\t\tif (handler.mimesAliases && typeof handler.mimesAliases !== 'object') {\n\t\t\t\t\t\tlogger.error('The following handler doesn\\'t have a valid mimesAliases object', { handler })\n\t\t\t\t\t\treturn\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// this is the targeted alias\n\t\t\t\t\tconst alias = handler.mimesAliases[mime]\n\n\t\t\t\t\t// checking valid mime\n\t\t\t\t\tif (this.components[mime]) {\n\t\t\t\t\t\tlogger.error('The following mime is already registered', { mime, handler })\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tif (!this.components[alias]) {\n\t\t\t\t\t\tlogger.error('The requested alias does not exists', { alias, mime, handler })\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\t// register file action and groups if the request alias had a group\n\t\t\t\t\tthis.registerLegacyAction({ mime, group: this.mimeGroups[alias] })\n\t\t\t\t\t// register groups if the request alias had a group\n\t\t\t\t\tthis.registerGroups({ mime, group: this.mimeGroups[alias] })\n\n\t\t\t\t\t// register mime's component\n\t\t\t\t\tthis.components[mime] = this.components[alias]\n\n\t\t\t\t\t// set the handler as registered\n\t\t\t\t\tthis.registeredHandlers[mime] = handler\n\t\t\t\t})\n\t\t\t}\n\t\t},\n\n\t\tregisterLegacyAction({ mime, group }) {\n\t\t\tif (!this.isStandalone && OCA?.Files?.fileActions) {\n\t\t\t\t// unregistered handler, let's go!\n\t\t\t\tOCA.Files.fileActions.registerAction({\n\t\t\t\t\tname: 'view',\n\t\t\t\t\tdisplayName: t('viewer', 'View'),\n\t\t\t\t\tmime,\n\t\t\t\t\tpermissions: OC.PERMISSION_READ,\n\t\t\t\t\tactionHandler: legacyFilesActionHandler,\n\t\t\t\t})\n\t\t\t\tOCA.Files.fileActions.setDefault(mime, 'view')\n\t\t\t\tlogger.debug('Legacy file action registered for mime ' + mime, { mime, group })\n\t\t\t}\n\n\t\t\t// register groups\n\t\t\tif (group) {\n\t\t\t\tthis.mimeGroups[mime] = group\n\t\t\t\t// init if undefined\n\t\t\t\tif (!this.mimeGroups[group]) {\n\t\t\t\t\tthis.mimeGroups[group] = []\n\t\t\t\t}\n\t\t\t\tthis.mimeGroups[group].push(mime)\n\t\t\t}\n\t\t},\n\n\t\tregisterGroups({ mime, group }) {\n\t\t\tif (group) {\n\t\t\t\tthis.mimeGroups[mime] = group\n\t\t\t\t// init if undefined\n\t\t\t\tif (!this.mimeGroups[group]) {\n\t\t\t\t\tthis.mimeGroups[group] = []\n\t\t\t\t}\n\t\t\t\tthis.mimeGroups[group].push(mime)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Close the viewer\n\t\t */\n\t\tclose() {\n\t\t\t// This will set file to ''\n\t\t\t// which then triggers cleanup.\n\t\t\tOCA.Viewer.close()\n\n\t\t\tif (OCA?.Files?.Sidebar) {\n\t\t\t\tOCA.Files.Sidebar.setFullScreenMode(false)\n\t\t\t}\n\n\t\t\tif (this.isFullscreenMode) {\n\t\t\t\tthis.exitFullscreen()\n\t\t\t}\n\t\t},\n\n\t\tkeyboardDeleteFile(event) {\n\t\t\tif (this.canDelete && event.key === 'Delete' && event.ctrlKey === true) {\n\t\t\t\tthis.onDelete()\n\t\t\t}\n\t\t},\n\n\t\tkeyboardDownloadFile(event) {\n\t\t\tif (event.key === 's' && event.ctrlKey === true) {\n\t\t\t\tevent.preventDefault()\n\t\t\t\tif (this.canDownload) {\n\t\t\t\t\tconst a = document.createElement('a')\n\t\t\t\t\ta.href = this.currentFile.davPath\n\t\t\t\t\ta.download = this.currentFile.basename\n\t\t\t\t\tdocument.body.appendChild(a)\n\t\t\t\t\ta.click()\n\t\t\t\t\tdocument.body.removeChild(a)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tkeyboardEditFile(event) {\n\t\t\tif (event.key === 'e' && event.ctrlKey === true) {\n\t\t\t\tevent.preventDefault()\n\t\t\t\tif (this.canEdit) {\n\t\t\t\t\tthis.onEdit()\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tcleanup() {\n\t\t\t// reset all properties\n\t\t\tthis.currentFile = {}\n\t\t\tthis.comparisonFile = null\n\t\t\tthis.currentModal = null\n\t\t\tthis.fileList = []\n\t\t\tthis.initiated = false\n\t\t\tthis.theme = null\n\n\t\t\t// cancel requests\n\t\t\tthis.cancelRequestFile()\n\t\t\tthis.cancelRequestFolder()\n\n\t\t\t// restore default\n\t\t\tdocument.body.style.overflow = null\n\t\t\tdocument.documentElement.style.overflow = null\n\n\t\t\t// Callback before updating the title\n\t\t\t// If the callback creates a new entry in browser history\n\t\t\t// the title update will affect the new entry\n\t\t\t// rather then the previous one.\n\t\t\tthis.Viewer.onClose()\n\n\t\t\t// swap back original title\n\t\t\tconst title = document.getElementsByTagName('head')[0].getElementsByTagName('title')[0]\n\t\t\tif (title && title.dataset.old) {\n\t\t\t\tdocument.title = title.dataset.old\n\t\t\t\tdelete title.dataset.old\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Open previous available file\n\t\t */\n\t\tprevious() {\n\t\t\tthis.currentIndex--\n\t\t\tif (this.currentIndex < 0) {\n\t\t\t\tthis.currentIndex = this.fileList.length - 1\n\t\t\t}\n\n\t\t\tconst fileInfo = this.fileList[this.currentIndex]\n\t\t\tthis.openFileFromList(fileInfo)\n\t\t\tthis.Viewer.onPrev(fileInfo)\n\t\t\tthis.updateTitle(this.currentFile.basename)\n\t\t},\n\n\t\t/**\n\t\t * Open next available file\n\t\t */\n\t\tnext() {\n\t\t\tthis.currentIndex++\n\t\t\tif (this.currentIndex > this.fileList.length - 1) {\n\t\t\t\tthis.currentIndex = 0\n\t\t\t}\n\n\t\t\tconst fileInfo = this.fileList[this.currentIndex]\n\t\t\tthis.openFileFromList(fileInfo)\n\t\t\tthis.Viewer.onNext(fileInfo)\n\n\t\t\tthis.updateTitle(this.currentFile.basename)\n\t\t},\n\n\t\t/**\n\t\t * Failures handlers\n\t\t */\n\t\tcomparisonFailed() {\n\t\t\tthis.comparisonFile.failed = true\n\t\t},\n\n\t\tpreviousFailed() {\n\t\t\tthis.previousFile.failed = true\n\t\t},\n\n\t\tcurrentFailed() {\n\t\t\tthis.currentFile.failed = true\n\t\t},\n\n\t\tnextFailed() {\n\t\t\tthis.nextFile.failed = true\n\t\t},\n\n\t\t/**\n\t\t * Show the sharing sidebar\n\t\t */\n\n\t\tasync showSidebar() {\n\t\t\t// Open the sidebar sharing tab\n\t\t\t// TODO: also hide figure, needs a proper method for it in server Sidebar\n\n\t\t\tif (this.enableSidebar && OCA?.Files?.Sidebar) {\n\t\t\t\tawait OCA.Files.Sidebar.open(this.sidebarOpenFilePath)\n\t\t\t}\n\t\t},\n\n\t\thandleAppSidebarOpen() {\n\t\t\tthis.isSidebarShown = true\n\t\t\tconst sidebar = document.querySelector('aside.app-sidebar')\n\t\t\tif (sidebar) {\n\t\t\t\tthis.sidebarPosition = sidebar.getBoundingClientRect().left\n\t\t\t\tthis.trapElements = [sidebar]\n\t\t\t}\n\t\t},\n\n\t\thandleAppSidebarClose() {\n\t\t\tthis.isSidebarShown = false\n\t\t\tthis.trapElements = []\n\t\t},\n\n\t\t// Update etag of updated file to break cache.\n\t\t/**\n\t\t *\n\t\t * @param {Node} node\n\t\t */\n\t\tasync handleFileUpdated(node) {\n\t\t\tconst index = this.fileList.findIndex(({ fileid: currentFileId }) => currentFileId === node.fileid)\n\n\t\t\t// Ensure compatibility with the legacy data model that the Viewer is using. (see \"model.ts\").\n\t\t\t// This can be removed once Viewer is migrated to the new Node API.\n\t\t\tnode.etag = node.attributes.etag\n\t\t\tthis.fileList.splice(index, 1, node)\n\t\t\tif (node.fileid === this.currentFile.fileid) {\n\t\t\t\tthis.currentFile.etag = node.attributes.etag\n\t\t\t}\n\t\t},\n\n\t\tonResize() {\n\t\t\tconst sidebar = document.querySelector('aside.app-sidebar')\n\t\t\tif (sidebar) {\n\t\t\t\tthis.sidebarPosition = sidebar.getBoundingClientRect().left\n\t\t\t}\n\t\t},\n\n\t\tasync onDelete() {\n\t\t\ttry {\n\t\t\t\tconst fileid = this.currentFile.fileid\n\t\t\t\tconst url = this.source ?? this.currentFile.davPath\n\n\t\t\t\tawait axios.delete(url)\n\t\t\t\temit('files:node:deleted', { fileid })\n\n\t\t\t\t// fileid is not unique, basename is not unqiue, filename is\n\t\t\t\tconst currentIndex = this.fileList.findIndex(file => file.filename === this.currentFile.filename)\n\t\t\t\tif (this.hasPrevious || this.hasNext) {\n\t\t\t\t\t// Checking the previous or next file\n\t\t\t\t\tthis.hasPrevious ? this.previous() : this.next()\n\n\t\t\t\t\tthis.fileList.splice(currentIndex, 1)\n\t\t\t\t} else {\n\t\t\t\t\tthis.close()\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(error)\n\t\t\t\tshowError(error)\n\t\t\t}\n\t\t},\n\n\t\tonEdit() {\n\t\t\tthis.editing = true\n\t\t},\n\n\t\thandleTrapElementsChange(element) {\n\t\t\tthis.trapElements.push(element)\n\t\t},\n\n\t\t// Support full screen API on standard-compliant browsers and Safari (apparently except iPhone).\n\t\t// Implementation based on:\n\t\t//   https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API/Guide\n\n\t\ttoggleFullScreen() {\n\t\t\tif (this.isFullscreenMode) {\n\t\t\t\tthis.exitFullscreen()\n\t\t\t} else {\n\t\t\t\tthis.requestFullscreen()\n\t\t\t}\n\t\t},\n\n\t\trequestFullscreen() {\n\t\t\tconst el = document.documentElement\n\t\t\tif (el.requestFullscreen) {\n\t\t\t\tel.requestFullscreen()\n\t\t\t} else if (el.webkitRequestFullscreen) {\n\t\t\t\tel.webkitRequestFullscreen()\n\t\t\t}\n\t\t},\n\n\t\texitFullscreen() {\n\t\t\tif (document.exitFullscreen) {\n\t\t\t\tdocument.exitFullscreen()\n\t\t\t} else if (document.webkitExitFullscreen) {\n\t\t\t\tdocument.webkitExitFullscreen()\n\t\t\t}\n\t\t},\n\n\t\taddFullscreenEventListeners() {\n\t\t\tdocument.addEventListener('fullscreenchange', this.onFullscreenchange)\n\t\t\tdocument.addEventListener('webkitfullscreenchange', this.onFullscreenchange)\n\t\t},\n\n\t\tremoveFullscreenEventListeners() {\n\t\t\tdocument.addEventListener('fullscreenchange', this.onFullscreenchange)\n\t\t\tdocument.addEventListener('webkitfullscreenchange', this.onFullscreenchange)\n\t\t},\n\n\t\tonFullscreenchange() {\n\t\t\tif (document.fullscreenElement === document.documentElement\n\t\t\t\t|| document.webkitFullscreenElement === document.documentElement) {\n\t\t\t\tthis.isFullscreenMode = true\n\t\t\t} else {\n\t\t\t\tthis.isFullscreenMode = false\n\t\t\t}\n\t\t},\n\n\t},\n}\n</script>\n\n<style lang=\"scss\" scoped>\n.viewer {\n\t&.modal-mask {\n\t\ttransition: width ease 100ms, background-color .3s ease;\n\t}\n\n\t:deep(.modal-container),\n\t&__content {\n\t\toverflow: visible !important;\n\t\tcursor: pointer;\n\t}\n\n\t&--split {\n\t\tdisplay: flex;\n\n\t\t.viewer__file--active {\n\t\t\twidth: 50%;\n\t\t\tleft: 0;\n\t\t\tposition: relative;\n\t\t}\n\t}\n\n\t:deep(.modal-wrapper) {\n\t\t.modal-container {\n\t\t\t// Ensure some space at the bottom\n\t\t\ttop: var(--header-height);\n\t\t\tbottom: var(--header-height);\n\t\t\theight: auto;\n\t\t\t// let the mime components manage their own background-color\n\t\t\tbackground-color: transparent;\n\t\t\tbox-shadow: none;\n\t\t}\n\t}\n\n\t&__content {\n\t\twidth: 100%;\n\t\theight: 100%;\n\t}\n\n\t&__file-wrapper {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\twidth: 100%;\n\t\theight: 100%;\n\n\t\t// display on page but make it invisible\n\t\t&--hidden {\n\t\t\tposition: absolute;\n\t\t\tz-index: -1;\n\t\t\tleft: -10000px;\n\t\t}\n\t}\n\n\t&__file {\n\t\ttransition: height 100ms ease,\n\t\t\twidth 100ms ease;\n\t}\n\n\t&.theme--dark:deep(.button-vue--vue-tertiary) {\n\t\t&:hover {\n\t\t\tbackground-color: rgba(255, 255, 255, .08) !important;\n\t\t}\n\t\t&:focus,\n\t\t&:focus-visible {\n\t\t\tbackground-color: rgba(255, 255, 255, .08) !important;\n\t\t\toutline: 2px solid var(--color-primary-element) !important;\n\t\t}\n\t\t&.action-item__menutoggle {\n\t\t\tbackground-color: transparent;\n\t\t}\n\t}\n\n\t&.theme--undefined.modal-mask {\n\t\tbackground-color: transparent !important;\n\t}\n\n\t&.theme--light {\n\t\t&.modal-mask {\n\t\t\tbackground-color: rgba(255, 255, 255, .92) !important;\n\t\t}\n\t\t:deep(.modal-header__name),\n\t\t:deep(.modal-header .icons-menu button svg) {\n\t\t\tcolor: #000 !important;\n\t\t}\n\t}\n\n\t&.theme--default {\n\t\t&.modal-mask {\n\t\t\tbackground-color: var(--color-main-background) !important;\n\t\t}\n\t\t:deep(.modal-header__name),\n\t\t:deep(.modal-header .icons-menu) {\n\t\t\tcolor: var(--color-main-text) !important;\n\n\t\t\tbutton svg, a {\n\t\t\t\tcolor: var(--color-main-text) !important;\n\t\t\t}\n\t\t}\n\t}\n\n\t&.image--fullscreen {\n\t\t// Special display mode for images in full screen\n\t\t:deep(.modal-header) {\n\t\t\t.modal-header__name {\n\t\t\t\t// Hide file name\n\t\t\t\topacity: 0;\n\t\t\t}\n\t\t\t.icons-menu {\n\t\t\t\t// Semi-transparent background for icons only\n\t\t\t\tbackground-color: rgba(0, 0, 0, 0.2);\n\t\t\t}\n\t\t}\n\t\t:deep(.modal-wrapper) {\n\t\t\t.modal-container {\n\t\t\t\t// Use entire screen height\n\t\t\t\ttop: 0;\n\t\t\t\tbottom: 0;\n\t\t\t\theight: 100%;\n\t\t\t}\n\t\t}\n\t}\n}\n\n</style>\n\n<style lang=\"scss\">\n.component-fade-enter-active,\n.component-fade-leave-active {\n\ttransition: opacity .3s ease;\n}\n\n.component-fade-enter, .component-fade-leave-to {\n\topacity: 0;\n}\n\n// force white icon on single buttons\n#viewer.modal-mask--dark .action-item--single.icon-menu-sidebar {\n\tbackground-image: url('../assets/menu-sidebar-white.svg');\n}\n\n#viewer.modal-mask--dark .action-item--single.icon-download {\n\tbackground-image: var(--icon-download-fff);\n}\n\n// put autocomplete over full sidebar\n// TODO: remove when new sharing sidebar (18)\n// is the min-version of viewer\n.ui-autocomplete {\n\tz-index: 2050 !important;\n}\n\n</style>\n","/**\n * @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>\n *\n * @author John Molakvoæ <skjnldsv@protonmail.com>\n *\n * @license AGPL-3.0-or-later\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n *\n */\nimport { t } from '@nextcloud/l10n'\nimport Vue from 'vue'\n\nimport ViewerComponent from './views/Viewer.vue'\n\nVue.mixin({\n\tmethods: {\n\t\tt,\n\t},\n})\n\nVue.prototype.OC = window.OC\nVue.prototype.OCA = window.OCA\n\n// Create document root\nconst ViewerRoot = document.createElement('div')\nViewerRoot.id = 'viewer'\ndocument.body.appendChild(ViewerRoot)\n\n// Put controls for video viewer\n// Needed as Firefox CSP blocks the loading of the svg through the normal plyr system\nconst VideoControls = document.createElement('div')\nVideoControls.innerHTML = PLYR_ICONS\nVideoControls.style.display = 'none'\ndocument.body.appendChild(VideoControls)\n\n// Init vue\nexport default new Vue({\n\tel: '#viewer',\n\t// When debugging the page, it's easier to find which app\n\t// is which. Especially when there is multiple apps\n\t// roots mounted o the same page!\n\t// eslint-disable-next-line vue/match-component-file-name\n\tname: 'ViewerRoot',\n\trender: h => h(ViewerComponent),\n})\n"],"file":"js/viewer-main.mjs"}

Zerion Mini Shell 1.0