mirror of
https://github.com/nextcloud/server.git
synced 2025-03-13 07:53:51 +00:00
feat: Add new Vue FilePicker from @nextcloud/dialogs and use it by default.
Still providing the legacy one until the Vue FilePicker is out of beta. Pin beta releases so we do not get version conflicts. Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
This commit is contained in:
parent
efeb517edd
commit
3d74ed85ff
8 changed files with 395 additions and 703 deletions
Binary file not shown.
Binary file not shown.
|
@ -8,5 +8,5 @@
|
|||
@import 'mobile.scss';
|
||||
@import 'tooltip.scss';
|
||||
// If you include .css, it will be imported as url
|
||||
@import '../../node_modules/@nextcloud/dialogs/dist/index';
|
||||
@import '../../node_modules/@nextcloud/dialogs/dist/style';
|
||||
@import 'public.scss';
|
||||
|
|
|
@ -48,8 +48,7 @@ import _ from 'underscore'
|
|||
import $ from 'jquery'
|
||||
|
||||
import OC from './index.js'
|
||||
import OCA from '../OCA/index.js'
|
||||
import { isA11yActivation } from '../Util/a11y.js'
|
||||
import { FilePickerVue, FilePickerType, spawnDialog } from '@nextcloud/dialogs'
|
||||
|
||||
/**
|
||||
* this class to ease the usage of jquery dialogs
|
||||
|
@ -59,10 +58,15 @@ const Dialogs = {
|
|||
YES_NO_BUTTONS: 70,
|
||||
OK_BUTTONS: 71,
|
||||
|
||||
/** @deprecated use FilePickerType from `@nextcloud/dialogs` */
|
||||
FILEPICKER_TYPE_CHOOSE: 1,
|
||||
/** @deprecated use FilePickerType from `@nextcloud/dialogs` */
|
||||
FILEPICKER_TYPE_MOVE: 2,
|
||||
/** @deprecated use FilePickerType from `@nextcloud/dialogs` */
|
||||
FILEPICKER_TYPE_COPY: 3,
|
||||
/** @deprecated use FilePickerType from `@nextcloud/dialogs` */
|
||||
FILEPICKER_TYPE_COPY_MOVE: 4,
|
||||
/** @deprecated use FilePickerType from `@nextcloud/dialogs` */
|
||||
FILEPICKER_TYPE_CUSTOM: 5,
|
||||
|
||||
// used to name each dialog
|
||||
|
@ -226,8 +230,11 @@ const Dialogs = {
|
|||
Dialogs.dialogsCounter++
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* show a file picker to pick a file from
|
||||
* Legacy wrapper to the new Vue based filepicker from `@nextcloud/dialogs`
|
||||
*
|
||||
* Prefer to use the Vue filepicker directly instead.
|
||||
*
|
||||
* In order to pick several types of mime types they need to be passed as an
|
||||
* array of strings.
|
||||
|
@ -237,339 +244,109 @@ const Dialogs = {
|
|||
* should be used instead.
|
||||
*
|
||||
* @param {string} title dialog title
|
||||
* @param {function} callback which will be triggered when user presses Choose
|
||||
* @param {Function} callback which will be triggered when user presses Choose
|
||||
* @param {boolean} [multiselect] whether it should be possible to select multiple files
|
||||
* @param {string[]} [mimetypeFilter] mimetype to filter by - directories will always be included
|
||||
* @param {boolean} [modal] make the dialog modal
|
||||
* @param {string[]} [mimetype] mimetype to filter by - directories will always be included
|
||||
* @param {boolean} [_modal] do not use
|
||||
* @param {string} [type] Type of file picker : Choose, copy, move, copy and move
|
||||
* @param {string} [path] path to the folder that the the file can be picket from
|
||||
* @param {Object} [options] additonal options that need to be set
|
||||
* @param {object} [options] additonal options that need to be set
|
||||
* @param {Function} [options.filter] filter function for advanced filtering
|
||||
* @param {boolean} [options.allowDirectoryChooser] Allow to select directories
|
||||
* @deprecated since 27.1.0 use the filepicker from `@nextcloud/dialogs` instead
|
||||
*/
|
||||
filepicker: function(title, callback, multiselect, mimetypeFilter, modal, type, path, options) {
|
||||
var self = this
|
||||
filepicker(title, callback, multiselect = false, mimetype = undefined, _modal = undefined, type = FilePickerType.Choose, path = undefined, options = undefined) {
|
||||
|
||||
this.filepicker.sortField = 'name'
|
||||
this.filepicker.sortOrder = 'asc'
|
||||
// avoid opening the picker twice
|
||||
if (this.filepicker.loading) {
|
||||
return
|
||||
}
|
||||
|
||||
if (type === undefined) {
|
||||
type = this.FILEPICKER_TYPE_CHOOSE
|
||||
}
|
||||
|
||||
var emptyText = t('core', 'No files in here')
|
||||
var newText = t('files', 'New folder')
|
||||
if (type === this.FILEPICKER_TYPE_COPY || type === this.FILEPICKER_TYPE_MOVE || type === this.FILEPICKER_TYPE_COPY_MOVE) {
|
||||
emptyText = t('core', 'No more subfolders in here')
|
||||
}
|
||||
|
||||
this.filepicker.loading = true
|
||||
this.filepicker.filesClient = (OCA.Sharing && OCA.Sharing.PublicApp && OCA.Sharing.PublicApp.fileList) ? OCA.Sharing.PublicApp.fileList.filesClient : OC.Files.getClient()
|
||||
|
||||
this.filelist = null
|
||||
path = path || ''
|
||||
options = Object.assign({
|
||||
allowDirectoryChooser: false
|
||||
}, options)
|
||||
|
||||
$.when(this._getFilePickerTemplate()).then(function($tmpl) {
|
||||
self.filepicker.loading = false
|
||||
var dialogName = 'oc-dialog-filepicker-content'
|
||||
if (self.$filePicker) {
|
||||
self.$filePicker.ocdialog('close')
|
||||
}
|
||||
|
||||
if (mimetypeFilter === undefined || mimetypeFilter === null) {
|
||||
mimetypeFilter = []
|
||||
}
|
||||
if (typeof (mimetypeFilter) === 'string') {
|
||||
mimetypeFilter = [mimetypeFilter]
|
||||
}
|
||||
|
||||
self.$filePicker = $tmpl.octemplate({
|
||||
dialog_name: dialogName,
|
||||
title: title,
|
||||
emptytext: emptyText,
|
||||
newtext: newText,
|
||||
nameCol: t('core', 'Name'),
|
||||
sizeCol: t('core', 'Size'),
|
||||
modifiedCol: t('core', 'Modified')
|
||||
}).data('path', path).data('multiselect', multiselect).data('mimetype', mimetypeFilter).data('allowDirectoryChooser', options.allowDirectoryChooser)
|
||||
if (typeof(options.filter) === 'function') {
|
||||
self.$filePicker.data('filter', options.filter)
|
||||
}
|
||||
|
||||
if (modal === undefined) {
|
||||
modal = false
|
||||
}
|
||||
if (multiselect === undefined) {
|
||||
multiselect = false
|
||||
}
|
||||
|
||||
$(options?.target ?? 'body').prepend(self.$filePicker)
|
||||
|
||||
self.$showGridView = $('button#picker-showgridview')
|
||||
self.$showGridView.on('click keydown', function(event) {
|
||||
if (isA11yActivation(event)) {
|
||||
self._onGridviewChange()
|
||||
/**
|
||||
* Create legacy callback wrapper to support old filepicker syntax
|
||||
* @param fn The original callback
|
||||
* @param type The file picker type which was used to pick the file(s)
|
||||
*/
|
||||
const legacyCallback = (fn, type) => {
|
||||
const getPath = (node) => {
|
||||
const root = node?.root || ''
|
||||
let path = node?.path || ''
|
||||
// TODO: Fix this in @nextcloud/files
|
||||
if (path.startsWith(root)) {
|
||||
path = path.slice(root.length) || '/'
|
||||
}
|
||||
})
|
||||
self._getGridSettings()
|
||||
|
||||
var newButton = self.$filePicker.find('.actions.creatable .button-add')
|
||||
if (type === self.FILEPICKER_TYPE_CHOOSE && !options.allowDirectoryChooser) {
|
||||
self.$filePicker.find('.actions.creatable').hide()
|
||||
}
|
||||
newButton.on('focus', function() {
|
||||
self.$filePicker.ocdialog('setEnterCallback', function(event) {
|
||||
event.stopImmediatePropagation()
|
||||
event.preventDefault()
|
||||
newButton.click()
|
||||
})
|
||||
})
|
||||
newButton.on('blur', function() {
|
||||
self.$filePicker.ocdialog('unsetEnterCallback')
|
||||
})
|
||||
|
||||
OC.registerMenu(newButton, self.$filePicker.find('.menu'), function() {
|
||||
$input.tooltip('hide')
|
||||
$input.focus()
|
||||
self.$filePicker.ocdialog('setEnterCallback', function(event) {
|
||||
event.stopImmediatePropagation()
|
||||
event.preventDefault()
|
||||
self.$filePicker.submit()
|
||||
})
|
||||
var newName = $input.val()
|
||||
var lastPos = newName.lastIndexOf('.')
|
||||
if (lastPos === -1) {
|
||||
lastPos = newName.length
|
||||
}
|
||||
$input.selectRange(0, lastPos)
|
||||
})
|
||||
var $form = self.$filePicker.find('.filenameform')
|
||||
var $input = $form.find('input[type=\'text\']')
|
||||
var $submit = $form.find('input[type=\'submit\']')
|
||||
$input.on('keydown', function(event) {
|
||||
if (isA11yActivation(event)) {
|
||||
event.stopImmediatePropagation()
|
||||
event.preventDefault()
|
||||
$form.submit()
|
||||
}
|
||||
})
|
||||
$submit.on('click', function(event) {
|
||||
event.stopImmediatePropagation()
|
||||
event.preventDefault()
|
||||
$form.submit()
|
||||
})
|
||||
|
||||
/**
|
||||
* Checks whether the given file name is valid.
|
||||
*
|
||||
* @param name file name to check
|
||||
* @return true if the file name is valid.
|
||||
* @throws a string exception with an error message if
|
||||
* the file name is not valid
|
||||
*
|
||||
* NOTE: This function is duplicated in the files app:
|
||||
* https://github.com/nextcloud/server/blob/b9bc2417e7a8dc81feb0abe20359bedaf864f790/apps/files/js/files.js#L127-L148
|
||||
*/
|
||||
var isFileNameValid = function (name) {
|
||||
var trimmedName = name.trim();
|
||||
if (trimmedName === '.' || trimmedName === '..')
|
||||
{
|
||||
throw t('files', '"{name}" is an invalid file name.', {name: name})
|
||||
} else if (trimmedName.length === 0) {
|
||||
throw t('files', 'File name cannot be empty.')
|
||||
} else if (trimmedName.indexOf('/') !== -1) {
|
||||
throw t('files', '"/" is not allowed inside a file name.')
|
||||
} else if (!!(trimmedName.match(OC.config.blacklist_files_regex))) {
|
||||
throw t('files', '"{name}" is not an allowed filetype', {name: name})
|
||||
}
|
||||
|
||||
return true
|
||||
return path
|
||||
}
|
||||
|
||||
var checkInput = function() {
|
||||
var filename = $input.val()
|
||||
try {
|
||||
if (!isFileNameValid(filename)) {
|
||||
// isFileNameValid(filename) throws an exception itself
|
||||
} else if (self.filelist.find(function(file) {
|
||||
return file.name === this
|
||||
}, filename)) {
|
||||
throw t('files', '{newName} already exists', { newName: filename }, undefined, {
|
||||
escape: false
|
||||
})
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
} catch (error) {
|
||||
$input.attr('title', error)
|
||||
$input.tooltip({
|
||||
placement: 'right',
|
||||
trigger: 'manual',
|
||||
'container': '.newFolderMenu'
|
||||
})
|
||||
$input.tooltip('_fixTitle')
|
||||
$input.tooltip('show')
|
||||
$input.addClass('error')
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
$form.on('submit', function(event) {
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
|
||||
if (checkInput()) {
|
||||
var newname = $input.val()
|
||||
self.filepicker.filesClient.createDirectory(self.$filePicker.data('path') + "/" + newname).always(function (status) {
|
||||
self._fillFilePicker(self.$filePicker.data('path') + "/" + newname, type)
|
||||
})
|
||||
OC.hideMenus()
|
||||
self.$filePicker.ocdialog('unsetEnterCallback')
|
||||
self.$filePicker.click()
|
||||
$input.val(newText)
|
||||
}
|
||||
})
|
||||
$input.on('input', function(event) {
|
||||
$input.tooltip('hide')
|
||||
})
|
||||
|
||||
self.$filePicker.ready(function() {
|
||||
self.$fileListHeader = self.$filePicker.find('.filelist thead tr')
|
||||
self.$filelist = self.$filePicker.find('.filelist tbody')
|
||||
self.$filelistContainer = self.$filePicker.find('.filelist-container')
|
||||
self.$dirTree = self.$filePicker.find('.dirtree')
|
||||
self.$dirTree.on('click keydown', '.crumb', self, function(event) {
|
||||
if (isA11yActivation(event)) {
|
||||
self._handleTreeListSelect(event, type)
|
||||
}
|
||||
})
|
||||
self.$filelist.on('click keydown', 'tr', function(event) {
|
||||
if (isA11yActivation(event)) {
|
||||
self._handlePickerClick(event, $(this), type)
|
||||
}
|
||||
})
|
||||
self.$fileListHeader.on('click keydown', 'a', function(event) {
|
||||
if (isA11yActivation(event)) {
|
||||
var dir = self.$filePicker.data('path')
|
||||
self.filepicker.sortField = $(event.currentTarget).data('sort')
|
||||
self.filepicker.sortOrder = self.filepicker.sortOrder === 'asc' ? 'desc' : 'asc'
|
||||
self._fillFilePicker(dir, type)
|
||||
}
|
||||
})
|
||||
self._fillFilePicker(path, type)
|
||||
})
|
||||
|
||||
// build buttons
|
||||
var functionToCall = function(returnType) {
|
||||
if (callback !== undefined) {
|
||||
var datapath
|
||||
if (multiselect === true) {
|
||||
datapath = []
|
||||
self.$filelist.find('tr.filepicker_element_selected').each(function(index, element) {
|
||||
datapath.push(self.$filePicker.data('path') + '/' + $(element).data('entryname'))
|
||||
})
|
||||
} else {
|
||||
datapath = self.$filePicker.data('path')
|
||||
var selectedName = self.$filelist.find('tr.filepicker_element_selected').data('entryname')
|
||||
if (selectedName) {
|
||||
datapath += '/' + selectedName
|
||||
}
|
||||
}
|
||||
callback(datapath, returnType)
|
||||
self.$filePicker.ocdialog('close')
|
||||
}
|
||||
}
|
||||
|
||||
var chooseCallback = function() {
|
||||
functionToCall(Dialogs.FILEPICKER_TYPE_CHOOSE)
|
||||
}
|
||||
|
||||
var copyCallback = function() {
|
||||
functionToCall(Dialogs.FILEPICKER_TYPE_COPY)
|
||||
}
|
||||
|
||||
var moveCallback = function() {
|
||||
functionToCall(Dialogs.FILEPICKER_TYPE_MOVE)
|
||||
}
|
||||
|
||||
var buttonlist = []
|
||||
if (type === Dialogs.FILEPICKER_TYPE_CHOOSE) {
|
||||
buttonlist.push({
|
||||
text: t('core', 'Choose'),
|
||||
click: chooseCallback,
|
||||
defaultButton: true
|
||||
})
|
||||
} else if (type === Dialogs.FILEPICKER_TYPE_CUSTOM) {
|
||||
options.buttons.forEach(function(button) {
|
||||
buttonlist.push({
|
||||
text: button.text,
|
||||
click: function() {
|
||||
functionToCall(button.type)
|
||||
},
|
||||
defaultButton: button.defaultButton
|
||||
})
|
||||
})
|
||||
if (multiselect) {
|
||||
return (nodes) => fn(nodes.map(getPath), type)
|
||||
} else {
|
||||
if (type === Dialogs.FILEPICKER_TYPE_COPY || type === Dialogs.FILEPICKER_TYPE_COPY_MOVE) {
|
||||
buttonlist.push({
|
||||
text: t('core', 'Copy'),
|
||||
click: copyCallback,
|
||||
defaultButton: false
|
||||
})
|
||||
}
|
||||
if (type === Dialogs.FILEPICKER_TYPE_MOVE || type === Dialogs.FILEPICKER_TYPE_COPY_MOVE) {
|
||||
buttonlist.push({
|
||||
text: t('core', 'Move'),
|
||||
click: moveCallback,
|
||||
defaultButton: true
|
||||
})
|
||||
}
|
||||
return (nodes) => fn(getPath(nodes[0]), type)
|
||||
}
|
||||
}
|
||||
|
||||
self.$filePicker.ocdialog({
|
||||
closeOnEscape: true,
|
||||
// max-width of 600
|
||||
width: 600,
|
||||
height: 500,
|
||||
modal: modal,
|
||||
buttons: buttonlist,
|
||||
style: {
|
||||
buttons: 'aside'
|
||||
},
|
||||
close: function() {
|
||||
try {
|
||||
$(this).ocdialog('destroy').remove()
|
||||
} catch (e) {
|
||||
}
|
||||
self.$filePicker = null
|
||||
}
|
||||
})
|
||||
|
||||
// We can access primary class only from oc-dialog.
|
||||
// Hence this is one of the approach to get the choose button.
|
||||
var getOcDialog = self.$filePicker.closest('.oc-dialog')
|
||||
var buttonEnableDisable = getOcDialog.find('.primary')
|
||||
if (self.$filePicker.data('mimetype').indexOf('httpd/unix-directory') !== -1 || self.$filePicker.data('allowDirectoryChooser')) {
|
||||
buttonEnableDisable.prop('disabled', false)
|
||||
} else {
|
||||
buttonEnableDisable.prop('disabled', true)
|
||||
}
|
||||
/**
|
||||
* Coverting a Node into a legacy file info to support the OC.dialogs.filepicker filter function
|
||||
* @param node The node to convert
|
||||
*/
|
||||
const nodeToLegacyFile = (node) => ({
|
||||
id: node.fileid || null,
|
||||
path: node.path,
|
||||
mimetype: node.mime || null,
|
||||
mtime: node.mtime?.getTime() || null,
|
||||
permissions: node.permissions,
|
||||
name: node.attributes?.displayname || node.basename,
|
||||
etag: node.attributes?.etag || null,
|
||||
hasPreview: node.attributes?.hasPreview || null,
|
||||
mountType: node.attributes?.mountType || null,
|
||||
quotaAvailableBytes: node.attributes?.quotaAvailableBytes || null,
|
||||
icon: null,
|
||||
sharePermissions: null,
|
||||
})
|
||||
.fail(function(status, error) {
|
||||
// If the method is called while navigating away
|
||||
// from the page, it is probably not needed ;)
|
||||
self.filepicker.loading = false
|
||||
if (status !== 0) {
|
||||
alert(t('core', 'Error loading file picker template: {error}', { error: error }))
|
||||
}
|
||||
|
||||
const buttons = []
|
||||
if (type === FilePickerType.Choose) {
|
||||
buttons.push({
|
||||
label: t('core', 'Choose'),
|
||||
type: 'primary',
|
||||
callback: legacyCallback(callback, FilePickerType.Choose),
|
||||
})
|
||||
} else if (type === FilePickerType.Copy || type === FilePickerType.CopyMove) {
|
||||
buttons.push({
|
||||
label: t('core', 'Copy'),
|
||||
callback: legacyCallback(callback, FilePickerType.Copy),
|
||||
})
|
||||
}
|
||||
if (type === FilePickerType.CopyMove || type === FilePickerType.Move) {
|
||||
buttons.push({
|
||||
label: t('core', 'Move'),
|
||||
type: 'primary',
|
||||
callback: legacyCallback(callback, FilePickerType.Move),
|
||||
})
|
||||
}
|
||||
if (type === FilePickerType.Custom) {
|
||||
(options.buttons || []).forEach((button) => {
|
||||
buttons.push({
|
||||
callback: legacyCallback(callback, button.type),
|
||||
label: button.text,
|
||||
type: button.defaultButton ? 'primary' : 'secondary',
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const filter = {}
|
||||
if (typeof options?.filter === 'function') {
|
||||
filter.filterFn = (node) => options.filter(nodeToLegacyFile(node))
|
||||
}
|
||||
|
||||
const mimetypeFilter = typeof mimetype === 'string' ? [mimetype] : (mimetype || [])
|
||||
|
||||
spawnDialog(FilePickerVue, {
|
||||
...filter,
|
||||
name: title,
|
||||
buttons,
|
||||
multiselect,
|
||||
path,
|
||||
mimetypeFilter,
|
||||
allowPickDirectory: options?.allowDirectoryChooser === true || mimetypeFilter.includes('httpd/unix-directory'),
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays raw dialog
|
||||
* You better use a wrapper instead ...
|
||||
|
@ -1038,52 +815,7 @@ const Dialogs = {
|
|||
// }
|
||||
return dialogDeferred.promise()
|
||||
},
|
||||
// get the gridview setting and set the input accordingly
|
||||
_getGridSettings: function() {
|
||||
const self = this
|
||||
$.get(OC.generateUrl('/apps/files/api/v1/showgridview'), function(response) {
|
||||
self.$showGridView
|
||||
.removeClass('icon-toggle-filelist icon-toggle-pictures')
|
||||
.addClass(response.gridview ? 'icon-toggle-filelist' : 'icon-toggle-pictures')
|
||||
self.$showGridView.attr(
|
||||
'aria-label',
|
||||
response.gridview ? t('files', 'Show list view') : t('files', 'Show grid view'),
|
||||
)
|
||||
$('.list-container').toggleClass('view-grid', response.gridview)
|
||||
})
|
||||
},
|
||||
_onGridviewChange: function() {
|
||||
const isGridView = this.$showGridView.hasClass('icon-toggle-filelist')
|
||||
// only save state if user is logged in
|
||||
if (OC.currentUser) {
|
||||
$.post(OC.generateUrl('/apps/files/api/v1/showgridview'), { show: !isGridView })
|
||||
}
|
||||
this.$showGridView
|
||||
.removeClass('icon-toggle-filelist icon-toggle-pictures')
|
||||
.addClass(isGridView ? 'icon-toggle-pictures' : 'icon-toggle-filelist')
|
||||
this.$showGridView.attr(
|
||||
'aria-label',
|
||||
isGridView ? t('files', 'Show grid view') : t('files', 'Show list view'),
|
||||
)
|
||||
this.$filePicker.find('.list-container').toggleClass('view-grid', !isGridView)
|
||||
},
|
||||
_getFilePickerTemplate: function() {
|
||||
var defer = $.Deferred()
|
||||
if (!this.$filePickerTemplate) {
|
||||
var self = this
|
||||
$.get(OC.filePath('core', 'templates', 'filepicker.html'), function(tmpl) {
|
||||
self.$filePickerTemplate = $(tmpl)
|
||||
self.$listTmpl = self.$filePickerTemplate.find('.filelist tbody tr:first-child').detach()
|
||||
defer.resolve(self.$filePickerTemplate)
|
||||
})
|
||||
.fail(function(jqXHR, textStatus, errorThrown) {
|
||||
defer.reject(jqXHR.status, errorThrown)
|
||||
})
|
||||
} else {
|
||||
defer.resolve(this.$filePickerTemplate)
|
||||
}
|
||||
return defer.promise()
|
||||
},
|
||||
|
||||
_getMessageTemplate: function() {
|
||||
var defer = $.Deferred()
|
||||
if (!this.$messageTemplate) {
|
||||
|
@ -1116,274 +848,6 @@ const Dialogs = {
|
|||
}
|
||||
return defer.promise()
|
||||
},
|
||||
|
||||
/**
|
||||
* fills the filepicker with files
|
||||
*/
|
||||
_fillFilePicker: async function(dir, type) {
|
||||
var self = this
|
||||
this.$filelist.empty()
|
||||
this.$filePicker.find('.emptycontent').hide()
|
||||
this.$filelistContainer.addClass('icon-loading')
|
||||
this.$filePicker.data('path', dir)
|
||||
var filter = this.$filePicker.data('mimetype')
|
||||
var advancedFilter = this.$filePicker.data('filter')
|
||||
if (typeof (filter) === 'string') {
|
||||
filter = [filter]
|
||||
}
|
||||
self.$fileListHeader.find('.sort-indicator').addClass('hidden').removeClass('icon-triangle-n').removeClass('icon-triangle-s')
|
||||
self.$fileListHeader.find('[data-sort=' + self.filepicker.sortField + '] .sort-indicator').removeClass('hidden')
|
||||
if (self.filepicker.sortOrder === 'asc') {
|
||||
self.$fileListHeader.find('[data-sort=' + self.filepicker.sortField + '] .sort-indicator').addClass('icon-triangle-n')
|
||||
} else {
|
||||
self.$fileListHeader.find('[data-sort=' + self.filepicker.sortField + '] .sort-indicator').addClass('icon-triangle-s')
|
||||
}
|
||||
|
||||
// Wrap within a method because a promise cannot return multiple values
|
||||
// But the client impleemntation still does it...
|
||||
var getFolderContents = async function(dir) {
|
||||
return self.filepicker.filesClient.getFolderContents(dir)
|
||||
.then((status, files) => {
|
||||
return files
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
var files = await getFolderContents(dir)
|
||||
} catch (error) {
|
||||
// fallback to root if requested dir is non-existent
|
||||
console.error('Requested path does not exists, falling back to root')
|
||||
var files = await getFolderContents('/')
|
||||
this.$filePicker.data('path', '/')
|
||||
this._changeButtonsText(type, '')
|
||||
}
|
||||
|
||||
self.filelist = files
|
||||
if (filter && filter.length > 0 && filter.indexOf('*') === -1) {
|
||||
files = files.filter(function(file) {
|
||||
return file.type === 'dir' || filter.indexOf(file.mimetype) !== -1
|
||||
})
|
||||
}
|
||||
|
||||
if (advancedFilter) {
|
||||
files = files.filter(advancedFilter)
|
||||
}
|
||||
|
||||
// Check if the showHidden input field exist and if it exist follow it
|
||||
// Otherwise just show the hidden files
|
||||
const showHiddenInput = document.getElementById('showHiddenFiles')
|
||||
if (showHiddenInput?.value !== "1") {
|
||||
files = files.filter(function (file) {
|
||||
return !file.name.startsWith('.')
|
||||
})
|
||||
}
|
||||
|
||||
var Comparators = {
|
||||
name: function(fileInfo1, fileInfo2) {
|
||||
if (fileInfo1.type === 'dir' && fileInfo2.type !== 'dir') {
|
||||
return -1
|
||||
}
|
||||
if (fileInfo1.type !== 'dir' && fileInfo2.type === 'dir') {
|
||||
return 1
|
||||
}
|
||||
return OC.Util.naturalSortCompare(fileInfo1.name, fileInfo2.name)
|
||||
},
|
||||
size: function(fileInfo1, fileInfo2) {
|
||||
return fileInfo1.size - fileInfo2.size
|
||||
},
|
||||
mtime: function(fileInfo1, fileInfo2) {
|
||||
return fileInfo1.mtime - fileInfo2.mtime
|
||||
}
|
||||
}
|
||||
var comparator = Comparators[self.filepicker.sortField] || Comparators.name
|
||||
files = files.sort(function(file1, file2) {
|
||||
var isFavorite = function(fileInfo) {
|
||||
return fileInfo.tags && fileInfo.tags.indexOf(OC.TAG_FAVORITE) >= 0
|
||||
}
|
||||
|
||||
if (isFavorite(file1) && !isFavorite(file2)) {
|
||||
return -1
|
||||
} else if (!isFavorite(file1) && isFavorite(file2)) {
|
||||
return 1
|
||||
}
|
||||
|
||||
return self.filepicker.sortOrder === 'asc' ? comparator(file1, file2) : -comparator(file1, file2)
|
||||
})
|
||||
|
||||
self._fillSlug()
|
||||
|
||||
if (files.length === 0) {
|
||||
self.$filePicker.find('.emptycontent').show()
|
||||
self.$fileListHeader.hide()
|
||||
} else {
|
||||
self.$filePicker.find('.emptycontent').hide()
|
||||
self.$fileListHeader.show()
|
||||
}
|
||||
|
||||
self.$filelist.empty();
|
||||
|
||||
$.each(files, function(idx, entry) {
|
||||
if (entry.isEncrypted && entry.mimetype === 'httpd/unix-directory') {
|
||||
entry.icon = OC.MimeType.getIconUrl('dir-encrypted')
|
||||
} else {
|
||||
entry.icon = OC.MimeType.getIconUrl(entry.mimetype)
|
||||
}
|
||||
|
||||
var simpleSize, sizeColor
|
||||
if (typeof (entry.size) !== 'undefined' && entry.size >= 0) {
|
||||
simpleSize = OC.Util.humanFileSize(parseInt(entry.size, 10), true)
|
||||
sizeColor = Math.round(160 - Math.pow((entry.size / (1024 * 1024)), 2))
|
||||
} else {
|
||||
simpleSize = t('files', 'Pending')
|
||||
sizeColor = 80
|
||||
}
|
||||
|
||||
// split the filename in half if the size is bigger than 20 char
|
||||
// for ellipsis
|
||||
if (entry.name.length >= 10) {
|
||||
// leave maximum 10 letters
|
||||
var split = Math.min(Math.floor(entry.name.length / 2), 10)
|
||||
var filename1 = entry.name.substr(0, entry.name.length - split)
|
||||
var filename2 = entry.name.substr(entry.name.length - split)
|
||||
} else {
|
||||
var filename1 = entry.name
|
||||
var filename2 = ''
|
||||
}
|
||||
|
||||
var $row = self.$listTmpl.octemplate({
|
||||
type: entry.type,
|
||||
dir: dir,
|
||||
filename: entry.name,
|
||||
filename1: filename1,
|
||||
filename2: filename2,
|
||||
date: OC.Util.relativeModifiedDate(entry.mtime),
|
||||
size: simpleSize,
|
||||
sizeColor: sizeColor,
|
||||
icon: entry.icon
|
||||
})
|
||||
if (entry.type === 'file') {
|
||||
var urlSpec = {
|
||||
file: dir + '/' + entry.name,
|
||||
x: 100,
|
||||
y: 100
|
||||
}
|
||||
var img = new Image()
|
||||
var previewUrl = OC.generateUrl('/core/preview.png?') + $.param(urlSpec)
|
||||
img.onload = function() {
|
||||
if (img.width > 5) {
|
||||
$row.find('td.filename').attr('style', 'background-image:url(' + previewUrl + ')')
|
||||
}
|
||||
}
|
||||
img.src = previewUrl
|
||||
}
|
||||
self.$filelist.append($row)
|
||||
})
|
||||
|
||||
self.$filelistContainer.removeClass('icon-loading')
|
||||
},
|
||||
/**
|
||||
* fills the tree list with directories
|
||||
*/
|
||||
_fillSlug: function() {
|
||||
var addButton = this.$dirTree.find('.actions.creatable').detach()
|
||||
this.$dirTree.empty()
|
||||
var self = this
|
||||
|
||||
self.$dirTree.append('<nav></nav>')
|
||||
self.$dirTree.append(addButton)
|
||||
|
||||
var dir
|
||||
var path = this.$filePicker.data('path')
|
||||
var $template = $('<li data-dir="{dir}" tabindex="0"><a class="{classList}">{name}</a></li>').addClass('crumb')
|
||||
var $breadcrumbs = $('<ul class="breadcrumb"></ul>')
|
||||
if (path) {
|
||||
var paths = path.split('/')
|
||||
$.each(paths, function(index, dir) {
|
||||
dir = paths.pop()
|
||||
if (dir === '') {
|
||||
return false
|
||||
}
|
||||
$breadcrumbs.prepend($template.octemplate({
|
||||
dir: paths.join('/') + '/' + dir,
|
||||
name: dir
|
||||
}))
|
||||
})
|
||||
}
|
||||
$template.octemplate({
|
||||
dir: '',
|
||||
name: t('core', 'Home'),
|
||||
classList: 'icon-home'
|
||||
}, { escapeFunction: null }).addClass('crumb svg crumbhome').prependTo($breadcrumbs)
|
||||
|
||||
|
||||
this.$dirTree.find('> nav').prepend($breadcrumbs)
|
||||
},
|
||||
/**
|
||||
* handle selection made in the tree list
|
||||
*/
|
||||
_handleTreeListSelect: function(event, type) {
|
||||
var self = event.data
|
||||
var dir = $(event.target).closest('.crumb').data('dir')
|
||||
self._fillFilePicker(dir, type)
|
||||
var getOcDialog = (event.target).closest('.oc-dialog')
|
||||
var buttonEnableDisable = $('.primary', getOcDialog)
|
||||
this._changeButtonsText(type, dir.split(/[/]+/).pop())
|
||||
if (this.$filePicker.data('mimetype').indexOf('httpd/unix-directory') !== -1 || this.$filePicker.data('allowDirectoryChooser')) {
|
||||
buttonEnableDisable.prop('disabled', false)
|
||||
} else {
|
||||
buttonEnableDisable.prop('disabled', true)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* handle clicks made in the filepicker
|
||||
*/
|
||||
_handlePickerClick: function(event, $element, type) {
|
||||
var getOcDialog = this.$filePicker.closest('.oc-dialog')
|
||||
var buttonEnableDisable = getOcDialog.find('.primary')
|
||||
if ($element.data('type') === 'file') {
|
||||
if (this.$filePicker.data('multiselect') !== true || !event.ctrlKey) {
|
||||
this.$filelist.find('.filepicker_element_selected').removeClass('filepicker_element_selected')
|
||||
}
|
||||
$element.toggleClass('filepicker_element_selected')
|
||||
buttonEnableDisable.prop('disabled', false)
|
||||
} else if ($element.data('type') === 'dir') {
|
||||
this._fillFilePicker(this.$filePicker.data('path') + '/' + $element.data('entryname'), type)
|
||||
this._changeButtonsText(type, $element.data('entryname'))
|
||||
if (this.$filePicker.data('mimetype').indexOf('httpd/unix-directory') !== -1 || this.$filePicker.data('allowDirectoryChooser')) {
|
||||
buttonEnableDisable.prop('disabled', false)
|
||||
} else {
|
||||
buttonEnableDisable.prop('disabled', true)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle
|
||||
* @param type of action
|
||||
* @param dir on which to change buttons text
|
||||
* @private
|
||||
*/
|
||||
_changeButtonsText: function(type, dir) {
|
||||
var copyText = dir === '' ? t('core', 'Copy') : t('core', 'Copy to {folder}', { folder: dir })
|
||||
var moveText = dir === '' ? t('core', 'Move') : t('core', 'Move to {folder}', { folder: dir })
|
||||
var buttons = $('.oc-dialog-buttonrow button')
|
||||
switch (type) {
|
||||
case this.FILEPICKER_TYPE_CHOOSE:
|
||||
break
|
||||
case this.FILEPICKER_TYPE_CUSTOM:
|
||||
break
|
||||
case this.FILEPICKER_TYPE_COPY:
|
||||
buttons.text(copyText)
|
||||
break
|
||||
case this.FILEPICKER_TYPE_MOVE:
|
||||
buttons.text(moveText)
|
||||
break
|
||||
case this.FILEPICKER_TYPE_COPY_MOVE:
|
||||
buttons.eq(0).text(copyText)
|
||||
buttons.eq(1).text(moveText)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Dialogs
|
||||
|
|
|
@ -35,6 +35,10 @@ import './globals.js'
|
|||
import './jquery/index.js'
|
||||
import { initCore } from './init.js'
|
||||
import { registerAppsSlideToggle } from './OC/apps.js'
|
||||
import { getRequestToken } from '@nextcloud/auth'
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
__webpack_nonce__ = btoa(getRequestToken())
|
||||
|
||||
window.addEventListener('DOMContentLoaded', function() {
|
||||
initCore()
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
<div id="{dialog_name}" title="{title}">
|
||||
<span class="dirtree">
|
||||
<nav></nav>
|
||||
<span class="actions creatable"><a href="#" class="icon icon-add button button-add" aria-label="{newtext}"></a>
|
||||
<nav class="menu popovermenu bubble menu-left newFolderMenu">
|
||||
<ul><li>
|
||||
<form class="filenameform">
|
||||
<input type="text" value={newtext}>
|
||||
<input class="icon-confirm" type="submit" value="">
|
||||
</form>
|
||||
</li></ul>
|
||||
</nav>
|
||||
</span>
|
||||
|
||||
</span>
|
||||
|
||||
<button id="picker-showgridview" class="icon-toggle-pictures"></button>
|
||||
<div class="filelist-container">
|
||||
<div class="emptycontent">
|
||||
<div class="icon-folder"></div>
|
||||
<h2>{emptytext}</h2>
|
||||
</div>
|
||||
<table id="picker-filestable" class="filelist list-container view-grid">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="column-name">
|
||||
<div id="column-name-container">
|
||||
<a class="name sort columntitle" data-sort="name" tabindex="0">
|
||||
<span>{nameCol}</span>
|
||||
<span class="sort-indicator hidden icon-triangle-n"></span>
|
||||
</a>
|
||||
</div>
|
||||
</th>
|
||||
<th class="column-size">
|
||||
<a class="size sort columntitle" data-sort="size" tabindex="0">
|
||||
<span>{sizeCol}</span>
|
||||
<span class="sort-indicator hidden icon-triangle-n"></span></a>
|
||||
</th>
|
||||
<th class="column-mtime">
|
||||
<a id="modified" class="columntitle" data-sort="mtime" tabindex="0">
|
||||
<span>{modifiedCol}</span>
|
||||
<span class="sort-indicator hidden icon-triangle-n"></span></a>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr data-entryname="{filename}" data-type="{type}" tabindex="0">
|
||||
<td class="filename"
|
||||
style="background-image:url({icon})">
|
||||
<span class="filename-parts">
|
||||
<span class="filename-parts__first">{filename1}</span>
|
||||
<span class="filename-parts__last">{filename2}</span>
|
||||
</span>
|
||||
</td>
|
||||
<td class="filesize">{size}</td>
|
||||
<td class="date">{date}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
291
package-lock.json
generated
291
package-lock.json
generated
|
@ -17,9 +17,9 @@
|
|||
"@nextcloud/browserslist-config": "^2.3.0",
|
||||
"@nextcloud/calendar-availability-vue": "^2.0.0-beta.1",
|
||||
"@nextcloud/capabilities": "^1.0.4",
|
||||
"@nextcloud/dialogs": "^4.1.0",
|
||||
"@nextcloud/dialogs": "^5.0.0-beta.2",
|
||||
"@nextcloud/event-bus": "^3.1.0",
|
||||
"@nextcloud/files": "^3.0.0-beta.18",
|
||||
"@nextcloud/files": "3.0.0-beta.18",
|
||||
"@nextcloud/initial-state": "^2.0.0",
|
||||
"@nextcloud/l10n": "^2.1.0",
|
||||
"@nextcloud/logger": "^2.5.0",
|
||||
|
@ -28,7 +28,7 @@
|
|||
"@nextcloud/paths": "^2.1.0",
|
||||
"@nextcloud/router": "^2.1.2",
|
||||
"@nextcloud/sharing": "^0.1.0",
|
||||
"@nextcloud/vue": "^8.0.0-beta.2",
|
||||
"@nextcloud/vue": "8.0.0-beta.2",
|
||||
"@nextcloud/vue-dashboard": "^2.0.1",
|
||||
"@skjnldsv/sanitize-svg": "^1.0.2",
|
||||
"@vueuse/components": "^10.2.0",
|
||||
|
@ -3571,6 +3571,31 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@nextcloud/dialogs": {
|
||||
"version": "5.0.0-beta.2",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/dialogs/-/dialogs-5.0.0-beta.2.tgz",
|
||||
"integrity": "sha512-IRf5iOzr0ZJnysdeBd6Q3tNfF7CgHFcsRCKBv/gayLCZQpV/kC4K8dg9ETtGqd/YNkfojqcOrEyRDzOy/sRE/w==",
|
||||
"dependencies": {
|
||||
"@mdi/svg": "^7.2.96",
|
||||
"@nextcloud/files": "^3.0.0-beta.16",
|
||||
"@nextcloud/l10n": "^2.2.0",
|
||||
"@nextcloud/typings": "^1.7.0",
|
||||
"@nextcloud/vue": "^8.0.0-beta.3",
|
||||
"@types/toastify-js": "^1.12.0",
|
||||
"@vueuse/core": "^10.3.0",
|
||||
"toastify-js": "^1.12.0",
|
||||
"vue-frag": "^1.4.3",
|
||||
"vue-material-design-icons": "^5.2.0",
|
||||
"webdav": "^5.2.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.0.0",
|
||||
"npm": "^9.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^2.7.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/dialogs/node_modules/@nextcloud/dialogs": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/dialogs/-/dialogs-4.1.0.tgz",
|
||||
"integrity": "sha512-7e0QMdJKL1Pn/RxOA6Fjm2PMSEUSvhRXuyoZqNFN/rvvVK9mXOCvkRI+vYwuCBCzoTi1Bv3k12BoXxB2UHAufQ==",
|
||||
|
@ -3585,6 +3610,183 @@
|
|||
"npm": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/dialogs/node_modules/@nextcloud/vue": {
|
||||
"version": "8.0.0-beta.4",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-8.0.0-beta.4.tgz",
|
||||
"integrity": "sha512-Kd5zGnfLVO05y8QytpUH9D3CMQACARty+guA548koq4cG5ad3myKGPNtP8qxFaUvzmTSYf57gGAbAbHX1eDPxg==",
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.1.0",
|
||||
"@nextcloud/auth": "^2.0.0",
|
||||
"@nextcloud/axios": "^2.0.0",
|
||||
"@nextcloud/browser-storage": "^0.2.0",
|
||||
"@nextcloud/calendar-js": "^6.0.0",
|
||||
"@nextcloud/capabilities": "^1.0.4",
|
||||
"@nextcloud/dialogs": "^4.0.0",
|
||||
"@nextcloud/event-bus": "^3.0.0",
|
||||
"@nextcloud/initial-state": "^2.0.0",
|
||||
"@nextcloud/l10n": "^2.0.1",
|
||||
"@nextcloud/logger": "^2.2.1",
|
||||
"@nextcloud/router": "^2.0.0",
|
||||
"@nextcloud/vue-select": "^3.23.0",
|
||||
"@skjnldsv/sanitize-svg": "^1.0.2",
|
||||
"@vueuse/components": "^10.0.2",
|
||||
"@vueuse/core": "^10.1.2",
|
||||
"clone": "^2.1.2",
|
||||
"debounce": "1.2.1",
|
||||
"emoji-mart-vue-fast": "^15.0.0",
|
||||
"escape-html": "^1.0.3",
|
||||
"floating-vue": "^1.0.0-beta.19",
|
||||
"focus-trap": "^7.4.3",
|
||||
"linkify-string": "^4.0.0",
|
||||
"md5": "^2.3.0",
|
||||
"node-polyfill-webpack-plugin": "^2.0.1",
|
||||
"rehype-react": "^7.1.2",
|
||||
"remark-breaks": "^3.0.2",
|
||||
"remark-external-links": "^9.0.1",
|
||||
"remark-parse": "^10.0.1",
|
||||
"remark-rehype": "^10.1.0",
|
||||
"splitpanes": "^2.4.1",
|
||||
"string-length": "^5.0.1",
|
||||
"striptags": "^3.2.0",
|
||||
"tributejs": "^5.1.3",
|
||||
"unified": "^11.0.1",
|
||||
"unist-builder": "^4.0.0",
|
||||
"unist-util-visit": "^5.0.0",
|
||||
"vue": "^2.7.14",
|
||||
"vue-color": "^2.8.1",
|
||||
"vue-frag": "^1.4.3",
|
||||
"vue-material-design-icons": "^5.1.2",
|
||||
"vue2-datepicker": "^3.11.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.0.0",
|
||||
"npm": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/dialogs/node_modules/@types/unist": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.0.tgz",
|
||||
"integrity": "sha512-MFETx3tbTjE7Uk6vvnWINA/1iJ7LuMdO4fcq8UfF0pRbj01aGLduVvQcRyswuACJdpnHgg8E3rQLhaRdNEJS0w=="
|
||||
},
|
||||
"node_modules/@nextcloud/dialogs/node_modules/is-plain-obj": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
|
||||
"integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/dialogs/node_modules/unified": {
|
||||
"version": "11.0.2",
|
||||
"resolved": "https://registry.npmjs.org/unified/-/unified-11.0.2.tgz",
|
||||
"integrity": "sha512-Zta++onvS/dJ6xUvXQOR5q8XJZOkiMCE5wQ8Yv9mLR25pxRS567EX0GO6HZRxxNV/lznwfsvRZ/1pqe9K9QLeQ==",
|
||||
"dependencies": {
|
||||
"@types/unist": "^3.0.0",
|
||||
"@ungap/structured-clone": "^1.0.0",
|
||||
"bail": "^2.0.0",
|
||||
"devlop": "^1.0.0",
|
||||
"is-plain-obj": "^4.0.0",
|
||||
"trough": "^2.0.0",
|
||||
"vfile": "^6.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/dialogs/node_modules/unist-builder": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-4.0.0.tgz",
|
||||
"integrity": "sha512-wmRFnH+BLpZnTKpc5L7O67Kac89s9HMrtELpnNaE6TAobq5DTZZs5YaTQfAZBA9bFPECx2uVAPO31c+GVug8mg==",
|
||||
"dependencies": {
|
||||
"@types/unist": "^3.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/dialogs/node_modules/unist-util-is": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz",
|
||||
"integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==",
|
||||
"dependencies": {
|
||||
"@types/unist": "^3.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/dialogs/node_modules/unist-util-stringify-position": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz",
|
||||
"integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==",
|
||||
"dependencies": {
|
||||
"@types/unist": "^3.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/dialogs/node_modules/unist-util-visit": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz",
|
||||
"integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==",
|
||||
"dependencies": {
|
||||
"@types/unist": "^3.0.0",
|
||||
"unist-util-is": "^6.0.0",
|
||||
"unist-util-visit-parents": "^6.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/dialogs/node_modules/unist-util-visit-parents": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz",
|
||||
"integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==",
|
||||
"dependencies": {
|
||||
"@types/unist": "^3.0.0",
|
||||
"unist-util-is": "^6.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/dialogs/node_modules/vfile": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz",
|
||||
"integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==",
|
||||
"dependencies": {
|
||||
"@types/unist": "^3.0.0",
|
||||
"unist-util-stringify-position": "^4.0.0",
|
||||
"vfile-message": "^4.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/dialogs/node_modules/vfile-message": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz",
|
||||
"integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==",
|
||||
"dependencies": {
|
||||
"@types/unist": "^3.0.0",
|
||||
"unist-util-stringify-position": "^4.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/eslint-config": {
|
||||
"version": "8.3.0-beta.2",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/eslint-config/-/eslint-config-8.3.0-beta.2.tgz",
|
||||
|
@ -3761,6 +3963,37 @@
|
|||
"npm": "^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/password-confirmation/node_modules/@nextcloud/dialogs": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/dialogs/-/dialogs-4.1.0.tgz",
|
||||
"integrity": "sha512-7e0QMdJKL1Pn/RxOA6Fjm2PMSEUSvhRXuyoZqNFN/rvvVK9mXOCvkRI+vYwuCBCzoTi1Bv3k12BoXxB2UHAufQ==",
|
||||
"dependencies": {
|
||||
"@nextcloud/l10n": "^2.1.0",
|
||||
"@nextcloud/typings": "^1.7.0",
|
||||
"core-js": "^3.31.0",
|
||||
"toastify-js": "^1.12.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.0.0",
|
||||
"npm": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/password-confirmation/node_modules/@nextcloud/dialogs/node_modules/@nextcloud/l10n": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-2.2.0.tgz",
|
||||
"integrity": "sha512-UAM2NJcl/NR46MANSF7Gr7q8/Up672zRyGrxLpN3k4URNmWQM9upkbRME+1K3T29wPrUyOIbQu710ZjvZafqFA==",
|
||||
"dependencies": {
|
||||
"@nextcloud/router": "^2.1.2",
|
||||
"@nextcloud/typings": "^1.7.0",
|
||||
"dompurify": "^3.0.3",
|
||||
"escape-html": "^1.0.3",
|
||||
"node-gettext": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.0.0",
|
||||
"npm": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/password-confirmation/node_modules/@nextcloud/l10n": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-1.6.0.tgz",
|
||||
|
@ -4252,6 +4485,21 @@
|
|||
"vue": "2.x"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/vue/node_modules/@nextcloud/dialogs": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/dialogs/-/dialogs-4.1.0.tgz",
|
||||
"integrity": "sha512-7e0QMdJKL1Pn/RxOA6Fjm2PMSEUSvhRXuyoZqNFN/rvvVK9mXOCvkRI+vYwuCBCzoTi1Bv3k12BoXxB2UHAufQ==",
|
||||
"dependencies": {
|
||||
"@nextcloud/l10n": "^2.1.0",
|
||||
"@nextcloud/typings": "^1.7.0",
|
||||
"core-js": "^3.31.0",
|
||||
"toastify-js": "^1.12.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.0.0",
|
||||
"npm": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/webpack-vue-config": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/webpack-vue-config/-/webpack-vue-config-6.0.0.tgz",
|
||||
|
@ -5456,6 +5704,11 @@
|
|||
"@types/jest": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/toastify-js": {
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/toastify-js/-/toastify-js-1.12.0.tgz",
|
||||
"integrity": "sha512-fqpDHaKhFukN9KRm24bbH0wozvHmSwjvkaLjBUrWcSfSS4zysIwTYqNLG3XbSNhRlsTNRNLGS23tp/VhPwsfHQ=="
|
||||
},
|
||||
"node_modules/@types/tough-cookie": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz",
|
||||
|
@ -5828,6 +6081,11 @@
|
|||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@ungap/structured-clone": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
|
||||
"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ=="
|
||||
},
|
||||
"node_modules/@vue/compiler-sfc": {
|
||||
"version": "2.7.14",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.14.tgz",
|
||||
|
@ -9848,6 +10106,18 @@
|
|||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/devlop": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz",
|
||||
"integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==",
|
||||
"dependencies": {
|
||||
"dequal": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/devtools-protocol": {
|
||||
"version": "0.0.1147663",
|
||||
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz",
|
||||
|
@ -18753,6 +19023,21 @@
|
|||
"vue": "^2.7.14"
|
||||
}
|
||||
},
|
||||
"node_modules/nextcloud-vue-collections/node_modules/@nextcloud/dialogs": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/dialogs/-/dialogs-4.1.0.tgz",
|
||||
"integrity": "sha512-7e0QMdJKL1Pn/RxOA6Fjm2PMSEUSvhRXuyoZqNFN/rvvVK9mXOCvkRI+vYwuCBCzoTi1Bv3k12BoXxB2UHAufQ==",
|
||||
"dependencies": {
|
||||
"@nextcloud/l10n": "^2.1.0",
|
||||
"@nextcloud/typings": "^1.7.0",
|
||||
"core-js": "^3.31.0",
|
||||
"toastify-js": "^1.12.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.0.0",
|
||||
"npm": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nextcloud-vue-collections/node_modules/@nextcloud/vue": {
|
||||
"version": "7.12.2",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-7.12.2.tgz",
|
||||
|
|
|
@ -43,9 +43,9 @@
|
|||
"@nextcloud/browserslist-config": "^2.3.0",
|
||||
"@nextcloud/calendar-availability-vue": "^2.0.0-beta.1",
|
||||
"@nextcloud/capabilities": "^1.0.4",
|
||||
"@nextcloud/dialogs": "^4.1.0",
|
||||
"@nextcloud/dialogs": "^5.0.0-beta.2",
|
||||
"@nextcloud/event-bus": "^3.1.0",
|
||||
"@nextcloud/files": "^3.0.0-beta.18",
|
||||
"@nextcloud/files": "3.0.0-beta.18",
|
||||
"@nextcloud/initial-state": "^2.0.0",
|
||||
"@nextcloud/l10n": "^2.1.0",
|
||||
"@nextcloud/logger": "^2.5.0",
|
||||
|
@ -54,7 +54,7 @@
|
|||
"@nextcloud/paths": "^2.1.0",
|
||||
"@nextcloud/router": "^2.1.2",
|
||||
"@nextcloud/sharing": "^0.1.0",
|
||||
"@nextcloud/vue": "^8.0.0-beta.2",
|
||||
"@nextcloud/vue": "8.0.0-beta.2",
|
||||
"@nextcloud/vue-dashboard": "^2.0.1",
|
||||
"@skjnldsv/sanitize-svg": "^1.0.2",
|
||||
"@vueuse/components": "^10.2.0",
|
||||
|
|
Loading…
Reference in a new issue