Merge pull request #23164 from nextcloud/feat/files-sidebar-cleanup-standards
This commit is contained in:
commit
fd178b92f6
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -3700,7 +3700,22 @@
|
||||||
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(),
|
||||||
|
mount: function(el, fileInfo) {
|
||||||
|
tabView.setFileInfo(fileInfo)
|
||||||
|
el.appendChild(tabView.el)
|
||||||
|
},
|
||||||
|
update: function(fileInfo) {
|
||||||
|
tabView.setFileInfo(fileInfo)
|
||||||
|
},
|
||||||
|
destroy: function() {
|
||||||
|
tabView.el.remove()
|
||||||
|
},
|
||||||
|
enabled: 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,106 @@
|
||||||
- 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"
|
ref="tab"
|
||||||
:name="name"
|
: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>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import AppSidebarTab from '@nextcloud/vue/dist/Components/AppSidebarTab'
|
import AppSidebarTab from '@nextcloud/vue/dist/Components/AppSidebarTab'
|
||||||
|
import EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'LegacyTab',
|
name: 'SidebarTab',
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
AppSidebarTab,
|
AppSidebarTab,
|
||||||
|
EmptyContent,
|
||||||
},
|
},
|
||||||
|
|
||||||
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,
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
icon() {
|
// TODO: implement a better way to force pass a prop from 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) {
|
async fileInfo(newFile, oldFile) {
|
||||||
if (fileInfo) {
|
// Update fileInfo on change
|
||||||
this.setFileInfo(fileInfo)
|
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
|
async mounted() {
|
||||||
this.component.$el.appendTo(this.$el)
|
this.loading = true
|
||||||
},
|
// Mount the tab: mounting point, fileInfo, vue context
|
||||||
beforeDestroy() {
|
await this.onMount(this.$refs.mount, this.fileInfo, this.$refs.tab)
|
||||||
this.component.remove()
|
this.loading = false
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
setFileInfo(fileInfo) {
|
|
||||||
this.component.setFileInfo(new OCA.Files.FileInfoModel(fileInfo))
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async beforeDestroy() {
|
||||||
|
// unmount the tab
|
||||||
|
await this.onDestroy()
|
||||||
},
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
|
||||||
</style>
|
|
|
@ -22,32 +22,61 @@
|
||||||
|
|
||||||
export default class Tab {
|
export default class Tab {
|
||||||
|
|
||||||
#component
|
|
||||||
#legacy
|
|
||||||
#id
|
#id
|
||||||
|
#name
|
||||||
|
#icon
|
||||||
|
#mount
|
||||||
|
#update
|
||||||
|
#destroy
|
||||||
#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.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') {
|
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.#mount = mount
|
||||||
|
this.#update = update
|
||||||
|
this.#destroy = destroy
|
||||||
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 +84,28 @@ 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 mount() {
|
||||||
|
return this.#mount
|
||||||
|
}
|
||||||
|
|
||||||
|
get update() {
|
||||||
|
return this.#update
|
||||||
|
}
|
||||||
|
|
||||||
|
get destroy() {
|
||||||
|
return this.#destroy
|
||||||
|
}
|
||||||
|
|
||||||
|
get enabled() {
|
||||||
return this.#enabled
|
return this.#enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
get isLegacyTab() {
|
|
||||||
return this.#legacy === true
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,12 +21,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
|
import { translate as t } from '@nextcloud/l10n'
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -52,34 +52,38 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- Error display -->
|
<!-- Error display -->
|
||||||
<div v-if="error" class="emptycontent">
|
<EmptyContent v-if="error" icon="icon-error">
|
||||||
<div class="icon-error" />
|
{{ error }}
|
||||||
<h2>{{ error }}</h2>
|
</EmptyContent>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- If fileInfo fetch is complete, display tabs -->
|
<!-- If fileInfo fetch is complete, render tabs -->
|
||||||
<template v-for="tab in tabs" v-else-if="fileInfo">
|
<template v-for="tab in tabs" v-else-if="fileInfo">
|
||||||
<component
|
<!-- Hide them if we're loading another file but keep them mounted -->
|
||||||
:is="tabComponent(tab).is"
|
<SidebarTab
|
||||||
v-if="canDisplay(tab)"
|
v-if="tab.enabled(fileInfo)"
|
||||||
|
v-show="!loading"
|
||||||
: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"
|
||||||
|
:on-mount="tab.mount"
|
||||||
|
:on-update="tab.update"
|
||||||
|
:on-destroy="tab.destroy"
|
||||||
:file-info="fileInfo" />
|
:file-info="fileInfo" />
|
||||||
</template>
|
</template>
|
||||||
</AppSidebar>
|
</AppSidebar>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
import { encodePath } from '@nextcloud/paths'
|
||||||
import $ from 'jquery'
|
import $ from 'jquery'
|
||||||
import axios from '@nextcloud/axios'
|
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 EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent'
|
||||||
|
|
||||||
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'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Sidebar',
|
name: 'Sidebar',
|
||||||
|
@ -87,7 +91,9 @@ export default {
|
||||||
components: {
|
components: {
|
||||||
ActionButton,
|
ActionButton,
|
||||||
AppSidebar,
|
AppSidebar,
|
||||||
|
EmptyContent,
|
||||||
LegacyView,
|
LegacyView,
|
||||||
|
SidebarTab,
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
@ -95,6 +101,7 @@ export default {
|
||||||
// reactive state
|
// reactive state
|
||||||
Sidebar: OCA.Files.Sidebar.state,
|
Sidebar: OCA.Files.Sidebar.state,
|
||||||
error: null,
|
error: null,
|
||||||
|
loading: true,
|
||||||
fileInfo: null,
|
fileInfo: null,
|
||||||
starLoading: false,
|
starLoading: false,
|
||||||
}
|
}
|
||||||
|
@ -185,15 +192,16 @@ export default {
|
||||||
appSidebar() {
|
appSidebar() {
|
||||||
if (this.fileInfo) {
|
if (this.fileInfo) {
|
||||||
return {
|
return {
|
||||||
background: this.background,
|
'data-mimetype': this.fileInfo.mimetype,
|
||||||
|
'star-loading': this.starLoading,
|
||||||
active: this.activeTab,
|
active: this.activeTab,
|
||||||
|
background: this.background,
|
||||||
class: { 'has-preview': this.fileInfo.hasPreview },
|
class: { 'has-preview': this.fileInfo.hasPreview },
|
||||||
compact: !this.fileInfo.hasPreview,
|
compact: !this.fileInfo.hasPreview,
|
||||||
'star-loading': this.starLoading,
|
loading: this.loading,
|
||||||
starred: this.fileInfo.isFavourited,
|
starred: this.fileInfo.isFavourited,
|
||||||
subtitle: this.subtitle,
|
subtitle: this.subtitle,
|
||||||
title: this.fileInfo.name,
|
title: this.fileInfo.name,
|
||||||
'data-mimetype': this.fileInfo.mimetype,
|
|
||||||
}
|
}
|
||||||
} else if (this.error) {
|
} else if (this.error) {
|
||||||
return {
|
return {
|
||||||
|
@ -201,13 +209,13 @@ export default {
|
||||||
subtitle: '',
|
subtitle: '',
|
||||||
title: '',
|
title: '',
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
// no fileInfo yet, showing empty data
|
||||||
return {
|
return {
|
||||||
class: 'icon-loading',
|
loading: this.loading,
|
||||||
subtitle: '',
|
subtitle: '',
|
||||||
title: '',
|
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.sidebar) {
|
|
||||||
this.$refs.sidebar.updateTabs()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
this.error = t('files', 'Error while loading the file data')
|
|
||||||
console.error('Error while loading the file data', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
/**
|
/**
|
||||||
* Can this tab be displayed ?
|
* Can this tab be displayed ?
|
||||||
|
@ -278,14 +257,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 +306,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
|
||||||
*
|
*
|
||||||
|
@ -415,9 +382,11 @@ export default {
|
||||||
// update current opened file
|
// update current opened file
|
||||||
this.Sidebar.file = path
|
this.Sidebar.file = path
|
||||||
|
|
||||||
// reset previous data
|
|
||||||
this.resetData()
|
|
||||||
if (path && path.trim() !== '') {
|
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 {
|
try {
|
||||||
this.fileInfo = await FileInfo(this.davPath)
|
this.fileInfo = await FileInfo(this.davPath)
|
||||||
// adding this as fallback because other apps expect it
|
// adding this as fallback because other apps expect it
|
||||||
|
@ -430,8 +399,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) {
|
||||||
|
@ -439,6 +408,8 @@ export default {
|
||||||
console.error('Error while loading the file data', error)
|
console.error('Error while loading the file data', error)
|
||||||
|
|
||||||
throw new Error(error)
|
throw new Error(error)
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,2 +1,2 @@
|
||||||
!function(e){var n={};function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:r})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var o in e)t.d(r,o,function(n){return e[n]}.bind(null,o));return r},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="/js/",t(t.s=152)}({152:function(e,n,r){r.p=OC.linkTo("files_sharing","js/dist/"),r.nc=btoa(OC.requestToken),window.OCP.Collaboration.registerType("file",{action:function(){return new Promise((function(e,n){OC.dialogs.filepicker(t("files_sharing","Link to a file"),(function(t){OC.Files.getClient().getFileInfo(t).then((function(n,t){e(t.id)})).fail((function(){n(new Error("Cannot get fileinfo"))}))}),!1,null,!1,OC.dialogs.FILEPICKER_TYPE_CHOOSE,"",{allowDirectoryChooser:!0})}))},typeString:t("files_sharing","Link to a file"),typeIconClass:"icon-files-dark"})}});
|
!function(e){var n={};function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:r})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var o in e)t.d(r,o,function(n){return e[n]}.bind(null,o));return r},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="/js/",t(t.s=153)}({153:function(e,n,r){r.p=OC.linkTo("files_sharing","js/dist/"),r.nc=btoa(OC.requestToken),window.OCP.Collaboration.registerType("file",{action:function(){return new Promise((function(e,n){OC.dialogs.filepicker(t("files_sharing","Link to a file"),(function(t){OC.Files.getClient().getFileInfo(t).then((function(n,t){e(t.id)})).fail((function(){n(new Error("Cannot get fileinfo"))}))}),!1,null,!1,OC.dialogs.FILEPICKER_TYPE_CHOOSE,"",{allowDirectoryChooser:!0})}))},typeString:t("files_sharing","Link to a file"),typeIconClass:"icon-files-dark"})}});
|
||||||
//# sourceMappingURL=collaboration.js.map
|
//# sourceMappingURL=collaboration.js.map
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,2 +1,2 @@
|
||||||
!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="/js/",r(r.s=277)}({277:function(e,t){Object.assign(OC,{Share:{SHARE_TYPE_USER:0,SHARE_TYPE_GROUP:1,SHARE_TYPE_LINK:3,SHARE_TYPE_EMAIL:4,SHARE_TYPE_REMOTE:6,SHARE_TYPE_CIRCLE:7,SHARE_TYPE_GUEST:8,SHARE_TYPE_REMOTE_GROUP:9,SHARE_TYPE_ROOM:10}})}});
|
!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="/js/",r(r.s=278)}({278:function(e,t){Object.assign(OC,{Share:{SHARE_TYPE_USER:0,SHARE_TYPE_GROUP:1,SHARE_TYPE_LINK:3,SHARE_TYPE_EMAIL:4,SHARE_TYPE_REMOTE:6,SHARE_TYPE_CIRCLE:7,SHARE_TYPE_GUEST:8,SHARE_TYPE_REMOTE_GROUP:9,SHARE_TYPE_ROOM:10}})}});
|
||||||
//# sourceMappingURL=main.js.map
|
//# sourceMappingURL=main.js.map
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -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,40 @@ 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)
|
||||||
|
let TabInstance = null
|
||||||
|
|
||||||
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',
|
||||||
|
|
||||||
|
async mount(el, fileInfo, context) {
|
||||||
|
if (TabInstance) {
|
||||||
|
TabInstance.$destroy()
|
||||||
|
}
|
||||||
|
TabInstance = new View({
|
||||||
|
// Better integration with vue parent component
|
||||||
|
parent: context,
|
||||||
|
})
|
||||||
|
// Only mount after we have all the info we need
|
||||||
|
await TabInstance.update(fileInfo)
|
||||||
|
TabInstance.$mount(el)
|
||||||
|
},
|
||||||
|
update(fileInfo) {
|
||||||
|
TabInstance.update(fileInfo)
|
||||||
|
},
|
||||||
|
destroy() {
|
||||||
|
TabInstance.$destroy()
|
||||||
|
TabInstance = null
|
||||||
|
},
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -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,56 +113,29 @@ export default {
|
||||||
SharingInput,
|
SharingInput,
|
||||||
SharingLinkList,
|
SharingLinkList,
|
||||||
SharingList,
|
SharingList,
|
||||||
Tab,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [ShareTypes],
|
mixins: [ShareTypes],
|
||||||
|
|
||||||
props: {
|
|
||||||
fileInfo: {
|
|
||||||
type: Object,
|
|
||||||
default: () => {},
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
error: '',
|
error: '',
|
||||||
expirationInterval: null,
|
expirationInterval: null,
|
||||||
icon: 'icon-share',
|
|
||||||
loading: true,
|
loading: true,
|
||||||
name: t('files_sharing', 'Sharing'),
|
|
||||||
|
fileInfo: null,
|
||||||
|
|
||||||
// reshare Share object
|
// reshare Share object
|
||||||
reshare: null,
|
reshare: null,
|
||||||
sharedWithMe: {},
|
sharedWithMe: {},
|
||||||
shares: [],
|
shares: [],
|
||||||
linkShares: [],
|
linkShares: [],
|
||||||
|
|
||||||
sections: OCA.Sharing.ShareTabSections.getSections(),
|
sections: OCA.Sharing.ShareTabSections.getSections(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
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?
|
||||||
*
|
*
|
||||||
|
@ -182,20 +151,17 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
methods: {
|
||||||
fileInfo(newFile, oldFile) {
|
/**
|
||||||
if (newFile.id !== oldFile.id) {
|
* Update current fileInfo and fetch new data
|
||||||
|
* @param {Object} fileInfo the current file FileInfo
|
||||||
|
*/
|
||||||
|
async update(fileInfo) {
|
||||||
|
this.fileInfo = fileInfo
|
||||||
this.resetState()
|
this.resetState()
|
||||||
this.getShares()
|
this.getShares()
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeMount() {
|
|
||||||
this.getShares()
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
/**
|
/**
|
||||||
* Get the existing shares infos
|
* Get the existing shares infos
|
||||||
*/
|
*/
|
||||||
|
@ -248,6 +214,7 @@ export default {
|
||||||
this.error = ''
|
this.error = ''
|
||||||
this.sharedWithMe = {}
|
this.sharedWithMe = {}
|
||||||
this.shares = []
|
this.shares = []
|
||||||
|
this.linkShares = []
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -341,7 +308,3 @@ export default {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1272,9 +1272,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@nextcloud/vue": {
|
"@nextcloud/vue": {
|
||||||
"version": "2.6.8",
|
"version": "2.6.9",
|
||||||
"resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-2.6.8.tgz",
|
"resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-2.6.9.tgz",
|
||||||
"integrity": "sha512-9yi9V4gX4Y1uxh2hNxCAlTHaS9zolzAy7x1sowII/WZfxMysF/yIGmEsnYGyz6CZ5eYCzxNUgrU5p/HQ21/09Q==",
|
"integrity": "sha512-Jx5h9WH+W9Tjz1mAhHq/QpqGMF9XbxpfQIK1DkEMPZ9N9ooLCpphaDN9qmPgOgt68ZGeUfGvJ+HrIfwD0r16Gw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@nextcloud/auth": "^1.2.3",
|
"@nextcloud/auth": "^1.2.3",
|
||||||
"@nextcloud/axios": "^1.3.2",
|
"@nextcloud/axios": "^1.3.2",
|
||||||
|
@ -3432,9 +3432,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"emoji-mart-vue-fast": {
|
"emoji-mart-vue-fast": {
|
||||||
"version": "7.0.5",
|
"version": "7.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/emoji-mart-vue-fast/-/emoji-mart-vue-fast-7.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/emoji-mart-vue-fast/-/emoji-mart-vue-fast-7.0.6.tgz",
|
||||||
"integrity": "sha512-+ayg30hhxqqM9oMtN9uUG470hT9gtOdFenByJJBm3XTfzI2QMVJ69euwk+xF55OphLfKZxQG7mnVz13lDOjb3g==",
|
"integrity": "sha512-nvGoIRMhgVYHFBcHJMjjYKS71RopuBRGuO/51DqOcIFreRJAaTvAwmk9eUjI1mwXHY7b/cCarrGi3FBE7Kz37A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/polyfill": "7.2.5",
|
"@babel/polyfill": "7.2.5",
|
||||||
"@babel/runtime": "7.3.4",
|
"@babel/runtime": "7.3.4",
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
"@nextcloud/password-confirmation": "^1.0.1",
|
"@nextcloud/password-confirmation": "^1.0.1",
|
||||||
"@nextcloud/paths": "^1.1.2",
|
"@nextcloud/paths": "^1.1.2",
|
||||||
"@nextcloud/router": "^1.1.0",
|
"@nextcloud/router": "^1.1.0",
|
||||||
"@nextcloud/vue": "^2.6.8",
|
"@nextcloud/vue": "^2.6.9",
|
||||||
"@nextcloud/vue-dashboard": "^1.0.1",
|
"@nextcloud/vue-dashboard": "^1.0.1",
|
||||||
"autosize": "^4.0.2",
|
"autosize": "^4.0.2",
|
||||||
"backbone": "^1.4.0",
|
"backbone": "^1.4.0",
|
||||||
|
|
Loading…
Reference in New Issue