browser-use-typescript
Version:
A TypeScript-based browser automation framework
158 lines • 5.56 kB
JavaScript
import { HistoryTreeProcessor } from "../domHIstory/historyTypes";
export class DOMTextNode {
text;
type = 'TEXT_NODE';
isVisible;
parent;
constructor(text, isVisible, parent) {
this.text = text;
this.isVisible = isVisible;
this.parent = parent;
}
hasParentWithHighlightIndex() {
let current = this.parent;
while (current !== null) {
if (current.highlightIndex !== null) {
return true;
}
current = current.parent;
}
return false;
}
isParentInViewport() {
return this.parent?.isInViewport ?? false;
}
isParentTopElement() {
return this.parent?.isTopElement ?? false;
}
}
export class DOMElementNode {
tagName; //okay
xpath; //okay
attributes; //okay
children; //okay
isVisible;
parent;
isInteractive = false; //okay
isTopElement = false; //okay
isInViewport = false; //okay
shadowRoot = false;
highlightIndex = null;
viewportCoordinates = null;
pageCoordinates = null;
viewportInfo = null;
constructor(tagName, xpath, attributes, children, isVisible, parent) {
this.tagName = tagName;
this.xpath = xpath;
this.attributes = attributes;
this.children = children;
this.isVisible = isVisible;
this.parent = parent;
}
toString() {
let tagStr = `<${this.tagName}`;
for (const [key, value] of Object.entries(this.attributes)) {
tagStr += ` ${key}="${value}"`;
}
tagStr += '>';
const extras = [];
if (this.isInteractive)
extras.push('interactive');
if (this.isTopElement)
extras.push('top');
if (this.shadowRoot)
extras.push('shadow-root');
if (this.highlightIndex !== null)
extras.push(`highlight:${this.highlightIndex}`);
if (this.isInViewport)
extras.push('in-viewport');
if (extras.length > 0) {
tagStr += ` [${extras.join(', ')}]`;
}
return tagStr;
}
get hash() {
return HistoryTreeProcessor.hashDomElement(this);
}
getAllTextTillNextClickableElement(maxDepth = -1) {
const textParts = [];
const collectText = (node, currentDepth) => {
if (maxDepth !== -1 && currentDepth > maxDepth)
return;
if (node instanceof DOMElementNode && node !== this && node.highlightIndex !== null)
return;
if (node instanceof DOMTextNode) {
textParts.push(node.text);
}
else if (node instanceof DOMElementNode) {
node.children.forEach(child => collectText(child, currentDepth + 1));
}
};
collectText(this, 0);
return textParts.join('\n').trim();
}
clickableElementsToString(includeAttributes = null) {
const formattedText = [];
const processNode = (node, depth) => {
if (node instanceof DOMElementNode) {
if (node.highlightIndex !== null) {
let attributesStr = '';
const text = node.getAllTextTillNextClickableElement();
if (includeAttributes) {
const attributes = Array.from(new Set(Object.entries(node.attributes)
.filter(([key, value]) => includeAttributes.includes(key) && value !== node.tagName)
.map(([, value]) => value)));
if (attributes.includes(text))
attributes.splice(attributes.indexOf(text), 1);
attributesStr = attributes.join(';');
}
let line = `[${node.highlightIndex}]<${node.tagName} `;
if (attributesStr)
line += `${attributesStr}`;
if (text)
line += `${attributesStr ? '>' : ''}${text}`;
line += '/>';
formattedText.push(line);
}
node.children.forEach(child => processNode(child, depth + 1));
}
else if (node instanceof DOMTextNode) {
if (!node.hasParentWithHighlightIndex() && node.isVisible) {
formattedText.push(node.text);
}
}
};
processNode(this, 0);
return formattedText.join('\n');
}
getFileUploadElement(checkSiblings = true) {
if (this.tagName === 'input' && this.attributes.type === 'file')
return this;
for (const child of this.children) {
if (child instanceof DOMElementNode) {
const result = child.getFileUploadElement(false);
if (result)
return result;
}
}
if (checkSiblings && this.parent) {
for (const sibling of this.parent.children) {
if (sibling !== this && sibling instanceof DOMElementNode) {
const result = sibling.getFileUploadElement(false);
if (result)
return result;
}
}
}
return null;
}
}
export class DOMState {
elementTree;
selectorMap;
constructor(elementTree, selectorMap) {
this.elementTree = elementTree;
this.selectorMap = selectorMap;
}
}
//# sourceMappingURL=domClass.js.map