Skip to content

Commit

Permalink
Meta: Deinit all feature delegates using AbortSignal (refined-githu…
Browse files Browse the repository at this point in the history
…b#5726)

Co-authored-by: Federico Brigante <[email protected]>
  • Loading branch information
cheap-glitch and fregante authored Jul 30, 2022
1 parent 808c68f commit 50cb939
Show file tree
Hide file tree
Showing 67 changed files with 350 additions and 394 deletions.
8 changes: 4 additions & 4 deletions contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,18 @@ Here's an example using all of the possible `feature.add` options:
```tsx
import React from 'dom-chef';
import select from 'select-dom';
import delegate from 'delegate-it';
import * as pageDetect from 'github-url-detection';
import delegate, {DelegateEvent} from 'delegate-it';

import features from '.';

function append(event: delegate.Event<MouseEvent, HTMLButtonElement>): void {
function append(event: DelegateEvent<MouseEvent, HTMLButtonElement>): void {
event.delegateTarget.after('', <div className="rgh-jsx-element">Button clicked!</div>);
}

function init(): Deinit {
function init(signal: AbortSignal): void {
// Events must be set via delegate, unless shortlived
return delegate(document, '.btn', 'click', append);
delegate(document, '.btn', 'click', append, {signal});
}

void features.add(import.meta.url, {
Expand Down
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"array-union": "^3.0.1",
"debounce-fn": "^5.1.2",
"delay": "^5.0.0",
"delegate-it": "^3.0.1",
"delegate-it": "^4.0.0",
"dom-chef": "^5.1.0",
"dom-loaded": "^3.0.0",
"doma": "^3.0.1",
Expand Down
8 changes: 4 additions & 4 deletions source/features/avoid-accidental-submissions.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React from 'dom-chef';
import select from 'select-dom';
import delegate from 'delegate-it';
import * as pageDetect from 'github-url-detection';
import delegate, {DelegateEvent} from 'delegate-it';

import {isMac} from '../github-helpers';
import features from '.';

function onKeyDown(event: delegate.Event<KeyboardEvent, HTMLInputElement>): void {
function onKeyDown(event: DelegateEvent<KeyboardEvent, HTMLInputElement>): void {
const field = event.delegateTarget;
const form = field.form!;
if (
Expand Down Expand Up @@ -49,8 +49,8 @@ const inputElements = [
'#merge_title_field',
];

function init(): Deinit {
return delegate(document, inputElements.join(','), 'keydown', onKeyDown);
function init(signal: AbortSignal): void {
delegate(document, inputElements.join(','), 'keydown', onKeyDown, {signal});
}

void features.add(import.meta.url, {
Expand Down
27 changes: 13 additions & 14 deletions source/features/batch-mark-files-as-viewed.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import select from 'select-dom';
import delegate from 'delegate-it';
import * as pageDetect from 'github-url-detection';
import delegate, {DelegateEvent} from 'delegate-it';

import features from '.';
import clickAll from '../helpers/click-all';
import showToast from '../github-helpers/toast';
import getItemsBetween from '../helpers/get-items-between';
import onAbort from '../helpers/abort-controller';

let previousFile: HTMLElement | undefined;
let runningBatch = false;

function remember(event: delegate.Event): void {
function remember(event: DelegateEvent): void {
// Only remember if the user clicked it. `isTrusted` doesn't work because `remember` is called on a fake `submit` event
if (!runningBatch) {
previousFile = event.delegateTarget.closest('.js-file')!;
Expand All @@ -21,7 +22,7 @@ function isChecked(file: HTMLElement): boolean {
return file.querySelector('input.js-reviewed-checkbox')!.checked;
}

function batchToggle(event: delegate.Event<MouseEvent, HTMLFormElement>): void {
function batchToggle(event: DelegateEvent<MouseEvent, HTMLFormElement>): void {
if (!event.shiftKey) {
return;
}
Expand Down Expand Up @@ -51,7 +52,7 @@ function markAsViewedSelector(target: HTMLElement): string {

const markAsViewed = clickAll(markAsViewedSelector);

function onAltClick(event: delegate.Event<MouseEvent, HTMLInputElement>): void {
function onAltClick(event: DelegateEvent<MouseEvent, HTMLInputElement>): void {
if (!event.altKey || !event.isTrusted) {
return;
}
Expand All @@ -66,16 +67,14 @@ function onAltClick(event: delegate.Event<MouseEvent, HTMLInputElement>): void {
});
}

function init(): Deinit {
return [
// `mousedown` required to avoid mouse selection on shift-click
delegate(document, '.js-reviewed-toggle', 'mousedown', batchToggle),
delegate(document, '.js-toggle-user-reviewed-file-form', 'submit', remember),
delegate(document, '.js-reviewed-toggle', 'click', onAltClick),
() => {
previousFile = undefined;
},
];
function init(signal: AbortSignal): void {
delegate(document, '.js-reviewed-toggle', 'click', onAltClick, {signal});
// `mousedown` required to avoid mouse selection on shift-click
delegate(document, '.js-reviewed-toggle', 'mousedown', batchToggle, {signal});
delegate(document, '.js-toggle-user-reviewed-file-form', 'submit', remember, {signal});
onAbort(signal, () => {
previousFile = undefined;
});
}

void features.add(import.meta.url, {
Expand Down
11 changes: 6 additions & 5 deletions source/features/close-out-of-view-modals.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import select from 'select-dom';
import onetime from 'onetime';
import delegate from 'delegate-it';
import delegate, {DelegateEvent} from 'delegate-it';

import features from '.';

Expand All @@ -24,13 +24,14 @@ const observer = new IntersectionObserver(entries => {
});

let lastOpen: number;
let delegation: delegate.Subscription;
function menuActivatedHandler(event: delegate.Event): void {
const safetySwitch = new AbortController();

function menuActivatedHandler(event: DelegateEvent): void {
const details = event.target as HTMLDetailsElement;

// Safety check #3742
if (!details.open && lastOpen > Date.now() - 500) {
delegation!.destroy();
safetySwitch.abort();
console.warn(`The modal was closed too quickly. Disabling ${features.getFeatureID(import.meta.url)} for this session.`);
return;
}
Expand All @@ -49,7 +50,7 @@ function menuActivatedHandler(event: delegate.Event): void {
}

function init(): void {
delegation = delegate(document, '.details-overlay', 'toggle', menuActivatedHandler, true);
delegate(document, '.details-overlay', 'toggle', menuActivatedHandler, {capture: true, signal: safetySwitch.signal});
}

void features.add(import.meta.url, {
Expand Down
13 changes: 5 additions & 8 deletions source/features/collapsible-content-button.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import React from 'dom-chef';
import select from 'select-dom';
import delegate from 'delegate-it';
import {FoldDownIcon} from '@primer/octicons-react';
import * as pageDetect from 'github-url-detection';
import * as textFieldEdit from 'text-field-edit';
import delegate, {DelegateEvent} from 'delegate-it';

import features from '.';
import smartBlockWrap from '../helpers/smart-block-wrap';
import {onCommentEdit} from '../github-events/on-fragment-load';

function addContentToDetails({delegateTarget}: delegate.Event<MouseEvent, HTMLButtonElement>): void {
function addContentToDetails({delegateTarget}: DelegateEvent<MouseEvent, HTMLButtonElement>): void {
/* There's only one rich-text editor even when multiple fields are visible; the class targets it #5303 */
const field = delegateTarget.form!.querySelector('textarea.js-comment-field')!;
const selection = field.value.slice(field.selectionStart, field.selectionEnd);
Expand Down Expand Up @@ -46,13 +46,10 @@ function addButtons(): void {
}
}

function init(): Deinit {
function init(signal: AbortSignal): void {
addButtons();

return [
delegate(document, '.rgh-collapsible-content-btn', 'click', addContentToDetails),
onCommentEdit(addButtons),
];
onCommentEdit(addButtons, signal);
delegate(document, '.rgh-collapsible-content-btn', 'click', addContentToDetails, {signal});
}

void features.add(import.meta.url, {
Expand Down
4 changes: 2 additions & 2 deletions source/features/command-palette-navigation-shortcuts.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import onetime from 'onetime';
import delegate from 'delegate-it';
import delegate, {DelegateEvent} from 'delegate-it';

import {isMac} from '../github-helpers';
import features from '.';

function commandPaletteKeydown(event: delegate.Event<KeyboardEvent>): void {
function commandPaletteKeydown(event: DelegateEvent<KeyboardEvent>): void {
const {key, ctrlKey, delegateTarget} = event;

if (!ctrlKey || (key !== 'n' && key !== 'p')) {
Expand Down
10 changes: 5 additions & 5 deletions source/features/comment-fields-keyboard-shortcuts.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React from 'dom-chef';
import select from 'select-dom';
import delegate from 'delegate-it';
import {DelegateEvent} from 'delegate-it';
import * as pageDetect from 'github-url-detection';
import filterAlteredClicks from 'filter-altered-clicks';

import features from '.';
import {onCommentFieldKeydown} from '../github-events/on-field-keydown';

function handleEscapeKey(event: delegate.Event<KeyboardEvent, HTMLTextAreaElement>, targetField: HTMLTextAreaElement): void {
function handleEscapeKey(event: DelegateEvent<KeyboardEvent, HTMLTextAreaElement>, targetField: HTMLTextAreaElement): void {
// Cancel buttons have different classes for inline comments and editable comments
const cancelButton = select(`
button.js-hide-inline-comment-form,
Expand Down Expand Up @@ -60,7 +60,7 @@ function handleArrowUpKey(targetField: HTMLTextAreaElement): void {
});
}

const eventHandler = filterAlteredClicks((event: delegate.Event<KeyboardEvent, HTMLTextAreaElement>): void => {
const eventHandler = filterAlteredClicks((event: DelegateEvent<KeyboardEvent, HTMLTextAreaElement>): void => {
const field = event.delegateTarget;

if (event.key === 'Escape') {
Expand All @@ -70,8 +70,8 @@ const eventHandler = filterAlteredClicks((event: delegate.Event<KeyboardEvent, H
}
});

function init(): Deinit {
return onCommentFieldKeydown(eventHandler);
function init(signal: AbortSignal): void {
onCommentFieldKeydown(eventHandler, signal);
}

void features.add(import.meta.url, {
Expand Down
9 changes: 7 additions & 2 deletions source/features/conversation-activity-filter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,9 @@ async function handleSelection({target}: Event): Promise<void> {
}

function applyState(state: State): void {
// `onNewComments` registers the selectors only once
onNewComments(processPage);
// `onNewComments` registers the listener only once
onNewComments(processPage, deinitSignal!);

// Actually process it right now
processPage();

Expand Down Expand Up @@ -224,7 +225,10 @@ function switchToNextFilter(): void {
}
}

let deinitSignal: AbortSignal | undefined;

async function init(signal: AbortSignal): Promise<Deinit> {
deinitSignal = signal;
const state = minorFixesIssuePages.some(url => location.href.startsWith(url))
? 'hideEventsAndCollapsedComments' // Automatically hide resolved comments on "Minor codebase updates and fixes" issue pages
: 'default';
Expand All @@ -237,6 +241,7 @@ async function init(signal: AbortSignal): Promise<Deinit> {
}

window.addEventListener('hashchange', uncollapseTargetedComment, {signal});

return registerHotkey('h', switchToNextFilter);
}

Expand Down
20 changes: 9 additions & 11 deletions source/features/convert-pr-to-draft-improvements.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React from 'dom-chef';
import select from 'select-dom';
import delegate from 'delegate-it';
import {observe} from 'selector-observer';
import * as pageDetect from 'github-url-detection';
import delegate, {DelegateEvent} from 'delegate-it';

import features from '.';
import IconLoading from '../github-helpers/icon-loading';

function closeModal({delegateTarget: button}: delegate.Event<MouseEvent, HTMLButtonElement>): void {
function closeModal({delegateTarget: button}: DelegateEvent<MouseEvent, HTMLButtonElement>): void {
button.append(' ', <IconLoading className="v-align-middle"/>);
button.disabled = true;
}
Expand All @@ -25,16 +25,14 @@ function addConvertToDraftButton(alternativeActions: Element): void {
alternativeActions.prepend(convertToDraft);
}

function init(): Deinit {
return [
// Immediately close lightbox after click instead of waiting for the ajaxed widget to refresh
delegate(document, '.js-convert-to-draft', 'click', closeModal),
function init(signal: AbortSignal): Deinit {
// Immediately close lightbox after click instead of waiting for the ajaxed widget to refresh
delegate(document, '.js-convert-to-draft', 'click', closeModal, {signal});

// Copy button to mergeability box
observe('.alt-merge-options:not(.rgh-convert-pr-draft-position)', {
add: addConvertToDraftButton,
}),
];
// Copy button to mergeability box
return observe('.alt-merge-options:not(.rgh-convert-pr-draft-position)', {
add: addConvertToDraftButton,
});
}

void features.add(import.meta.url, {
Expand Down
8 changes: 4 additions & 4 deletions source/features/convert-release-to-draft.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'dom-chef';
import select from 'select-dom';
import delegate from 'delegate-it';
import elementReady from 'element-ready';
import * as pageDetect from 'github-url-detection';
import delegate, {DelegateEvent} from 'delegate-it';

import features from '.';
import * as api from '../github-helpers/api';
Expand All @@ -13,7 +13,7 @@ const editReleaseButtonSelector = [
'.Box-btn-octicon[aria-label="Edit"]',
].join(',');

async function convertToDraft({delegateTarget: draftButton}: delegate.Event): Promise<void> {
async function convertToDraft({delegateTarget: draftButton}: DelegateEvent): Promise<void> {
try {
draftButton.append(<LoadingIcon className="ml-2 v-align-text-bottom" width={16}/>);

Expand All @@ -33,7 +33,7 @@ async function convertToDraft({delegateTarget: draftButton}: delegate.Event): Pr
}
}

async function init(): Promise<Deinit | false> {
async function init(signal: AbortSignal): Promise<void | false> {
await api.expectToken();

const editButton = await elementReady(editReleaseButtonSelector);
Expand All @@ -58,7 +58,7 @@ async function init(): Promise<Deinit | false> {
editButton.classList.replace('ml-1', 'ml-0');
}

return delegate(document, '.rgh-convert-draft', 'click', convertToDraft);
delegate(document, '.rgh-convert-draft', 'click', convertToDraft, {signal});
}

void features.add(import.meta.url, {
Expand Down
Loading

0 comments on commit 50cb939

Please sign in to comment.