webmarker-js 0.3.0 → 0.5.0
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 +2 -2
- package/chrome-extension/dist/index.d.ts +72 -0
- package/chrome-extension/dist/main.js +1069 -0
- package/chrome-extension/dist/module.js +1048 -0
- package/dist/index.d.ts +10 -2
- package/dist/main.js +66 -55
- package/dist/module.js +66 -55
- package/package.json +2 -1
- package/src/index.ts +114 -78
package/dist/index.d.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
type Placement = "top" | "top-start" | "top-end" | "right" | "right-start" | "right-end" | "bottom" | "bottom-start" | "bottom-end" | "left" | "left-start" | "left-end";
|
2
|
-
type StyleFunction = (element: Element) => Partial<CSSStyleDeclaration>;
|
2
|
+
type StyleFunction = (element: Element, index: number) => Partial<CSSStyleDeclaration>;
|
3
3
|
type StyleObject = Partial<CSSStyleDeclaration>;
|
4
4
|
interface MarkOptions {
|
5
5
|
/**
|
@@ -51,13 +51,21 @@ interface MarkOptions {
|
|
51
51
|
* @default false
|
52
52
|
*/
|
53
53
|
viewPortOnly?: boolean;
|
54
|
+
/**
|
55
|
+
* Additional class to apply to the mark elements.
|
56
|
+
*/
|
57
|
+
markClass?: string;
|
58
|
+
/**
|
59
|
+
* Additional class to apply to the bounding box elements.
|
60
|
+
*/
|
61
|
+
boundingBoxClass?: string;
|
54
62
|
}
|
55
63
|
interface MarkedElement {
|
56
64
|
element: Element;
|
57
65
|
markElement: HTMLElement;
|
58
66
|
boundingBoxElement?: HTMLElement;
|
59
67
|
}
|
60
|
-
declare function mark(options?: MarkOptions):
|
68
|
+
declare function mark(options?: MarkOptions): Record<string, MarkedElement>;
|
61
69
|
declare function unmark(): void;
|
62
70
|
declare function isMarked(): boolean;
|
63
71
|
export { mark, unmark, isMarked };
|
package/dist/main.js
CHANGED
@@ -928,8 +928,8 @@ var WebMarker = (() => {
|
|
928
928
|
|
929
929
|
// src/index.ts
|
930
930
|
var cleanupFns = [];
|
931
|
-
function mark() {
|
932
|
-
|
931
|
+
function mark(options = {}) {
|
932
|
+
try {
|
933
933
|
const {
|
934
934
|
selector = "button, input, a, select, textarea",
|
935
935
|
getLabel = (_, index) => index.toString(),
|
@@ -948,34 +948,57 @@ var WebMarker = (() => {
|
|
948
948
|
},
|
949
949
|
showBoundingBoxes = true,
|
950
950
|
containerElement = document.body,
|
951
|
-
viewPortOnly = false
|
951
|
+
viewPortOnly = false,
|
952
|
+
markClass = "",
|
953
|
+
boundingBoxClass = ""
|
952
954
|
} = options;
|
955
|
+
const isInViewport = (el) => {
|
956
|
+
const rect = el.getBoundingClientRect();
|
957
|
+
return rect.top < window.innerHeight && rect.bottom >= 0;
|
958
|
+
};
|
953
959
|
const elements = Array.from(
|
954
960
|
containerElement.querySelectorAll(selector)
|
955
|
-
).filter(
|
956
|
-
(el) => !viewPortOnly || el.getBoundingClientRect().top < window.innerHeight
|
957
|
-
);
|
961
|
+
).filter((el) => !viewPortOnly || isInViewport(el));
|
958
962
|
const markedElements = {};
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
963
|
+
const fragment = document.createDocumentFragment();
|
964
|
+
elements.forEach((element, index) => {
|
965
|
+
const label = getLabel(element, index);
|
966
|
+
const markElement = createMark(
|
967
|
+
element,
|
968
|
+
index,
|
969
|
+
markStyle,
|
970
|
+
label,
|
971
|
+
markPlacement,
|
972
|
+
markClass
|
973
|
+
);
|
974
|
+
fragment.appendChild(markElement);
|
975
|
+
const boundingBoxElement = showBoundingBoxes ? createBoundingBox(element, boundingBoxStyle, label, boundingBoxClass) : void 0;
|
976
|
+
if (boundingBoxElement) {
|
977
|
+
fragment.appendChild(boundingBoxElement);
|
978
|
+
}
|
979
|
+
markedElements[label] = { element, markElement, boundingBoxElement };
|
980
|
+
element.setAttribute(markAttribute, label);
|
981
|
+
});
|
982
|
+
document.body.appendChild(fragment);
|
968
983
|
document.documentElement.setAttribute("data-marked", "true");
|
969
984
|
return markedElements;
|
970
|
-
})
|
985
|
+
} catch (error) {
|
986
|
+
console.error("Error in mark function:", error);
|
987
|
+
throw error;
|
988
|
+
}
|
971
989
|
}
|
972
|
-
function createMark(element, style, label, markPlacement = "top-start") {
|
990
|
+
function createMark(element, index, style, label, markPlacement = "top-start", markClass) {
|
973
991
|
const markElement = document.createElement("div");
|
974
|
-
markElement.className =
|
992
|
+
markElement.className = `webmarker ${markClass}`.trim();
|
975
993
|
markElement.id = `webmarker-${label}`;
|
976
994
|
markElement.textContent = label;
|
977
|
-
|
978
|
-
|
995
|
+
markElement.setAttribute("aria-hidden", "true");
|
996
|
+
positionElement(markElement, element, markPlacement, (x, y) => {
|
997
|
+
Object.assign(markElement.style, {
|
998
|
+
left: `${x}px`,
|
999
|
+
top: `${y}px`
|
1000
|
+
});
|
1001
|
+
});
|
979
1002
|
applyStyle(
|
980
1003
|
markElement,
|
981
1004
|
{
|
@@ -983,16 +1006,24 @@ var WebMarker = (() => {
|
|
983
1006
|
position: "absolute",
|
984
1007
|
pointerEvents: "none"
|
985
1008
|
},
|
986
|
-
typeof style === "function" ? style(element) : style
|
1009
|
+
typeof style === "function" ? style(element, index) : style
|
987
1010
|
);
|
988
1011
|
return markElement;
|
989
1012
|
}
|
990
|
-
function createBoundingBox(element, style, label) {
|
1013
|
+
function createBoundingBox(element, style, label, boundingBoxClass) {
|
991
1014
|
const boundingBoxElement = document.createElement("div");
|
992
|
-
boundingBoxElement.className =
|
1015
|
+
boundingBoxElement.className = `webmarker-bounding-box ${boundingBoxClass}`.trim();
|
993
1016
|
boundingBoxElement.id = `webmarker-bounding-box-${label}`;
|
994
|
-
|
995
|
-
|
1017
|
+
boundingBoxElement.setAttribute("aria-hidden", "true");
|
1018
|
+
positionElement(boundingBoxElement, element, "top-start", (x, y) => {
|
1019
|
+
const { width, height } = element.getBoundingClientRect();
|
1020
|
+
Object.assign(boundingBoxElement.style, {
|
1021
|
+
left: `${x}px`,
|
1022
|
+
top: `${y + height}px`,
|
1023
|
+
width: `${width}px`,
|
1024
|
+
height: `${height}px`
|
1025
|
+
});
|
1026
|
+
});
|
996
1027
|
applyStyle(
|
997
1028
|
boundingBoxElement,
|
998
1029
|
{
|
@@ -1000,47 +1031,27 @@ var WebMarker = (() => {
|
|
1000
1031
|
position: "absolute",
|
1001
1032
|
pointerEvents: "none"
|
1002
1033
|
},
|
1003
|
-
typeof style === "function" ? style(element) : style
|
1034
|
+
typeof style === "function" ? style(element, parseInt(label)) : style
|
1004
1035
|
);
|
1005
1036
|
return boundingBoxElement;
|
1006
1037
|
}
|
1007
|
-
function
|
1038
|
+
function positionElement(target, anchor, placement, updateCallback) {
|
1008
1039
|
function updatePosition() {
|
1009
|
-
|
1010
|
-
|
1011
|
-
placement: markPlacement
|
1012
|
-
});
|
1013
|
-
Object.assign(markElement.style, {
|
1014
|
-
left: `${x}px`,
|
1015
|
-
top: `${y}px`
|
1016
|
-
});
|
1040
|
+
computePosition2(anchor, target, { placement }).then(({ x, y }) => {
|
1041
|
+
updateCallback(x, y);
|
1017
1042
|
});
|
1018
1043
|
}
|
1019
|
-
cleanupFns.push(autoUpdate(
|
1020
|
-
}
|
1021
|
-
function positionBoundingBox(boundingBox, element) {
|
1022
|
-
return __async(this, null, function* () {
|
1023
|
-
const { width, height } = element.getBoundingClientRect();
|
1024
|
-
function updatePosition() {
|
1025
|
-
return __async(this, null, function* () {
|
1026
|
-
const { x, y } = yield computePosition2(element, boundingBox, {
|
1027
|
-
placement: "top-start"
|
1028
|
-
});
|
1029
|
-
Object.assign(boundingBox.style, {
|
1030
|
-
left: `${x}px`,
|
1031
|
-
top: `${y + height}px`,
|
1032
|
-
width: `${width}px`,
|
1033
|
-
height: `${height}px`
|
1034
|
-
});
|
1035
|
-
});
|
1036
|
-
}
|
1037
|
-
cleanupFns.push(autoUpdate(element, boundingBox, updatePosition));
|
1038
|
-
});
|
1044
|
+
cleanupFns.push(autoUpdate(anchor, target, updatePosition));
|
1039
1045
|
}
|
1040
1046
|
function applyStyle(element, defaultStyle, customStyle) {
|
1041
1047
|
Object.assign(element.style, defaultStyle, customStyle);
|
1042
1048
|
}
|
1043
1049
|
function unmark() {
|
1050
|
+
var _a;
|
1051
|
+
const markAttribute = ((_a = document.querySelector("[data-mark-label]")) == null ? void 0 : _a.getAttribute("data-mark-label")) ? "data-mark-label" : "data-webmarker-label";
|
1052
|
+
document.querySelectorAll(`[${markAttribute}]`).forEach((el) => {
|
1053
|
+
el.removeAttribute(markAttribute);
|
1054
|
+
});
|
1044
1055
|
document.querySelectorAll(".webmarker, .webmarker-bounding-box").forEach((el) => el.remove());
|
1045
1056
|
document.documentElement.removeAttribute("data-marked");
|
1046
1057
|
cleanupFns.forEach((fn) => fn());
|
package/dist/module.js
CHANGED
@@ -904,8 +904,8 @@ var computePosition2 = (reference, floating, options) => {
|
|
904
904
|
|
905
905
|
// src/index.ts
|
906
906
|
var cleanupFns = [];
|
907
|
-
function mark() {
|
908
|
-
|
907
|
+
function mark(options = {}) {
|
908
|
+
try {
|
909
909
|
const {
|
910
910
|
selector = "button, input, a, select, textarea",
|
911
911
|
getLabel = (_, index) => index.toString(),
|
@@ -924,34 +924,57 @@ function mark() {
|
|
924
924
|
},
|
925
925
|
showBoundingBoxes = true,
|
926
926
|
containerElement = document.body,
|
927
|
-
viewPortOnly = false
|
927
|
+
viewPortOnly = false,
|
928
|
+
markClass = "",
|
929
|
+
boundingBoxClass = ""
|
928
930
|
} = options;
|
931
|
+
const isInViewport = (el) => {
|
932
|
+
const rect = el.getBoundingClientRect();
|
933
|
+
return rect.top < window.innerHeight && rect.bottom >= 0;
|
934
|
+
};
|
929
935
|
const elements = Array.from(
|
930
936
|
containerElement.querySelectorAll(selector)
|
931
|
-
).filter(
|
932
|
-
(el) => !viewPortOnly || el.getBoundingClientRect().top < window.innerHeight
|
933
|
-
);
|
937
|
+
).filter((el) => !viewPortOnly || isInViewport(el));
|
934
938
|
const markedElements = {};
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
939
|
+
const fragment = document.createDocumentFragment();
|
940
|
+
elements.forEach((element, index) => {
|
941
|
+
const label = getLabel(element, index);
|
942
|
+
const markElement = createMark(
|
943
|
+
element,
|
944
|
+
index,
|
945
|
+
markStyle,
|
946
|
+
label,
|
947
|
+
markPlacement,
|
948
|
+
markClass
|
949
|
+
);
|
950
|
+
fragment.appendChild(markElement);
|
951
|
+
const boundingBoxElement = showBoundingBoxes ? createBoundingBox(element, boundingBoxStyle, label, boundingBoxClass) : void 0;
|
952
|
+
if (boundingBoxElement) {
|
953
|
+
fragment.appendChild(boundingBoxElement);
|
954
|
+
}
|
955
|
+
markedElements[label] = { element, markElement, boundingBoxElement };
|
956
|
+
element.setAttribute(markAttribute, label);
|
957
|
+
});
|
958
|
+
document.body.appendChild(fragment);
|
944
959
|
document.documentElement.setAttribute("data-marked", "true");
|
945
960
|
return markedElements;
|
946
|
-
})
|
961
|
+
} catch (error) {
|
962
|
+
console.error("Error in mark function:", error);
|
963
|
+
throw error;
|
964
|
+
}
|
947
965
|
}
|
948
|
-
function createMark(element, style, label, markPlacement = "top-start") {
|
966
|
+
function createMark(element, index, style, label, markPlacement = "top-start", markClass) {
|
949
967
|
const markElement = document.createElement("div");
|
950
|
-
markElement.className =
|
968
|
+
markElement.className = `webmarker ${markClass}`.trim();
|
951
969
|
markElement.id = `webmarker-${label}`;
|
952
970
|
markElement.textContent = label;
|
953
|
-
|
954
|
-
|
971
|
+
markElement.setAttribute("aria-hidden", "true");
|
972
|
+
positionElement(markElement, element, markPlacement, (x, y) => {
|
973
|
+
Object.assign(markElement.style, {
|
974
|
+
left: `${x}px`,
|
975
|
+
top: `${y}px`
|
976
|
+
});
|
977
|
+
});
|
955
978
|
applyStyle(
|
956
979
|
markElement,
|
957
980
|
{
|
@@ -959,16 +982,24 @@ function createMark(element, style, label, markPlacement = "top-start") {
|
|
959
982
|
position: "absolute",
|
960
983
|
pointerEvents: "none"
|
961
984
|
},
|
962
|
-
typeof style === "function" ? style(element) : style
|
985
|
+
typeof style === "function" ? style(element, index) : style
|
963
986
|
);
|
964
987
|
return markElement;
|
965
988
|
}
|
966
|
-
function createBoundingBox(element, style, label) {
|
989
|
+
function createBoundingBox(element, style, label, boundingBoxClass) {
|
967
990
|
const boundingBoxElement = document.createElement("div");
|
968
|
-
boundingBoxElement.className =
|
991
|
+
boundingBoxElement.className = `webmarker-bounding-box ${boundingBoxClass}`.trim();
|
969
992
|
boundingBoxElement.id = `webmarker-bounding-box-${label}`;
|
970
|
-
|
971
|
-
|
993
|
+
boundingBoxElement.setAttribute("aria-hidden", "true");
|
994
|
+
positionElement(boundingBoxElement, element, "top-start", (x, y) => {
|
995
|
+
const { width, height } = element.getBoundingClientRect();
|
996
|
+
Object.assign(boundingBoxElement.style, {
|
997
|
+
left: `${x}px`,
|
998
|
+
top: `${y + height}px`,
|
999
|
+
width: `${width}px`,
|
1000
|
+
height: `${height}px`
|
1001
|
+
});
|
1002
|
+
});
|
972
1003
|
applyStyle(
|
973
1004
|
boundingBoxElement,
|
974
1005
|
{
|
@@ -976,47 +1007,27 @@ function createBoundingBox(element, style, label) {
|
|
976
1007
|
position: "absolute",
|
977
1008
|
pointerEvents: "none"
|
978
1009
|
},
|
979
|
-
typeof style === "function" ? style(element) : style
|
1010
|
+
typeof style === "function" ? style(element, parseInt(label)) : style
|
980
1011
|
);
|
981
1012
|
return boundingBoxElement;
|
982
1013
|
}
|
983
|
-
function
|
1014
|
+
function positionElement(target, anchor, placement, updateCallback) {
|
984
1015
|
function updatePosition() {
|
985
|
-
|
986
|
-
|
987
|
-
placement: markPlacement
|
988
|
-
});
|
989
|
-
Object.assign(markElement.style, {
|
990
|
-
left: `${x}px`,
|
991
|
-
top: `${y}px`
|
992
|
-
});
|
1016
|
+
computePosition2(anchor, target, { placement }).then(({ x, y }) => {
|
1017
|
+
updateCallback(x, y);
|
993
1018
|
});
|
994
1019
|
}
|
995
|
-
cleanupFns.push(autoUpdate(
|
996
|
-
}
|
997
|
-
function positionBoundingBox(boundingBox, element) {
|
998
|
-
return __async(this, null, function* () {
|
999
|
-
const { width, height } = element.getBoundingClientRect();
|
1000
|
-
function updatePosition() {
|
1001
|
-
return __async(this, null, function* () {
|
1002
|
-
const { x, y } = yield computePosition2(element, boundingBox, {
|
1003
|
-
placement: "top-start"
|
1004
|
-
});
|
1005
|
-
Object.assign(boundingBox.style, {
|
1006
|
-
left: `${x}px`,
|
1007
|
-
top: `${y + height}px`,
|
1008
|
-
width: `${width}px`,
|
1009
|
-
height: `${height}px`
|
1010
|
-
});
|
1011
|
-
});
|
1012
|
-
}
|
1013
|
-
cleanupFns.push(autoUpdate(element, boundingBox, updatePosition));
|
1014
|
-
});
|
1020
|
+
cleanupFns.push(autoUpdate(anchor, target, updatePosition));
|
1015
1021
|
}
|
1016
1022
|
function applyStyle(element, defaultStyle, customStyle) {
|
1017
1023
|
Object.assign(element.style, defaultStyle, customStyle);
|
1018
1024
|
}
|
1019
1025
|
function unmark() {
|
1026
|
+
var _a;
|
1027
|
+
const markAttribute = ((_a = document.querySelector("[data-mark-label]")) == null ? void 0 : _a.getAttribute("data-mark-label")) ? "data-mark-label" : "data-webmarker-label";
|
1028
|
+
document.querySelectorAll(`[${markAttribute}]`).forEach((el) => {
|
1029
|
+
el.removeAttribute(markAttribute);
|
1030
|
+
});
|
1020
1031
|
document.querySelectorAll(".webmarker, .webmarker-bounding-box").forEach((el) => el.remove());
|
1021
1032
|
document.documentElement.removeAttribute("data-marked");
|
1022
1033
|
cleanupFns.forEach((fn) => fn());
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "webmarker-js",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.5.0",
|
4
4
|
"description": "A library for marking web pages for Set-of-Mark prompting with vision-language models.",
|
5
5
|
"source": "src/index.ts",
|
6
6
|
"main": "dist/main.js",
|
@@ -26,6 +26,7 @@
|
|
26
26
|
"@mdx-js/react": "^3.0.1",
|
27
27
|
"@next/mdx": "^14.2.3",
|
28
28
|
"@playwright/test": "^1.46.1",
|
29
|
+
"@types/jest": "^29.5.13",
|
29
30
|
"@types/mdx": "^2.0.13",
|
30
31
|
"@types/node": "^22.5.1",
|
31
32
|
"autoprefixer": "^10.4.19",
|
package/src/index.ts
CHANGED
@@ -14,7 +14,10 @@ type Placement =
|
|
14
14
|
| "left-start"
|
15
15
|
| "left-end";
|
16
16
|
|
17
|
-
type StyleFunction = (
|
17
|
+
type StyleFunction = (
|
18
|
+
element: Element,
|
19
|
+
index: number
|
20
|
+
) => Partial<CSSStyleDeclaration>;
|
18
21
|
type StyleObject = Partial<CSSStyleDeclaration>;
|
19
22
|
|
20
23
|
interface MarkOptions {
|
@@ -67,6 +70,14 @@ interface MarkOptions {
|
|
67
70
|
* @default false
|
68
71
|
*/
|
69
72
|
viewPortOnly?: boolean;
|
73
|
+
/**
|
74
|
+
* Additional class to apply to the mark elements.
|
75
|
+
*/
|
76
|
+
markClass?: string;
|
77
|
+
/**
|
78
|
+
* Additional class to apply to the bounding box elements.
|
79
|
+
*/
|
80
|
+
boundingBoxClass?: string;
|
70
81
|
}
|
71
82
|
|
72
83
|
interface MarkedElement {
|
@@ -77,68 +88,94 @@ interface MarkedElement {
|
|
77
88
|
|
78
89
|
let cleanupFns: (() => void)[] = [];
|
79
90
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
91
|
+
function mark(options: MarkOptions = {}): Record<string, MarkedElement> {
|
92
|
+
try {
|
93
|
+
const {
|
94
|
+
selector = "button, input, a, select, textarea",
|
95
|
+
getLabel = (_, index) => index.toString(),
|
96
|
+
markAttribute = "data-mark-label",
|
97
|
+
markPlacement = "top-start",
|
98
|
+
markStyle = {
|
99
|
+
backgroundColor: "red",
|
100
|
+
color: "white",
|
101
|
+
padding: "2px 4px",
|
102
|
+
fontSize: "12px",
|
103
|
+
fontWeight: "bold",
|
104
|
+
},
|
105
|
+
boundingBoxStyle = {
|
106
|
+
outline: "2px dashed red",
|
107
|
+
backgroundColor: "transparent",
|
108
|
+
},
|
109
|
+
showBoundingBoxes = true,
|
110
|
+
containerElement = document.body,
|
111
|
+
viewPortOnly = false,
|
112
|
+
markClass = "",
|
113
|
+
boundingBoxClass = "",
|
114
|
+
} = options;
|
115
|
+
|
116
|
+
const isInViewport = (el: Element) => {
|
117
|
+
const rect = el.getBoundingClientRect();
|
118
|
+
return rect.top < window.innerHeight && rect.bottom >= 0;
|
119
|
+
};
|
120
|
+
|
121
|
+
const elements = Array.from(
|
122
|
+
containerElement.querySelectorAll(selector)
|
123
|
+
).filter((el) => !viewPortOnly || isInViewport(el));
|
109
124
|
|
110
|
-
|
125
|
+
const markedElements: Record<string, MarkedElement> = {};
|
126
|
+
const fragment = document.createDocumentFragment();
|
111
127
|
|
112
|
-
|
113
|
-
elements.map(async (element, index) => {
|
128
|
+
elements.forEach((element, index) => {
|
114
129
|
const label = getLabel(element, index);
|
115
|
-
const markElement = createMark(
|
130
|
+
const markElement = createMark(
|
131
|
+
element,
|
132
|
+
index,
|
133
|
+
markStyle,
|
134
|
+
label,
|
135
|
+
markPlacement,
|
136
|
+
markClass
|
137
|
+
);
|
138
|
+
fragment.appendChild(markElement);
|
116
139
|
|
117
140
|
const boundingBoxElement = showBoundingBoxes
|
118
|
-
? createBoundingBox(element, boundingBoxStyle, label)
|
141
|
+
? createBoundingBox(element, boundingBoxStyle, label, boundingBoxClass)
|
119
142
|
: undefined;
|
143
|
+
if (boundingBoxElement) {
|
144
|
+
fragment.appendChild(boundingBoxElement);
|
145
|
+
}
|
120
146
|
|
121
147
|
markedElements[label] = { element, markElement, boundingBoxElement };
|
122
148
|
element.setAttribute(markAttribute, label);
|
123
|
-
})
|
124
|
-
);
|
149
|
+
});
|
125
150
|
|
126
|
-
|
127
|
-
|
151
|
+
document.body.appendChild(fragment);
|
152
|
+
document.documentElement.setAttribute("data-marked", "true");
|
153
|
+
return markedElements;
|
154
|
+
} catch (error) {
|
155
|
+
console.error("Error in mark function:", error);
|
156
|
+
throw error;
|
157
|
+
}
|
128
158
|
}
|
129
159
|
|
130
160
|
function createMark(
|
131
161
|
element: Element,
|
162
|
+
index: number,
|
132
163
|
style: StyleObject | StyleFunction,
|
133
164
|
label: string,
|
134
|
-
markPlacement: Placement = "top-start"
|
165
|
+
markPlacement: Placement = "top-start",
|
166
|
+
markClass: string
|
135
167
|
): HTMLElement {
|
136
168
|
const markElement = document.createElement("div");
|
137
|
-
markElement.className =
|
169
|
+
markElement.className = `webmarker ${markClass}`.trim();
|
138
170
|
markElement.id = `webmarker-${label}`;
|
139
171
|
markElement.textContent = label;
|
140
|
-
|
141
|
-
|
172
|
+
markElement.setAttribute("aria-hidden", "true");
|
173
|
+
positionElement(markElement, element, markPlacement, (x, y) => {
|
174
|
+
Object.assign(markElement.style, {
|
175
|
+
left: `${x}px`,
|
176
|
+
top: `${y}px`,
|
177
|
+
});
|
178
|
+
});
|
142
179
|
applyStyle(
|
143
180
|
markElement,
|
144
181
|
{
|
@@ -146,7 +183,7 @@ function createMark(
|
|
146
183
|
position: "absolute",
|
147
184
|
pointerEvents: "none",
|
148
185
|
},
|
149
|
-
typeof style === "function" ? style(element) : style
|
186
|
+
typeof style === "function" ? style(element, index) : style
|
150
187
|
);
|
151
188
|
return markElement;
|
152
189
|
}
|
@@ -154,13 +191,23 @@ function createMark(
|
|
154
191
|
function createBoundingBox(
|
155
192
|
element: Element,
|
156
193
|
style: StyleObject | StyleFunction,
|
157
|
-
label: string
|
194
|
+
label: string,
|
195
|
+
boundingBoxClass: string
|
158
196
|
): HTMLElement {
|
159
197
|
const boundingBoxElement = document.createElement("div");
|
160
|
-
boundingBoxElement.className =
|
198
|
+
boundingBoxElement.className =
|
199
|
+
`webmarker-bounding-box ${boundingBoxClass}`.trim();
|
161
200
|
boundingBoxElement.id = `webmarker-bounding-box-${label}`;
|
162
|
-
|
163
|
-
|
201
|
+
boundingBoxElement.setAttribute("aria-hidden", "true");
|
202
|
+
positionElement(boundingBoxElement, element, "top-start", (x, y) => {
|
203
|
+
const { width, height } = element.getBoundingClientRect();
|
204
|
+
Object.assign(boundingBoxElement.style, {
|
205
|
+
left: `${x}px`,
|
206
|
+
top: `${y + height}px`,
|
207
|
+
width: `${width}px`,
|
208
|
+
height: `${height}px`,
|
209
|
+
});
|
210
|
+
});
|
164
211
|
applyStyle(
|
165
212
|
boundingBoxElement,
|
166
213
|
{
|
@@ -168,43 +215,23 @@ function createBoundingBox(
|
|
168
215
|
position: "absolute",
|
169
216
|
pointerEvents: "none",
|
170
217
|
},
|
171
|
-
typeof style === "function" ? style(element) : style
|
218
|
+
typeof style === "function" ? style(element, parseInt(label)) : style
|
172
219
|
);
|
173
220
|
return boundingBoxElement;
|
174
221
|
}
|
175
222
|
|
176
|
-
function
|
177
|
-
|
178
|
-
|
179
|
-
|
223
|
+
function positionElement(
|
224
|
+
target: HTMLElement,
|
225
|
+
anchor: Element,
|
226
|
+
placement: Placement,
|
227
|
+
updateCallback: (x: number, y: number) => void
|
180
228
|
) {
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
});
|
185
|
-
Object.assign(markElement.style, {
|
186
|
-
left: `${x}px`,
|
187
|
-
top: `${y}px`,
|
229
|
+
function updatePosition() {
|
230
|
+
computePosition(anchor, target, { placement }).then(({ x, y }) => {
|
231
|
+
updateCallback(x, y);
|
188
232
|
});
|
189
233
|
}
|
190
|
-
|
191
|
-
cleanupFns.push(autoUpdate(element, markElement, updatePosition));
|
192
|
-
}
|
193
|
-
|
194
|
-
async function positionBoundingBox(boundingBox: HTMLElement, element: Element) {
|
195
|
-
const { width, height } = element.getBoundingClientRect();
|
196
|
-
async function updatePosition() {
|
197
|
-
const { x, y } = await computePosition(element, boundingBox, {
|
198
|
-
placement: "top-start",
|
199
|
-
});
|
200
|
-
Object.assign(boundingBox.style, {
|
201
|
-
left: `${x}px`,
|
202
|
-
top: `${y + height}px`,
|
203
|
-
width: `${width}px`,
|
204
|
-
height: `${height}px`,
|
205
|
-
});
|
206
|
-
}
|
207
|
-
cleanupFns.push(autoUpdate(element, boundingBox, updatePosition));
|
234
|
+
cleanupFns.push(autoUpdate(anchor, target, updatePosition));
|
208
235
|
}
|
209
236
|
|
210
237
|
function applyStyle(
|
@@ -216,6 +243,15 @@ function applyStyle(
|
|
216
243
|
}
|
217
244
|
|
218
245
|
function unmark(): void {
|
246
|
+
const markAttribute = document
|
247
|
+
.querySelector("[data-mark-label]")
|
248
|
+
?.getAttribute("data-mark-label")
|
249
|
+
? "data-mark-label"
|
250
|
+
: "data-webmarker-label";
|
251
|
+
|
252
|
+
document.querySelectorAll(`[${markAttribute}]`).forEach((el) => {
|
253
|
+
el.removeAttribute(markAttribute);
|
254
|
+
});
|
219
255
|
document
|
220
256
|
.querySelectorAll(".webmarker, .webmarker-bounding-box")
|
221
257
|
.forEach((el) => el.remove());
|