More updates to itb (wip)
This commit is contained in:
208
tools/itb/js/dom_analyzer.js.orig
Normal file
208
tools/itb/js/dom_analyzer.js.orig
Normal file
@@ -0,0 +1,208 @@
|
||||
// Helper function to check if element is clickable
|
||||
function isClickable(element) {
|
||||
// Check tag name
|
||||
if (element.tagName === 'BUTTON' ||
|
||||
element.tagName === 'A' ||
|
||||
(element.tagName === 'INPUT' && element.type === 'submit')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check ARIA role
|
||||
if (element.getAttribute('role') === 'button') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for click handlers
|
||||
if (element.onclick ||
|
||||
element.getAttribute('onclick') ||
|
||||
element.getAttribute('ng-click') ||
|
||||
element.getAttribute('v-on:click')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check computed style
|
||||
const style = window.getComputedStyle(element);
|
||||
if (style.cursor === 'pointer') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Helper function to check if element is an input
|
||||
function isInputElement(element) {
|
||||
const inputTags = ['INPUT', 'TEXTAREA', 'SELECT'];
|
||||
if (inputTags.includes(element.tagName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (element.getAttribute('contenteditable') === 'true') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (element.getAttribute('role') === 'textbox' ||
|
||||
element.getAttribute('role') === 'combobox') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Helper function to check if element is scrollable
|
||||
function isScrollable(element) {
|
||||
const style = window.getComputedStyle(element);
|
||||
|
||||
// Check for scroll overflow
|
||||
if (style.overflow === 'auto' ||
|
||||
style.overflow === 'scroll' ||
|
||||
style.overflowY === 'auto' ||
|
||||
style.overflowY === 'scroll' ||
|
||||
style.overflowX === 'auto' ||
|
||||
style.overflowX === 'scroll') {
|
||||
|
||||
// Verify element has scrollable content
|
||||
return element.scrollHeight > element.clientHeight ||
|
||||
element.scrollWidth > element.clientWidth;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Helper function to check if element is actually visible
|
||||
function isElementVisible(element) {
|
||||
const style = window.getComputedStyle(element);
|
||||
|
||||
// Special handling for fixed position elements
|
||||
if (style.position === 'fixed') {
|
||||
// Fixed elements are always considered visible if they have dimensions
|
||||
if (element.offsetWidth > 0 && element.offsetHeight > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// For non-fixed elements, check offsetParent
|
||||
if (!element.offsetParent && element !== document.body) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (style.display === 'none' ||
|
||||
style.visibility === 'hidden' ||
|
||||
style.opacity === '0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const rect = element.getBoundingClientRect();
|
||||
if (rect.width === 0 || rect.height === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// For non-fixed elements, check viewport boundaries
|
||||
if (style.position !== 'fixed') {
|
||||
const viewportWidth = window.innerWidth;
|
||||
const viewportHeight = window.innerHeight;
|
||||
|
||||
if (rect.right < 0 ||
|
||||
rect.bottom < 0 ||
|
||||
rect.left > viewportWidth ||
|
||||
rect.top > viewportHeight) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Helper function to get element text
|
||||
function getElementText(element) {
|
||||
// Only process direct text nodes
|
||||
const textNodes = Array.from(element.childNodes)
|
||||
.filter(node => node.nodeType === Node.TEXT_NODE);
|
||||
|
||||
if (textNodes.length === 0) return '';
|
||||
|
||||
return textNodes
|
||||
.map(node => node.textContent.trim())
|
||||
.filter(text => text.length > 0)
|
||||
.join(' ');
|
||||
}
|
||||
|
||||
function processElements(element) {
|
||||
if (!element || !isElementVisible(element)) return [];
|
||||
|
||||
const rect = element.getBoundingClientRect();
|
||||
const styles = window.getComputedStyle(element);
|
||||
const isFixed = styles.position === 'fixed';
|
||||
|
||||
// Get element base info
|
||||
const elementInfo = {
|
||||
tag: element.tagName.toLowerCase(),
|
||||
x: Math.round(isFixed ? rect.left : rect.left + window.pageXOffset),
|
||||
y: Math.round(isFixed ? rect.top : rect.top + window.pageYOffset),
|
||||
width: Math.round(rect.width),
|
||||
height: Math.round(rect.height),
|
||||
interactions: [],
|
||||
fixed: isFixed
|
||||
};
|
||||
|
||||
// Add ID or suggested click coordinates for any interactive element
|
||||
if (isClickable(element) || isInputElement(element)) {
|
||||
const id = element.id;
|
||||
if (id) {
|
||||
elementInfo.id = id;
|
||||
} else {
|
||||
// Only add suggested click if there's no ID
|
||||
elementInfo.suggestedClick = {
|
||||
x: Math.round(elementInfo.x + elementInfo.width / 2),
|
||||
y: Math.round(elementInfo.y + elementInfo.height / 2)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Add text only if this isn't going to be an interactive element
|
||||
const isInteractive = isClickable(element) || isInputElement(element);
|
||||
if (!isInteractive) {
|
||||
elementInfo.text = getElementText(element);
|
||||
}
|
||||
|
||||
// Add interactions
|
||||
if (isClickable(element)) {
|
||||
elementInfo.interactions.push('click');
|
||||
elementInfo.buttonText = getElementText(element);
|
||||
}
|
||||
|
||||
if (isInputElement(element)) {
|
||||
const inputType = element.getAttribute('type') || 'text';
|
||||
elementInfo.interactions.push(`input:${inputType}`);
|
||||
|
||||
const placeholder = element.getAttribute('placeholder');
|
||||
if (placeholder) {
|
||||
elementInfo.placeholder = placeholder;
|
||||
}
|
||||
}
|
||||
|
||||
if (isScrollable(element)) {
|
||||
elementInfo.interactions.push('scroll');
|
||||
}
|
||||
|
||||
// Special handling for images
|
||||
if (element.tagName === 'IMG') {
|
||||
elementInfo.src = element.src;
|
||||
elementInfo.alt = element.alt;
|
||||
}
|
||||
|
||||
// Process children
|
||||
elementInfo.children = Array.from(element.children)
|
||||
.map(child => processElements(child))
|
||||
.flat()
|
||||
.filter(child => child !== null);
|
||||
|
||||
return elementInfo;
|
||||
}
|
||||
|
||||
function analyzePageContent() {
|
||||
const body = document.body;
|
||||
return {
|
||||
viewport: getViewportInfo(),
|
||||
content: body ? processElements(body) : []
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user