let vueFile = new Vue({ el: '#modal-editor-file', data: { isLoading: false, isLoadingText: '', newFolderName: '', newFolderShow: false, newFolderError: false, folders: [], currentFolder: '', currentFile: '', files: [], uploadSucceeded: false, postUploadChecks: 0, renameFileShow: false, renameFileId: '', renameFileFilename: '', deleteFileShow: false, deleteFileId: '', deleteFileFilename: '' }, methods: { open: () => { mdeModalOpenState = true $('#modal-editor-file').addClass('is-active') vueFile.refreshFolders() }, cancel: (ev) => { mdeModalOpenState = false $('#modal-editor-file').removeClass('is-active') }, // ------------------------------------------- // INSERT LINK TO FILE // ------------------------------------------- selectFile: (fileId) => { vueFile.currentFile = fileId }, insertFileLink: (ev) => { if (mde.codemirror.doc.somethingSelected()) { mde.codemirror.execCommand('singleSelection') } let selFile = _.find(vueFile.files, ['_id', vueFile.currentFile]) selFile.normalizedPath = (selFile.folder === 'f:') ? selFile.filename : selFile.folder.slice(2) + '/' + selFile.filename selFile.titleGuess = _.startCase(selFile.basename) let fileText = '[' + selFile.titleGuess + '](/uploads/' + selFile.normalizedPath + ' "' + selFile.titleGuess + '")' mde.codemirror.doc.replaceSelection(fileText) vueFile.cancel() }, // ------------------------------------------- // NEW FOLDER // ------------------------------------------- newFolder: (ev) => { vueFile.newFolderName = '' vueFile.newFolderError = false vueFile.newFolderShow = true _.delay(() => { $('#txt-editor-file-newfoldername').focus() }, 400) }, newFolderDiscard: (ev) => { vueFile.newFolderShow = false }, newFolderCreate: (ev) => { let regFolderName = new RegExp('^[a-z0-9][a-z0-9\-]*[a-z0-9]$') vueFile.newFolderName = _.kebabCase(_.trim(vueFile.newFolderName)) if (_.isEmpty(vueFile.newFolderName) || !regFolderName.test(vueFile.newFolderName)) { vueFile.newFolderError = true return } vueFile.newFolderDiscard() vueFile.isLoadingText = 'Creating new folder...' vueFile.isLoading = true Vue.nextTick(() => { socket.emit('uploadsCreateFolder', { foldername: vueFile.newFolderName }, (data) => { vueFile.folders = data vueFile.currentFolder = vueFile.newFolderName vueFile.files = [] vueFile.isLoading = false }) }) }, // ------------------------------------------- // RENAME FILE // ------------------------------------------- renameFile: () => { let c = _.find(vueFile.files, ['_id', vueFile.renameFileId ]) vueFile.renameFileFilename = c.basename || '' vueFile.renameFileShow = true _.delay(() => { $('#txt-editor-renamefile').focus() _.defer(() => { $('#txt-editor-file-rename').select() }) }, 400) }, renameFileDiscard: () => { vueFile.renameFileShow = false }, renameFileGo: () => { vueFile.renameFileDiscard() vueFile.isLoadingText = 'Renaming file...' vueFile.isLoading = true Vue.nextTick(() => { socket.emit('uploadsRenameFile', { uid: vueFile.renameFileId, folder: vueFile.currentFolder, filename: vueFile.renameFileFilename }, (data) => { if (data.ok) { vueFile.waitChangeComplete(vueFile.files.length, false) } else { vueFile.isLoading = false alerts.pushError('Rename error', data.msg) } }) }) }, // ------------------------------------------- // MOVE FILE // ------------------------------------------- moveFile: (uid, fld) => { vueFile.isLoadingText = 'Moving file...' vueFile.isLoading = true Vue.nextTick(() => { socket.emit('uploadsMoveFile', { uid, folder: fld }, (data) => { if (data.ok) { vueFile.loadFiles() } else { vueFile.isLoading = false alerts.pushError('Rename error', data.msg) } }) }) }, // ------------------------------------------- // DELETE FILE // ------------------------------------------- deleteFileWarn: (show) => { if (show) { let c = _.find(vueFile.files, ['_id', vueFile.deleteFileId ]) vueFile.deleteFileFilename = c.filename || 'this file' } vueFile.deleteFileShow = show }, deleteFileGo: () => { vueFile.deleteFileWarn(false) vueFile.isLoadingText = 'Deleting file...' vueFile.isLoading = true Vue.nextTick(() => { socket.emit('uploadsDeleteFile', { uid: vueFile.deleteFileId }, (data) => { vueFile.loadFiles() }) }) }, // ------------------------------------------- // LOAD FROM REMOTE // ------------------------------------------- selectFolder: (fldName) => { vueFile.currentFolder = fldName vueFile.loadFiles() }, refreshFolders: () => { vueFile.isLoadingText = 'Fetching folders list...' vueFile.isLoading = true vueFile.currentFolder = '' vueFile.currentImage = '' Vue.nextTick(() => { socket.emit('uploadsGetFolders', { }, (data) => { vueFile.folders = data vueFile.loadFiles() }) }) }, loadFiles: (silent) => { if (!silent) { vueFile.isLoadingText = 'Fetching files...' vueFile.isLoading = true } return new Promise((resolve, reject) => { Vue.nextTick(() => { socket.emit('uploadsGetFiles', { folder: vueFile.currentFolder }, (data) => { vueFile.files = data if (!silent) { vueFile.isLoading = false } vueFile.attachContextMenus() resolve(true) }) }) }) }, waitChangeComplete: (oldAmount, expectChange) => { expectChange = (_.isBoolean(expectChange)) ? expectChange : true vueFile.postUploadChecks++ vueFile.isLoadingText = 'Processing...' Vue.nextTick(() => { vueFile.loadFiles(true).then(() => { if ((vueFile.files.length !== oldAmount) === expectChange) { vueFile.postUploadChecks = 0 vueFile.isLoading = false } else if (vueFile.postUploadChecks > 5) { vueFile.postUploadChecks = 0 vueFile.isLoading = false alerts.pushError('Unable to fetch updated listing', 'Try again later') } else { _.delay(() => { vueFile.waitChangeComplete(oldAmount, expectChange) }, 1500) } }) }) }, // ------------------------------------------- // IMAGE CONTEXT MENU // ------------------------------------------- attachContextMenus: () => { let moveFolders = _.map(vueFile.folders, (f) => { return { name: (f !== '') ? f : '/ (root)', icon: 'fa-folder', callback: (key, opt) => { let moveFileId = _.toString($(opt.$trigger).data('uid')) let moveFileDestFolder = _.nth(vueFile.folders, key) vueFile.moveFile(moveFileId, moveFileDestFolder) } } }) $.contextMenu('destroy', '.editor-modal-file-choices > figure') $.contextMenu({ selector: '.editor-modal-file-choices > figure', appendTo: '.editor-modal-file-choices', position: (opt, x, y) => { $(opt.$trigger).addClass('is-contextopen') let trigPos = $(opt.$trigger).position() let trigDim = { w: $(opt.$trigger).width() / 5, h: $(opt.$trigger).height() / 2 } opt.$menu.css({ top: trigPos.top + trigDim.h, left: trigPos.left + trigDim.w }) }, events: { hide: (opt) => { $(opt.$trigger).removeClass('is-contextopen') } }, items: { rename: { name: 'Rename', icon: 'fa-edit', callback: (key, opt) => { vueFile.renameFileId = _.toString(opt.$trigger[0].dataset.uid) vueFile.renameFile() } }, move: { name: 'Move to...', icon: 'fa-folder-open-o', items: moveFolders }, delete: { name: 'Delete', icon: 'fa-trash', callback: (key, opt) => { vueFile.deleteFileId = _.toString(opt.$trigger[0].dataset.uid) vueFile.deleteFileWarn(true) } } } }) } } }) $('#btn-editor-file-upload input').on('change', (ev) => { let curFileAmount = vueFile.files.length $(ev.currentTarget).simpleUpload('/uploads/file', { name: 'binfile', data: { folder: vueFile.currentFolder }, limit: 20, expect: 'json', maxFileSize: 0, init: (totalUploads) => { vueFile.uploadSucceeded = false vueFile.isLoadingText = 'Preparing to upload...' vueFile.isLoading = true }, progress: (progress) => { vueFile.isLoadingText = 'Uploading...' + Math.round(progress) + '%' }, success: (data) => { if (data.ok) { let failedUpls = _.filter(data.results, ['ok', false]) if (failedUpls.length) { _.forEach(failedUpls, (u) => { alerts.pushError('Upload error', u.msg) }) if (failedUpls.length < data.results.length) { alerts.push({ title: 'Some uploads succeeded', message: 'Files that are not mentionned in the errors above were uploaded successfully.' }) vueFile.uploadSucceeded = true } } else { vueFile.uploadSucceeded = true } } else { alerts.pushError('Upload error', data.msg) } }, error: (error) => { alerts.pushError(error.message, this.upload.file.name) }, finish: () => { if (vueFile.uploadSucceeded) { vueFile.waitChangeComplete(curFileAmount, true) } else { vueFile.isLoading = false } } }) })