diff options
author | John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com> | 2020-10-04 13:49:57 +0200 |
---|---|---|
committer | John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com> | 2020-10-07 09:40:59 +0200 |
commit | 4de6e807714560329e55c3ed09d6ff029a1eb6df (patch) | |
tree | f79cad4ba84ca7c54503e53eea4c15bba9d58a5b /apps/files/src | |
parent | 843d799a2e2c884026883e3f41b81066801a877d (diff) | |
download | nextcloud-server-4de6e807714560329e55c3ed09d6ff029a1eb6df.tar.gz nextcloud-server-4de6e807714560329e55c3ed09d6ff029a1eb6df.zip |
Upgrade lifecycle and vue parent context
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
Signed-off-by: npmbuildbot[bot] <npmbuildbot[bot]@users.noreply.github.com>
Diffstat (limited to 'apps/files/src')
-rw-r--r-- | apps/files/src/components/SidebarTab.vue | 56 | ||||
-rw-r--r-- | apps/files/src/models/Tab.js | 36 | ||||
-rw-r--r-- | apps/files/src/sidebar.js | 2 | ||||
-rw-r--r-- | apps/files/src/views/Sidebar.vue | 81 |
4 files changed, 106 insertions, 69 deletions
diff --git a/apps/files/src/components/SidebarTab.vue b/apps/files/src/components/SidebarTab.vue index ecf04e9c9b3..1fc93486bc0 100644 --- a/apps/files/src/components/SidebarTab.vue +++ b/apps/files/src/components/SidebarTab.vue @@ -23,21 +23,28 @@ <template> <AppSidebarTab :id="id" + ref="tab" :name="name" :icon="icon"> + <!-- Fallback loading --> + <EmptyContent v-if="loading" icon="icon-loading" /> + <!-- Using a dummy div as Vue mount replace the element directly It does NOT append to the content --> - <div ref="mount"></div> + <div ref="mount" /> </AppSidebarTab> </template> <script> import AppSidebarTab from '@nextcloud/vue/dist/Components/AppSidebarTab' +import EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent' + export default { name: 'SidebarTab', components: { AppSidebarTab, + EmptyContent, }, props: { @@ -58,36 +65,61 @@ export default { type: String, required: true, }, - render: { + + /** + * Lifecycle methods. + * They are prefixed with `on` to avoid conflict with Vue + * methods like this.destroy + */ + onMount: { type: Function, required: true, }, + onUpdate: { + type: Function, + required: true, + }, + onDestroy: { + type: Function, + required: true, + }, + }, + + data() { + return { + loading: true, + } }, computed: { - // TODO: implement a better way to force pass a prop fromm Sidebar + // TODO: implement a better way to force pass a prop from Sidebar activeTab() { return this.$parent.activeTab }, }, watch: { - fileInfo(newFile, oldFile) { + async fileInfo(newFile, oldFile) { + // Update fileInfo on change if (newFile.id !== oldFile.id) { - this.mountTab() + this.loading = true + await this.onUpdate(this.fileInfo) + this.loading = false } }, }, - mounted() { - this.mountTab() + async mounted() { + this.loading = true + // Mount the tab: mounting point, fileInfo, vue context + await this.onMount(this.$refs.mount, this.fileInfo, this.$refs.tab) + this.loading = false }, - methods: { - mountTab() { - // Mount the tab into this component - this.render(this.$refs.mount, this.fileInfo) - }, + async beforeDestroy() { + // unmount the tab + await this.onDestroy() }, + } </script> diff --git a/apps/files/src/models/Tab.js b/apps/files/src/models/Tab.js index 753b9c9c282..2c587e5f70a 100644 --- a/apps/files/src/models/Tab.js +++ b/apps/files/src/models/Tab.js @@ -25,7 +25,9 @@ export default class Tab { #id #name #icon - #render + #mount + #update + #destroy #enabled /** @@ -35,10 +37,12 @@ export default class Tab { * @param {string} options.id the unique id of this tab * @param {string} options.name the translated tab name * @param {string} options.icon the vue component - * @param {Function} options.render function to render the tab + * @param {Function} options.mount function to mount the tab + * @param {Function} options.update function to update the tab + * @param {Function} options.destroy function to destroy the tab * @param {Function} [options.enabled] define conditions whether this tab is active. Must returns a boolean */ - constructor({ id, name, icon, render, enabled }) { + constructor({ id, name, icon, mount, update, destroy, enabled } = {}) { if (enabled === undefined) { enabled = () => true } @@ -53,8 +57,14 @@ export default class Tab { if (typeof icon !== 'string' || icon.trim() === '') { throw new Error('The icon argument is not a valid string') } - if (typeof render !== 'function') { - throw new Error('The render argument should be a function') + if (typeof mount !== 'function') { + throw new Error('The mount argument should be a function') + } + if (typeof update !== 'function') { + throw new Error('The update argument should be a function') + } + if (typeof destroy !== 'function') { + throw new Error('The destroy argument should be a function') } if (typeof enabled !== 'function') { throw new Error('The enabled argument should be a function') @@ -63,7 +73,9 @@ export default class Tab { this.#id = id this.#name = name this.#icon = icon - this.#render = render + this.#mount = mount + this.#update = update + this.#destroy = destroy this.#enabled = enabled } @@ -80,8 +92,16 @@ export default class Tab { return this.#icon } - get render() { - return this.#render + get mount() { + return this.#mount + } + + get update() { + return this.#update + } + + get destroy() { + return this.#destroy } get enabled() { diff --git a/apps/files/src/sidebar.js b/apps/files/src/sidebar.js index 508093465d4..54293bd24c8 100644 --- a/apps/files/src/sidebar.js +++ b/apps/files/src/sidebar.js @@ -21,6 +21,8 @@ */ import Vue from 'vue' +import { translate as t } from '@nextcloud/l10n' + import SidebarView from './views/Sidebar.vue' import Sidebar from './services/Sidebar' import Tab from './models/Tab' diff --git a/apps/files/src/views/Sidebar.vue b/apps/files/src/views/Sidebar.vue index 6fa5c35dca2..664bc6f4075 100644 --- a/apps/files/src/views/Sidebar.vue +++ b/apps/files/src/views/Sidebar.vue @@ -52,33 +52,38 @@ </template> <!-- Error display --> - <div v-if="error" class="emptycontent"> - <div class="icon-error" /> - <h2>{{ error }}</h2> - </div> + <EmptyContent v-if="error" icon="icon-error"> + {{ error }} + </EmptyContent> - <!-- If fileInfo fetch is complete, display tabs --> - <template v-else-if="fileInfo" v-for="tab in tabs"> + <!-- If fileInfo fetch is complete, render tabs --> + <template v-for="tab in tabs" v-else-if="fileInfo"> + <!-- Hide them if we're loading another file but keep them mounted --> <SidebarTab v-if="tab.enabled(fileInfo)" + v-show="!loading" :id="tab.id" :key="tab.id" :name="tab.name" :icon="tab.icon" - :render="tab.render" + :on-mount="tab.mount" + :on-update="tab.update" + :on-destroy="tab.destroy" :file-info="fileInfo" /> </template> </AppSidebar> </template> <script> +import { encodePath } from '@nextcloud/paths' import $ from 'jquery' import axios from '@nextcloud/axios' import AppSidebar from '@nextcloud/vue/dist/Components/AppSidebar' import ActionButton from '@nextcloud/vue/dist/Components/ActionButton' +import EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent' + import FileInfo from '../services/FileInfo' import SidebarTab from '../components/SidebarTab' import LegacyView from '../components/LegacyView' -import { encodePath } from '@nextcloud/paths' export default { name: 'Sidebar', @@ -86,8 +91,9 @@ export default { components: { ActionButton, AppSidebar, - SidebarTab, + EmptyContent, LegacyView, + SidebarTab, }, data() { @@ -95,6 +101,7 @@ export default { // reactive state Sidebar: OCA.Files.Sidebar.state, error: null, + loading: true, fileInfo: null, starLoading: false, } @@ -185,15 +192,16 @@ export default { appSidebar() { if (this.fileInfo) { return { - background: this.background, + 'data-mimetype': this.fileInfo.mimetype, + 'star-loading': this.starLoading, active: this.activeTab, + background: this.background, class: { 'has-preview': this.fileInfo.hasPreview }, compact: !this.fileInfo.hasPreview, - 'star-loading': this.starLoading, + loading: this.loading, starred: this.fileInfo.isFavourited, subtitle: this.subtitle, title: this.fileInfo.name, - 'data-mimetype': this.fileInfo.mimetype, } } else if (this.error) { return { @@ -201,12 +209,12 @@ export default { subtitle: '', title: '', } - } else { - return { - class: 'icon-loading', - subtitle: '', - title: '', - } + } + // no fileInfo yet, showing empty data + return { + loading: this.loading, + subtitle: '', + title: '', } }, @@ -241,35 +249,6 @@ export default { }, }, - watch: { - // update the sidebar data - async file(curr, prev) { - this.resetData() - if (curr && curr.trim() !== '') { - try { - this.fileInfo = await FileInfo(this.davPath) - // adding this as fallback because other apps expect it - this.fileInfo.dir = this.file.split('/').slice(0, -1).join('/') - - // DEPRECATED legacy views - // TODO: remove - this.views.forEach(view => { - view.setFileInfo(this.fileInfo) - }) - - this.$nextTick(() => { - if (this.$refs.tabs) { - this.$refs.tabs.updateTabs() - } - }) - } catch (error) { - this.error = t('files', 'Error while loading the file data') - console.error('Error while loading the file data', error) - } - } - }, - }, - methods: { /** * Can this tab be displayed ? @@ -403,9 +382,11 @@ export default { // update current opened file this.Sidebar.file = path - // reset previous data - this.resetData() if (path && path.trim() !== '') { + // reset data, keep old fileInfo to not reload all tabs and just hide them + this.error = null + this.loading = true + try { this.fileInfo = await FileInfo(this.davPath) // adding this as fallback because other apps expect it @@ -427,6 +408,8 @@ export default { console.error('Error while loading the file data', error) throw new Error(error) + } finally { + this.loading = false } } }, |