UNPKG

@agentic-intelligence/dom-engine

Version:

Agentic DOM Intelligence - A lightweight TypeScript library for DOM analysis and manipulation, designed for web automation and AI agents

103 lines 4.2 kB
"use strict"; /** * Interactive elements finder */ Object.defineProperty(exports, "__esModule", { value: true }); exports.getInteractiveSelectors = getInteractiveSelectors; exports.findInteractiveElements = findInteractiveElements; const helpers_1 = require("../utils/helpers"); const element_analyzer_1 = require("./element-analyzer"); /** * Gets CSS selectors for interactive elements * @returns Array of CSS selectors */ function getInteractiveSelectors() { return [ // Form elements 'input:not([type="hidden"])', 'input[type="checkbox"]', 'textarea', 'select', 'button', // Links 'a[href]', 'a[onclick]', // Elements with click events '[onclick]', '[onmousedown]', '[onmouseup]', // Elements with interactive roles '[role="button"]', '[role="link"]', '[role="menuitem"]', '[role="tab"]', '[role="option"]', // Editable elements '[contenteditable="true"]', // Elements with tabindex (keyboard navigable) '[tabindex]:not([tabindex="-1"])', // Elements with pointer cursor '[style*="cursor: pointer"]', // Elements with custom events '[data-action]', '[data-toggle]', '[data-target]' ]; } /** * Finds and categorizes visible interactive elements in the DOM * @returns Object with categorized elements and total counter */ function findInteractiveElements() { const selectors = getInteractiveSelectors().join(', '); const allElements = document.body.querySelectorAll(selectors); // Categorizers const categorizers = { buttons: (el) => el.constructor.name === 'HTMLButtonElement' || el.getAttribute('role') === 'button', inputs: (el) => ['HTMLInputElement', 'HTMLTextAreaElement', 'HTMLSelectElement'].includes(el.constructor.name), links: (el) => el.constructor.name === 'HTMLAnchorElement', editable: (el) => el.contentEditable === 'true', custom: (el) => !!el.onclick || !!el.getAttribute('onclick'), selectable: () => true // fallback }; // Process elements in a single pass const categorized = Object.keys(categorizers).reduce((acc, key) => ({ ...acc, [key]: [] }), {}); let totalProcessed = 0; for (const element of allElements) { if (!(0, element_analyzer_1.isElementVisible)(element)) continue; let textContent = (0, element_analyzer_1.getElementText)(element); const isButtonWithSvgIcon = !textContent && (0, element_analyzer_1.hasSvgIcon)(element); // Skip elements without text content, unless it's a button with SVG icon if (!textContent && !isButtonWithSvgIcon) continue; // Handle button with SVG icon - assign text content if (isButtonWithSvgIcon) { textContent = '[This is an Icon Button]'; } const domId = (0, helpers_1.generateUniqueId)(); element.setAttribute('agentic-purpose-id', domId); const elementInfo = (0, helpers_1.filterValidProperties)({ text: textContent, constructorName: element.constructor.name, agenticPurposeId: domId, type: element.type, id: element.id?.substring(0, 40), className: (0, helpers_1.filterStylingClasses)(element.className), rect: element.getBoundingClientRect(), onclick: element.onclick ? 'Yes' : 'No', tabindex: element.tabIndex, role: element.getAttribute('role'), href: element.getAttribute('href'), title: element.getAttribute('title'), ariaLabel: element.getAttribute('aria-label'), ...(element.constructor.name === 'HTMLInputElement' && (0, element_analyzer_1.getSiblingText)(element)) }); // Find category const category = Object.keys(categorizers).find(key => categorizers[key](element)) || 'selectable'; categorized[category].push(elementInfo); totalProcessed++; } return { ...categorized, total: totalProcessed }; } //# sourceMappingURL=interactive-finder.js.map