Skip to content

Commit

Permalink
misc: deduplicate all the dom helpers (#15960)
Browse files Browse the repository at this point in the history
  • Loading branch information
connorjclark committed Apr 17, 2024
1 parent c3c85ae commit a387680
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 128 deletions.
48 changes: 18 additions & 30 deletions clients/extension/scripts/popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
*/

import * as SettingsController from './settings-controller.js';
import {DOM} from '../../../report/renderer/dom.js';

const dom = new DOM(document, document.documentElement);

// Replaced with 'chrome' or 'firefox' in the build script.
/** @type {string} */
Expand All @@ -22,21 +25,6 @@ const FIREFOX_STRINGS = {

const STRINGS = BROWSER_BRAND === 'chrome' ? CHROME_STRINGS : FIREFOX_STRINGS;

/**
* Guaranteed context.querySelector. Always returns an element or throws if
* nothing matches query.
* @template {string} T
* @param {T} query
* @param {ParentNode=} context
*/
function find(query, context = document) {
const result = context.querySelector(query);
if (result === null) {
throw new Error(`query ${query} not found`);
}
return result;
}

/**
* @param {string} text
* @param {string} id
Expand Down Expand Up @@ -129,7 +117,7 @@ function generateCategoryOptionsList(settings) {
frag.append(createOptionItem(category.title, category.id, isChecked));
});

const optionsCategoriesList = find('.options__categories');
const optionsCategoriesList = dom.find('.options__categories');
optionsCategoriesList.append(frag);
}

Expand All @@ -146,7 +134,7 @@ function generateBackendOptionsList(settings) {
frag.append(createRadioItem('backend', backend.title, backend.id, isChecked));
});

const optionsCategoriesList = find('.options__backend');
const optionsCategoriesList = dom.find('.options__backend');
optionsCategoriesList.append(frag);
}

Expand Down Expand Up @@ -214,20 +202,20 @@ function generateLocaleOptionsList(settings) {
frag.append(optionEl);
});

const optionsLocalesList = find('.options__locales');
const optionsLocalesList = dom.find('.options__locales');
optionsLocalesList.append(frag);
}

/**
* @param {SettingsController.Settings} settings
*/
function configureVisibleSettings(settings) {
const optionsCategoriesList = find('.options__categories');
const optionsCategoriesList = dom.find('.options__categories');
optionsCategoriesList.parentElement?.classList.toggle('hidden', settings.backend === 'psi');
}

function fillDevToolsShortcut() {
const el = find('.devtools-shortcut');
const el = dom.find('.devtools-shortcut');
const isMac = /mac/i.test(navigator.platform);
el.textContent = isMac ? '⌘⌥I (Cmd+Opt+I)' : 'F12';
}
Expand All @@ -237,13 +225,13 @@ function fillDevToolsShortcut() {
* @return {SettingsController.Settings}
*/
function readSettingsFromDomAndPersist() {
const optionsEl = find('.section--options');
const optionsEl = dom.find('.section--options');
// Save settings when options page is closed.
const backend = find('.options__backend input:checked').value;
const locale = find('select.options__locales').value;
const backend = dom.find('.options__backend input:checked').value;
const locale = dom.find('select.options__locales').value;
const checkboxes = optionsEl.querySelectorAll('.options__categories input:checked');
const selectedCategories = Array.from(checkboxes).map(input => input.value);
const device = find('input[name="device"]:checked').value;
const device = dom.find('input[name="device"]:checked').value;

const settings = {
backend,
Expand Down Expand Up @@ -284,13 +272,13 @@ async function initPopup() {
if (BROWSER_BRAND === 'chrome') {
fillDevToolsShortcut();
}
const browserBrandEl = find(`.browser-brand--${BROWSER_BRAND}`);
const browserBrandEl = dom.find(`.browser-brand--${BROWSER_BRAND}`);
browserBrandEl.classList.remove('hidden');

const generateReportButton = find('button.button--generate');
const psiDisclaimerEl = find('.psi-disclaimer');
const errorMessageEl = find('.errormsg');
const optionsFormEl = find('.options__form');
const generateReportButton = dom.find('button.button--generate');
const psiDisclaimerEl = dom.find('.psi-disclaimer');
const errorMessageEl = dom.find('.errormsg');
const optionsFormEl = dom.find('.options__form');

/** @type {URL} */
let siteUrl;
Expand All @@ -314,7 +302,7 @@ async function initPopup() {
generateCategoryOptionsList(settings);
generateLocaleOptionsList(settings);
configureVisibleSettings(settings);
const selectedDeviceEl = find(`.options__device input[value="${settings.device}"]`);
const selectedDeviceEl = dom.find(`.options__device input[value="${settings.device}"]`);
selectedDeviceEl.checked = true;

generateReportButton.addEventListener('click', () => {
Expand Down
2 changes: 1 addition & 1 deletion report/renderer/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ export class DOM {
* @param {ParentNode} context
* @return {ParseSelector<T>}
*/
find(query, context) {
find(query, context = this.rootEl ?? this._document) {
const result = this.maybeFind(query, context);
if (result === null) {
throw new Error(`query ${query} not found`);
Expand Down
59 changes: 31 additions & 28 deletions treemap/app/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ import {GithubApi} from '../../../viewer/app/src/github-api.js';
import {I18nFormatter} from '../../../report/renderer/i18n-formatter.js';
import {TextEncoding} from '../../../report/renderer/text-encoding.js';
import {Logger} from '../../../report/renderer/logger.js';
import {DOM} from '../../../report/renderer/dom.js';

/** @typedef {LH.Treemap.Node & {dom?: HTMLElement}} NodeWithElement */

const dom = new DOM(document, document.documentElement);

const DUPLICATED_MODULES_IGNORE_THRESHOLD = 1024;
const DUPLICATED_MODULES_IGNORE_ROOT_RATIO = 0.01;

Expand Down Expand Up @@ -129,15 +132,15 @@ class TreemapViewer {
}

createHeader() {
const urlEl = TreemapUtil.find('a.lh-header--url');
const urlEl = dom.find('a.lh-header--url');
urlEl.textContent = this.documentUrl.toString();
urlEl.href = this.documentUrl.toString();

this.createBundleSelector();
}

createBundleSelector() {
const bundleSelectorEl = TreemapUtil.find('select.bundle-selector');
const bundleSelectorEl = dom.find('select.bundle-selector');
bundleSelectorEl.textContent = ''; // Clear just in case document was saved with Ctrl+S.

/** @type {LH.Treemap.Selector[]} */
Expand All @@ -148,7 +151,7 @@ class TreemapViewer {
* @param {string} text
*/
function makeOption(selector, text) {
const optionEl = TreemapUtil.createChildOf(bundleSelectorEl, 'option');
const optionEl = dom.createChildOf(bundleSelectorEl, 'option');
optionEl.value = String(selectors.length);
selectors.push(selector);
optionEl.textContent = text;
Expand Down Expand Up @@ -183,7 +186,7 @@ class TreemapViewer {

initListeners() {
const options = {signal: this.abortController.signal};
const treemapEl = TreemapUtil.find('.lh-treemap');
const treemapEl = dom.find('.lh-treemap');

const resizeObserver = new ResizeObserver(() => this.resize());
resizeObserver.observe(treemapEl);
Expand Down Expand Up @@ -222,7 +225,7 @@ class TreemapViewer {
nodeEl.classList.remove('webtreemap-node--hover');
}, options);

TreemapUtil.find('.lh-table').addEventListener('mouseover', e => {
dom.find('.lh-table').addEventListener('mouseover', e => {
const target = e.target;
if (!(target instanceof HTMLElement)) return;

Expand All @@ -240,7 +243,7 @@ class TreemapViewer {
}, {once: true});
}, options);

const toggleTableBtn = TreemapUtil.find('.lh-button--toggle-table');
const toggleTableBtn = dom.find('.lh-button--toggle-table');
toggleTableBtn.addEventListener('click', () => treemapViewer.toggleTable(), options);
}

Expand Down Expand Up @@ -430,7 +433,7 @@ class TreemapViewer {
});
this.el.textContent = '';
this.treemap.render(this.el);
TreemapUtil.find('.webtreemap-node').classList.add('webtreemap-node--root');
dom.find('.webtreemap-node').classList.add('webtreemap-node--root');

this.createTable();
}
Expand All @@ -447,7 +450,7 @@ class TreemapViewer {
}

createTable() {
const tableEl = TreemapUtil.find('.lh-table');
const tableEl = dom.find('.lh-table');
tableEl.textContent = '';

/** @type {Array<{node: NodeWithElement, name: string, bundleNode?: LH.Treemap.Node, resourceBytes: number, unusedBytes?: number}>} */
Expand Down Expand Up @@ -550,15 +553,15 @@ class TreemapViewer {
/** @type {typeof data[number]} */
const dataRow = cell.getRow().getData();

const el = TreemapUtil.createElement('div', 'lh-coverage-bar');
const el = dom.createElement('div', 'lh-coverage-bar');
if (dataRow.unusedBytes === undefined) return el;

el.style.setProperty('--max', String(maxSize));
el.style.setProperty('--used', String(dataRow.resourceBytes - dataRow.unusedBytes));
el.style.setProperty('--unused', String(dataRow.unusedBytes));

TreemapUtil.createChildOf(el, 'div', 'lh-coverage-bar--used');
TreemapUtil.createChildOf(el, 'div', 'lh-coverage-bar--unused');
dom.createChildOf(el, 'div', 'lh-coverage-bar--used');
dom.createChildOf(el, 'div', 'lh-coverage-bar--unused');

return el;
}},
Expand All @@ -573,9 +576,9 @@ class TreemapViewer {
* @param {boolean=} show
*/
toggleTable(show) {
const mainEl = TreemapUtil.find('main');
const mainEl = dom.find('main');
mainEl.classList.toggle('lh-main--show-table', show);
const buttonEl = TreemapUtil.find('.lh-button--toggle-table');
const buttonEl = dom.find('.lh-button--toggle-table');
buttonEl.classList.toggle('lh-button--active', show);
}

Expand Down Expand Up @@ -669,20 +672,20 @@ function renderViewModeButtons(viewModes) {
* @param {LH.Treemap.ViewMode} viewMode
*/
function render(viewMode) {
const viewModeEl = TreemapUtil.createChildOf(viewModesEl, 'div', 'view-mode');
const viewModeEl = dom.createChildOf(viewModesEl, 'div', 'view-mode');
if (!viewMode.enabled) viewModeEl.classList.add('view-mode--disabled');
viewModeEl.id = `view-mode--${viewMode.id}`;

const inputEl = TreemapUtil.createChildOf(viewModeEl, 'input', 'view-mode__button');
const inputEl = dom.createChildOf(viewModeEl, 'input', 'view-mode__button');
inputEl.id = `view-mode--${viewMode.id}__label`;
inputEl.type = 'radio';
inputEl.name = 'view-mode';
inputEl.disabled = !viewMode.enabled;

const labelEl = TreemapUtil.createChildOf(viewModeEl, 'label');
const labelEl = dom.createChildOf(viewModeEl, 'label');
labelEl.htmlFor = inputEl.id;
TreemapUtil.createChildOf(labelEl, 'span', 'view-mode__label').textContent = viewMode.label;
TreemapUtil.createChildOf(labelEl, 'span', 'view-mode__sublabel lh-text-dim').textContent =
dom.createChildOf(labelEl, 'span', 'view-mode__label').textContent = viewMode.label;
dom.createChildOf(labelEl, 'span', 'view-mode__sublabel lh-text-dim').textContent =
` (${viewMode.subLabel})`;

inputEl.addEventListener('click', () => {
Expand All @@ -691,7 +694,7 @@ function renderViewModeButtons(viewModes) {
});
}

const viewModesEl = TreemapUtil.find('.lh-modes');
const viewModesEl = dom.find('.lh-modes');
viewModesEl.textContent = '';
viewModes.forEach(render);
}
Expand All @@ -701,7 +704,7 @@ function renderViewModeButtons(viewModes) {
* @param {HTMLElement} el
*/
function applyActiveClass(currentViewModeId, el) {
const viewModesEl = TreemapUtil.find('.lh-modes');
const viewModesEl = dom.find('.lh-modes');
for (const viewModeEl of viewModesEl.querySelectorAll('.view-mode')) {
if (!(viewModeEl instanceof HTMLElement)) continue;

Expand All @@ -721,7 +724,7 @@ function injectOptions(options) {
scriptEl.remove();
}

scriptEl = TreemapUtil.createChildOf(document.head, 'script', 'lh-injectedoptions');
scriptEl = dom.createChildOf(document.head, 'script', 'lh-injectedoptions');
scriptEl.textContent = `
window.__treemapOptions = ${JSON.stringify(options)};
`;
Expand All @@ -742,7 +745,7 @@ class LighthouseTreemap {
document.addEventListener('paste', this._onPaste);

// Hidden file input to trigger manual file selector.
const fileInput = TreemapUtil.find('input#hidden-file-input', document);
const fileInput = dom.find('input#hidden-file-input', document);
fileInput.addEventListener('change', e => {
if (!e.target) {
return;
Expand All @@ -758,7 +761,7 @@ class LighthouseTreemap {
});

// A click on the visual placeholder will trigger the hidden file input.
const placeholderTarget = TreemapUtil.find('.treemap-placeholder-inner', document);
const placeholderTarget = dom.find('.treemap-placeholder-inner', document);
placeholderTarget.addEventListener('click', e => {
const target = /** @type {?Element} */ (e.target);

Expand All @@ -772,8 +775,8 @@ class LighthouseTreemap {
* @param {LH.Treemap.Options} options
*/
init(options) {
TreemapUtil.find('.treemap-placeholder').classList.add('hidden');
TreemapUtil.find('main').classList.remove('hidden');
dom.find('.treemap-placeholder').classList.add('hidden');
dom.find('main').classList.remove('hidden');

const locale = options.lhr.configSettings.locale;
document.documentElement.lang = locale;
Expand All @@ -792,11 +795,11 @@ class LighthouseTreemap {
}

if (treemapViewer) {
TreemapUtil.find('.lh-treemap').textContent = '';
TreemapUtil.find('.lh-table').textContent = '';
dom.find('.lh-treemap').textContent = '';
dom.find('.lh-table').textContent = '';
treemapViewer.abortController.abort();
}
treemapViewer = new TreemapViewer(options, TreemapUtil.find('div.lh-treemap'));
treemapViewer = new TreemapViewer(options, dom.find('div.lh-treemap'));

injectOptions(options);

Expand Down
Loading

0 comments on commit a387680

Please sign in to comment.