mirror of
https://github.com/coderaiser/cloudcmd.git
synced 2026-01-23 02:35:49 +00:00
feature(user-menu) add ability to run selected items without showing dialog
This commit is contained in:
parent
28caa05292
commit
5d589ee31d
6 changed files with 135 additions and 27 deletions
|
|
@ -17,7 +17,9 @@ const Images = require('../../dom/images');
|
|||
const Dialog = require('../../dom/dialog');
|
||||
const getUserMenu = require('./get-user-menu');
|
||||
const navigate = require('./navigate');
|
||||
const parse = require('./parse-error');
|
||||
const parseError = require('./parse-error');
|
||||
const parseUserMenu = require('./parse-user-menu');
|
||||
const {runSelected} = require('./run');
|
||||
|
||||
const loadCSS = load.css;
|
||||
const sourceStore = fullstore();
|
||||
|
|
@ -37,10 +39,6 @@ module.exports.init = async () => {
|
|||
module.exports.show = show;
|
||||
module.exports.hide = hide;
|
||||
|
||||
const getKey = (a) => a.split(' - ')[0];
|
||||
const beginWith = (a) => (b) => a === getKey(b);
|
||||
const notPrivate = ([a]) => a !== '_';
|
||||
|
||||
const {CurrentInfo} = DOM;
|
||||
|
||||
async function show() {
|
||||
|
|
@ -58,9 +56,15 @@ async function show() {
|
|||
|
||||
sourceStore(source);
|
||||
|
||||
const options = Object
|
||||
.keys(userMenu)
|
||||
.filter(notPrivate);
|
||||
const {
|
||||
names,
|
||||
keys,
|
||||
items,
|
||||
settings,
|
||||
} = parseUserMenu(userMenu);
|
||||
|
||||
if (settings.run)
|
||||
return runSelected(settings.select, items, runUserMenu);
|
||||
|
||||
const button = createElement('button', {
|
||||
className: 'cloudcmd-user-menu-button',
|
||||
|
|
@ -69,15 +73,13 @@ async function show() {
|
|||
|
||||
const select = createElement('select', {
|
||||
className: 'cloudcmd-user-menu',
|
||||
innerHTML: fillTemplate(options),
|
||||
innerHTML: fillTemplate(names),
|
||||
size: 10,
|
||||
});
|
||||
|
||||
const keys = options.map(getKey);
|
||||
|
||||
button.addEventListener('click', onButtonClick(options, userMenu, select));
|
||||
select.addEventListener('keydown', onKeyDown(keys, options, userMenu));
|
||||
select.addEventListener('dblclick', onDblClick(options, userMenu));
|
||||
button.addEventListener('click', onButtonClick(items, select));
|
||||
select.addEventListener('keydown', onKeyDown(keys));
|
||||
select.addEventListener('dblclick', onDblClick(userMenu));
|
||||
|
||||
const afterShow = () => select.focus();
|
||||
const autoSize = true;
|
||||
|
|
@ -101,22 +103,22 @@ function hide() {
|
|||
CloudCmd.View.hide();
|
||||
}
|
||||
|
||||
const onDblClick = currify(async (options, userMenu, e) => {
|
||||
const onDblClick = currify(async (items, e) => {
|
||||
const {value} = e.target;
|
||||
await runUserMenu(value, options, userMenu);
|
||||
await runUserMenu(items[value]);
|
||||
});
|
||||
|
||||
const onButtonClick = wraptile(async (options, userMenu, {value}) => {
|
||||
await runUserMenu(value, options, userMenu);
|
||||
const onButtonClick = wraptile(async (items, {value}) => {
|
||||
await runUserMenu(items[value]);
|
||||
});
|
||||
|
||||
const onKeyDown = currify(async (keys, options, userMenu, e) => {
|
||||
const onKeyDown = currify(async (keys, e) => {
|
||||
const {
|
||||
keyCode,
|
||||
target,
|
||||
} = e;
|
||||
|
||||
const key = e.key.toUpperCase();
|
||||
const keyName = e.key.toUpperCase();
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
|
@ -127,18 +129,18 @@ const onKeyDown = currify(async (keys, options, userMenu, e) => {
|
|||
return hide();
|
||||
else if (keyCode === Key.ENTER)
|
||||
({value} = target);
|
||||
else if (keys.includes(key))
|
||||
value = options.find(beginWith(key));
|
||||
else if (keys[keyName])
|
||||
value = keys[keyName];
|
||||
else
|
||||
return navigate(target, e);
|
||||
|
||||
await runUserMenu(value, options, userMenu);
|
||||
await runUserMenu(value);
|
||||
});
|
||||
|
||||
const runUserMenu = async (value, options, userMenu) => {
|
||||
const runUserMenu = async (fn) => {
|
||||
hide();
|
||||
|
||||
const [error] = await tryToCatch(userMenu[value], {
|
||||
const [error] = await tryToCatch(fn, {
|
||||
DOM,
|
||||
CloudCmd,
|
||||
tryToCatch,
|
||||
|
|
@ -160,7 +162,7 @@ function getCodeFrame({error, source}) {
|
|||
if (!code || code === 'frame')
|
||||
return error.message;
|
||||
|
||||
const [line, column] = parse(error);
|
||||
const [line, column] = parseError(error);
|
||||
const start = {
|
||||
line,
|
||||
column,
|
||||
|
|
|
|||
35
client/modules/user-menu/parse-user-menu.js
Normal file
35
client/modules/user-menu/parse-user-menu.js
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
'use strict';
|
||||
|
||||
const {entries, assign} = Object;
|
||||
|
||||
module.exports = (userMenu) => {
|
||||
const names = [];
|
||||
const keys = {};
|
||||
const items = {};
|
||||
const settings = {};
|
||||
|
||||
for (const [str, fn] of entries(userMenu)) {
|
||||
if (str === '__settings') {
|
||||
assign(settings, userMenu[str]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (/^_/.test(str)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
names.push(str);
|
||||
const [key, name] = str.split(' - ');
|
||||
|
||||
keys[key] = fn;
|
||||
items[name] = fn;
|
||||
}
|
||||
|
||||
return {
|
||||
names,
|
||||
keys,
|
||||
items,
|
||||
settings,
|
||||
};
|
||||
};
|
||||
|
||||
32
client/modules/user-menu/parse-user-menu.spec.js
Normal file
32
client/modules/user-menu/parse-user-menu.spec.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
'use strict';
|
||||
|
||||
const test = require('supertape');
|
||||
const stub = require('@cloudcmd/stub');
|
||||
const parse = require('./parse-user-menu');
|
||||
|
||||
test('cloudcmd: user menu: parse', (t) => {
|
||||
const fn = stub();
|
||||
const __settings = {};
|
||||
const result = parse({
|
||||
__settings,
|
||||
'F2 - Rename file': fn,
|
||||
'_f': fn,
|
||||
});
|
||||
|
||||
const keys = {
|
||||
F2: fn,
|
||||
};
|
||||
|
||||
const items = {
|
||||
'Rename file': fn,
|
||||
};
|
||||
|
||||
const expected = {
|
||||
keys,
|
||||
items,
|
||||
settings: __settings,
|
||||
};
|
||||
|
||||
t.deepEqual(result, expected);
|
||||
t.end();
|
||||
});
|
||||
8
client/modules/user-menu/run.js
Normal file
8
client/modules/user-menu/run.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
'use strict';
|
||||
|
||||
module.exports.runSelected = async (selectedItems, items, runUserMenu) => {
|
||||
for (const selected of selectedItems) {
|
||||
await runUserMenu(items[selected]);
|
||||
}
|
||||
};
|
||||
|
||||
23
client/modules/user-menu/run.spec.js
Normal file
23
client/modules/user-menu/run.spec.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
'use strict';
|
||||
|
||||
const test = require('supertape');
|
||||
const stub = require('@cloudcmd/stub');
|
||||
const {runSelected} = require('./run');
|
||||
|
||||
test('cloudcmd: client: user menu: run', async (t) => {
|
||||
const runUserMenu = stub();
|
||||
const fn = stub();
|
||||
const selected = [
|
||||
'hello',
|
||||
];
|
||||
|
||||
const items = {
|
||||
hello: fn,
|
||||
};
|
||||
|
||||
await runSelected(selected, items, runUserMenu);
|
||||
|
||||
t.ok(runUserMenu.calledWith(fn));
|
||||
t.end();
|
||||
});
|
||||
|
||||
|
|
@ -1,7 +1,15 @@
|
|||
'use strict';
|
||||
|
||||
const RENAME_FILE= 'Rename file';
|
||||
|
||||
module.exports = {
|
||||
'F2 - Rename file': async ({DOM}) => {
|
||||
__settings: {
|
||||
select: [
|
||||
RENAME_FILE,
|
||||
],
|
||||
run: false,
|
||||
},
|
||||
[`F2 - ${RENAME_FILE}`]: async ({DOM}) => {
|
||||
await DOM.renameCurrent();
|
||||
},
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue