@nodebug/browser-element-finder 1.2.0 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/index.js +45 -13
- package/index.min.js +2 -2
- package/package.json +1 -1
- package/src/element-finder.js +76 -20
package/README.md
CHANGED
|
@@ -22,11 +22,11 @@ const results = ElementFinder.findElements(null, 'seleniumbase')
|
|
|
22
22
|
|
|
23
23
|
// Count semantic element types on the screen
|
|
24
24
|
const counts = ElementFinder.getElementCounts()
|
|
25
|
-
// Returns
|
|
25
|
+
// Returns { button: { visible: 3, hidden: 0, total: 3 }, ... }
|
|
26
26
|
|
|
27
27
|
// Count one semantic type
|
|
28
28
|
const buttonCount = ElementFinder.getElementCounts('button')
|
|
29
|
-
// Returns `{ button: 3 }`
|
|
29
|
+
// Returns `{ button: { visible: 3, hidden: 0, total: 3 } }`
|
|
30
30
|
|
|
31
31
|
// Find in all frames (default)
|
|
32
32
|
const results = ElementFinder.findElements('button')
|
|
@@ -225,7 +225,7 @@ The package is ESM-only (`"type": "module"`), so CommonJS `require()` examples a
|
|
|
225
225
|
| `findElements(type, text, exact, parent)` | Find elements by type/text, returns `{ elements: [...] }` |
|
|
226
226
|
| `findElementsByType(type, parent)` | Find elements by type only, returns `{ elements: [...] }` |
|
|
227
227
|
| `findElementsByAttribute(value, exact, parent)` | Find elements by text/attribute, returns `{ elements: [...] }` |
|
|
228
|
-
| `getElementCounts(type, parent)` | Count elements by semantic type, excluding generic `element` by default
|
|
228
|
+
| `getElementCounts(type, parent)` | Count elements by semantic type and visibility, excluding generic `element` by default |
|
|
229
229
|
| `findProbableElements(type, text, exact, parent)` | Find elements with fallback to nearby elements, returns `{ elements: [...] }` |
|
|
230
230
|
| `highlight(elements, color, width)` | Highlight elements with outline |
|
|
231
231
|
| `unhighlight(elements)` | Remove highlight |
|
|
@@ -418,30 +418,30 @@ Finds elements by type only. Searches all frames by default.
|
|
|
418
418
|
|
|
419
419
|
### `getElementCounts(type, parent)`
|
|
420
420
|
|
|
421
|
-
Counts elements by semantic type on the current screen. Searches all frames (main document + iframes) by default.
|
|
421
|
+
Counts elements by semantic type and visibility on the current screen. Searches all frames (main document + iframes) by default.
|
|
422
422
|
|
|
423
423
|
| Parameter | Type | Default | Description |
|
|
424
424
|
| --------- | --------- | ------- | ------------------------------------------------------------------------------------------------------------- |
|
|
425
425
|
| `type` | `string` | `null` | Specific element type to count. If `null`/`undefined`, returns counts for all defined types except `element`. |
|
|
426
426
|
| `parent` | `Element` | `null` | Parent element to count within |
|
|
427
427
|
|
|
428
|
-
**Returns**: `Object.<string, number>` keyed by semantic element type.
|
|
428
|
+
**Returns**: `Object.<string, { visible: number, hidden: number, total: number }>` keyed by semantic element type.
|
|
429
429
|
|
|
430
430
|
```javascript
|
|
431
431
|
// Count all defined non-generic types
|
|
432
432
|
const counts = ElementFinder.getElementCounts()
|
|
433
|
-
// { button: 3, textbox: 2,
|
|
433
|
+
// { button: { visible: 3, hidden: 0, total: 3 }, textbox: { visible: 2, hidden: 0, total: 2 }, ... }
|
|
434
434
|
|
|
435
435
|
// Count one type
|
|
436
436
|
const buttons = ElementFinder.getElementCounts('button')
|
|
437
|
-
// { button: 3 }
|
|
437
|
+
// { button: { visible: 3, hidden: 0, total: 3 } }
|
|
438
438
|
|
|
439
439
|
// Count within a parent element
|
|
440
440
|
const inputs = ElementFinder.getElementCounts(
|
|
441
441
|
'textbox',
|
|
442
442
|
document.querySelector('form'),
|
|
443
443
|
)
|
|
444
|
-
// { textbox: 2 }
|
|
444
|
+
// { textbox: { visible: 2, hidden: 0, total: 2 } }
|
|
445
445
|
```
|
|
446
446
|
|
|
447
447
|
The generic `element` type is excluded from the all-types count so the result contains only semantic types such as `button`, `textbox`, `link`, and `table`.
|
package/index.js
CHANGED
|
@@ -107,6 +107,7 @@ var ElementFinder = (() => {
|
|
|
107
107
|
operatorAnd: /^\s*\band\b\s*/i
|
|
108
108
|
};
|
|
109
109
|
var MAX_RECURSION_DEPTH = 100;
|
|
110
|
+
var MAX_IDENTIFIABLE_TEXT_LENGTH = 25;
|
|
110
111
|
var TYPE_MATCHERS = /* @__PURE__ */ new Map();
|
|
111
112
|
for (const [type, expr] of Object.entries(element_definitions_default)) {
|
|
112
113
|
if (expr === "true()") {
|
|
@@ -147,6 +148,21 @@ var ElementFinder = (() => {
|
|
|
147
148
|
if (text == null) return "";
|
|
148
149
|
return String(text).replace(/\s+/g, " ").trim();
|
|
149
150
|
}
|
|
151
|
+
function shortenDescriptorText(text) {
|
|
152
|
+
if (text == null) return "";
|
|
153
|
+
const lines = String(text).split(/\r\n|\r|\n/);
|
|
154
|
+
let normalizedText = "";
|
|
155
|
+
for (let i = 0; i < lines.length; i++) {
|
|
156
|
+
normalizedText = normalizeDescriptorText(lines[i]);
|
|
157
|
+
if (normalizedText) break;
|
|
158
|
+
}
|
|
159
|
+
if (!normalizedText || normalizedText.length <= MAX_IDENTIFIABLE_TEXT_LENGTH) {
|
|
160
|
+
return normalizedText;
|
|
161
|
+
}
|
|
162
|
+
const shortened = normalizedText.slice(0, MAX_IDENTIFIABLE_TEXT_LENGTH);
|
|
163
|
+
const lastSpaceIndex = shortened.lastIndexOf(" ");
|
|
164
|
+
return lastSpaceIndex > 0 ? shortened.slice(0, lastSpaceIndex) : normalizedText;
|
|
165
|
+
}
|
|
150
166
|
function getImageFilenameWithoutExtension(src) {
|
|
151
167
|
const normalizedSrc = normalizeDescriptorText(src);
|
|
152
168
|
if (!normalizedSrc) return "";
|
|
@@ -190,11 +206,11 @@ var ElementFinder = (() => {
|
|
|
190
206
|
return { attributeName: attr, identifiableText };
|
|
191
207
|
}
|
|
192
208
|
}
|
|
193
|
-
const directText =
|
|
209
|
+
const directText = shortenDescriptorText(getDirectText(el));
|
|
194
210
|
if (directText) {
|
|
195
211
|
return { attributeName: "text", identifiableText: directText };
|
|
196
212
|
}
|
|
197
|
-
const fullText =
|
|
213
|
+
const fullText = shortenDescriptorText(el.textContent);
|
|
198
214
|
if (fullText) {
|
|
199
215
|
return { attributeName: "text", identifiableText: fullText };
|
|
200
216
|
}
|
|
@@ -546,22 +562,36 @@ var ElementFinder = (() => {
|
|
|
546
562
|
}
|
|
547
563
|
function isHidden(el) {
|
|
548
564
|
if (el == null) return true;
|
|
549
|
-
|
|
565
|
+
let parent = el;
|
|
566
|
+
while (parent) {
|
|
567
|
+
if (isElementHidden(parent)) {
|
|
568
|
+
return true;
|
|
569
|
+
}
|
|
570
|
+
parent = parent.parentElement;
|
|
571
|
+
}
|
|
572
|
+
return false;
|
|
573
|
+
}
|
|
574
|
+
function isElementHidden(el) {
|
|
575
|
+
if (el.hasAttribute("hidden") || el.getAttribute("aria-hidden") === "true" || el.inert || el.offsetWidth === 0 && el.offsetHeight === 0) {
|
|
550
576
|
return true;
|
|
551
577
|
}
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
578
|
+
if (typeof el.checkVisibility === "function") {
|
|
579
|
+
if (!el.checkVisibility({
|
|
580
|
+
checkOpacity: true,
|
|
581
|
+
checkVisibilityCSS: true,
|
|
582
|
+
contentVisibilityAuto: true
|
|
583
|
+
})) {
|
|
555
584
|
return true;
|
|
556
585
|
}
|
|
557
|
-
|
|
586
|
+
return false;
|
|
587
|
+
}
|
|
588
|
+
try {
|
|
589
|
+
const style = window.getComputedStyle(el);
|
|
590
|
+
if (style.visibility === "hidden" || style.visibility === "collapse" || style.display === "none" || style.opacity === "0") {
|
|
558
591
|
return true;
|
|
559
592
|
}
|
|
560
593
|
} catch (e) {
|
|
561
594
|
}
|
|
562
|
-
if (el.hasAttribute("hidden")) {
|
|
563
|
-
return true;
|
|
564
|
-
}
|
|
565
595
|
return false;
|
|
566
596
|
}
|
|
567
597
|
function findElementsByType(type = "element", parent = null, options = null) {
|
|
@@ -726,13 +756,13 @@ var ElementFinder = (() => {
|
|
|
726
756
|
throw new TypeError(`Unknown element type: ${type}`);
|
|
727
757
|
}
|
|
728
758
|
console.warn(message);
|
|
729
|
-
return { [type]: 0 };
|
|
759
|
+
return { [type]: { visible: 0, hidden: 0, total: 0 } };
|
|
730
760
|
}
|
|
731
761
|
}
|
|
732
762
|
const counts = {};
|
|
733
763
|
const targetTypes = hasType ? [type] : Object.keys(ELEMENT_DEFINITIONS).filter((item) => item !== "element");
|
|
734
764
|
for (let i = 0; i < targetTypes.length; i++) {
|
|
735
|
-
counts[targetTypes[i]] = 0;
|
|
765
|
+
counts[targetTypes[i]] = { visible: 0, hidden: 0, total: 0 };
|
|
736
766
|
}
|
|
737
767
|
const frames = getAllFrames(window);
|
|
738
768
|
for (let i = 0; i < frames.length; i++) {
|
|
@@ -743,7 +773,9 @@ var ElementFinder = (() => {
|
|
|
743
773
|
for (let k = 0; k < targetTypes.length; k++) {
|
|
744
774
|
const targetType = targetTypes[k];
|
|
745
775
|
if (matchesType(el, targetType)) {
|
|
746
|
-
|
|
776
|
+
const bucket = isHidden(el) ? "hidden" : "visible";
|
|
777
|
+
counts[targetType][bucket] += 1;
|
|
778
|
+
counts[targetType].total += 1;
|
|
747
779
|
}
|
|
748
780
|
}
|
|
749
781
|
}
|
package/index.min.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var ElementFinder=(()=>{var P=Object.defineProperty;var W=Object.getOwnPropertyDescriptor;var Y=Object.getOwnPropertyNames;var X=Object.prototype.hasOwnProperty;var Z=(e,t)=>{for(var n in t)P(e,n,{get:t[n],enumerable:!0})},Q=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Y(t))!X.call(e,r)&&r!==n&&P(e,r,{get:()=>t[r],enumerable:!(o=W(t,r))||o.enumerable});return e};var G=e=>Q(P({},"__esModule",{value:!0}),e);var we={};Z(we,{ELEMENT_DEFINITIONS:()=>p,findElements:()=>ce,findElementsByAttribute:()=>V,findElementsByType:()=>F,findProbableElements:()=>me,getAllElements:()=>y,getAllFrames:()=>x,getBoundingBox:()=>A,getElementCounts:()=>fe,getElementDescriptor:()=>le,getSearchableAttributeValues:()=>j,getSearchableAttributes:()=>te,getValidAttributes:()=>be,getValidTypes:()=>ye,highlight:()=>de,isHidden:()=>k,matchesAttribute:()=>S,matchesType:()=>g,parseCondition:()=>H,parseXPath:()=>w,pauseAnimations:()=>ge,resumeAnimations:()=>pe,setSearchableAttributes:()=>ee,splitByOperator:()=>B,unhighlight:()=>he});var D={link:"self::a or @role='link' or @href",navigation:"@role='navigation' or self::nav",heading:"@role='heading' or self::h1 or self::h2 or self::h3 or self::h4 or self::h5 or self::h6",button:"self::button or @role='button' or @type='button' or @type='submit'",checkbox:"(self::input and @type='checkbox') or @role='checkbox'",switch:"(self::input and @type='checkbox') or @role='switch' or (self::button and (contains(@class, 'switch') or @data-state))",slider:"self::input[@type='range'] or @role='slider'",datepicker:"self::input[@type='date'] or @role='date'",colorpicker:"self::input[@type='color'] or @role='color'",radio:"(self::input and @type='radio') or @role='radio'",dropdown:"(self::select[descendant::option] or @role='combobox' or @role='listbox' or contains(@class, 'dropdown') or contains(@class, 'trigger') or ancestor::*[contains(@class, 'dropdown') or @role='combobox'])",textbox:"self::textarea or (self::input and (@type='text' or @type='password' or @type='search' or @type='email' or @type='number' or @type='tel' or @type='url')) or @role='textbox'",file:"self::input and @type='file'",list:"self::ul or self::ol or @role='list'",listitem:"self::li or @role='listitem'",menu:"self::menu or @role='menu'",menuitem:"@role='menuitem'",toolbar:"@role='toolbar'",dialog:"@role='dialog' or @role='alertdialog'",table:"self::table or @role='table'",row:"self::tr or @role='row'",column:"self::td or self::th or @role='cell' or @role='gridcell' or @role='columnheader'",cell:"self::td or @role='cell' or @role='gridcell'",image:"self::img or @role='img' or @alt",element:"true()"};var R=["placeholder","value","data-value","data-test-id","data-testid","id","resource-id","name","aria-label","hint","title","tooltip","alt","src","aria-labelledby"];var b={selfWithTag:/^self::([a-zA-Z0-9-]+)(?:\[([^\]]+)\])?$/,contains:/contains\(@([a-zA-Z0-9-]+),\s*['"]([^'"]+)['"]\)/i,attrEquals:/@([a-zA-Z0-9-]+)\s*=\s*['"]([^'"]*)['"]/,attrExists:/^@([a-zA-Z0-9-]+)$/,descendant:/descendant::([a-zA-Z0-9-]+)/i,ancestor:/ancestor::\*\[([^\]]+)\]/i,operatorOr:/^\s*\bor\b\s*/i,operatorAnd:/^\s*\band\b\s*/i},v=100,C=new Map;for(let[e,t]of Object.entries(D))t==="true()"?C.set(e,()=>!0):C.set(e,n=>w(t,n));var E=R;function ee(e){if(!Array.isArray(e))throw new TypeError("attributes must be an array");E=e}function te(){return[...E]}function j(e){if(e==null||e.nodeType!==Node.ELEMENT_NODE)return{};let t={},n=E;for(let o=0;o<n.length;o++){let r=n[o],i;try{i=e.getAttribute(r)}catch(l){continue}i!=null&&i!==""&&(t[r]=i)}return t}function T(e){return e==null?"":String(e).replace(/\s+/g," ").trim()}function ne(e){let t=T(e);if(!t)return"";let n=t.split(/[?#]/)[0],o=Math.max(n.lastIndexOf("/"),n.lastIndexOf("\\")),r=o>=0?n.slice(o+1):n,i=r.lastIndexOf(".");return i>0?r.slice(0,i):r}function re(e){let t=e.getAttribute("aria-labelledby");if(!t)return"";let n=t.split(/\s+/),o=e.ownerDocument||document,r="";for(let i of n)try{let l=o.getElementById(i);if(!l)continue;let s=T(l.textContent);s&&(r=r?`${r} ${s}`:s)}catch(l){}return r}function q(e){let t=j(e),n=E;for(let i=0;i<n.length;i++){let l=n[i];if(!Object.prototype.hasOwnProperty.call(t,l))continue;let s=l==="aria-labelledby"?re(e):l==="src"?ne(t[l]):t[l],a=T(s);if(a)return{attributeName:l,identifiableText:a}}let o=T(L(e));if(o)return{attributeName:"text",identifiableText:o};let r=T(e.textContent);return r?{attributeName:"text",identifiableText:r}:null}function oe(e){if(!e||!e.ownerDocument)return null;try{let t=x(window);for(let n=0;n<t.length;n++)if(t[n].document===e.ownerDocument)return t[n].document}catch(t){}return e.ownerDocument}function ie(e,t){let n=oe(e);if(!n)return{index:1};let o=y(n),r=1,i=0;for(let l=0;l<o.length;l++){let s=o[l];if(s!==e&&(s===n.documentElement||s.tagName==="BODY"))continue;let a=q(s);!a||a.identifiableText!==t||(i++,s===e&&(r=i))}return{index:r}}function se(e){if(e==null||e.nodeType!==Node.ELEMENT_NODE)return null;let t=Object.keys(p);for(let n=0;n<t.length;n++){let o=t[n];if(o!=="element"&&g(e,o))return o}return"element"}function le(e){if(e==null||e.nodeType!==Node.ELEMENT_NODE)return{identifiableText:null,attributeName:null,index:1,type:null,tagName:null};let t=se(e),n=q(e);if(!n)return{identifiableText:null,attributeName:null,index:1,type:t,tagName:e.tagName.toLowerCase()};let o=ie(e,n.identifiableText);return{identifiableText:n.identifiableText,attributeName:n.attributeName,index:o.index,type:t,tagName:e.tagName.toLowerCase()}}function w(e,t,n=0){if(e==null||t==null)return!1;if(n>v)throw new Error("XPath expression exceeds maximum recursion depth");if(e=e.trim(),e==="true()")return!0;if(e[0]==="("&&e[e.length-1]===")"){let i=1,l=!0;for(let s=1;s<e.length-1;s++)if(e[s]==="("?i++:e[s]===")"&&i--,i===0){l=!1;break}if(l)return w(e.slice(1,-1),t,n+1)}let o=B(e,"or");if(o.length>1){for(let i of o)if(w(i,t,n+1))return!0;return!1}let r=B(e,"and");if(r.length>1){for(let i of r)if(!w(i,t,n+1))return!1;return!0}return H(e,t,n)}function B(e,t){let n=[],o=0,r="",i=!1,l="",s=t==="or"?b.operatorOr:b.operatorAnd;for(let a=0;a<e.length;a++){let f=e[a];if((f==="'"||f==='"')&&(a===0||e[a-1]!=="\\")&&(i?f===l&&(i=!1):(i=!0,l=f)),!i&&(f==="("?o++:f===")"&&o--,o===0)){let c=e.slice(a).match(s);if(c){n.push(r.trim()),a+=c[0].length-1,r="";continue}}r+=f}return r.trim()&&n.push(r.trim()),n}function H(e,t,n=0){if(e==null||t==null)return!1;e=e.trim();let o=e.match(b.selfWithTag);if(o){let f=o[1].toUpperCase();return t.tagName!==f?!1:o[2]?w(o[2],t,n+1):!0}let r=e.match(b.contains);if(r)return(t.getAttribute(r[1])||"").toLowerCase().includes(r[2].toLowerCase());let i=e.match(b.attrEquals);if(i)return t.getAttribute(i[1])===i[2];let l=e.match(b.attrExists);if(l)return t.hasAttribute(l[1]);let s=e.match(b.descendant);if(s)return t.querySelector(s[1])!==null;let a=e.match(b.ancestor);if(a){let f=t.parentElement;for(;f;){if(w(a[1],f,n+1))return!0;f=f.parentElement}return!1}return!1}var p=Object.freeze(D);function L(e){let t="";for(let n=0;n<e.childNodes.length;n++){let o=e.childNodes[n];o.nodeType===Node.TEXT_NODE&&(t+=o.textContent)}return t.trim()}function ae(e){if(e.tagName==="STYLE"||e.tagName==="SCRIPT"||e.querySelector("STYLE, SCRIPT"))return!0;let t=e.parentElement;for(;t;){if(t.tagName==="STYLE"||t.tagName==="SCRIPT")return!0;t=t.parentElement}return!1}function _(e){let t=e.getAttribute("aria-labelledby");if(!t)return"";let n=t.split(/\s+/),o="";for(let r of n)try{let i=document.getElementById(r);i&&(o+=i.textContent)}catch(i){}return o}function S(e,t,n=!1){if(e==null)return!1;if(t==null||t==="")return!0;if(ae(e))return!1;let o=E;for(let l=0;l<o.length;l++){let s=o[l],a;try{a=e.getAttribute(s)}catch(f){continue}if(a){if(s==="aria-labelledby"){if(n?a===t:a.includes(t))return!0;let f=_(e);if(f&&(n?f===t:f.includes(t)))return!0}else if(n?a===t:a.includes(t))return!0}}let r=L(e);if(n?r===t:r.includes(t))return!0;let i=e.textContent;return!!(n?i.trim()===t:i.includes(t))}function g(e,t){if(e==null)return!1;let n=C.get(t);return n?n(e):!1}function y(e=document){let t=[];if(e==null)return t;let n=e.nodeType===Node.DOCUMENT_NODE?e.documentElement:e;if(!n)return t;let o=[n];for(;o.length>0;){let r=o.pop();if(r.nodeType!==Node.ELEMENT_NODE||r.tagName==="SCRIPT"||r.tagName==="STYLE")continue;t.push(r);let i=r.children;for(let l=i.length-1;l>=0;l--)o.push(i[l]);try{if(r.shadowRoot){let l=r.shadowRoot.children;for(let s=l.length-1;s>=0;s--)o.push(l[s])}}catch(l){}}return t}function x(e=window){let t=[];try{t.push({window:e,document:e.document,isMainFrame:!0,frameIndex:-1});let n=e.document.querySelectorAll("iframe");for(let o=0;o<n.length;o++){let r=n[o];try{r.contentWindow&&r.contentDocument&&t.push({window:r.contentWindow,document:r.contentDocument,isMainFrame:!1,frameElement:r,frameIndex:o})}catch(i){i.name==="SecurityError"?console.warn("Skipping cross-origin iframe:",i.message):console.warn("Error accessing iframe:",i.message)}}}catch(n){console.warn("Error getting frames:",n.message)}return t}function A(e){let t=e.getBoundingClientRect();return{x:t.x,y:t.y,width:t.width,height:t.height,top:t.top,bottom:t.bottom,left:t.left,right:t.right,midx:t.x+t.width/2,midy:t.y+t.height/2,tagName:e.tagName.toLowerCase()}}function k(e){if(e==null||e.offsetWidth===0&&e.offsetHeight===0)return!0;try{let t=window.getComputedStyle(e);if(t.visibility==="hidden"||t.visibility==="collapse"||t.display==="none")return!0}catch(t){}return!!e.hasAttribute("hidden")}function F(e="element",t=null,n=null){if(e==null&&(e="element"),typeof e!="string")throw new TypeError(`type must be a string, got ${typeof e}`);let o=n&&n.failOnUnknownType===!0;if(e&&!p[e]){let a=`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`;if(o)throw new TypeError(`Unknown element type: ${e}`);return console.warn(a),{elements:[]}}let r=[],i=x(window);for(let a of i){let f=y(t||a.document);for(let u=0;u<f.length;u++){let c=f[u];e&&!g(c,e)||r.push({element:c,frame:a})}}let l=[];if(r.length>0){let a=new Set(r.map(u=>u.element)),f=new Set;for(let u=r.length-1;u>=0;u--){let c=r[u],m=c.element;if(!f.has(m)){l.unshift(c);let d=m.parentElement;for(;d;)a.has(d)&&f.add(d),d=d.parentElement}}}return{elements:l.map(a=>{let f=A(a.element),u=a.element.tagName.toLowerCase(),c=k(a.element);return a.frame.isMainFrame?{element:a.element,boundingBox:f,tagName:u,frameIndex:a.frame.frameIndex,isHidden:c}:{boundingBox:f,tagName:u,frameIndex:a.frame.frameIndex,isHidden:c}})}}function V(e,t=!1,n=null){if(e==null&&(e=""),typeof e!="string")throw new TypeError(`value must be a string, got ${typeof e}`);let o=[],r=x(window);for(let s of r){let a=y(n||s.document);for(let f=0;f<a.length;f++){let u=a[f];S(u,e,t)&&o.push({element:u,frame:s})}}return{elements:o.filter(s=>{let a=s.element;if(I(a,e,t))return!0;for(let u of o)if(u.element!==a&&a.contains(u.element))return!1;return!0}).map(s=>{let a=A(s.element),f=s.element.tagName.toLowerCase(),u=k(s.element);return s.frame.isMainFrame?{element:s.element,boundingBox:a,tagName:f,frameIndex:s.frame.frameIndex,isHidden:u}:{boundingBox:a,tagName:f,frameIndex:s.frame.frameIndex,isHidden:u}})}}function I(e,t,n=!1){if(t==null||t==="")return!0;let o=E;for(let i=0;i<o.length;i++){let l=o[i],s;try{s=e.getAttribute(l)}catch(a){continue}if(s){if(l==="aria-labelledby"){if(n?s===t:s.includes(t))return!0;let a=_(e);if(a&&(n?a===t:a.includes(t)))return!0}else if(n?s===t:s.includes(t))return!0}}let r=L(e);return!!(n?r===t:r.includes(t))}function fe(e=null,t=null,n=null){let o=e!=null;if(o){if(typeof e!="string")throw new TypeError(`type must be a string, got ${typeof e}`);if(!p[e]){let s=`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`;if(n&&n.failOnUnknownType===!0)throw new TypeError(`Unknown element type: ${e}`);return console.warn(s),{[e]:0}}}let r={},i=o?[e]:Object.keys(p).filter(s=>s!=="element");for(let s=0;s<i.length;s++)r[i[s]]=0;let l=x(window);for(let s=0;s<l.length;s++){let a=l[s],f=y(t||a.document);for(let u=0;u<f.length;u++){let c=f[u];for(let m=0;m<i.length;m++){let d=i[m];g(c,d)&&(r[d]+=1)}}}return r}function ce(e=null,t=null,n=!1,o=null,r=null){if(t==null&&(t=""),e!=null){if(typeof e!="string")throw new TypeError(`type must be a string, got ${typeof e}`);if(!p[e]){let f=`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`;if(r&&r.failOnUnknownType===!0)throw new TypeError(`Unknown element type: ${e}`);return console.warn(f),{elements:[]}}}if(t!==""&&typeof t!="string")throw new TypeError(`text must be a string, got ${typeof t}`);let i=[],l=x(window);for(let f of l){let u=y(o||f.document);for(let c=0;c<u.length;c++){let m=u[c];e!=null&&!g(m,e)||t!==""&&!S(m,t,n)||i.push({element:m,frame:f})}}return{elements:(t!==""?i.filter(f=>{let u=f.element;if(I(u,t,n))return!0;for(let m of i)if(m.element!==u&&u.contains(m.element))return!1;return!0}):i).map(f=>{let u=A(f.element),c=f.element.tagName.toLowerCase(),m=k(f.element);return f.frame.isMainFrame?{element:f.element,boundingBox:u,tagName:c,frameIndex:f.frame.frameIndex,isHidden:m}:{boundingBox:u,tagName:c,frameIndex:f.frame.frameIndex,isHidden:m}})}}function $(e){if(e.parentElement)return e.parentElement;try{let t=e.getRootNode();if(t&&t.host)return t.host}catch(t){}return null}function U(e){let t=$(e);if(!t)return[];if(t.shadowRoot)try{return Array.from(t.shadowRoot.children)}catch(n){return[]}return Array.from(t.children)}function ue(e,t){let n=$(e);for(;n;){if(g(n,t))return n;n=$(n)}let o=e.children||[];for(let l of o)if(g(l,t))return l;let r=U(e);for(let l of r)if(l!==e&&g(l,t))return l;for(let l of r){if(l===e)continue;let s=y(l);for(let a=0;a<s.length;a++)if(g(s[a],t))return s[a]}let i=e.parentElement;for(;i;){let l=U(i);for(let s of l)if(s!==i){if(g(s,t))return s;let a=y(s);for(let f=0;f<a.length;f++)if(g(a[f],t))return a[f]}i=i.parentElement}return null}function me(e,t,n=!1,o=null,r=null){let i=e!=null&&e!=="",l=t!=null&&t!=="";if(i&&!l)return F(e,o,r);if(!i&&l)return V(t,n,o);if(i){if(typeof e!="string")throw new TypeError(`elementType must be a string, got ${typeof e}`);if(!p[e]){let c=`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`;if(r&&r.failOnUnknownType===!0)throw new TypeError(`Unknown element type: ${e}`);return console.warn(c),{elements:[]}}}if(l&&typeof t!="string")throw new TypeError(`attributeText must be a string, got ${typeof t}`);let s=[],a=x(window);for(let c of a){let m=y(o||c.document);for(let d=0;d<m.length;d++){let h=m[d];i&&!g(h,e)||l&&!S(h,t,n)||s.push({element:h,frame:c})}}if(s.length===0&&i&&l){let c=[];for(let d of a){let h=y(o||d.document);for(let M=0;M<h.length;M++){let O=h[M];S(O,t,n)&&I(O,t,n)&&c.push({element:O,frame:d})}}let m=new Set;for(let d of c){let h=ue(d.element,e);h&&!m.has(h)&&(m.add(h),s.push({element:h,frame:d.frame}))}}return{elements:(l?s.filter(c=>{let m=c.element;if(I(m,t,n))return!0;for(let h of s)if(h.element!==m&&m.contains(h.element))return!1;return!0}):s).map(c=>{let m=A(c.element),d=c.element.tagName.toLowerCase(),h=k(c.element);return c.frame.isMainFrame?{element:c.element,boundingBox:m,tagName:d,frameIndex:c.frame.frameIndex,isHidden:h}:{boundingBox:m,tagName:d,frameIndex:c.frame.frameIndex,isHidden:h}})}}function z(e){return e?e&&e.elements&&Array.isArray(e.elements)?e.elements:Array.isArray(e)?e:[e]:[]}function de(e,t="red",n=3){let o=z(e);for(let r=0;r<o.length;r++){let i=o[r],l=i.element?i.element:i;l&&l.style&&(l.style.outline=`${n}px solid ${t}`,l.style.outlineOffset="2px",l.style.boxShadow="0 0 0 2px rgba(255, 255, 255, 0.8)",l.classList.add("elementfinder-highlighted"))}}function he(e){let t=z(e);for(let n=0;n<t.length;n++){let o=t[n],r=o.element?o.element:o;r&&r.style&&(r.style.outline="",r.style.outlineOffset="",r.style.boxShadow="",r.classList.remove("elementfinder-highlighted"))}}var N=[];function ge(){let e=new Map,t=y();for(let r of t)r&&r.style&&r.style.animationPlayState!=="paused"&&(e.set(r,{animationPlayState:r.style.animationPlayState,transitionProperty:r.style.transitionProperty,webkitAnimationPlayState:r.style.webkitAnimationPlayState,webkitTransitionProperty:r.style.webkitTransitionProperty}),r.style.animationPlayState="paused",r.style.transitionProperty="none",r.style.webkitAnimationPlayState="paused",r.style.webkitTransitionProperty="none");let n=document.getElementById("elementfinder-animation-pause");n||(n=document.createElement("style"),n.id="elementfinder-animation-pause",n.textContent=`
|
|
1
|
+
var ElementFinder=(()=>{var D=Object.defineProperty;var Y=Object.getOwnPropertyDescriptor;var Z=Object.getOwnPropertyNames;var G=Object.prototype.hasOwnProperty;var Q=(e,t)=>{for(var n in t)D(e,n,{get:t[n],enumerable:!0})},J=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Z(t))!G.call(e,r)&&r!==n&&D(e,r,{get:()=>t[r],enumerable:!(o=Y(t,r))||o.enumerable});return e};var K=e=>J(D({},"__esModule",{value:!0}),e);var Te={};Q(Te,{ELEMENT_DEFINITIONS:()=>p,findElements:()=>me,findElementsByAttribute:()=>W,findElementsByType:()=>z,findProbableElements:()=>ge,getAllElements:()=>y,getAllFrames:()=>x,getBoundingBox:()=>A,getElementCounts:()=>de,getElementDescriptor:()=>fe,getSearchableAttributeValues:()=>H,getSearchableAttributes:()=>re,getValidAttributes:()=>xe,getValidTypes:()=>Ee,highlight:()=>pe,isHidden:()=>N,matchesAttribute:()=>S,matchesType:()=>g,parseCondition:()=>V,parseXPath:()=>w,pauseAnimations:()=>be,resumeAnimations:()=>we,setSearchableAttributes:()=>ne,splitByOperator:()=>B,unhighlight:()=>ye});var P={link:"self::a or @role='link' or @href",navigation:"@role='navigation' or self::nav",heading:"@role='heading' or self::h1 or self::h2 or self::h3 or self::h4 or self::h5 or self::h6",button:"self::button or @role='button' or @type='button' or @type='submit'",checkbox:"(self::input and @type='checkbox') or @role='checkbox'",switch:"(self::input and @type='checkbox') or @role='switch' or (self::button and (contains(@class, 'switch') or @data-state))",slider:"self::input[@type='range'] or @role='slider'",datepicker:"self::input[@type='date'] or @role='date'",colorpicker:"self::input[@type='color'] or @role='color'",radio:"(self::input and @type='radio') or @role='radio'",dropdown:"(self::select[descendant::option] or @role='combobox' or @role='listbox' or contains(@class, 'dropdown') or contains(@class, 'trigger') or ancestor::*[contains(@class, 'dropdown') or @role='combobox'])",textbox:"self::textarea or (self::input and (@type='text' or @type='password' or @type='search' or @type='email' or @type='number' or @type='tel' or @type='url')) or @role='textbox'",file:"self::input and @type='file'",list:"self::ul or self::ol or @role='list'",listitem:"self::li or @role='listitem'",menu:"self::menu or @role='menu'",menuitem:"@role='menuitem'",toolbar:"@role='toolbar'",dialog:"@role='dialog' or @role='alertdialog'",table:"self::table or @role='table'",row:"self::tr or @role='row'",column:"self::td or self::th or @role='cell' or @role='gridcell' or @role='columnheader'",cell:"self::td or @role='cell' or @role='gridcell'",image:"self::img or @role='img' or @alt",element:"true()"};var R=["placeholder","value","data-value","data-test-id","data-testid","id","resource-id","name","aria-label","hint","title","tooltip","alt","src","aria-labelledby"];var b={selfWithTag:/^self::([a-zA-Z0-9-]+)(?:\[([^\]]+)\])?$/,contains:/contains\(@([a-zA-Z0-9-]+),\s*['"]([^'"]+)['"]\)/i,attrEquals:/@([a-zA-Z0-9-]+)\s*=\s*['"]([^'"]*)['"]/,attrExists:/^@([a-zA-Z0-9-]+)$/,descendant:/descendant::([a-zA-Z0-9-]+)/i,ancestor:/ancestor::\*\[([^\]]+)\]/i,operatorOr:/^\s*\bor\b\s*/i,operatorAnd:/^\s*\band\b\s*/i},te=100,U=25,C=new Map;for(let[e,t]of Object.entries(P))t==="true()"?C.set(e,()=>!0):C.set(e,n=>w(t,n));var E=R;function ne(e){if(!Array.isArray(e))throw new TypeError("attributes must be an array");E=e}function re(){return[...E]}function H(e){if(e==null||e.nodeType!==Node.ELEMENT_NODE)return{};let t={},n=E;for(let o=0;o<n.length;o++){let r=n[o],i;try{i=e.getAttribute(r)}catch(l){continue}i!=null&&i!==""&&(t[r]=i)}return t}function I(e){return e==null?"":String(e).replace(/\s+/g," ").trim()}function j(e){if(e==null)return"";let t=String(e).split(/\r\n|\r|\n/),n="";for(let i=0;i<t.length&&(n=I(t[i]),!n);i++);if(!n||n.length<=U)return n;let o=n.slice(0,U),r=o.lastIndexOf(" ");return r>0?o.slice(0,r):n}function oe(e){let t=I(e);if(!t)return"";let n=t.split(/[?#]/)[0],o=Math.max(n.lastIndexOf("/"),n.lastIndexOf("\\")),r=o>=0?n.slice(o+1):n,i=r.lastIndexOf(".");return i>0?r.slice(0,i):r}function ie(e){let t=e.getAttribute("aria-labelledby");if(!t)return"";let n=t.split(/\s+/),o=e.ownerDocument||document,r="";for(let i of n)try{let l=o.getElementById(i);if(!l)continue;let s=I(l.textContent);s&&(r=r?`${r} ${s}`:s)}catch(l){}return r}function _(e){let t=H(e),n=E;for(let i=0;i<n.length;i++){let l=n[i];if(!Object.prototype.hasOwnProperty.call(t,l))continue;let s=l==="aria-labelledby"?ie(e):l==="src"?oe(t[l]):t[l],a=I(s);if(a)return{attributeName:l,identifiableText:a}}let o=j($(e));if(o)return{attributeName:"text",identifiableText:o};let r=j(e.textContent);return r?{attributeName:"text",identifiableText:r}:null}function se(e){if(!e||!e.ownerDocument)return null;try{let t=x(window);for(let n=0;n<t.length;n++)if(t[n].document===e.ownerDocument)return t[n].document}catch(t){}return e.ownerDocument}function le(e,t){let n=se(e);if(!n)return{index:1};let o=y(n),r=1,i=0;for(let l=0;l<o.length;l++){let s=o[l];if(s!==e&&(s===n.documentElement||s.tagName==="BODY"))continue;let a=_(s);!a||a.identifiableText!==t||(i++,s===e&&(r=i))}return{index:r}}function ae(e){if(e==null||e.nodeType!==Node.ELEMENT_NODE)return null;let t=Object.keys(p);for(let n=0;n<t.length;n++){let o=t[n];if(o!=="element"&&g(e,o))return o}return"element"}function fe(e){if(e==null||e.nodeType!==Node.ELEMENT_NODE)return{identifiableText:null,attributeName:null,index:1,type:null,tagName:null};let t=ae(e),n=_(e);if(!n)return{identifiableText:null,attributeName:null,index:1,type:t,tagName:e.tagName.toLowerCase()};let o=le(e,n.identifiableText);return{identifiableText:n.identifiableText,attributeName:n.attributeName,index:o.index,type:t,tagName:e.tagName.toLowerCase()}}function w(e,t,n=0){if(e==null||t==null)return!1;if(n>te)throw new Error("XPath expression exceeds maximum recursion depth");if(e=e.trim(),e==="true()")return!0;if(e[0]==="("&&e[e.length-1]===")"){let i=1,l=!0;for(let s=1;s<e.length-1;s++)if(e[s]==="("?i++:e[s]===")"&&i--,i===0){l=!1;break}if(l)return w(e.slice(1,-1),t,n+1)}let o=B(e,"or");if(o.length>1){for(let i of o)if(w(i,t,n+1))return!0;return!1}let r=B(e,"and");if(r.length>1){for(let i of r)if(!w(i,t,n+1))return!1;return!0}return V(e,t,n)}function B(e,t){let n=[],o=0,r="",i=!1,l="",s=t==="or"?b.operatorOr:b.operatorAnd;for(let a=0;a<e.length;a++){let f=e[a];if((f==="'"||f==='"')&&(a===0||e[a-1]!=="\\")&&(i?f===l&&(i=!1):(i=!0,l=f)),!i&&(f==="("?o++:f===")"&&o--,o===0)){let c=e.slice(a).match(s);if(c){n.push(r.trim()),a+=c[0].length-1,r="";continue}}r+=f}return r.trim()&&n.push(r.trim()),n}function V(e,t,n=0){if(e==null||t==null)return!1;e=e.trim();let o=e.match(b.selfWithTag);if(o){let f=o[1].toUpperCase();return t.tagName!==f?!1:o[2]?w(o[2],t,n+1):!0}let r=e.match(b.contains);if(r)return(t.getAttribute(r[1])||"").toLowerCase().includes(r[2].toLowerCase());let i=e.match(b.attrEquals);if(i)return t.getAttribute(i[1])===i[2];let l=e.match(b.attrExists);if(l)return t.hasAttribute(l[1]);let s=e.match(b.descendant);if(s)return t.querySelector(s[1])!==null;let a=e.match(b.ancestor);if(a){let f=t.parentElement;for(;f;){if(w(a[1],f,n+1))return!0;f=f.parentElement}return!1}return!1}var p=Object.freeze(P);function $(e){let t="";for(let n=0;n<e.childNodes.length;n++){let o=e.childNodes[n];o.nodeType===Node.TEXT_NODE&&(t+=o.textContent)}return t.trim()}function ce(e){if(e.tagName==="STYLE"||e.tagName==="SCRIPT"||e.querySelector("STYLE, SCRIPT"))return!0;let t=e.parentElement;for(;t;){if(t.tagName==="STYLE"||t.tagName==="SCRIPT")return!0;t=t.parentElement}return!1}function F(e){let t=e.getAttribute("aria-labelledby");if(!t)return"";let n=t.split(/\s+/),o="";for(let r of n)try{let i=document.getElementById(r);i&&(o+=i.textContent)}catch(i){}return o}function S(e,t,n=!1){if(e==null)return!1;if(t==null||t==="")return!0;if(ce(e))return!1;let o=E;for(let l=0;l<o.length;l++){let s=o[l],a;try{a=e.getAttribute(s)}catch(f){continue}if(a){if(s==="aria-labelledby"){if(n?a===t:a.includes(t))return!0;let f=F(e);if(f&&(n?f===t:f.includes(t)))return!0}else if(n?a===t:a.includes(t))return!0}}let r=$(e);if(n?r===t:r.includes(t))return!0;let i=e.textContent;return!!(n?i.trim()===t:i.includes(t))}function g(e,t){if(e==null)return!1;let n=C.get(t);return n?n(e):!1}function y(e=document){let t=[];if(e==null)return t;let n=e.nodeType===Node.DOCUMENT_NODE?e.documentElement:e;if(!n)return t;let o=[n];for(;o.length>0;){let r=o.pop();if(r.nodeType!==Node.ELEMENT_NODE||r.tagName==="SCRIPT"||r.tagName==="STYLE")continue;t.push(r);let i=r.children;for(let l=i.length-1;l>=0;l--)o.push(i[l]);try{if(r.shadowRoot){let l=r.shadowRoot.children;for(let s=l.length-1;s>=0;s--)o.push(l[s])}}catch(l){}}return t}function x(e=window){let t=[];try{t.push({window:e,document:e.document,isMainFrame:!0,frameIndex:-1});let n=e.document.querySelectorAll("iframe");for(let o=0;o<n.length;o++){let r=n[o];try{r.contentWindow&&r.contentDocument&&t.push({window:r.contentWindow,document:r.contentDocument,isMainFrame:!1,frameElement:r,frameIndex:o})}catch(i){i.name==="SecurityError"?console.warn("Skipping cross-origin iframe:",i.message):console.warn("Error accessing iframe:",i.message)}}}catch(n){console.warn("Error getting frames:",n.message)}return t}function A(e){let t=e.getBoundingClientRect();return{x:t.x,y:t.y,width:t.width,height:t.height,top:t.top,bottom:t.bottom,left:t.left,right:t.right,midx:t.x+t.width/2,midy:t.y+t.height/2,tagName:e.tagName.toLowerCase()}}function N(e){if(e==null)return!0;let t=e;for(;t;){if(ue(t))return!0;t=t.parentElement}return!1}function ue(e){if(e.hasAttribute("hidden")||e.getAttribute("aria-hidden")==="true"||e.inert||e.offsetWidth===0&&e.offsetHeight===0)return!0;if(typeof e.checkVisibility=="function")return!e.checkVisibility({checkOpacity:!0,checkVisibilityCSS:!0,contentVisibilityAuto:!0});try{let t=window.getComputedStyle(e);if(t.visibility==="hidden"||t.visibility==="collapse"||t.display==="none"||t.opacity==="0")return!0}catch(t){}return!1}function z(e="element",t=null,n=null){if(e==null&&(e="element"),typeof e!="string")throw new TypeError(`type must be a string, got ${typeof e}`);let o=n&&n.failOnUnknownType===!0;if(e&&!p[e]){let a=`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`;if(o)throw new TypeError(`Unknown element type: ${e}`);return console.warn(a),{elements:[]}}let r=[],i=x(window);for(let a of i){let f=y(t||a.document);for(let u=0;u<f.length;u++){let c=f[u];e&&!g(c,e)||r.push({element:c,frame:a})}}let l=[];if(r.length>0){let a=new Set(r.map(u=>u.element)),f=new Set;for(let u=r.length-1;u>=0;u--){let c=r[u],d=c.element;if(!f.has(d)){l.unshift(c);let m=d.parentElement;for(;m;)a.has(m)&&f.add(m),m=m.parentElement}}}return{elements:l.map(a=>{let f=A(a.element),u=a.element.tagName.toLowerCase(),c=N(a.element);return a.frame.isMainFrame?{element:a.element,boundingBox:f,tagName:u,frameIndex:a.frame.frameIndex,isHidden:c}:{boundingBox:f,tagName:u,frameIndex:a.frame.frameIndex,isHidden:c}})}}function W(e,t=!1,n=null){if(e==null&&(e=""),typeof e!="string")throw new TypeError(`value must be a string, got ${typeof e}`);let o=[],r=x(window);for(let s of r){let a=y(n||s.document);for(let f=0;f<a.length;f++){let u=a[f];S(u,e,t)&&o.push({element:u,frame:s})}}return{elements:o.filter(s=>{let a=s.element;if(k(a,e,t))return!0;for(let u of o)if(u.element!==a&&a.contains(u.element))return!1;return!0}).map(s=>{let a=A(s.element),f=s.element.tagName.toLowerCase(),u=N(s.element);return s.frame.isMainFrame?{element:s.element,boundingBox:a,tagName:f,frameIndex:s.frame.frameIndex,isHidden:u}:{boundingBox:a,tagName:f,frameIndex:s.frame.frameIndex,isHidden:u}})}}function k(e,t,n=!1){if(t==null||t==="")return!0;let o=E;for(let i=0;i<o.length;i++){let l=o[i],s;try{s=e.getAttribute(l)}catch(a){continue}if(s){if(l==="aria-labelledby"){if(n?s===t:s.includes(t))return!0;let a=F(e);if(a&&(n?a===t:a.includes(t)))return!0}else if(n?s===t:s.includes(t))return!0}}let r=$(e);return!!(n?r===t:r.includes(t))}function de(e=null,t=null,n=null){let o=e!=null;if(o){if(typeof e!="string")throw new TypeError(`type must be a string, got ${typeof e}`);if(!p[e]){let s=`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`;if(n&&n.failOnUnknownType===!0)throw new TypeError(`Unknown element type: ${e}`);return console.warn(s),{[e]:{visible:0,hidden:0,total:0}}}}let r={},i=o?[e]:Object.keys(p).filter(s=>s!=="element");for(let s=0;s<i.length;s++)r[i[s]]={visible:0,hidden:0,total:0};let l=x(window);for(let s=0;s<l.length;s++){let a=l[s],f=y(t||a.document);for(let u=0;u<f.length;u++){let c=f[u];for(let d=0;d<i.length;d++){let m=i[d];if(g(c,m)){let h=N(c)?"hidden":"visible";r[m][h]+=1,r[m].total+=1}}}}return r}function me(e=null,t=null,n=!1,o=null,r=null){if(t==null&&(t=""),e!=null){if(typeof e!="string")throw new TypeError(`type must be a string, got ${typeof e}`);if(!p[e]){let f=`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`;if(r&&r.failOnUnknownType===!0)throw new TypeError(`Unknown element type: ${e}`);return console.warn(f),{elements:[]}}}if(t!==""&&typeof t!="string")throw new TypeError(`text must be a string, got ${typeof t}`);let i=[],l=x(window);for(let f of l){let u=y(o||f.document);for(let c=0;c<u.length;c++){let d=u[c];e!=null&&!g(d,e)||t!==""&&!S(d,t,n)||i.push({element:d,frame:f})}}return{elements:(t!==""?i.filter(f=>{let u=f.element;if(k(u,t,n))return!0;for(let d of i)if(d.element!==u&&u.contains(d.element))return!1;return!0}):i).map(f=>{let u=A(f.element),c=f.element.tagName.toLowerCase(),d=N(f.element);return f.frame.isMainFrame?{element:f.element,boundingBox:u,tagName:c,frameIndex:f.frame.frameIndex,isHidden:d}:{boundingBox:u,tagName:c,frameIndex:f.frame.frameIndex,isHidden:d}})}}function L(e){if(e.parentElement)return e.parentElement;try{let t=e.getRootNode();if(t&&t.host)return t.host}catch(t){}return null}function q(e){let t=L(e);if(!t)return[];if(t.shadowRoot)try{return Array.from(t.shadowRoot.children)}catch(n){return[]}return Array.from(t.children)}function he(e,t){let n=L(e);for(;n;){if(g(n,t))return n;n=L(n)}let o=e.children||[];for(let l of o)if(g(l,t))return l;let r=q(e);for(let l of r)if(l!==e&&g(l,t))return l;for(let l of r){if(l===e)continue;let s=y(l);for(let a=0;a<s.length;a++)if(g(s[a],t))return s[a]}let i=e.parentElement;for(;i;){let l=q(i);for(let s of l)if(s!==i){if(g(s,t))return s;let a=y(s);for(let f=0;f<a.length;f++)if(g(a[f],t))return a[f]}i=i.parentElement}return null}function ge(e,t,n=!1,o=null,r=null){let i=e!=null&&e!=="",l=t!=null&&t!=="";if(i&&!l)return z(e,o,r);if(!i&&l)return W(t,n,o);if(i){if(typeof e!="string")throw new TypeError(`elementType must be a string, got ${typeof e}`);if(!p[e]){let c=`Unknown element type: ${e}. Valid types: ${Object.keys(p).join(", ")}`;if(r&&r.failOnUnknownType===!0)throw new TypeError(`Unknown element type: ${e}`);return console.warn(c),{elements:[]}}}if(l&&typeof t!="string")throw new TypeError(`attributeText must be a string, got ${typeof t}`);let s=[],a=x(window);for(let c of a){let d=y(o||c.document);for(let m=0;m<d.length;m++){let h=d[m];i&&!g(h,e)||l&&!S(h,t,n)||s.push({element:h,frame:c})}}if(s.length===0&&i&&l){let c=[];for(let m of a){let h=y(o||m.document);for(let O=0;O<h.length;O++){let M=h[O];S(M,t,n)&&k(M,t,n)&&c.push({element:M,frame:m})}}let d=new Set;for(let m of c){let h=he(m.element,e);h&&!d.has(h)&&(d.add(h),s.push({element:h,frame:m.frame}))}}return{elements:(l?s.filter(c=>{let d=c.element;if(k(d,t,n))return!0;for(let h of s)if(h.element!==d&&d.contains(h.element))return!1;return!0}):s).map(c=>{let d=A(c.element),m=c.element.tagName.toLowerCase(),h=N(c.element);return c.frame.isMainFrame?{element:c.element,boundingBox:d,tagName:m,frameIndex:c.frame.frameIndex,isHidden:h}:{boundingBox:d,tagName:m,frameIndex:c.frame.frameIndex,isHidden:h}})}}function X(e){return e?e&&e.elements&&Array.isArray(e.elements)?e.elements:Array.isArray(e)?e:[e]:[]}function pe(e,t="red",n=3){let o=X(e);for(let r=0;r<o.length;r++){let i=o[r],l=i.element?i.element:i;l&&l.style&&(l.style.outline=`${n}px solid ${t}`,l.style.outlineOffset="2px",l.style.boxShadow="0 0 0 2px rgba(255, 255, 255, 0.8)",l.classList.add("elementfinder-highlighted"))}}function ye(e){let t=X(e);for(let n=0;n<t.length;n++){let o=t[n],r=o.element?o.element:o;r&&r.style&&(r.style.outline="",r.style.outlineOffset="",r.style.boxShadow="",r.classList.remove("elementfinder-highlighted"))}}var T=[];function be(){let e=new Map,t=y();for(let r of t)r&&r.style&&r.style.animationPlayState!=="paused"&&(e.set(r,{animationPlayState:r.style.animationPlayState,transitionProperty:r.style.transitionProperty,webkitAnimationPlayState:r.style.webkitAnimationPlayState,webkitTransitionProperty:r.style.webkitTransitionProperty}),r.style.animationPlayState="paused",r.style.transitionProperty="none",r.style.webkitAnimationPlayState="paused",r.style.webkitTransitionProperty="none");let n=document.getElementById("elementfinder-animation-pause");n||(n=document.createElement("style"),n.id="elementfinder-animation-pause",n.textContent=`
|
|
2
2
|
*, *::before, *::after {
|
|
3
3
|
animation-play-state: paused !important;
|
|
4
4
|
transition-property: none !important;
|
|
@@ -12,4 +12,4 @@ var ElementFinder=(()=>{var P=Object.defineProperty;var W=Object.getOwnPropertyD
|
|
|
12
12
|
transition-duration: 0s !important;
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
-
`,document.head.appendChild(n));let o={originalStyles:e,pausedCount:e.size};return
|
|
15
|
+
`,document.head.appendChild(n));let o={originalStyles:e,pausedCount:e.size};return T.push(o),o}function we(e){if(e){let n=T.indexOf(e);if(n===-1)return;T.splice(n,1)}else{if(T.length===0)return;e=T.pop()}let t=e.originalStyles;if(t)for(let[n,o]of t)n&&n.style&&(n.style.animationPlayState=o.animationPlayState||"",n.style.transitionProperty=o.transitionProperty||"",n.style.webkitAnimationPlayState=o.webkitAnimationPlayState||"",n.style.webkitTransitionProperty=o.webkitTransitionProperty||"");if(T.length===0){let n=document.getElementById("elementfinder-animation-pause");n&&n.remove()}}function Ee(){return Object.keys(p)}function xe(){return[...E]}return K(Te);})();
|
package/package.json
CHANGED
package/src/element-finder.js
CHANGED
|
@@ -23,6 +23,9 @@ const REGEX_PATTERNS = {
|
|
|
23
23
|
// Maximum recursion depth for XPath parsing to prevent stack overflow
|
|
24
24
|
const MAX_RECURSION_DEPTH = 100;
|
|
25
25
|
|
|
26
|
+
// Maximum length for text/textContent fallback descriptors
|
|
27
|
+
const MAX_IDENTIFIABLE_TEXT_LENGTH = 25;
|
|
28
|
+
|
|
26
29
|
// Pre-compiled type matcher functions for faster type checking
|
|
27
30
|
const TYPE_MATCHERS = new Map();
|
|
28
31
|
|
|
@@ -99,6 +102,33 @@ function normalizeDescriptorText(text) {
|
|
|
99
102
|
return String(text).replace(/\s+/g, ' ').trim();
|
|
100
103
|
}
|
|
101
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Shortens text fallback descriptors without cutting words.
|
|
107
|
+
* Uses only the first non-empty line so text after new lines is ignored.
|
|
108
|
+
* @param {string|null|undefined} text - Text to shorten
|
|
109
|
+
* @returns {string} Shortened normalized text
|
|
110
|
+
*/
|
|
111
|
+
function shortenDescriptorText(text) {
|
|
112
|
+
if (text == null) return '';
|
|
113
|
+
|
|
114
|
+
const lines = String(text).split(/\r\n|\r|\n/);
|
|
115
|
+
let normalizedText = '';
|
|
116
|
+
|
|
117
|
+
for (let i = 0; i < lines.length; i++) {
|
|
118
|
+
normalizedText = normalizeDescriptorText(lines[i]);
|
|
119
|
+
if (normalizedText) break;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (!normalizedText || normalizedText.length <= MAX_IDENTIFIABLE_TEXT_LENGTH) {
|
|
123
|
+
return normalizedText;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const shortened = normalizedText.slice(0, MAX_IDENTIFIABLE_TEXT_LENGTH);
|
|
127
|
+
const lastSpaceIndex = shortened.lastIndexOf(' ');
|
|
128
|
+
|
|
129
|
+
return lastSpaceIndex > 0 ? shortened.slice(0, lastSpaceIndex) : normalizedText;
|
|
130
|
+
}
|
|
131
|
+
|
|
102
132
|
/**
|
|
103
133
|
* Gets the filename portion of an image src without path or extension.
|
|
104
134
|
* @param {string|null|undefined} src - Image src value
|
|
@@ -178,12 +208,12 @@ function getElementDescriptorText(el) {
|
|
|
178
208
|
}
|
|
179
209
|
}
|
|
180
210
|
|
|
181
|
-
const directText =
|
|
211
|
+
const directText = shortenDescriptorText(getDirectText(el));
|
|
182
212
|
if (directText) {
|
|
183
213
|
return { attributeName: 'text', identifiableText: directText };
|
|
184
214
|
}
|
|
185
215
|
|
|
186
|
-
const fullText =
|
|
216
|
+
const fullText = shortenDescriptorText(el.textContent);
|
|
187
217
|
if (fullText) {
|
|
188
218
|
return { attributeName: 'text', identifiableText: fullText };
|
|
189
219
|
}
|
|
@@ -711,36 +741,60 @@ export function getBoundingBox(el) {
|
|
|
711
741
|
|
|
712
742
|
/**
|
|
713
743
|
* Checks if an element is hidden (not visible on the page).
|
|
714
|
-
* Considers
|
|
744
|
+
* Considers native visibility checks, ancestor visibility, CSS visibility/display/opacity,
|
|
745
|
+
* hidden/inert/aria-hidden attributes, and offset dimensions.
|
|
715
746
|
* @param {Element} el - The DOM element to check
|
|
716
747
|
* @returns {boolean} True if the element is hidden
|
|
717
748
|
*/
|
|
718
749
|
export function isHidden(el) {
|
|
719
750
|
if (el == null) return true;
|
|
720
751
|
|
|
721
|
-
|
|
722
|
-
|
|
752
|
+
let parent = el;
|
|
753
|
+
while (parent) {
|
|
754
|
+
if (isElementHidden(parent)) {
|
|
755
|
+
return true;
|
|
756
|
+
}
|
|
757
|
+
parent = parent.parentElement;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
return false;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
function isElementHidden(el) {
|
|
764
|
+
if (
|
|
765
|
+
el.hasAttribute('hidden') ||
|
|
766
|
+
el.getAttribute('aria-hidden') === 'true' ||
|
|
767
|
+
el.inert ||
|
|
768
|
+
(el.offsetWidth === 0 && el.offsetHeight === 0)
|
|
769
|
+
) {
|
|
723
770
|
return true;
|
|
724
771
|
}
|
|
725
772
|
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
773
|
+
if (typeof el.checkVisibility === 'function') {
|
|
774
|
+
if (!el.checkVisibility({
|
|
775
|
+
checkOpacity: true,
|
|
776
|
+
checkVisibilityCSS: true,
|
|
777
|
+
contentVisibilityAuto: true
|
|
778
|
+
})) {
|
|
730
779
|
return true;
|
|
731
780
|
}
|
|
732
|
-
|
|
781
|
+
return false;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
try {
|
|
785
|
+
const style = window.getComputedStyle(el);
|
|
786
|
+
if (
|
|
787
|
+
style.visibility === 'hidden' ||
|
|
788
|
+
style.visibility === 'collapse' ||
|
|
789
|
+
style.display === 'none' ||
|
|
790
|
+
style.opacity === '0'
|
|
791
|
+
) {
|
|
733
792
|
return true;
|
|
734
793
|
}
|
|
735
794
|
} catch {
|
|
736
795
|
// Restricted access - continue with other checks
|
|
737
796
|
}
|
|
738
797
|
|
|
739
|
-
// Check hidden attribute
|
|
740
|
-
if (el.hasAttribute('hidden')) {
|
|
741
|
-
return true;
|
|
742
|
-
}
|
|
743
|
-
|
|
744
798
|
return false;
|
|
745
799
|
}
|
|
746
800
|
|
|
@@ -962,14 +1016,14 @@ function hasOwnMatch(el, value, exact = false) {
|
|
|
962
1016
|
}
|
|
963
1017
|
|
|
964
1018
|
/**
|
|
965
|
-
* Gets counts of elements by semantic type on the current screen.
|
|
1019
|
+
* Gets counts of elements by semantic type and visibility on the current screen.
|
|
966
1020
|
* Excludes the generic `element` type unless a specific type is requested.
|
|
967
1021
|
* If no type is provided, returns counts for all defined non-generic types.
|
|
968
1022
|
* Searches all frames (main document + iframes) by default.
|
|
969
1023
|
* @param {string|null|undefined} [type=null] - Element type to count. If null/undefined, count all defined non-generic types.
|
|
970
1024
|
* @param {Element|null} [parent=null] - Parent element to count within
|
|
971
1025
|
* @param {{failOnUnknownType?: boolean}} [options=null] - Search options
|
|
972
|
-
* @returns {Object.<string, number>} Counts keyed by semantic element type, or `{ [type]:
|
|
1026
|
+
* @returns {Object.<string, {visible: number, hidden: number, total: number}>} Counts keyed by semantic element type, or `{ [type]: { visible, hidden, total } }` when type is provided
|
|
973
1027
|
*/
|
|
974
1028
|
export function getElementCounts(type = null, parent = null, options = null) {
|
|
975
1029
|
const hasType = type !== null && type !== undefined;
|
|
@@ -984,7 +1038,7 @@ export function getElementCounts(type = null, parent = null, options = null) {
|
|
|
984
1038
|
throw new TypeError(`Unknown element type: ${type}`);
|
|
985
1039
|
}
|
|
986
1040
|
console.warn(message);
|
|
987
|
-
return { [type]: 0 };
|
|
1041
|
+
return { [type]: { visible: 0, hidden: 0, total: 0 } };
|
|
988
1042
|
}
|
|
989
1043
|
}
|
|
990
1044
|
|
|
@@ -992,7 +1046,7 @@ export function getElementCounts(type = null, parent = null, options = null) {
|
|
|
992
1046
|
const targetTypes = hasType ? [type] : Object.keys(ELEMENT_DEFINITIONS).filter((item) => item !== 'element');
|
|
993
1047
|
|
|
994
1048
|
for (let i = 0; i < targetTypes.length; i++) {
|
|
995
|
-
counts[targetTypes[i]] = 0;
|
|
1049
|
+
counts[targetTypes[i]] = { visible: 0, hidden: 0, total: 0 };
|
|
996
1050
|
}
|
|
997
1051
|
|
|
998
1052
|
const frames = getAllFrames(window);
|
|
@@ -1008,7 +1062,9 @@ export function getElementCounts(type = null, parent = null, options = null) {
|
|
|
1008
1062
|
for (let k = 0; k < targetTypes.length; k++) {
|
|
1009
1063
|
const targetType = targetTypes[k];
|
|
1010
1064
|
if (matchesType(el, targetType)) {
|
|
1011
|
-
|
|
1065
|
+
const bucket = isHidden(el) ? 'hidden' : 'visible';
|
|
1066
|
+
counts[targetType][bucket] += 1;
|
|
1067
|
+
counts[targetType].total += 1;
|
|
1012
1068
|
}
|
|
1013
1069
|
}
|
|
1014
1070
|
}
|