diff --git a/eslint.config.js b/eslint.config.js index 2878134cf546..aefc8f6517b1 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -91,7 +91,7 @@ export default defineConfig([ 'error', { selector: - ':matches([callee.name=delegate], [callee.name=$], [callee.name=$$], [callee.name=$optional], [callee.name=$closest], [callee.name=$closestOptional], [callee.name=observe], [callee.property.name=querySelector], [callee.property.name=querySelectorAll])[arguments.0.value=/,/][arguments.0.value.length>=20]:not([arguments.0.value=/:has|:is/])', + ':matches([callee.name=delegate], [callee.name=$], [callee.name=$$], [callee.name=$optional], [callee.name=$closest], [callee.name=$closestOptional], [callee.name=observe], [callee.property.name=querySelector], [callee.property.name=querySelectorAll])[arguments.0.value=/,/][arguments.0.value.length>=20]:not([arguments.0.value=/:has|:is|:not/])', message: 'Instead of a single string, pass an array of selectors and add comments to each selector', }, { diff --git a/source/features/closing-remarks.tsx b/source/features/closing-remarks.tsx index 6cbfa9602b1f..c99a57c2300b 100644 --- a/source/features/closing-remarks.tsx +++ b/source/features/closing-remarks.tsx @@ -1,5 +1,5 @@ import React from 'dom-chef'; -import {$, $$} from 'select-dom'; +import {$, $$optional} from 'select-dom'; import {CachedFunction} from 'webext-storage-cache'; import * as pageDetect from 'github-url-detection'; @@ -30,7 +30,7 @@ function ExplanationLink(): JSX.Element { const firstTag = new CachedFunction('first-tag', { async updater(commit: string): Promise { const tagsAndBranches = await fetchDom(buildRepoUrl('branch_commits', commit)); - const tags = $$('ul.branches-tag-list a', tagsAndBranches); + const tags = $$optional('ul.branches-tag-list a', tagsAndBranches); // eslint-disable-next-line unicorn/no-array-callback-reference -- Just this once, I swear return tags.findLast(excludeNightliesAndJunk)?.textContent ?? false; }, diff --git a/source/features/conversation-activity-filter.tsx b/source/features/conversation-activity-filter.tsx index 4cb4f2b3d0e3..426c02b86bab 100644 --- a/source/features/conversation-activity-filter.tsx +++ b/source/features/conversation-activity-filter.tsx @@ -36,7 +36,7 @@ const minorFixesIssuePages = [ const states = { showAll: 'Show all activities', hideEvents: 'Hide events', - hideEventsAndCollapsedComments: 'Hide events, bots, collapsed comments', + hideEventsBotsCollapsedComments: 'Hide events, bots, collapsed comments', } as const; type State = keyof typeof states; @@ -290,7 +290,7 @@ function switchToNextFilter(): void { async function init(signal: AbortSignal): Promise { currentState = SessionPageSetting.get() ?? (minorFixesIssuePages.some(url => location.href.startsWith(url)) - ? 'hideEventsAndCollapsedComments' // Automatically hide resolved comments on "Minor codebase updates and fixes" issue pages + ? 'hideEventsBotsCollapsedComments' // Automatically hide resolved comments on "Minor codebase updates and fixes" issue pages : 'showAll'); const initialSetupOnce = onetime(() => { diff --git a/source/features/hide-inactive-deployments.tsx b/source/features/hide-inactive-deployments.tsx index 30fef6973999..694d91e5bb0d 100644 --- a/source/features/hide-inactive-deployments.tsx +++ b/source/features/hide-inactive-deployments.tsx @@ -1,12 +1,12 @@ import * as pageDetect from 'github-url-detection'; -import {elementExists, $$} from 'select-dom'; +import {elementExists, $$optional} from 'select-dom'; import features from '../feature-manager.js'; // This feature doesn't need an active observer function init(): void { // Selects all the deployments first so that we can leave the last one on the page - const deployments = $$('.js-socket-channel[data-gid^="PR"]:has(.octicon-rocket)'); + const deployments = $$optional('.js-socket-channel[data-gid^="PR"]:has(.octicon-rocket)'); deployments.pop(); // Don't hide the last deployment, even if it is inactive for (const deployment of deployments) { diff --git a/source/features/linkify-line-numbers.tsx b/source/features/linkify-line-numbers.tsx index a8c62efccdb5..2a2b3e282e54 100644 --- a/source/features/linkify-line-numbers.tsx +++ b/source/features/linkify-line-numbers.tsx @@ -24,7 +24,7 @@ function linkify(lineNumberCell: HTMLTableCellElement): void { } function init(signal: AbortSignal): void { - observe('.blob-num:empty:not(.blob-num-hunk)', linkify, {signal}); + observe('.blob-num:not(.blob-num-hunk, .empty-cell)', linkify, {signal}); } void features.add(import.meta.url, { diff --git a/source/features/reactions-avatars.tsx b/source/features/reactions-avatars.tsx index 9213214ff997..614a36d24f19 100644 --- a/source/features/reactions-avatars.tsx +++ b/source/features/reactions-avatars.tsx @@ -3,7 +3,7 @@ import './reactions-avatars.css'; import React from 'dom-chef'; import {flatZip} from 'flat-zip'; import * as pageDetect from 'github-url-detection'; -import {$$} from 'select-dom'; +import {$$optional} from 'select-dom'; import {onAbort} from 'abort-utils'; @@ -73,12 +73,16 @@ const viewportObserver = new IntersectionObserver(changes => { rootMargin: '500px', }); -function showAvatarsOn(commentReactions: Element): void { - const reactions = $$([ - 'button[aria-pressed]', // Discussions, releases, PRs, old issues - 'button[aria-checked]', // React issues - ], commentReactions) +function showAvatarsOn(reactionsContainer: Element): void { + const reactions = $$optional([ + 'button[aria-pressed]', // Discussions, releases, PRs + 'button[aria-checked]', // Issues + ], reactionsContainer) .map(button => getParticipants(button)); // Get all participants for each reaction + if (reactions.length === 0) { + return; + } + const avatarLimit = arbitraryAvatarLimit - (reactions.length * approximateHeaderLength); const flatParticipants = flatZip(reactions, avatarLimit); @@ -107,7 +111,7 @@ function init(signal: AbortSignal): void { [ // `batch-deferred-content` means the participant list hasn't loaded yet '.has-reactions .js-comment-reactions-options:not(batch-deferred-content .js-comment-reactions-options)', - '[aria-label="Reactions"]', + 'div[aria-label="Reactions"]', ], observeCommentReactions, {signal}, diff --git a/source/github-helpers/selectors.ts b/source/github-helpers/selectors.ts index 130393ce331b..f7f3c5a196d8 100644 --- a/source/github-helpers/selectors.ts +++ b/source/github-helpers/selectors.ts @@ -46,11 +46,7 @@ export const branchSelector_ = [ export const branchSelectorParent = 'details#branch-select-menu'; export const branchSelectorParent_ = branchSelector_; -export const directoryListingFileIcon = [ - // .color-fg-muted selects only files; some icon extensions use `img` tags - '.react-directory-filename-column > :is(svg, img).color-fg-muted', - '.js-navigation-container .octicon-file', -]; +export const directoryListingFileIcon = '.react-directory-filename-column > .octicon-file'; export const directoryListingFileIcon_ = [ [18, 'https://github.com/refined-github/refined-github'], [3, 'https://github.com/refined-github/refined-github/tree/main/.github'], diff --git a/source/helpers/on-altered-click.ts b/source/helpers/on-altered-click.ts index d7317c3ab549..8f74de173f02 100644 --- a/source/helpers/on-altered-click.ts +++ b/source/helpers/on-altered-click.ts @@ -2,6 +2,10 @@ import type {ParseSelector} from 'typed-query-selector/parser.d.js'; import delegate, {type DelegateEventHandler, type DelegateOptions} from 'delegate-it'; import {isAlteredClick} from 'filter-altered-clicks'; +function isMiddleClick(event: MouseEvent): boolean { + return event.button === 1; +} + export default function onAlteredClick( selector: Selector | readonly Selector[], callback: DelegateEventHandler>, @@ -14,14 +18,15 @@ export default function onAlteredClick( }; const auxClickListener: typeof callback = event => { - // Is middle click - if (event.button === 1) { + if (isMiddleClick(event)) { callback(event); } }; const preventAutoScrolling = (event: MouseEvent): void => { - event.preventDefault(); + if (isMiddleClick(event)) { + event.preventDefault(); + } }; delegate(selector, 'click', clickListener, {capture: true, ...options});