diff options
author | 2019-06-21 18:21:23 +0530 | |
---|---|---|
committer | 2019-06-21 20:51:23 +0800 | |
commit | de42edc3a006da6d68e0f573911d7f81dc00b26e (patch) | |
tree | 587d67bf2048ed8b66c001ed4e511484b17bb2a6 /source/features/cycle-lists-with-keyboard-shortcuts.tsx | |
parent | 558f2d3a159f805c142141c237ec000f71e6f710 (diff) | |
download | refined-github-de42edc3a006da6d68e0f573911d7f81dc00b26e.tar.gz refined-github-de42edc3a006da6d68e0f573911d7f81dc00b26e.tar.zst refined-github-de42edc3a006da6d68e0f573911d7f81dc00b26e.zip |
Add `cycle-lists-with-keyboard-shortcuts` feature (#2140)
Diffstat (limited to 'source/features/cycle-lists-with-keyboard-shortcuts.tsx')
-rw-r--r-- | source/features/cycle-lists-with-keyboard-shortcuts.tsx | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/source/features/cycle-lists-with-keyboard-shortcuts.tsx b/source/features/cycle-lists-with-keyboard-shortcuts.tsx new file mode 100644 index 00000000..0373ee23 --- /dev/null +++ b/source/features/cycle-lists-with-keyboard-shortcuts.tsx @@ -0,0 +1,68 @@ +import select from 'select-dom'; +import delegate from 'delegate-it'; +import features from '../libs/features'; + +function init(): void { + let selectableItems: HTMLElement[] = []; + let lastSelectableItemIndex: number; + + function populateSelectableItems(): void { + requestAnimationFrame(() => { + selectableItems = select.all([ + '.js-active-navigation-container .select-menu-list:not([hidden]) .js-navigation-item:not([hidden])', // All selectable items in the current tab + '.js-active-navigation-container .js-new-label-modal:not(.d-none) .js-navigation-item', // "Create label" button, when selecting labels + '.js-active-navigation-container a.js-navigation-item.js-label-options' // "Edit labels" link, when selecting labels + ].join(',')); + + lastSelectableItemIndex = selectableItems.length - 1; + }); + } + + function performSwapFocus(event: KeyboardEvent, from: number, to: number): void { + event.preventDefault(); + event.stopPropagation(); + + selectableItems[from].classList.remove('navigation-focus'); + selectableItems[from].setAttribute('aria-selected', 'false'); + selectableItems[to].classList.add('navigation-focus'); + selectableItems[to].setAttribute('aria-selected', 'true'); + + selectableItems[to].scrollIntoView({ + block: 'nearest' + }); + } + + function handleKeyDown(event: KeyboardEvent): void { + if (selectableItems.length === 0) { // Empty projects and milestones list + return; + } + + if (selectableItems[0].matches('.navigation-focus') && event.key === 'ArrowUp') { + performSwapFocus(event, 0, lastSelectableItemIndex); + } else if (selectableItems[lastSelectableItemIndex].matches('.navigation-focus') && event.key === 'ArrowDown') { + performSwapFocus(event, lastSelectableItemIndex, 0); + } + } + + // Input fields for projects and milestones are added dynamically to the page + // GitHub triggers events on the document element for us, which can be used to detect new input elements + delegate(document, '.js-filterable-field', 'filterable:change', event => { + populateSelectableItems(); + + const input = event.delegateTarget as HTMLElement; + input.addEventListener('keydown', handleKeyDown); + }); +} + +features.add({ + id: 'cycle-lists-with-keyboard-shortcuts', + description: 'Cycle "popover lists" (labels, milestones, etc) when selecting them with the `↑` and `↓` keys.', + screenshot: 'https://user-images.githubusercontent.com/37769974/59158786-6fd2c400-8add-11e9-9db1-db80186fa6ea.gif', + init, + load: features.onAjaxedPages, + include: [ + features.isPRConversation, + features.isIssue, + features.isCompare + ] +}); |