feat: add iframe support for child selector generation
This commit is contained in:
@@ -1679,33 +1679,130 @@ export const getChildSelectors = async (page: Page, parentSelector: string): Pro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Function to generate selector path from an element to its parent
|
// Function to generate selector path from an element to its parent
|
||||||
function getSelectorPath(element: HTMLElement | null): string {
|
function getSelectorPath(element: HTMLElement): string {
|
||||||
if (!element || !element.parentElement) return '';
|
if (!element || !element.parentElement) return '';
|
||||||
|
|
||||||
const parentSelector = getNonUniqueSelector(element.parentElement);
|
const parentSelector = getNonUniqueSelector(element.parentElement);
|
||||||
const elementSelector = getNonUniqueSelector(element);
|
const elementSelector = getNonUniqueSelector(element);
|
||||||
|
|
||||||
|
// Check if element is in an iframe
|
||||||
|
const ownerDocument = element.ownerDocument;
|
||||||
|
const frameElement = ownerDocument?.defaultView?.frameElement as HTMLIFrameElement;
|
||||||
|
|
||||||
|
if (frameElement) {
|
||||||
|
const frameSelector = getNonUniqueSelector(frameElement);
|
||||||
|
return `${frameSelector} :>> ${elementSelector}`;
|
||||||
|
}
|
||||||
|
|
||||||
return `${parentSelector} > ${elementSelector}`;
|
return `${parentSelector} > ${elementSelector}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getIframeChildren(element: HTMLElement): HTMLElement[] {
|
||||||
|
const children: HTMLElement[] = [];
|
||||||
|
|
||||||
|
// Find all iframe elements
|
||||||
|
const iframes = Array.from(element.querySelectorAll('iframe')) as HTMLIFrameElement[];
|
||||||
|
|
||||||
|
for (const iframe of iframes) {
|
||||||
|
try {
|
||||||
|
// Access iframe's document
|
||||||
|
const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document;
|
||||||
|
if (iframeDoc) {
|
||||||
|
// Get all elements in the iframe
|
||||||
|
const iframeElements = Array.from(iframeDoc.querySelectorAll('*')) as HTMLElement[];
|
||||||
|
children.push(...iframeElements);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Cannot access iframe content:', error);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
// Function to recursively get all descendant selectors
|
// Function to recursively get all descendant selectors
|
||||||
function getAllDescendantSelectors(element: HTMLElement): string[] {
|
function getAllDescendantSelectors(element: HTMLElement): string[] {
|
||||||
let selectors: string[] = [];
|
let selectors: string[] = [];
|
||||||
|
|
||||||
|
// Handle regular DOM children
|
||||||
const children = Array.from(element.children) as HTMLElement[];
|
const children = Array.from(element.children) as HTMLElement[];
|
||||||
|
|
||||||
for (const child of children) {
|
for (const child of children) {
|
||||||
const childPath = getSelectorPath(child);
|
const childPath = getSelectorPath(child);
|
||||||
if (childPath) {
|
if (childPath) {
|
||||||
selectors.push(childPath); // Add direct child path
|
selectors.push(childPath);
|
||||||
selectors = selectors.concat(getAllDescendantSelectors(child)); // Recursively process descendants
|
// Recursively process regular DOM descendants
|
||||||
|
selectors = selectors.concat(getAllDescendantSelectors(child));
|
||||||
|
|
||||||
|
// Check for iframes in this child
|
||||||
|
const iframeChildren = getIframeChildren(child);
|
||||||
|
for (const iframeChild of iframeChildren) {
|
||||||
|
try {
|
||||||
|
const iframePath = getSelectorPath(iframeChild);
|
||||||
|
if (iframePath) {
|
||||||
|
selectors.push(iframePath);
|
||||||
|
// Recursively process iframe descendants
|
||||||
|
selectors = selectors.concat(getAllDescendantSelectors(iframeChild));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Error processing iframe child:', error);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle direct iframe children of the current element
|
||||||
|
const iframeChildren = getIframeChildren(element);
|
||||||
|
for (const iframeChild of iframeChildren) {
|
||||||
|
try {
|
||||||
|
const iframePath = getSelectorPath(iframeChild);
|
||||||
|
if (iframePath) {
|
||||||
|
selectors.push(iframePath);
|
||||||
|
selectors = selectors.concat(getAllDescendantSelectors(iframeChild));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Error processing direct iframe child:', error);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return selectors;
|
return selectors;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find all occurrences of the parent selector in the DOM
|
const selectorParts = parentSelector.split(':>>').map(part => part.trim());
|
||||||
const parentElements = Array.from(document.querySelectorAll(parentSelector)) as HTMLElement[];
|
let parentElements: HTMLElement[] = [];
|
||||||
|
|
||||||
|
// Handle iframe traversal if needed
|
||||||
|
if (selectorParts.length > 1) {
|
||||||
|
// Start with the initial iframe elements
|
||||||
|
parentElements = Array.from(document.querySelectorAll(selectorParts[0])) as HTMLElement[];
|
||||||
|
|
||||||
|
// Traverse through iframe parts
|
||||||
|
for (let i = 1; i < selectorParts.length; i++) {
|
||||||
|
const newParentElements: HTMLElement[] = [];
|
||||||
|
for (const element of parentElements) {
|
||||||
|
if (element.tagName === 'IFRAME') {
|
||||||
|
try {
|
||||||
|
const iframeDoc = (element as HTMLIFrameElement).contentDocument ||
|
||||||
|
(element as HTMLIFrameElement).contentWindow?.document;
|
||||||
|
if (iframeDoc) {
|
||||||
|
const iframeChildren = Array.from(iframeDoc.querySelectorAll(selectorParts[i])) as HTMLElement[];
|
||||||
|
newParentElements.push(...iframeChildren);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Cannot access iframe content during traversal:', error);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parentElements = newParentElements;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Regular DOM selector
|
||||||
|
parentElements = Array.from(document.querySelectorAll(parentSelector)) as HTMLElement[];
|
||||||
|
}
|
||||||
|
|
||||||
const allChildSelectors = new Set<string>(); // Use a set to ensure uniqueness
|
const allChildSelectors = new Set<string>(); // Use a set to ensure uniqueness
|
||||||
|
|
||||||
// Process each parent element and its descendants
|
// Process each parent element and its descendants
|
||||||
|
|||||||
Reference in New Issue
Block a user