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 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,
|
||||||
|
|
|
||||||
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';
|
'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();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue