@midscene/web 0.3.0 → 0.3.1
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/LICENSE +1 -1
- package/dist/es/index.js +343 -41
- package/dist/es/playwright-report.js +0 -1
- package/dist/lib/index.js +344 -40
- package/dist/script/htmlElement.js +73 -52
- package/dist/script/htmlElementDebug.js +871 -0
- package/dist/script/types/htmlElement.d.ts +4 -2
- package/dist/script/types/htmlElementDebug.d.ts +2 -0
- package/dist/types/index.d.ts +18 -2
- package/package.json +9 -6
|
@@ -580,9 +580,6 @@ var midscene_element_inspector = (() => {
|
|
|
580
580
|
extractTextWithPosition: () => extractTextWithPosition
|
|
581
581
|
});
|
|
582
582
|
|
|
583
|
-
// src/extractor/constants.ts
|
|
584
|
-
var TEXT_SIZE_THRESHOLD = 9;
|
|
585
|
-
|
|
586
583
|
// src/extractor/dom-util.ts
|
|
587
584
|
function isInputElement(node) {
|
|
588
585
|
return node instanceof HTMLElement && (node.tagName.toLowerCase() === "input" || node.tagName.toLowerCase() === "textarea");
|
|
@@ -593,10 +590,21 @@ var midscene_element_inspector = (() => {
|
|
|
593
590
|
function isImgElement(node) {
|
|
594
591
|
return node instanceof HTMLElement && node.tagName.toLowerCase() === "img";
|
|
595
592
|
}
|
|
593
|
+
function isTextElement(node) {
|
|
594
|
+
return node.nodeName.toLowerCase() === "#text";
|
|
595
|
+
}
|
|
596
596
|
|
|
597
597
|
// src/extractor/util.ts
|
|
598
598
|
var import_js_sha256 = __toESM(require_sha256());
|
|
599
|
+
var debugMode = false;
|
|
600
|
+
function setDebugMode(mode) {
|
|
601
|
+
debugMode = mode;
|
|
602
|
+
}
|
|
599
603
|
function logger(..._msg) {
|
|
604
|
+
if (!debugMode) {
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
console.log(..._msg);
|
|
600
608
|
}
|
|
601
609
|
var taskIdKey = "_midscene_retrieve_task_id";
|
|
602
610
|
function selectorForValue(val) {
|
|
@@ -626,40 +634,61 @@ var midscene_element_inspector = (() => {
|
|
|
626
634
|
after: afterContent === "none" ? "" : afterContent.replace(/"/g, "")
|
|
627
635
|
};
|
|
628
636
|
}
|
|
637
|
+
function getRect(el) {
|
|
638
|
+
if (!(el instanceof HTMLElement)) {
|
|
639
|
+
const range = document.createRange();
|
|
640
|
+
range.selectNodeContents(el);
|
|
641
|
+
return range.getBoundingClientRect();
|
|
642
|
+
}
|
|
643
|
+
return el.getBoundingClientRect();
|
|
644
|
+
}
|
|
629
645
|
function visibleRect(el) {
|
|
630
646
|
if (!el) {
|
|
631
|
-
logger("Element is not in the DOM hierarchy");
|
|
647
|
+
logger(el, "Element is not in the DOM hierarchy");
|
|
632
648
|
return false;
|
|
633
649
|
}
|
|
634
|
-
if (!(el instanceof HTMLElement)) {
|
|
635
|
-
logger("Element is not in the DOM hierarchy");
|
|
650
|
+
if (!(el instanceof HTMLElement) && el.nodeType !== Node.TEXT_NODE) {
|
|
651
|
+
logger(el, "Element is not in the DOM hierarchy");
|
|
636
652
|
return false;
|
|
637
653
|
}
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
654
|
+
if (el instanceof HTMLElement) {
|
|
655
|
+
const style = window.getComputedStyle(el);
|
|
656
|
+
if (style.display === "none" || style.visibility === "hidden" || style.opacity === "0" && el.tagName !== "INPUT") {
|
|
657
|
+
logger(el, "Element is hidden");
|
|
658
|
+
return false;
|
|
659
|
+
}
|
|
642
660
|
}
|
|
643
|
-
const rect = el
|
|
661
|
+
const rect = getRect(el);
|
|
644
662
|
if (rect.width === 0 && rect.height === 0) {
|
|
645
|
-
logger("Element has no size");
|
|
663
|
+
logger(el, "Element has no size");
|
|
646
664
|
return false;
|
|
647
665
|
}
|
|
648
666
|
const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
|
|
649
667
|
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
|
650
|
-
const
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
668
|
+
const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
|
|
669
|
+
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
|
|
670
|
+
const isPartiallyInViewport = rect.right > 0 && rect.bottom > 0 && rect.left < viewportWidth && rect.top < viewportHeight;
|
|
671
|
+
if (!isPartiallyInViewport) {
|
|
672
|
+
logger(el, "Element is completely outside the viewport", {
|
|
673
|
+
rect,
|
|
674
|
+
viewportHeight,
|
|
675
|
+
viewportWidth,
|
|
676
|
+
scrollTop,
|
|
677
|
+
scrollLeft
|
|
678
|
+
});
|
|
654
679
|
return false;
|
|
655
680
|
}
|
|
656
681
|
let parent = el;
|
|
657
682
|
while (parent && parent !== document.body) {
|
|
683
|
+
if (!(parent instanceof HTMLElement)) {
|
|
684
|
+
parent = parent.parentElement;
|
|
685
|
+
continue;
|
|
686
|
+
}
|
|
658
687
|
const parentStyle = window.getComputedStyle(parent);
|
|
659
688
|
if (parentStyle.overflow === "hidden") {
|
|
660
689
|
const parentRect = parent.getBoundingClientRect();
|
|
661
690
|
const tolerance = 10;
|
|
662
|
-
if (rect.top < parentRect.top - tolerance
|
|
691
|
+
if (rect.top < parentRect.top - tolerance && rect.left < parentRect.left - tolerance && rect.bottom > parentRect.bottom + tolerance && rect.right > parentRect.right + tolerance) {
|
|
663
692
|
logger("Element is clipped by an ancestor", parent, rect, parentRect);
|
|
664
693
|
return false;
|
|
665
694
|
}
|
|
@@ -673,29 +702,6 @@ var midscene_element_inspector = (() => {
|
|
|
673
702
|
height: Math.round(rect.height)
|
|
674
703
|
};
|
|
675
704
|
}
|
|
676
|
-
function validTextNodeContent(node) {
|
|
677
|
-
if (!node) {
|
|
678
|
-
return false;
|
|
679
|
-
}
|
|
680
|
-
if (node.nodeType !== Node.ELEMENT_NODE && node.nodeType !== Node.TEXT_NODE) {
|
|
681
|
-
return false;
|
|
682
|
-
}
|
|
683
|
-
const everyChildNodeIsText = Array.from(node.childNodes).every((child) => {
|
|
684
|
-
const tagName = (child.tagName || "").toLowerCase();
|
|
685
|
-
if (tagName === "script" || tagName === "style" || tagName === "link") {
|
|
686
|
-
return false;
|
|
687
|
-
}
|
|
688
|
-
return true;
|
|
689
|
-
});
|
|
690
|
-
if (!everyChildNodeIsText) {
|
|
691
|
-
return false;
|
|
692
|
-
}
|
|
693
|
-
const content = node.textContent || node.innerText;
|
|
694
|
-
if (content && !/^\s*$/.test(content)) {
|
|
695
|
-
return content.trim();
|
|
696
|
-
}
|
|
697
|
-
return false;
|
|
698
|
-
}
|
|
699
705
|
function getNodeAttributes(node) {
|
|
700
706
|
if (!node || !(node instanceof HTMLElement) || !node.attributes) {
|
|
701
707
|
return {};
|
|
@@ -723,7 +729,8 @@ var midscene_element_inspector = (() => {
|
|
|
723
729
|
function generateId(numberId) {
|
|
724
730
|
return `${numberId}`;
|
|
725
731
|
}
|
|
726
|
-
function extractTextWithPosition(initNode = container) {
|
|
732
|
+
function extractTextWithPosition(initNode = container, debugMode2 = false) {
|
|
733
|
+
setDebugMode(debugMode2);
|
|
727
734
|
const elementInfoArray = [];
|
|
728
735
|
const nodeMapTree = { node: initNode, children: [] };
|
|
729
736
|
let nodeIndex = 1;
|
|
@@ -735,17 +742,22 @@ var midscene_element_inspector = (() => {
|
|
|
735
742
|
if (parentNode == null ? void 0 : parentNode.children) {
|
|
736
743
|
parentNode.children.push(currentNodeDes);
|
|
737
744
|
}
|
|
738
|
-
collectElementInfo(node);
|
|
745
|
+
const shouldContinue = collectElementInfo(node);
|
|
746
|
+
if (!shouldContinue) {
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
739
749
|
for (let i = 0; i < node.childNodes.length; i++) {
|
|
740
750
|
logger("will dfs", node.childNodes[i]);
|
|
741
751
|
dfs(node.childNodes[i], currentNodeDes);
|
|
742
752
|
}
|
|
743
753
|
}
|
|
744
754
|
function collectElementInfo(node) {
|
|
755
|
+
var _a;
|
|
745
756
|
const rect = visibleRect(node);
|
|
757
|
+
logger("collectElementInfo", node, node.nodeName, rect);
|
|
746
758
|
if (!rect) {
|
|
747
759
|
logger("Element is not visible", node);
|
|
748
|
-
return;
|
|
760
|
+
return true;
|
|
749
761
|
}
|
|
750
762
|
if (isInputElement(node)) {
|
|
751
763
|
const attributes = getNodeAttributes(node);
|
|
@@ -756,6 +768,7 @@ var midscene_element_inspector = (() => {
|
|
|
756
768
|
indexId: generateId(nodeIndex++),
|
|
757
769
|
nodeHashId,
|
|
758
770
|
locator: selector,
|
|
771
|
+
nodeType: "INPUT Node" /* INPUT */,
|
|
759
772
|
attributes: __spreadProps(__spreadValues({}, attributes), {
|
|
760
773
|
nodeType: "INPUT Node" /* INPUT */
|
|
761
774
|
}),
|
|
@@ -764,7 +777,8 @@ var midscene_element_inspector = (() => {
|
|
|
764
777
|
center: [
|
|
765
778
|
Math.round(rect.left + rect.width / 2),
|
|
766
779
|
Math.round(rect.top + rect.height / 2)
|
|
767
|
-
]
|
|
780
|
+
],
|
|
781
|
+
htmlNode: debugMode2 ? node : null
|
|
768
782
|
});
|
|
769
783
|
return;
|
|
770
784
|
}
|
|
@@ -778,6 +792,7 @@ var midscene_element_inspector = (() => {
|
|
|
778
792
|
id: nodeHashId,
|
|
779
793
|
indexId: generateId(nodeIndex++),
|
|
780
794
|
nodeHashId,
|
|
795
|
+
nodeType: "BUTTON Node" /* BUTTON */,
|
|
781
796
|
locator: selector,
|
|
782
797
|
attributes: __spreadProps(__spreadValues({}, attributes), {
|
|
783
798
|
nodeType: "BUTTON Node" /* BUTTON */
|
|
@@ -787,7 +802,8 @@ var midscene_element_inspector = (() => {
|
|
|
787
802
|
center: [
|
|
788
803
|
Math.round(rect.left + rect.width / 2),
|
|
789
804
|
Math.round(rect.top + rect.height / 2)
|
|
790
|
-
]
|
|
805
|
+
],
|
|
806
|
+
htmlNode: debugMode2 ? node : null
|
|
791
807
|
});
|
|
792
808
|
return;
|
|
793
809
|
}
|
|
@@ -803,19 +819,20 @@ var midscene_element_inspector = (() => {
|
|
|
803
819
|
attributes: __spreadProps(__spreadValues({}, attributes), {
|
|
804
820
|
nodeType: "IMG Node" /* IMG */
|
|
805
821
|
}),
|
|
822
|
+
nodeType: "IMG Node" /* IMG */,
|
|
806
823
|
content: "",
|
|
807
824
|
rect,
|
|
808
825
|
center: [
|
|
809
826
|
Math.round(rect.left + rect.width / 2),
|
|
810
827
|
Math.round(rect.top + rect.height / 2)
|
|
811
|
-
]
|
|
828
|
+
],
|
|
829
|
+
htmlNode: debugMode2 ? node : null
|
|
812
830
|
});
|
|
813
831
|
return;
|
|
814
832
|
}
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
if (
|
|
818
|
-
logger("Element is too small", text);
|
|
833
|
+
if (isTextElement(node)) {
|
|
834
|
+
const text = (_a = node.textContent) == null ? void 0 : _a.trim().replace(/\n+/g, " ");
|
|
835
|
+
if (!text) {
|
|
819
836
|
return;
|
|
820
837
|
}
|
|
821
838
|
const attributes = getNodeAttributes(node);
|
|
@@ -825,19 +842,23 @@ var midscene_element_inspector = (() => {
|
|
|
825
842
|
id: nodeHashId,
|
|
826
843
|
indexId: generateId(nodeIndex++),
|
|
827
844
|
nodeHashId,
|
|
845
|
+
nodeType: "TEXT Node" /* TEXT */,
|
|
846
|
+
locator: selector,
|
|
828
847
|
attributes: __spreadProps(__spreadValues({}, attributes), {
|
|
829
848
|
nodeType: "TEXT Node" /* TEXT */
|
|
830
849
|
}),
|
|
831
|
-
locator: selector,
|
|
832
850
|
center: [
|
|
833
851
|
Math.round(rect.left + rect.width / 2),
|
|
834
852
|
Math.round(rect.top + rect.height / 2)
|
|
835
853
|
],
|
|
836
854
|
// attributes,
|
|
837
855
|
content: text,
|
|
838
|
-
rect
|
|
856
|
+
rect,
|
|
857
|
+
htmlNode: debugMode2 ? node : null
|
|
839
858
|
});
|
|
859
|
+
return;
|
|
840
860
|
}
|
|
861
|
+
return true;
|
|
841
862
|
}
|
|
842
863
|
dfs(initNode, nodeMapTree);
|
|
843
864
|
return elementInfoArray;
|