Move Files Sidebar to proper javascript standard
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
This commit is contained in:
parent
678ef8466d
commit
843d799a2e
|
@ -3700,7 +3700,16 @@
|
||||||
console.warn('registerTabView is deprecated! It will be removed in nextcloud 20.');
|
console.warn('registerTabView is deprecated! It will be removed in nextcloud 20.');
|
||||||
const enabled = tabView.canDisplay || undefined
|
const enabled = tabView.canDisplay || undefined
|
||||||
if (tabView.id) {
|
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(),
|
||||||
|
render: function(el, fileInfo) {
|
||||||
|
tabView.setFileInfo(fileInfo)
|
||||||
|
el.appendChild(tabView.el)
|
||||||
|
},
|
||||||
|
enabled,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
- @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
|
- @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
|
||||||
-
|
-
|
||||||
|
@ -19,74 +20,74 @@
|
||||||
- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
-
|
-
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<AppSidebarTab
|
<AppSidebarTab
|
||||||
:id="id"
|
:id="id"
|
||||||
:icon="icon"
|
|
||||||
:name="name"
|
:name="name"
|
||||||
:active-tab="activeTab" />
|
:icon="icon">
|
||||||
|
<!-- Using a dummy div as Vue mount replace the element directly
|
||||||
|
It does NOT append to the content -->
|
||||||
|
<div ref="mount"></div>
|
||||||
|
</AppSidebarTab>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import AppSidebarTab from '@nextcloud/vue/dist/Components/AppSidebarTab'
|
import AppSidebarTab from '@nextcloud/vue/dist/Components/AppSidebarTab'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'LegacyTab',
|
name: 'SidebarTab',
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
AppSidebarTab,
|
AppSidebarTab,
|
||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
component: {
|
fileInfo: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
id: {
|
id: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
fileInfo: {
|
name: {
|
||||||
type: Object,
|
type: String,
|
||||||
default: () => {},
|
required: true,
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
render: {
|
||||||
|
type: Function,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
icon() {
|
// TODO: implement a better way to force pass a prop fromm Sidebar
|
||||||
return this.component.getIcon()
|
|
||||||
},
|
|
||||||
name() {
|
|
||||||
return this.component.getLabel()
|
|
||||||
},
|
|
||||||
order() {
|
|
||||||
return this.component.order
|
|
||||||
? this.component.order
|
|
||||||
: 0
|
|
||||||
},
|
|
||||||
// needed because AppSidebarTab also uses $parent.activeTab
|
|
||||||
activeTab() {
|
activeTab() {
|
||||||
return this.$parent.activeTab
|
return this.$parent.activeTab
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
fileInfo(fileInfo) {
|
fileInfo(newFile, oldFile) {
|
||||||
if (fileInfo) {
|
if (newFile.id !== oldFile.id) {
|
||||||
this.setFileInfo(fileInfo)
|
this.mountTab()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
// append the backbone element and set the FileInfo
|
this.mountTab()
|
||||||
this.component.$el.appendTo(this.$el)
|
|
||||||
},
|
|
||||||
beforeDestroy() {
|
|
||||||
this.component.remove()
|
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
setFileInfo(fileInfo) {
|
mountTab() {
|
||||||
this.component.setFileInfo(new OCA.Files.FileInfoModel(fileInfo))
|
// Mount the tab into this component
|
||||||
|
this.render(this.$refs.mount, this.fileInfo)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
|
||||||
</style>
|
|
|
@ -22,32 +22,49 @@
|
||||||
|
|
||||||
export default class Tab {
|
export default class Tab {
|
||||||
|
|
||||||
#component
|
|
||||||
#legacy
|
|
||||||
#id
|
#id
|
||||||
|
#name
|
||||||
|
#icon
|
||||||
|
#render
|
||||||
#enabled
|
#enabled
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new tab instance
|
* Create a new tab instance
|
||||||
*
|
*
|
||||||
* @param {string} id the unique id of this tab
|
* @param {Object} options destructuring object
|
||||||
* @param {Object} component the vue component
|
* @param {string} options.id the unique id of this tab
|
||||||
* @param {Function} [enabled] function that returns if the tab should be shown or not
|
* @param {string} options.name the translated tab name
|
||||||
* @param {boolean} [legacy] is this a legacy tab
|
* @param {string} options.icon the vue component
|
||||||
|
* @param {Function} options.render function to render 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, render, 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 render !== 'function') {
|
||||||
|
throw new Error('The render argument should be a function')
|
||||||
|
}
|
||||||
if (typeof enabled !== 'function') {
|
if (typeof enabled !== 'function') {
|
||||||
throw new Error('The enabled argument should be a function')
|
throw new Error('The enabled argument should be a function')
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#id = id
|
this.#id = id
|
||||||
this.#component = component
|
this.#name = name
|
||||||
|
this.#icon = icon
|
||||||
|
this.#render = render
|
||||||
this.#enabled = enabled
|
this.#enabled = enabled
|
||||||
this.#legacy = legacy === true
|
|
||||||
|
|
||||||
if (this.#legacy) {
|
|
||||||
console.warn('Legacy tabs are deprecated! They will be removed in nextcloud 20.')
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,16 +72,20 @@ export default class Tab {
|
||||||
return this.#id
|
return this.#id
|
||||||
}
|
}
|
||||||
|
|
||||||
get component() {
|
get name() {
|
||||||
return this.#component
|
return this.#name
|
||||||
}
|
}
|
||||||
|
|
||||||
get isEnabled() {
|
get icon() {
|
||||||
|
return this.#icon
|
||||||
|
}
|
||||||
|
|
||||||
|
get render() {
|
||||||
|
return this.#render
|
||||||
|
}
|
||||||
|
|
||||||
|
get enabled() {
|
||||||
return this.#enabled
|
return this.#enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
get isLegacyTab() {
|
|
||||||
return this.#legacy === true
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,9 +24,6 @@ import Vue from 'vue'
|
||||||
import SidebarView from './views/Sidebar.vue'
|
import SidebarView from './views/Sidebar.vue'
|
||||||
import Sidebar from './services/Sidebar'
|
import Sidebar from './services/Sidebar'
|
||||||
import Tab from './models/Tab'
|
import Tab from './models/Tab'
|
||||||
import VueClipboard from 'vue-clipboard2'
|
|
||||||
|
|
||||||
Vue.use(VueClipboard)
|
|
||||||
|
|
||||||
Vue.prototype.t = t
|
Vue.prototype.t = t
|
||||||
|
|
||||||
|
|
|
@ -58,15 +58,14 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- If fileInfo fetch is complete, display tabs -->
|
<!-- If fileInfo fetch is complete, display tabs -->
|
||||||
<template v-for="tab in tabs" v-else-if="fileInfo">
|
<template v-else-if="fileInfo" v-for="tab in tabs">
|
||||||
<component
|
<SidebarTab
|
||||||
:is="tabComponent(tab).is"
|
v-if="tab.enabled(fileInfo)"
|
||||||
v-if="canDisplay(tab)"
|
|
||||||
:id="tab.id"
|
:id="tab.id"
|
||||||
:key="tab.id"
|
:key="tab.id"
|
||||||
:component="tabComponent(tab).component"
|
|
||||||
:name="tab.name"
|
:name="tab.name"
|
||||||
:dav-path="davPath"
|
:icon="tab.icon"
|
||||||
|
:render="tab.render"
|
||||||
:file-info="fileInfo" />
|
:file-info="fileInfo" />
|
||||||
</template>
|
</template>
|
||||||
</AppSidebar>
|
</AppSidebar>
|
||||||
|
@ -77,7 +76,7 @@ import axios from '@nextcloud/axios'
|
||||||
import AppSidebar from '@nextcloud/vue/dist/Components/AppSidebar'
|
import AppSidebar from '@nextcloud/vue/dist/Components/AppSidebar'
|
||||||
import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
|
import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
|
||||||
import FileInfo from '../services/FileInfo'
|
import FileInfo from '../services/FileInfo'
|
||||||
import LegacyTab from '../components/LegacyTab'
|
import SidebarTab from '../components/SidebarTab'
|
||||||
import LegacyView from '../components/LegacyView'
|
import LegacyView from '../components/LegacyView'
|
||||||
import { encodePath } from '@nextcloud/paths'
|
import { encodePath } from '@nextcloud/paths'
|
||||||
|
|
||||||
|
@ -87,6 +86,7 @@ export default {
|
||||||
components: {
|
components: {
|
||||||
ActionButton,
|
ActionButton,
|
||||||
AppSidebar,
|
AppSidebar,
|
||||||
|
SidebarTab,
|
||||||
LegacyView,
|
LegacyView,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -258,8 +258,8 @@ export default {
|
||||||
})
|
})
|
||||||
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
if (this.$refs.sidebar) {
|
if (this.$refs.tabs) {
|
||||||
this.$refs.sidebar.updateTabs()
|
this.$refs.tabs.updateTabs()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -278,14 +278,14 @@ export default {
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
canDisplay(tab) {
|
canDisplay(tab) {
|
||||||
return tab.isEnabled(this.fileInfo)
|
return tab.enabled(this.fileInfo)
|
||||||
},
|
},
|
||||||
resetData() {
|
resetData() {
|
||||||
this.error = null
|
this.error = null
|
||||||
this.fileInfo = null
|
this.fileInfo = null
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
if (this.$refs.sidebar) {
|
if (this.$refs.tabs) {
|
||||||
this.$refs.sidebar.updateTabs()
|
this.$refs.tabs.updateTabs()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -327,18 +327,6 @@ export default {
|
||||||
return OC.MimeType.getIconUrl(mimeType)
|
return OC.MimeType.getIconUrl(mimeType)
|
||||||
},
|
},
|
||||||
|
|
||||||
tabComponent(tab) {
|
|
||||||
if (tab.isLegacyTab) {
|
|
||||||
return {
|
|
||||||
is: LegacyTab,
|
|
||||||
component: tab.component,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
is: tab.component,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set current active tab
|
* Set current active tab
|
||||||
*
|
*
|
||||||
|
@ -430,8 +418,8 @@ export default {
|
||||||
})
|
})
|
||||||
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
if (this.$refs.sidebar) {
|
if (this.$refs.tabs) {
|
||||||
this.$refs.sidebar.updateTabs()
|
this.$refs.tabs.updateTabs()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
@ -19,11 +19,13 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
import Vue from 'vue'
|
||||||
|
import VueClipboard from 'vue-clipboard2'
|
||||||
|
import { translate as t, translatePlural as n } from '@nextcloud/l10n'
|
||||||
|
|
||||||
import SharingTab from './views/SharingTab'
|
import SharingTab from './views/SharingTab'
|
||||||
import ShareSearch from './services/ShareSearch'
|
import ShareSearch from './services/ShareSearch'
|
||||||
import ExternalLinkActions from './services/ExternalLinkActions'
|
import ExternalLinkActions from './services/ExternalLinkActions'
|
||||||
|
|
||||||
import TabSections from './services/TabSections'
|
import TabSections from './services/TabSections'
|
||||||
|
|
||||||
// Init Sharing Tab Service
|
// Init Sharing Tab Service
|
||||||
|
@ -34,8 +36,28 @@ Object.assign(window.OCA.Sharing, { ShareSearch: new ShareSearch() })
|
||||||
Object.assign(window.OCA.Sharing, { ExternalLinkActions: new ExternalLinkActions() })
|
Object.assign(window.OCA.Sharing, { ExternalLinkActions: new ExternalLinkActions() })
|
||||||
Object.assign(window.OCA.Sharing, { ShareTabSections: new TabSections() })
|
Object.assign(window.OCA.Sharing, { ShareTabSections: new TabSections() })
|
||||||
|
|
||||||
|
Vue.prototype.t = t
|
||||||
|
Vue.prototype.n = n
|
||||||
|
Vue.use(VueClipboard)
|
||||||
|
|
||||||
|
// Init Sharing tab component
|
||||||
|
const View = Vue.extend(SharingTab)
|
||||||
|
|
||||||
window.addEventListener('DOMContentLoaded', function() {
|
window.addEventListener('DOMContentLoaded', function() {
|
||||||
if (OCA.Files && OCA.Files.Sidebar) {
|
if (OCA.Files && OCA.Files.Sidebar) {
|
||||||
OCA.Files.Sidebar.registerTab(new OCA.Files.Sidebar.Tab('sharing', SharingTab))
|
OCA.Files.Sidebar.registerTab(new OCA.Files.Sidebar.Tab({
|
||||||
|
id: 'sharing',
|
||||||
|
name: t('files_sharing', 'Sharing'),
|
||||||
|
icon: 'icon-share',
|
||||||
|
|
||||||
|
render: (el, fileInfo) => {
|
||||||
|
new View({
|
||||||
|
propsData: {
|
||||||
|
fileInfo,
|
||||||
|
},
|
||||||
|
}).$mount(el)
|
||||||
|
console.info(el)
|
||||||
|
},
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -21,10 +21,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Tab :id="id"
|
<div :class="{ 'icon-loading': loading }">
|
||||||
:icon="icon"
|
|
||||||
:name="name"
|
|
||||||
:class="{ 'icon-loading': loading }">
|
|
||||||
<!-- error message -->
|
<!-- error message -->
|
||||||
<div v-if="error" class="emptycontent">
|
<div v-if="error" class="emptycontent">
|
||||||
<div class="icon icon-error" />
|
<div class="icon icon-error" />
|
||||||
|
@ -84,7 +81,7 @@
|
||||||
<component :is="section($refs['section-'+index], fileInfo)" :file-info="fileInfo" />
|
<component :is="section($refs['section-'+index], fileInfo)" :file-info="fileInfo" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Tab>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -92,7 +89,6 @@ import { CollectionList } from 'nextcloud-vue-collections'
|
||||||
import { generateOcsUrl } from '@nextcloud/router'
|
import { generateOcsUrl } from '@nextcloud/router'
|
||||||
import Avatar from '@nextcloud/vue/dist/Components/Avatar'
|
import Avatar from '@nextcloud/vue/dist/Components/Avatar'
|
||||||
import axios from '@nextcloud/axios'
|
import axios from '@nextcloud/axios'
|
||||||
import Tab from '@nextcloud/vue/dist/Components/AppSidebarTab'
|
|
||||||
|
|
||||||
import { shareWithTitle } from '../utils/SharedWithMe'
|
import { shareWithTitle } from '../utils/SharedWithMe'
|
||||||
import Share from '../models/Share'
|
import Share from '../models/Share'
|
||||||
|
@ -117,7 +113,6 @@ export default {
|
||||||
SharingInput,
|
SharingInput,
|
||||||
SharingLinkList,
|
SharingLinkList,
|
||||||
SharingList,
|
SharingList,
|
||||||
Tab,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [ShareTypes],
|
mixins: [ShareTypes],
|
||||||
|
@ -134,9 +129,7 @@ export default {
|
||||||
return {
|
return {
|
||||||
error: '',
|
error: '',
|
||||||
expirationInterval: null,
|
expirationInterval: null,
|
||||||
icon: 'icon-share',
|
|
||||||
loading: true,
|
loading: true,
|
||||||
name: t('files_sharing', 'Sharing'),
|
|
||||||
// reshare Share object
|
// reshare Share object
|
||||||
reshare: null,
|
reshare: null,
|
||||||
sharedWithMe: {},
|
sharedWithMe: {},
|
||||||
|
@ -147,26 +140,6 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
/**
|
|
||||||
* Needed to differenciate the tabs
|
|
||||||
* pulled from the AppSidebarTab component
|
|
||||||
*
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
id() {
|
|
||||||
return 'sharing'
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current active tab
|
|
||||||
* needed because AppSidebarTab also uses $parent.activeTab
|
|
||||||
*
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
activeTab() {
|
|
||||||
return this.$parent.activeTab
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this share shared with me?
|
* Is this share shared with me?
|
||||||
*
|
*
|
||||||
|
@ -341,7 +314,3 @@ export default {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
Loading…
Reference in New Issue