diff --git a/client/modules/user-menu/index.js b/client/modules/user-menu/index.js index 78e1f5dc..f1b6512c 100644 --- a/client/modules/user-menu/index.js +++ b/client/modules/user-menu/index.js @@ -11,6 +11,7 @@ const createElement = require('@cloudcmd/create-element'); const Images = require('../../dom/images'); const getUserMenu = require('./get-user-menu'); +const navigate = require('./navigate'); const loadCSS = promisify(load.css); @@ -83,21 +84,26 @@ const onDblClick = currify(async (options, userMenu, e) => { }); const onKeyDown = currify(async (keys, options, userMenu, e) => { - const {keyCode} = e; + const { + keyCode, + target, + } = 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(); + let value; + + if (keyCode === Key.ESC) + return hide(); + else if (keyCode === Key.ENTER) + ({value} = target); + else if (keys.includes(key)) + value = options.find(beginWith(key)); + else + return navigate(target, e); + await runUserMenu(value, options, userMenu); }); diff --git a/client/modules/user-menu/navigate.js b/client/modules/user-menu/navigate.js new file mode 100644 index 00000000..67c12e0a --- /dev/null +++ b/client/modules/user-menu/navigate.js @@ -0,0 +1,35 @@ +'use strict'; + +const { + J, + K, + UP, + DOWN, +} = require('../../key/key.js'); + +module.exports = (el, {keyCode}) => { + if (keyCode === DOWN || keyCode === J) + return down(el); + + if (keyCode === UP || keyCode === K) + return up(el); +}; + +function down(el) { + const {length} = el; + + if (el.selectedIndex === length - 1) + el.selectedIndex = 0; + else + ++el.selectedIndex; +} + +function up(el) { + const {length} = el; + + if (!el.selectedIndex) + el.selectedIndex = length - 1; + else + --el.selectedIndex; +} + diff --git a/client/modules/user-menu/navigate.spec.js b/client/modules/user-menu/navigate.spec.js new file mode 100644 index 00000000..7a5ba70b --- /dev/null +++ b/client/modules/user-menu/navigate.spec.js @@ -0,0 +1,110 @@ +'use strict'; + +const test = require('supertape'); +const navigate = require('./navigate'); + +const { + UP, + DOWN, + J, + K, +} = require('../../key/key.js'); + +test('cloudcmd: user-menu: navigate: DOWN', (t) => { + const el = { + length: 3, + selectedIndex: 0, + }; + + navigate(el, { + keyCode: DOWN, + }); + + t.equal(el.selectedIndex, 1); + t.end(); +}); + +test('cloudcmd: user-menu: navigate: J', (t) => { + const el = { + length: 3, + selectedIndex: 0, + }; + + navigate(el, { + keyCode: J, + }); + + t.equal(el.selectedIndex, 1); + t.end(); +}); + +test('cloudcmd: user-menu: navigate: DOWN: bottom', (t) => { + const el = { + length: 3, + selectedIndex: 2, + }; + + navigate(el, { + keyCode: DOWN, + }); + + t.equal(el.selectedIndex, 0); + t.end(); +}); + +test('cloudcmd: user-menu: navigate: K', (t) => { + const el = { + length: 3, + selectedIndex: 2, + }; + + navigate(el, { + keyCode: K, + }); + + t.equal(el.selectedIndex, 1); + t.end(); +}); + +test('cloudcmd: user-menu: navigate: UP', (t) => { + const el = { + length: 3, + selectedIndex: 2, + }; + + navigate(el, { + keyCode: UP, + }); + + t.equal(el.selectedIndex, 1); + t.end(); +}); + +test('cloudcmd: user-menu: navigate: UP: top', (t) => { + const el = { + length: 3, + selectedIndex: 0, + }; + + navigate(el, { + keyCode: UP, + }); + + t.equal(el.selectedIndex, 2); + t.end(); +}); + +test('cloudcmd: user-menu: navigate', (t) => { + const el = { + length: 3, + selectedIndex: 0, + }; + + navigate(el, { + keyCode: 0, + }); + + t.equal(el.selectedIndex, 0, 'should not change'); + t.end(); +}); +