<commit_before>import './reactions-avatars.css';
import React from 'dom-chef';
import select from 'select-dom';
import debounce from 'debounce-fn';
import {timerIntervalometer} from 'intervalometer';
import features from '../libs/features';
import {getUsername, flatZip} from '../libs/utils';

const arbitraryAvatarLimit = 36;
const approximateHeaderLength = 3; // Each button header takes about as much as 3 avatars

type Participant = {
	container: HTMLElement;
	username: string;
};

function getParticipants(container: HTMLElement): Participant[] {
	const currentUser = getUsername();
	return container.getAttribute('aria-label')!
		.replace(/ reacted with.*/, '')
		.replace(/,? and /, ', ')
		.replace(/, \d+ more/, '')
		.replace(/\[bot\]/g, '')
		.split(', ')
		.filter(username => username !== currentUser)
		.map((username): Participant => ({
			container,
			username
		}));
}

function add(): void {
	for (const list of select.all('.has-reactions .comment-reactions-options:not(.rgh-reactions)')) {
		const avatarLimit = arbitraryAvatarLimit - (list.children.length * approximateHeaderLength);

		const participantByReaction = [...list.children as HTMLCollectionOf<HTMLElement>].map(getParticipants);
		const flatParticipants = flatZip(participantByReaction, avatarLimit);

		for (const participant of flatParticipants) {
			participant.container.append(
				<a href={`/${participant.username}`}>
					<img src={`/${participant.username}.png?size=${window.devicePixelRatio * 20}`}/>
				</a>
			);
		}

		list.classList.add('rgh-reactions');

		// Overlap reaction avatars when near the avatarLimit
		if (flatParticipants.length > avatarLimit * 0.9) {
			list.classList.add('rgh-reactions-near-limit');
		}
	}
}
<commit_msg>Improve clickability of reaction buttons in Firefox (#2062)<commit_after>import './reactions-avatars.css';
import React from 'dom-chef';
import select from 'select-dom';
import debounce from 'debounce-fn';
import {timerIntervalometer} from 'intervalometer';
import features from '../libs/features';
import {getUsername, flatZip} from '../libs/utils';

const arbitraryAvatarLimit = 36;
const approximateHeaderLength = 3; // Each button header takes about as much as 3 avatars

type Participant = {
	container: HTMLElement;
	username: string;
};

function getParticipants(container: HTMLElement): Participant[] {
	const currentUser = getUsername();
	return container.getAttribute('aria-label')!
		.replace(/ reacted with.*/, '')
		.replace(/,? and /, ', ')
		.replace(/, \d+ more/, '')
		.replace(/\[bot\]/g, '')
		.split(', ')
		.filter(username => username !== currentUser)
		.map((username): Participant => ({
			container,
			username
		}));
}

function add(): void {
	for (const list of select.all('.has-reactions .comment-reactions-options:not(.rgh-reactions)')) {
		const avatarLimit = arbitraryAvatarLimit - (list.children.length * approximateHeaderLength);

		const participantByReaction = [...list.children as HTMLCollectionOf<HTMLElement>].map(getParticipants);
		const flatParticipants = flatZip(participantByReaction, avatarLimit);

		for (const {container, username} of flatParticipants) {
			container.append(
				<a>
					<img src={`/${username}.png?size=${window.devicePixelRatio * 20}`} />
				</a>
			);

			// Without this, Firefox will follow the link instead of submitting the reaction button
			if (!navigator.userAgent.includes('Firefox/')) {
				(container.lastElementChild as HTMLAnchorElement).href = `/${username}`;
			}
		}

		list.classList.add('rgh-reactions');

		// Overlap reaction avatars when near the avatarLimit
		if (flatParticipants.length > avatarLimit * 0.9) {
			list.classList.add('rgh-reactions-near-limit');
		}
	}
}

{'fraction_non_alphanumeric': 0.15282661617527726, 'fraction_numerical': 0.005409791723018664, 'mean_word_length': 4.454277286135693, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '509359', 'n_tokens_mistral': 1257, 'n_tokens_neox': 1109, 'n_words': 272}