Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/dashboard/js/dashboard.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion apps/dashboard/js/dashboard.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion apps/files/js/dist/files-app-settings.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion apps/files/js/dist/files-app-settings.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion apps/files/js/dist/personal-settings.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion apps/files/js/dist/personal-settings.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion apps/files/js/dist/sidebar.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion apps/files/js/dist/sidebar.js.map

Large diffs are not rendered by default.

17 changes: 16 additions & 1 deletion apps/files/js/filelist.js
Original file line number Diff line number Diff line change
Expand Up @@ -3700,7 +3700,22 @@
console.warn('registerTabView is deprecated! It will be removed in nextcloud 20.');
const enabled = tabView.canDisplay || undefined
if (tabView.id) {
OCA.Files.Sidebar.registerTab(new OCA.Files.Sidebar.Tab(tabView.id, tabView, enabled, true))
OCA.Files.Sidebar.registerTab(new OCA.Files.Sidebar.Tab({
id: tabView.id,
name: tabView.getLabel(),
icon: tabView.getIcon(),
mount: function(el, fileInfo) {
tabView.setFileInfo(fileInfo)
el.appendChild(tabView.el)
},
update: function(fileInfo) {
tabView.setFileInfo(fileInfo)
},
destroy: function() {
tabView.el.remove()
},
enabled: enabled
}))
}
},

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

<!--
- @copyright Copyright (c) 2019 John Molakvoæ <[email protected]>
-
Expand All @@ -19,74 +20,106 @@
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-->

<template>
<AppSidebarTab
:id="id"
:icon="icon"
ref="tab"
:name="name"
:active-tab="activeTab" />
: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" />
</AppSidebarTab>
</template>

<script>
import AppSidebarTab from '@nextcloud/vue/dist/Components/AppSidebarTab'
import EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent'

export default {
name: 'LegacyTab',
name: 'SidebarTab',

components: {
AppSidebarTab,
EmptyContent,
},

props: {
component: {
fileInfo: {
type: Object,
default: () => {},
required: true,
},
id: {
type: String,
required: true,
},
fileInfo: {
type: Object,
default: () => {},
name: {
type: String,
required: true,
},
},
computed: {
icon() {
return this.component.getIcon()
icon: {
type: String,
required: true,
},
name() {
return this.component.getLabel()

/**
* 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,
},
order() {
return this.component.order
? this.component.order
: 0
onDestroy: {
type: Function,
required: true,
},
// needed because AppSidebarTab also uses $parent.activeTab
},

data() {
return {
loading: true,
}
},

computed: {
// TODO: implement a better way to force pass a prop from Sidebar
activeTab() {
return this.$parent.activeTab
},
},

watch: {
fileInfo(fileInfo) {
if (fileInfo) {
this.setFileInfo(fileInfo)
async fileInfo(newFile, oldFile) {
// Update fileInfo on change
if (newFile.id !== oldFile.id) {
this.loading = true
await this.onUpdate(this.fileInfo)
this.loading = false
}
},
},
mounted() {
// append the backbone element and set the FileInfo
this.component.$el.appendTo(this.$el)
},
beforeDestroy() {
this.component.remove()

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: {
setFileInfo(fileInfo) {
this.component.setFileInfo(new OCA.Files.FileInfoModel(fileInfo))
},

async beforeDestroy() {
// unmount the tab
await this.onDestroy()
},

}
</script>
<style>
</style>
79 changes: 60 additions & 19 deletions apps/files/src/models/Tab.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,49 +22,90 @@

export default class Tab {

#component
#legacy
#id
#name
#icon
#mount
#update
#destroy
#enabled

/**
* Create a new tab instance
*
* @param {string} id the unique id of this tab
* @param {Object} component the vue component
* @param {Function} [enabled] function that returns if the tab should be shown or not
* @param {boolean} [legacy] is this a legacy tab
* @param {Object} options destructuring object
* @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.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, component, enabled = () => true, legacy) {
constructor({ id, name, icon, mount, update, destroy, enabled } = {}) {
if (enabled === undefined) {
enabled = () => true
}

// Sanity checks
if (typeof id !== 'string' || id.trim() === '') {
throw new Error('The id argument is not a valid string')
}
if (typeof name !== 'string' || name.trim() === '') {
throw new Error('The name argument is not a valid string')
}
if (typeof icon !== 'string' || icon.trim() === '') {
throw new Error('The icon argument is not a valid string')
}
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')
}

this.#id = id
this.#component = component
this.#name = name
this.#icon = icon
this.#mount = mount
this.#update = update
this.#destroy = destroy
this.#enabled = enabled
this.#legacy = legacy === true

if (this.#legacy) {
console.warn('Legacy tabs are deprecated! They will be removed in nextcloud 20.')
}

}

get id() {
return this.#id
}

get component() {
return this.#component
get name() {
return this.#name
}

get isEnabled() {
return this.#enabled
get icon() {
return this.#icon
}

get isLegacyTab() {
return this.#legacy === true
get mount() {
return this.#mount
}

get update() {
return this.#update
}

get destroy() {
return this.#destroy
}

get enabled() {
return this.#enabled
}

}
5 changes: 2 additions & 3 deletions apps/files/src/sidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,11 @@
*/

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'
import VueClipboard from 'vue-clipboard2'

Vue.use(VueClipboard)

Vue.prototype.t = t

Expand Down
Loading