Skip to content

Commit fc83354

Browse files
LeoLiang000mmmay0722
authored andcommitted
update element_detector.js: support to crawl shadow root elements
1 parent 35aa16a commit fc83354

File tree

1 file changed

+56
-13
lines changed

1 file changed

+56
-13
lines changed

webqa_agent/crawler/js/element_detector.js

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,47 @@
745745
return '/' + parts.join('/');
746746
}
747747

748+
/**
749+
* Retrieves all child container elements from the specified node
750+
*
751+
* This function is used to get child elements when traversing the DOM tree,
752+
* supporting multiple container types:
753+
* - Child elements of regular DOM elements
754+
* - Child elements of Shadow DOM
755+
* - Body element of iframe internal documents
756+
*
757+
* @param {Node|ShadowRoot} node - The node to get child containers from, can be a regular DOM node or Shadow Root
758+
* @returns {Array<Element>} Returns an array containing all child container elements
759+
*/
760+
function getChildContainers(node) {
761+
const out = [];
762+
763+
// Handle Shadow Root nodes
764+
if (node instanceof ShadowRoot) {
765+
out.push(...Array.from(node.children));
766+
}
767+
// Handle regular DOM element nodes
768+
else if (node && node.nodeType === Node.ELEMENT_NODE) {
769+
// Add all direct child elements
770+
out.push(...Array.from(node.children));
771+
772+
// If the element has a Shadow Root, add it to the container list
773+
if (node.shadowRoot instanceof ShadowRoot) out.push(node.shadowRoot);
774+
775+
// Special handling for iframe elements, attempt to get the body of their internal document
776+
if (node.tagName?.toLowerCase() === 'iframe') {
777+
try {
778+
const doc = node.contentDocument;
779+
if (doc?.body) out.push(doc.body);
780+
} catch (_) {
781+
/* Ignore errors when cross-origin iframe access is blocked */
782+
}
783+
}
784+
}
785+
786+
return out;
787+
}
788+
748789
/**
749790
* Gathers comprehensive information about a DOM element.
750791
*
@@ -980,29 +1021,31 @@
9801021
* @returns {object | null} A tree node object, or `null` if the element and its descendants are not relevant.
9811022
*/
9821023
function buildTree(elemObj, wasParentHighlighted = false) {
983-
// 1) get element info
984-
const elemInfo = getElementInfo(elemObj, wasParentHighlighted);
1024+
// If it is a ShadowRoot, use host as element info; otherwise use the element itself
1025+
const infoTarget = (elemObj instanceof ShadowRoot) ? elemObj.host : elemObj;
1026+
1027+
// get element info
1028+
const elemInfo = getElementInfo(infoTarget, wasParentHighlighted);
9851029

986-
// 2) check node satisfies highlight condition
987-
const isCurNodeHighlighted = handleHighlighting(elemInfo, elemObj, wasParentHighlighted)
1030+
// Highlight check
1031+
const isCurNodeHighlighted = elemInfo ? handleHighlighting(elemInfo, infoTarget, wasParentHighlighted) : false;
9881032
const isParentHighlighted = wasParentHighlighted || isCurNodeHighlighted;
9891033

990-
// 3) recursively build structured dom tree, with 'isParentHighlighted' state
1034+
// Recursively process “container” child nodes: Element children, shadowRoot, and same-origin iframe
9911035
const children = [];
992-
Array.from(elemObj.children).forEach(child => {
1036+
for (const child of getChildContainers(elemObj)) {
9931037
const subtree = buildTree(child, isParentHighlighted);
9941038
if (subtree) children.push(subtree);
995-
});
1039+
}
9961040

997-
// 4) highlight filter
1041+
// highlight filter
9981042
if (isCurNodeHighlighted) {
999-
highlightIdMap[elemInfo.highlightIndex] = elemInfo; // map highlightIndex to element info
1000-
return {node: elemInfo, children}; // keep info if is highlightable
1043+
highlightIdMap[elemInfo.highlightIndex] = elemInfo; // map highlightIndex to element info
1044+
return {node: elemInfo, children};
10011045
} else if (children.length > 0) {
1002-
return {node: null, children}; // child node is highlightable
1003-
} else {
1004-
return null; // skip
1046+
return {node: null, children}; // child node is highlightable
10051047
}
1048+
return null;
10061049
}
10071050

10081051
// ============================= Main Function =============================

0 commit comments

Comments
 (0)