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; } } }); });