summaryrefslogtreecommitdiff
path: root/source/features/cycle-lists-with-keyboard-shortcuts.tsx
diff options
context:
space:
mode:
authorGravatar Laxman <notlmn@outlook.com> 2019-06-21 18:21:23 +0530
committerGravatar Federico Brigante <github@bfred.it> 2019-06-21 20:51:23 +0800
commitde42edc3a006da6d68e0f573911d7f81dc00b26e (patch)
tree587d67bf2048ed8b66c001ed4e511484b17bb2a6 /source/features/cycle-lists-with-keyboard-shortcuts.tsx
parent558f2d3a159f805c142141c237ec000f71e6f710 (diff)
downloadrefined-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.tsx68
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
+ ]
+});