diff --git a/.cloudcmd.menu.js b/.cloudcmd.menu.js new file mode 100644 index 0000000000..9755da320c --- /dev/null +++ b/.cloudcmd.menu.js @@ -0,0 +1,15 @@ +'use strict'; + +module.exports = { + 'F2 - Rename file': ({DOM}) => { + const {element} = DOM.CurrentInfo; + DOM.renameCurrent(element); + }, + 'D - Build Dev': async ({DOM, tryToCatch}) => { + return 'npm run build:client:dev'; + }, + 'P - Build Prod': () => { + return 'npm run build:client'; + }, +}; + diff --git a/.webpack/css.js b/.webpack/css.js index f28fa100be..2338b53d7b 100644 --- a/.webpack/css.js +++ b/.webpack/css.js @@ -21,6 +21,7 @@ const cssNames = [ 'view', 'config', 'terminal', + 'user-menu', ...getCSSList('columns'), ]; @@ -35,7 +36,7 @@ const plugins = clean([ const rules = [{ test: /\.css$/, - exclude: /css\/(nojs|view|config|terminal|columns.*)\.css/, + exclude: /css\/(nojs|view|config|terminal|user-menu|columns.*)\.css/, use: extractMain.extract([ 'css-loader', ]), diff --git a/.webpack/js.js b/.webpack/js.js index 7fd45044d2..fa52237f6a 100644 --- a/.webpack/js.js +++ b/.webpack/js.js @@ -32,7 +32,6 @@ const babelDev = { babelrc: false, plugins: [ 'module:babel-plugin-macros', - '@babel/plugin-proposal-object-rest-spread', ], }; @@ -43,7 +42,7 @@ const rules = clean([ loader: 'babel-loader', }, isDev && { - test: /sw\.js$/, + test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', options: babelDev, @@ -91,6 +90,7 @@ module.exports = { [modules + '/konsole']: `${dirModules}/konsole.js`, [modules + '/terminal']: `${dirModules}/terminal.js`, [modules + '/cloud']: `${dirModules}/cloud.js`, + [modules + '/user-menu']: `${dirModules}/user-menu.js`, [modules + '/polyfill']: `${dirModules}/polyfill.js`, }, output: { diff --git a/bin/cloudcmd.js b/bin/cloudcmd.js index 95da413657..1e4e3ac506 100755 --- a/bin/cloudcmd.js +++ b/bin/cloudcmd.js @@ -73,6 +73,7 @@ const args = require('minimist')(argv.slice(2), { 'import-listen', 'log', 'dropbox', + 'user-menu', ], default: { server : true, @@ -111,6 +112,7 @@ const args = require('minimist')(argv.slice(2), { 'one-file-panel': choose(env.bool('one_file_panel'), config('oneFilePanel')), 'confirm-copy': choose(env.bool('confirm_copy'), config('confirmCopy')), 'confirm-move': choose(env.bool('confirm_move'), config('confirmMove')), + 'user-menu': choose(env.bool('user_menu'), config('userMenu')), 'keys-panel': env.bool('keys_panel') || config('keysPanel'), 'import-token': env('import_token') || config('importToken'), 'export-token': env('export_token') || config('exportToken'), @@ -180,6 +182,7 @@ function main() { config('importToken', args['import-token']); config('importListen', args['import-listen']); config('importUrl', args['import-url']); + config('userMenu', args['user-menu']); config('dropbox', args['dropbox']); config('dropboxToken', args['dropbox-token'] || ''); diff --git a/client/key/index.js b/client/key/index.js index 6cb11e4dc2..627400a46c 100644 --- a/client/key/index.js +++ b/client/key/index.js @@ -186,6 +186,9 @@ function KeyProto() { break; case Key.F2: + if (CloudCmd.config('userMenu')) + return CloudCmd.UserMenu.show(); + DOM.renameCurrent(current); break; diff --git a/client/listeners/index.js b/client/listeners/index.js index ffc4d8c531..2f8c6771ea 100644 --- a/client/listeners/index.js +++ b/client/listeners/index.js @@ -123,7 +123,7 @@ module.exports.initKeysPanel = () => { const clickFuncs = { 'f1' : CloudCmd.Help.show, - 'f2' : DOM.renameCurrent, + 'f2' : initF2, 'f3' : CloudCmd.View.show, 'f4' : CloudCmd.EditFile.show, 'f5' : operation('copy'), @@ -141,6 +141,13 @@ module.exports.initKeysPanel = () => { }); }; +function initF2() { + if (CloudCmd.config('userMenu')) + return CloudCmd.UserMenu.show(); + + return DOM.renameCurrent(); +} + const getPanel = (side) => { if (!itype.string(side)) return side; diff --git a/client/modules/operation/set-listeners.js b/client/modules/operation/set-listeners.js index f341477245..71d7b64e13 100644 --- a/client/modules/operation/set-listeners.js +++ b/client/modules/operation/set-listeners.js @@ -1,7 +1,6 @@ 'use strict'; /* global DOM */ -/* global CloudCmd */ const { Dialog, diff --git a/client/modules/user-menu.js b/client/modules/user-menu.js new file mode 100644 index 0000000000..323f7b3b3c --- /dev/null +++ b/client/modules/user-menu.js @@ -0,0 +1,138 @@ +'use strict'; + +/* global CloudCmd, DOM */ + +require('../../css/user-menu.css'); + +const currify = require('currify/legacy'); +const {promisify} = require('es6-promisify'); +const load = require('load.js'); +const createElement = require('@cloudcmd/create-element'); +const Images = require('../dom/images'); + +const loadCSS = promisify(load.css); + +const Name = 'UserMenu'; +CloudCmd[Name] = module.exports; + +const {Key} = CloudCmd; +const {stringify} = JSON; + +const userMenuUrl = '/api/v1/user-menu'; + +module.exports.init = async () => { + await Promise.all([ + loadCSS(`${CloudCmd.prefix}/dist/user-menu.css`), + CloudCmd.View(), + ]); +}; + +module.exports.show = show; +module.exports.hide = hide; + +const getKey = (a) => a.split(' - ')[0]; +const beginWith = (a) => (b) => !b.indexOf(a); + +const defaultUserMenu = { + 'F2 - Rename file': async ({DOM}) => { + const {element} = DOM.CurrentInfo; + DOM.renameCurrent(element); + }, +}; + +function getUserMenu(menuFn) { + if (!menuFn) + return defaultUserMenu; + + const module = {}; + const fn = Function('module', menuFn); + + fn(module); + + return module.exports; +} + +const {CurrentInfo} = DOM; + +async function show() { + Images.show.load('top'); + + const {dirPath} = CurrentInfo; + const res = await fetch(`${userMenuUrl}?dir=${dirPath}`); + const userMenu = getUserMenu(await res.text()); + const options = Object.keys(userMenu); + + const el = createElement('select', { + className: 'cloudcmd-user-menu', + innerHTML: fillTemplate(options), + size: 10, + }); + + const keys = options.map(getKey); + el.addEventListener('keydown', onKeyDown(keys, options, userMenu)); + + const afterShow = () => el.focus(); + const autoSize = true; + + Images.hide(); + + CloudCmd.View.show(el, { + autoSize, + afterShow, + }); +} + +function fillTemplate(options) { + const result = []; + + for (const option of options) { + result.push(``); + } + + return result.join(''); +} + +function hide() { + CloudCmd.View.hide(); +} + +const onKeyDown = currify(async (keys, options, userMenu, e) => { + const {keyCode} = e; + const key = e.key.toUpperCase(); + + let value; + + if (keyCode === Key.ENTER) + ({value} = e.target); + else if (keys.includes(key)) + value = options.find(beginWith(key)); + else + return; + + e.preventDefault(); + e.stopPropagation(); + + hide(); + + const cmd = await userMenu[value]({ + DOM, + }); + + if (!cmd) + return; + + const res = await fetch(userMenuUrl, { + method: 'PUT', + body: stringify({ + cmd, + }), + }); + + const data = await res.text(); + + if (data) + DOM.Dialog.alert(data); + + CloudCmd.refresh(); +}); + diff --git a/css/icons.css b/css/icons.css index 4f979db7c4..253b3593aa 100644 --- a/css/icons.css +++ b/css/icons.css @@ -132,3 +132,8 @@ font-family : 'Fontello'; content : '\e81b '; } + +.icon-user-menu::before { + font-family : 'Fontello'; + content : '\e81c '; +} diff --git a/css/user-menu.css b/css/user-menu.css new file mode 100644 index 0000000000..37f07c1447 --- /dev/null +++ b/css/user-menu.css @@ -0,0 +1,14 @@ +.cloudcmd-user-menu { + font-size: 16px; + font-family: 'Droid Sans Mono', 'Ubuntu Mono', 'Consolas', monospace; + width: 400px; +} + +.cloudcmd-user-menu:focus { + outline: 0; +} + +.cloudcmd-user-menu > option:checked { + box-shadow: 20px -20px 0 2px rgba(49, 123, 249) inset; +} + diff --git a/font/fontello.eot b/font/fontello.eot index 4274ddd290..c886783f81 100644 Binary files a/font/fontello.eot and b/font/fontello.eot differ diff --git a/font/fontello.json b/font/fontello.json deleted file mode 100644 index 61c8d00eb4..0000000000 --- a/font/fontello.json +++ /dev/null @@ -1,234 +0,0 @@ -{ - "name": "fontello", - "css_prefix_text": "icon-", - "css_use_suffix": false, - "hinting": true, - "units_per_em": 1000, - "ascent": 850, - "glyphs": [ - { - "uid": "b035c28eba2b35c6ffe92aee8b0df507", - "css": "attention-circled", - "code": 59392, - "src": "fontawesome" - }, - { - "uid": "17ebadd1e3f274ff0205601eef7b9cc4", - "css": "help-circled", - "code": 59393, - "src": "fontawesome" - }, - { - "uid": "67f793f91864e379458a92ccc61d9ccf", - "css": "sort-alphabet", - "code": 59394, - "src": "typicons" - }, - { - "uid": "c5fd349cbd3d23e4ade333789c29c729", - "css": "eye", - "code": 59395, - "src": "fontawesome" - }, - { - "uid": "41087bc74d4b20b55059c60a33bf4008", - "css": "edit", - "code": 59396, - "src": "fontawesome" - }, - { - "uid": "c8585e1e5b0467f28b70bce765d5840c", - "css": "docs", - "code": 59397, - "src": "fontawesome" - }, - { - "uid": "6020aff067fc3c119cdd75daa5249220", - "css": "exchange", - "code": 59398, - "src": "fontawesome" - }, - { - "uid": "0ccb084ddeeae372673793ed0b45bb4a", - "css": "folder", - "code": 59399, - "src": "entypo" - }, - { - "uid": "f48ae54adfb27d8ada53d0fd9e34ee10", - "css": "trash", - "code": 59400, - "src": "fontawesome" - }, - { - "uid": "559647a6f430b3aeadbecd67194451dd", - "css": "menu", - "code": 59401, - "src": "fontawesome" - }, - { - "uid": "7336247ba3db350dec8d6c0a47cef966", - "css": "cog-1", - "code": 59402, - "src": "mfglabs" - }, - { - "uid": "fa10777b2d88cc64cd6e4f26ef0e5264", - "css": "terminal", - "code": 59403, - "src": "fontawesome" - }, - { - "uid": "85528017f1e6053b2253785c31047f44", - "css": "comment", - "code": 59404, - "src": "fontawesome" - }, - { - "uid": "1189604bf305b6b03a74685ce60e6632", - "css": "doc-text", - "code": 59405, - "src": "entypo" - }, - { - "uid": "de2fc7a5c986ab8c622f63455d7cf814", - "css": "upload-cloud", - "code": 59406, - "src": "fontawesome" - }, - { - "uid": "f5999a012fc3752386635ec02a858447", - "css": "download-cloud", - "code": 59407, - "src": "fontawesome" - }, - { - "uid": "9a76bc135eac17d2c8b8ad4a5774fc87", - "css": "download", - "code": 59408, - "src": "fontawesome" - }, - { - "uid": "9e0404ba55575a540164db9a5ad511df", - "css": "doc-new", - "code": 59409, - "src": "elusive" - }, - { - "uid": "823a9e02e643318116fea40a00190e4e", - "css": "asterisk", - "code": 59410, - "src": "fontawesome" - }, - { - "uid": "3c24ee33c9487bbf18796ca6dffa1905", - "css": "resize-small", - "code": 59411, - "src": "fontawesome" - }, - { - "uid": "e594fc6e5870b4ab7e49f52571d52577", - "css": "resize-full", - "code": 59412, - "src": "fontawesome" - }, - { - "uid": "3bd18d47a12b8709e9f4fe9ead4f7518", - "css": "arrows-ccw", - "code": 59414, - "src": "entypo" - }, - { - "uid": "8772331a9fec983cdb5d72902a6f9e0e", - "css": "scissors", - "code": 59415, - "src": "fontawesome" - }, - { - "uid": "b429436ec5a518c78479d44ef18dbd60", - "css": "paste", - "code": 59416, - "src": "fontawesome" - }, - { - "uid": "eeec3208c90b7b48e804919d0d2d4a41", - "css": "upload", - "code": 59417, - "src": "fontawesome" - }, - { - "uid": "2d76f2c8d13be40694ecadfea7fb83c3", - "css": "logout", - "code": 59418, - "src": "entypo" - }, - { - "uid": "e92e6cad2da0ee4bc374a1ef4c6ab12b", - "css": "terminal-1", - "code": 59419, - "src": "websymbols" - }, - { - "uid": "b95cfc96d48a72dd665e0ab109880b5e", - "css": "clipboard", - "code": 59413, - "src": "entypo" - }, - { - "uid": "60617c8adc1e7eb3c444a5491dd13f57", - "css": "attention-circled-1", - "code": 59395, - "src": "custom_icons", - "selected": false, - "svg": { - "path": "M429 71Q545 71 644 129T800 285T857 500T800 715T644 871T429 929T213 871T58 715T0 500T58 285T213 129T429 71ZM500 767V661Q500 653 495 648T483 643H376Q368 643 363 648T357 661V767Q357 775 363 780T376 786H483Q490 786 495 780T500 767ZM499 575L509 229Q509 222 503 219Q498 214 490 214H367Q359 214 354 219Q348 222 348 229L358 575Q358 581 363 585T377 589H480Q488 589 493 585T499 575Z", - "width": 857.1 - }, - "search": [ - "attention-circled" - ] - }, - { - "uid": "9347a40928618e76958fa67e5333f1c5", - "css": "doc-text-1", - "code": 59397, - "src": "custom_icons", - "selected": false, - "svg": { - "path": "M212 542L212 452L492 452L492 542L212 542ZM600 50Q642 50 671 79T700 150L700 850Q700 890 671 920T600 950L100 950Q60 950 30 920T0 850L0 150Q0 108 30 79T100 50L600 50ZM600 850L600 150L100 150L100 850L600 850ZM490 258L490 346L210 346L210 258L490 258ZM490 650L490 738L210 738L210 650L490 650Z", - "width": 700 - }, - "search": [ - "doc-text" - ] - }, - { - "uid": "6405321f27abab4a505476c917d8c748", - "css": "folder-1", - "code": 59398, - "src": "custom_icons", - "selected": false, - "svg": { - "path": "M954 350Q986 350 994 362T1000 398L958 850Q956 874 946 887T904 900L98 900Q46 900 42 850L0 398Q-2 374 6 362T46 350L954 350ZM920 240L930 280L84 280L98 148Q102 128 118 114T154 100L318 100Q370 100 404 134L434 164Q466 200 520 200L860 200Q880 200 898 212T920 240Z", - "width": 1001 - }, - "search": [ - "folder" - ] - }, - { - "uid": "2ba2063e74ee7b74f6c46a949d37a130", - "css": "cog-2", - "code": 59399, - "src": "custom_icons", - "selected": false, - "svg": { - "path": "M0 498Q0 460 7 415Q57 419 102 396T172 328Q197 283 195 233T165 142Q229 86 315 56Q338 97 379 122T469 146T558 122T622 56Q707 86 772 142Q751 181 751 227T774 313Q798 354 839 377T926 400Q937 449 937 498Q937 530 930 572Q885 573 846 597T783 660Q758 704 760 752T786 841Q720 901 641 934Q618 892 577 867T487 842Q434 842 391 870T327 944Q245 918 174 862Q202 821 204 771T181 676Q154 630 107 606T9 589Q0 548 0 498ZM293 498Q293 571 344 622T469 673T593 622T644 498T593 374T469 322T344 374T293 498Z", - "width": 937.5 - }, - "search": [ - "cog-1" - ] - } - ] -} \ No newline at end of file diff --git a/font/fontello.svg b/font/fontello.svg index afc5a84448..ac6e533b46 100644 --- a/font/fontello.svg +++ b/font/fontello.svg @@ -1,7 +1,7 @@ \ No newline at end of file diff --git a/font/fontello.ttf b/font/fontello.ttf index 1065b0d3a9..57d3d33173 100644 Binary files a/font/fontello.ttf and b/font/fontello.ttf differ diff --git a/font/fontello.woff b/font/fontello.woff index 9a4a595269..fd4d9d12c4 100644 Binary files a/font/fontello.woff and b/font/fontello.woff differ diff --git a/font/fontello.woff2 b/font/fontello.woff2 index b8c98b96e3..dae8571004 100644 Binary files a/font/fontello.woff2 and b/font/fontello.woff2 differ diff --git a/html/index.html b/html/index.html index e0fd85953b..7f6edac541 100644 --- a/html/index.html +++ b/html/index.html @@ -21,6 +21,7 @@