#include "hints.h" namespace { constexpr auto kChars = "1qaz2wsx3edc4rfv5tgb6yhn7ujm8ik9ol0p"; // Installs window.__attHints and shows the labels. "@CHARS@" is substituted // with kChars before running. constexpr auto kShowScript = R"JS( (function () { 'use strict'; if (window.__attHints) window.__attHints.clear(); const CHARS = '@CHARS@'; const SELECTOR = [ 'a[href]', 'area[href]', 'button', 'input:not([type=hidden])', 'select', 'textarea', 'summary', 'label', '[onclick]', '[contenteditable=""]', '[contenteditable=true]', '[role=link]', '[role=button]', '[role=checkbox]', '[role=radio]', '[role=tab]', '[role=menuitem]', '[role=option]', '[role=switch]', '[tabindex]:not([tabindex="-1"])', ].join(','); const TEXT_INPUTS = new Set(['', 'text', 'search', 'email', 'url', 'tel', 'password', 'number', 'date', 'datetime-local', 'month', 'time', 'week']); function visibleRect(el) { const style = getComputedStyle(el); if (style.visibility !== 'visible' || parseFloat(style.opacity) === 0) return null; // getClientRects rather than getBoundingClientRect so a link wrapped // over two lines gets its label on the first line, not in the gap. for (const r of el.getClientRects()) { if (r.width < 1 || r.height < 1) continue; if (r.bottom <= 0 || r.right <= 0 || r.top >= innerHeight || r.left >= innerWidth) continue; return r; } return null; } function isEditable(el) { if (el.isContentEditable || el.tagName === 'TEXTAREA') return true; return el.tagName === 'INPUT' && TEXT_INPUTS.has((el.getAttribute('type') || '').toLowerCase()); } // All labels have the same length, so none is a prefix of another. function makeLabels(count) { const n = CHARS.length; let len = 1; while (Math.pow(n, len) < count) len++; const labels = []; for (let i = 0; i < count; i++) { let label = ''; for (let j = 0, k = i; j < len; j++, k = Math.floor(k / n)) label = CHARS[k % n] + label; labels.push(label); } return labels; } const targets = []; const seen = new Set(); for (const el of document.querySelectorAll(SELECTOR)) { if (el.disabled || seen.has(el)) continue; const rect = visibleRect(el); if (!rect) continue; // A