diff --git a/HELP.md b/HELP.md index f105f1a0..278ef881 100644 --- a/HELP.md +++ b/HELP.md @@ -139,6 +139,7 @@ Hot keys | `Ctrl + r` | refresh | `Ctrl + d` | clear local storage | `Ctrl + a` | select all files in a panel +| `Ctrl + m` | rename selected files | `Ctrl + u` | swap panels | `Up`, `Down`, `Enter` | file system navigation | `Alt + Left/Right` | show content of directory under cursor in target panel diff --git a/client/edit-file.js b/client/edit-file.js index 82075e78..f658f88a 100644 --- a/client/edit-file.js +++ b/client/edit-file.js @@ -18,7 +18,7 @@ var CloudCmd, Util, DOM, CloudFunc, MenuIO, Format; ConfigView = { beforeClose: function() { exec.ifExist(Menu, 'hide'); - isChanged(EditFile.hide); + isChanged(); } }; @@ -66,7 +66,8 @@ var CloudCmd, Util, DOM, CloudFunc, MenuIO, Format; .getEditor() .setValueFirst(path, data) .setModeForPath(name) - .setOption('fontSize', 16); + .setOption('fontSize', 16) + .enableKey(); CloudCmd.Edit.show(ConfigView); }); diff --git a/client/edit-names.js b/client/edit-names.js new file mode 100644 index 00000000..e1590930 --- /dev/null +++ b/client/edit-names.js @@ -0,0 +1,233 @@ +/* global Promise */ + +var CloudCmd, Util, DOM, CloudFunc, MenuIO; + +(function(CloudCmd, Util, DOM) { + 'use strict'; + + CloudCmd.EditNames = function EditNamesProto(callback) { + var Info = DOM.CurrentInfo; + var Dialog = DOM.Dialog; + var exec = Util.exec; + var EditNames = this; + var Menu; + var TITLE = 'Edit Names'; + var ConfigView = { + beforeClose: function() { + exec.ifExist(Menu, 'hide'); + isChanged(); + DOM.Events.remove('keydown', keyListener); + } + }; + + var getName = DOM.getCurrentName.bind(DOM); + + function init(callback) { + var editor; + + exec.series([ + CloudCmd.Edit, + + function(callback) { + editor = CloudCmd.Edit.getEditor(); + callback(); + }, + + function(callback) { + setListeners(editor); + callback(); + }, + + function(callback) { + EditNames.show(); + callback(); + }, + ], callback); + } + + this.show = function() { + if (Info.name === '..') + return Dialog.alert.noFiles(TITLE); + + var names = getActiveNames().join('\n'); + + CloudCmd.Edit + .getEditor() + .setValueFirst('edit-names', names) + .setOption('fontSize', 16) + .disableKey(); + + DOM.Events.addKey(keyListener); + CloudCmd.Edit.show(ConfigView); + }; + + function keyListener(event) { + var ctrl = event.ctrlKey; + var meta = event.metaKey; + var ctrlMeta = ctrl || meta; + var Key = CloudCmd.Key; + + if (!ctrlMeta || event.keyCode !== Key.S) + return; + + EditNames.hide(); + } + + function getActiveNames() { + return DOM + .getActiveFiles() + .map(getName); + } + + this.hide = function() { + CloudCmd.Edit.hide(); + }; + + function setListeners() { + var element = CloudCmd.Edit.getElement(); + + DOM.Events.addOnce('contextmenu', element, setMenu); + } + + function applyNames() { + var dir = Info.dirPath; + var from = getActiveNames(); + var nameIndex = from.indexOf(Info.name); + + var editor = CloudCmd.Edit.getEditor(); + var to = editor + .getValue() + .split('\n'); + + var reject = Promise.reject.bind(Promise); + + getRoot() + .then(rename(dir, from, to)) + .then(function(res) { + if (res.status === 404) + return res.text().then(reject); + + CloudCmd.refresh(null, function() { + var name = to[nameIndex]; + DOM.setCurrentByName(name); + }); + }).catch(function(message) { + Dialog.alert(TITLE, message); + }); + } + + function getDir(root, dir) { + if (root === '/') + return dir; + + return root + dir; + } + + function rename(dir, from, to) { + return function(root) { + return fetch(CloudCmd.PREFIX + '/rename', { + method: 'put', + credentials: 'include', + body: JSON.stringify({ + from: from, + to: to, + dir: getDir(root, dir) + }) + }); + }; + } + + function setMenu(event) { + var position = { + x: event.clientX, + y: event.clientY + }; + + event.preventDefault(); + + !Menu && DOM.loadRemote('menu', function(error) { + var noFocus; + var options = { + beforeShow: function(params) { + params.x -= 18; + params.y -= 27; + }, + + afterClick: function() { + !noFocus && editor.focus(); + } + }; + + var editor = CloudCmd.Edit.getEditor(); + + var menuData = { + 'Save Ctrl+S' : function() { + editor.save(); + EditNames.hide(); + }, + 'Go To Line Ctrl+G' : function() { + noFocus = true; + editor.goToLine(); + }, + 'Cut Ctrl+X' : function() { + editor.cutToClipboard(); + }, + 'Copy Ctrl+C' : function() { + editor.copyToClipboard(); + }, + 'Paste Ctrl+V' : function() { + editor.pasteFromClipboard(); + }, + 'Delete Del' : function() { + editor.remove('right'); + }, + 'Select All Ctrl+A' : function() { + editor.selectAll(); + }, + 'Close Esc' : function() { + EditNames.hide(); + } + }; + + if (error) + return Dialog.alert(TITLE, error); + + if (Menu || !MenuIO) + return; + + var element = CloudCmd.Edit.getElement(); + + Menu = new MenuIO(element, options, menuData); + Menu.show(position.x, position.y); + }); + } + + function getRoot() { + return new Promise(function(resolve, reject) { + DOM.Files.get('config', function(error, config) { + if (error) + return reject(error); + + resolve(config.root); + }); + }); + } + + function isChanged() { + var editor = CloudCmd.Edit.getEditor(); + var msg = 'Apply new names?'; + + if (!editor.isChanged()) + return; + + Dialog.confirm(TITLE, msg) + .then(EditNames.hide) + .then(applyNames) + .catch(EditNames.hide); + } + + init(callback); + }; + +})(CloudCmd, Util, DOM, CloudFunc); + diff --git a/client/edit.js b/client/edit.js index db621df9..a21386ff 100644 --- a/client/edit.js +++ b/client/edit.js @@ -1,3 +1,5 @@ +/* global itype */ + var CloudCmd, Util, DOM, CloudFunc; (function(CloudCmd, Util, DOM) { @@ -26,6 +28,13 @@ var CloudCmd, Util, DOM, CloudFunc; } }; + var Edit = function(fn) { + if (!itype.function(fn)) + return; + + fn(); + }; + function init(callback) { var element = createElement(); @@ -79,22 +88,22 @@ var CloudCmd, Util, DOM, CloudFunc; return config; } - this.show = function(options) { + Edit.show = function(options) { if (Loading) return; CloudCmd.View.show(Element, initConfig(options)); }; - this.getEditor = function() { + Edit.getEditor = function() { return editor; }; - this.getElement = function() { + Edit.getElement = function() { return Element; }; - this.hide = function() { + Edit.hide = function() { CloudCmd.View.hide(); }; @@ -135,6 +144,8 @@ var CloudCmd, Util, DOM, CloudFunc; } init(callback); + + return Edit; } })(CloudCmd, Util, DOM, CloudFunc); diff --git a/client/key.js b/client/key.js index ebdc4ac8..ed2246d6 100644 --- a/client/key.js +++ b/client/key.js @@ -37,6 +37,8 @@ var CloudCmd, Util, DOM; G : 71, + M : 77, + O : 79, Q : 81, R : 82, @@ -493,6 +495,14 @@ var CloudCmd, Util, DOM; break; + case Key.M: + if (ctrlMeta) { + CloudCmd.EditNames.show(); + event.preventDefault(); + } + + break; + /** * обновляем страницу, * загружаем содержимое каталога diff --git a/json/modules.json b/json/modules.json index c653ea58..bba7fa32 100644 --- a/json/modules.json +++ b/json/modules.json @@ -1,6 +1,7 @@ [ "edit", "edit-file", + "edit-names", "menu", "view", "help", diff --git a/package.json b/package.json index 3132fcc2..6d6fbd41 100644 --- a/package.json +++ b/package.json @@ -103,9 +103,9 @@ "copymitter": "^1.8.0", "criton": "^1.0.0", "currify": "^2.0.3", - "deepword": "^1.1.2", - "dword": "^4.0.0", - "edward": "^4.0.0", + "deepword": "^1.3.0", + "dword": "^4.1.0", + "edward": "^4.2.0", "execon": "^1.2.0", "express": "^4.13.0", "files-io": "^1.2.0",