File size: 1,887 Bytes
795f737 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | (el, suppliedPath) => {
const norm = s => (s || '').replace(/\s+/g, ' ').trim().slice(0, 512);
const tag = el.tagName.toLowerCase();
const type = (el.getAttribute('type') || 'text').toLowerCase();
const auto = (el.getAttribute('autocomplete') || '').toLowerCase();
const sensitive = type === 'password' || /password|cc-|one-time-code/.test(auto);
const roles = {button:'button', a:'link', textarea:'textbox', select:'combobox',
summary:'button', h1:'heading', h2:'heading', h3:'heading', p:'text', output:'status'};
const inputRoles = {checkbox:'checkbox', radio:'radio', button:'button', submit:'button', range:'slider'};
const role = el.getAttribute('role') || (tag === 'input' ? (inputRoles[type] || 'textbox') : roles[tag]) || 'generic';
const root = el.getRootNode();
const labelled = (el.getAttribute('aria-labelledby') || '').split(/\s+/)
.map(id => root.getElementById?.(id)?.textContent || '').join(' ').trim();
const label = [...(el.labels || [])].map(x => x.textContent).join(' ');
const name = sensitive ? '[REDACTED]' : norm(labelled || el.getAttribute('aria-label') || label ||
(['input','textarea','select'].includes(tag) ? (el.getAttribute('placeholder') || el.getAttribute('title')) : el.textContent));
const rect = el.getBoundingClientRect();
const css = getComputedStyle(el);
const visible = !!(el.isConnected && rect.width && rect.height && css.visibility !== 'hidden' && css.display !== 'none');
const enabled = !el.matches(':disabled') && el.getAttribute('aria-disabled') !== 'true' && !el.closest('[inert]');
let path = [], node = el;
while (suppliedPath == null && node?.nodeType === 1) {
const parent = node.parentNode;
path.push([...parent.children].indexOf(node));
node = parent.host || parent;
}
return {role, name, path:suppliedPath ?? path.reverse().join('/'), visible, enabled, sensitive};
}
|