feature(user-menu) add ability to run selected items without showing dialog

This commit is contained in:
coderaiser 2020-04-26 23:44:27 +03:00
parent 28caa05292
commit 5d589ee31d
6 changed files with 135 additions and 27 deletions

View file

@ -17,7 +17,9 @@ const Images = require('../../dom/images');
const Dialog = require('../../dom/dialog'); const Dialog = require('../../dom/dialog');
const getUserMenu = require('./get-user-menu'); const getUserMenu = require('./get-user-menu');
const navigate = require('./navigate'); 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 loadCSS = load.css;
const sourceStore = fullstore(); const sourceStore = fullstore();
@ -37,10 +39,6 @@ module.exports.init = async () => {
module.exports.show = show; module.exports.show = show;
module.exports.hide = hide; module.exports.hide = hide;
const getKey = (a) => a.split(' - ')[0];
const beginWith = (a) => (b) => a === getKey(b);
const notPrivate = ([a]) => a !== '_';
const {CurrentInfo} = DOM; const {CurrentInfo} = DOM;
async function show() { async function show() {
@ -58,9 +56,15 @@ async function show() {
sourceStore(source); sourceStore(source);
const options = Object const {
.keys(userMenu) names,
.filter(notPrivate); keys,
items,
settings,
} = parseUserMenu(userMenu);
if (settings.run)
return runSelected(settings.select, items, runUserMenu);
const button = createElement('button', { const button = createElement('button', {
className: 'cloudcmd-user-menu-button', className: 'cloudcmd-user-menu-button',
@ -69,15 +73,13 @@ async function show() {
const select = createElement('select', { const select = createElement('select', {
className: 'cloudcmd-user-menu', className: 'cloudcmd-user-menu',
innerHTML: fillTemplate(options), innerHTML: fillTemplate(names),
size: 10, size: 10,
}); });
const keys = options.map(getKey); button.addEventListener('click', onButtonClick(items, select));
select.addEventListener('keydown', onKeyDown(keys));
button.addEventListener('click', onButtonClick(options, userMenu, select)); select.addEventListener('dblclick', onDblClick(userMenu));
select.addEventListener('keydown', onKeyDown(keys, options, userMenu));
select.addEventListener('dblclick', onDblClick(options, userMenu));
const afterShow = () => select.focus(); const afterShow = () => select.focus();
const autoSize = true; const autoSize = true;
@ -101,22 +103,22 @@ function hide() {
CloudCmd.View.hide(); CloudCmd.View.hide();
} }
const onDblClick = currify(async (options, userMenu, e) => { const onDblClick = currify(async (items, e) => {
const {value} = e.target; const {value} = e.target;
await runUserMenu(value, options, userMenu); await runUserMenu(items[value]);
}); });
const onButtonClick = wraptile(async (options, userMenu, {value}) => { const onButtonClick = wraptile(async (items, {value}) => {
await runUserMenu(value, options, userMenu); await runUserMenu(items[value]);
}); });
const onKeyDown = currify(async (keys, options, userMenu, e) => { const onKeyDown = currify(async (keys, e) => {
const { const {
keyCode, keyCode,
target, target,
} = e; } = e;
const key = e.key.toUpperCase(); const keyName = e.key.toUpperCase();
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
@ -127,18 +129,18 @@ const onKeyDown = currify(async (keys, options, userMenu, e) => {
return hide(); return hide();
else if (keyCode === Key.ENTER) else if (keyCode === Key.ENTER)
({value} = target); ({value} = target);
else if (keys.includes(key)) else if (keys[keyName])
value = options.find(beginWith(key)); value = keys[keyName];
else else
return navigate(target, e); return navigate(target, e);
await runUserMenu(value, options, userMenu); await runUserMenu(value);
}); });
const runUserMenu = async (value, options, userMenu) => { const runUserMenu = async (fn) => {
hide(); hide();
const [error] = await tryToCatch(userMenu[value], { const [error] = await tryToCatch(fn, {
DOM, DOM,
CloudCmd, CloudCmd,
tryToCatch, tryToCatch,
@ -160,7 +162,7 @@ function getCodeFrame({error, source}) {
if (!code || code === 'frame') if (!code || code === 'frame')
return error.message; return error.message;
const [line, column] = parse(error); const [line, column] = parseError(error);
const start = { const start = {
line, line,
column, column,

View 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,
};
};

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

View file

@ -0,0 +1,8 @@
'use strict';
module.exports.runSelected = async (selectedItems, items, runUserMenu) => {
for (const selected of selectedItems) {
await runUserMenu(items[selected]);
}
};

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

View file

@ -1,7 +1,15 @@
'use strict'; 'use strict';
const RENAME_FILE= 'Rename file';
module.exports = { module.exports = {
'F2 - Rename file': async ({DOM}) => { __settings: {
select: [
RENAME_FILE,
],
run: false,
},
[`F2 - ${RENAME_FILE}`]: async ({DOM}) => {
await DOM.renameCurrent(); await DOM.renameCurrent();
}, },