feat: parent-child filtering anchor tags
This commit is contained in:
@@ -123,6 +123,7 @@ class ClientSelectorGenerator {
|
|||||||
private selectorElementCache = new Map<string, HTMLElement[]>();
|
private selectorElementCache = new Map<string, HTMLElement[]>();
|
||||||
private elementSelectorCache = new WeakMap<HTMLElement, string[]>();
|
private elementSelectorCache = new WeakMap<HTMLElement, string[]>();
|
||||||
private lastCachedDocument: Document | null = null;
|
private lastCachedDocument: Document | null = null;
|
||||||
|
private classCache = new Map<string, string[]>();
|
||||||
private spatialIndex = new Map<string, string[]>();
|
private spatialIndex = new Map<string, string[]>();
|
||||||
|
|
||||||
private performanceConfig = {
|
private performanceConfig = {
|
||||||
@@ -164,7 +165,12 @@ class ClientSelectorGenerator {
|
|||||||
return Array.from(classList)
|
return Array.from(classList)
|
||||||
.filter((cls) => {
|
.filter((cls) => {
|
||||||
// Filter out classes that look like they contain IDs or dynamic content
|
// Filter out classes that look like they contain IDs or dynamic content
|
||||||
return !cls.match(/\d{3,}|uuid|hash|id-|_\d+$/i);
|
return (
|
||||||
|
!cls.match(/\d{3,}|uuid|hash|id-|_\d+$/i) &&
|
||||||
|
!cls.startsWith("_ngcontent-") &&
|
||||||
|
!cls.startsWith("_nghost-") &&
|
||||||
|
!cls.match(/^ng-tns-c\d+-\d+$/)
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.sort()
|
.sort()
|
||||||
.join(" ");
|
.join(" ");
|
||||||
@@ -887,43 +893,70 @@ class ClientSelectorGenerator {
|
|||||||
|
|
||||||
elementsAtPoint.forEach((element) => {
|
elementsAtPoint.forEach((element) => {
|
||||||
if (element.tagName === "TD" || element.tagName === "TH") {
|
if (element.tagName === "TD" || element.tagName === "TH") {
|
||||||
// Find parent TR for table cells
|
|
||||||
const parentRow = element.closest("tr") as HTMLElement;
|
const parentRow = element.closest("tr") as HTMLElement;
|
||||||
if (parentRow && !transformedElements.includes(parentRow)) {
|
if (parentRow && !transformedElements.includes(parentRow)) {
|
||||||
transformedElements.push(parentRow);
|
transformedElements.push(parentRow);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Keep non-table-cell elements as is
|
|
||||||
if (!transformedElements.includes(element)) {
|
if (!transformedElements.includes(element)) {
|
||||||
transformedElements.push(element);
|
transformedElements.push(element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Now filter for grouped elements from the transformed list
|
|
||||||
const groupedElementsAtPoint = transformedElements.filter((element) =>
|
const groupedElementsAtPoint = transformedElements.filter((element) =>
|
||||||
this.isElementGrouped(element)
|
this.isElementGrouped(element)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (groupedElementsAtPoint.length > 0) {
|
if (groupedElementsAtPoint.length > 0) {
|
||||||
|
const hasAnchorTag = groupedElementsAtPoint.some(
|
||||||
|
(el) => el.tagName === "A"
|
||||||
|
);
|
||||||
|
|
||||||
|
let filteredElements = groupedElementsAtPoint;
|
||||||
|
|
||||||
|
if (hasAnchorTag) {
|
||||||
|
// Apply parent-child filtering when anchor tags are present
|
||||||
|
filteredElements = this.filterParentChildGroupedElements(
|
||||||
|
groupedElementsAtPoint
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Sort by DOM depth (deeper elements first for more specificity)
|
// Sort by DOM depth (deeper elements first for more specificity)
|
||||||
groupedElementsAtPoint.sort((a, b) => {
|
filteredElements.sort((a, b) => {
|
||||||
const aDepth = this.getElementDepth(a);
|
const aDepth = this.getElementDepth(a);
|
||||||
const bDepth = this.getElementDepth(b);
|
const bDepth = this.getElementDepth(b);
|
||||||
return bDepth - aDepth;
|
return bDepth - aDepth;
|
||||||
});
|
});
|
||||||
|
|
||||||
const selectedElement = groupedElementsAtPoint[0];
|
const selectedElement = filteredElements[0];
|
||||||
return selectedElement;
|
return selectedElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For other modes or when list selector exists, return regular element
|
|
||||||
return this.getDeepestElementFromPoint(x, y, iframeDoc);
|
return this.getDeepestElementFromPoint(x, y, iframeDoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private filterParentChildGroupedElements(
|
||||||
|
groupedElements: HTMLElement[]
|
||||||
|
): HTMLElement[] {
|
||||||
|
const result: HTMLElement[] = [];
|
||||||
|
|
||||||
|
for (const element of groupedElements) {
|
||||||
|
const hasGroupedChild = groupedElements.some(
|
||||||
|
(other) => other !== element && element.contains(other)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (hasGroupedChild) {
|
||||||
|
result.push(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.length > 0 ? result : groupedElements;
|
||||||
|
}
|
||||||
|
|
||||||
public getElementInformation = (
|
public getElementInformation = (
|
||||||
iframeDoc: Document,
|
iframeDoc: Document,
|
||||||
coordinates: Coordinates,
|
coordinates: Coordinates,
|
||||||
|
|||||||
Reference in New Issue
Block a user