This commit is contained in:
Yao Liu
2025-01-22 11:32:35 -08:00
parent dac181a456
commit 4b8dbfd9c5
298 changed files with 56437 additions and 9 deletions

View File

@@ -0,0 +1,43 @@
import os
from pathlib import Path
rootdir = Path(__file__).parent
# marker, gpt-4v-act style
with open(os.path.join(rootdir, 'local_marker.js'), 'r') as f:
local_marker_script = f.read()
with open(os.path.join(rootdir, 'mix_marker.js'), 'r') as f:
mix_marker_script = f.read()
with open(os.path.join(rootdir, 'get_data.js'), 'r') as f:
get_rect_script = f.read()
# canva handler
with open(os.path.join(rootdir, 'canva_handler.js'), 'r') as f:
canva_handler_script = f.read()
# draw label on page
with open(os.path.join(rootdir, 'label_marker.js'), 'r') as f:
label_marker_script = f.read()
# get text from page
with open(os.path.join(rootdir, 'get_text.js'), 'r') as f:
get_text_script = f.read()
# remove label draw on page
remove_label_mark_script = """
() => {
document.querySelectorAll(".our-dom-marker").forEach(item => {
document.body.removeChild(item);
});
}
"""
remove_id_script = """
() => {
Array.from(document.getElementsByClassName('possible-clickable-element')).forEach((element) => {
element.classList.remove('possible-clickable-element');
element.removeAttribute('data-testid');
});
}
"""

View File

@@ -0,0 +1,44 @@
() => {
var items = Array.prototype.slice.call(
document.querySelectorAll("canvas")
);
var vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
var vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0);
items = items.map(element => {
// var img = element.toDataURL("image/png");
var bb = element.getClientRects();
var rect = {
left: -1,
top: -1,
right: -1,
bottom: -1,
width: 0,
height: 0,
};
if (bb.length > 0) {
bb = bb[0];
rect = {
left: Math.max(0, bb.left),
top: Math.max(0, bb.top),
right: Math.min(vw, bb.right),
bottom: Math.min(vh, bb.bottom)
};
rect = {
...rect,
width: rect.right - rect.left,
height: rect.bottom - rect.top
};
}
return {
rects: rect,
tag: element.tagName.toLowerCase?.() || "",
text: element.textContent.trim().replace(/\s{2,}/g, ' '),
// img: img
};
});
return items;
}

View File

@@ -0,0 +1,73 @@
(packet) => {
function int2str(index) {
var str = "";
while (index >= 0) {
str = String.fromCharCode(65 + index % 26) + str;
index = Math.floor(index / 26) - 1;
}
return str;
};
selector = packet.selector
index = packet.startIndex
var items = Array.prototype.slice.call(
document.querySelectorAll(selector)
);
var vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
var vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0);
items = items.filter(
x => !items.some(y => x.contains(y) && !(x == y))
).map(element => {
var bb = element.getClientRects();
var rect = {
left: 0,
top: 0,
right: 0,
bottom: 0,
width: 0,
height: 0
};
var keep = false;
var text = "", id = -1;
if (bb.length > 0) {
bb = bb[0];
rect = {
left: Math.max(0, bb.left),
top: Math.max(0, bb.top),
right: Math.min(vw, bb.right),
bottom: Math.min(vh, bb.bottom)
};
rect = {
...rect,
width: rect.right - rect.left,
height: rect.bottom - rect.top
};
if (rect.width > 0 || rect.height > 0) {
keep = true;
if (index >= 0) {
id = int2str(index++);
element.setAttribute("data-testid", id);
}
var childNodes = element.childNodes;
for (var i = 0; i < childNodes.length; i++) {
if (childNodes[i].nodeType == Node.TEXT_NODE) {
text += childNodes[i].textContent;
}
}
}
}
return {
keep: true,
id,
rects: rect,
tag: element.tagName.toLowerCase?.() || "",
text,//: element.innerText?.trim().replace(/\s{2,}/g, " ") || ""
};
}).filter(x => x.keep);
return [items, index];
}

View File

@@ -0,0 +1,48 @@
() => {
var items = Array.prototype.slice.call(
document.querySelectorAll("*")
);
var vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
var vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0);
const ignoreTags = ["script", "html"];
items = items.map(element => {
const tag = element.tagName.toLowerCase?.() || "";
var bb = element.getClientRects();
var keep = false;
var text = '';
const domId = element.getAttribute('data-testid');
var id = domId? parseInt(domId): "-";
if (bb.length > 0) {
bb = bb[0];
var width = Math.min(vw, bb.right) - Math.max(0, bb.left);
var height = Math.min(vh, bb.bottom) - Math.max(0, bb.top);
if (width > 0 && height > 0) {
keep = true;
var childNodes = element.childNodes;
for (var i = 0; i < childNodes.length; i++) {
if (childNodes[i].nodeType == Node.TEXT_NODE) {
text += childNodes[i].textContent;
}
}
}
}
text = text.trim().replace(/\s{2,}/g, ' ');
if (ignoreTags.includes(tag)) keep = false;
if (id == "-" && text.length == 0) keep = false;
return {
keep,
tag,
id,
text, //:element.innerText?.trim().replace(/\s{2,}/g, " ") || ""
};
}).filter(x => x.keep);
return items;
}

View File

@@ -0,0 +1,65 @@
(items) => {
function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
items.filter(
item => item.id != ""
).forEach((item) => {
const bbox = item.rects;
const id_string = `dom-marker-id-${index}`;
index = item.id;
outerElement = document.createElement("div");
outerElement.classList.add("our-dom-marker");
// var borderColor = getRandomColor();
var borderColor = "#FFFF00";
outerElement.style.outline = `2px dashed ${borderColor}`;
outerElement.style.position = "fixed";
outerElement.style.left = bbox.left - 2 + "px";
outerElement.style.top = bbox.top - 2 + "px";
outerElement.style.width = bbox.width + 4 + "px";
outerElement.style.height = bbox.height + 4 + "px";
outerElement.style.pointerEvents = "none";
outerElement.style.boxSizing = "border-box";
outerElement.style.zIndex = 2147483647;
innerElement = document.createElement("div");
innerElement.classList.add("our-dom-marker");
innerElement.style.outline = `2px dashed #222288`;
innerElement.style.position = "fixed";
innerElement.style.left = bbox.left + "px";
innerElement.style.top = bbox.top + "px";
innerElement.style.width = bbox.width + "px";
innerElement.style.height = bbox.height + "px";
innerElement.style.pointerEvents = "none";
innerElement.style.boxSizing = "border-box";
innerElement.style.zIndex = 2147483647;
// Add floating label at the corner
var label = document.createElement("span");
var topPosition = 25;
if (bbox.top < 25) topPosition = bbox.top;
label.textContent = index;
label.style.position = "absolute";
label.style.top = `-${topPosition}px`;
label.style.left = "0px";
label.style.background = borderColor;
label.style.color = "black";
label.style.padding = "2px 4px";
label.style.fontSize = "16px";
label.style.borderRadius = "2px";
label.style.fontWeight = "bold";
outerElement.appendChild(label);
document.body.appendChild(outerElement);
document.body.appendChild(innerElement);
})
return items;
}

View File

@@ -0,0 +1,46 @@
() => {
var items = Array.prototype.slice.call(
document.querySelectorAll('*')
).map((element) => {
var vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
var vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0);
var rects = [...element.getClientRects()].filter(bb => {
var center_x = bb.left + bb.width / 2;
var center_y = bb.top + bb.height / 2;
var elAtCenter = document.elementFromPoint(center_x, center_y);
return elAtCenter === element || element.contains(elAtCenter)
}).map(bb => {
const rect = {
left: Math.max(0, bb.left),
top: Math.max(0, bb.top),
right: Math.min(vw, bb.right),
bottom: Math.min(vh, bb.bottom)
};
return {
...rect,
width: rect.right - rect.left,
height: rect.bottom - rect.top
}
});
var area = rects.reduce((acc, rect) => acc + rect.width * rect.height, 0);
return {
element: element,
include: window.getComputedStyle(element).cursor == "pointer",
area,
rects,
text: element.textContent.trim().replace(/\s{2,}/g, ' '),
};
}).filter(item =>
item.include && (item.area >= 20)
)
items = items.filter(x => !items.some(y => x.element.contains(y.element) && !(x == y)))
items.forEach(item => {
item.element.classList.add('possible-clickable-element');
});
}

View File

@@ -0,0 +1,148 @@
() => {
var items = Array.prototype.slice.call(
document.querySelectorAll('*')
).map(function(element) {
var vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
var vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0);
var rects = [...element.getClientRects()].filter(bb => {
var center_x = bb.left + bb.width / 2;
var center_y = bb.top + bb.height / 2;
var elAtCenter = document.elementFromPoint(center_x, center_y);
if (!elAtCenter) return false;
return elAtCenter === element || element.contains(elAtCenter)
}).map(bb => {
const rect = {
left: Math.max(0, bb.left),
top: Math.max(0, bb.top),
right: Math.min(vw, bb.right),
bottom: Math.min(vh, bb.bottom)
};
return {
...rect,
width: rect.right - rect.left,
height: rect.bottom - rect.top
}
});
// var rects = [];
var area = rects.reduce((acc, rect) => acc + rect.width * rect.height, 0);
const tagName = element.tagName.toLowerCase?.() || "";
let isClickable = ((element.onclick != null) || window.getComputedStyle(element).cursor == "pointer");
// Insert area elements that provide click functionality to an img.
if (tagName === "img") {
let mapName = element.getAttribute("usemap");
if (mapName) {
const imgClientRects = element.getClientRects();
mapName = mapName.replace(/^#/, "").replace('"', '\\"');
const map = document.querySelector(`map[name=\"${mapName}\"]`);
if (map && (imgClientRects.length > 0)) isClickable = true;
}
}
if (!isClickable) {
const role = element.getAttribute("role");
const clickableRoles = [
"button",
"tab",
"link",
"checkbox",
"menuitem",
"menuitemcheckbox",
"menuitemradio",
"radio",
];
if (role != null && clickableRoles.includes(role.toLowerCase())) {
isClickable = true;
} else {
const contentEditable = element.getAttribute("contentEditable");
if (
contentEditable != null &&
["", "contenteditable", "true"].includes(contentEditable.toLowerCase())
) {
isClickable = true;
}
}
}
// Check for jsaction event listeners on the element.
if (!isClickable && element.hasAttribute("jsaction")) {
const jsactionRules = element.getAttribute("jsaction").split(";");
for (let jsactionRule of jsactionRules) {
const ruleSplit = jsactionRule.trim().split(":");
if ((ruleSplit.length >= 1) && (ruleSplit.length <= 2)) {
const [eventType, namespace, actionName] = ruleSplit.length === 1
? ["click", ...ruleSplit[0].trim().split("."), "_"]
: [ruleSplit[0], ...ruleSplit[1].trim().split("."), "_"];
if (!isClickable) {
isClickable = (eventType === "click") && (namespace !== "none") && (actionName !== "_");
}
}
}
}
if (!isClickable) {
const clickableTags = [
"input",
"textarea",
"select",
"button",
"a",
"iframe",
"video",
"object",
"embed",
"details"
];
isClickable = clickableTags.includes(tagName);
}
if (!isClickable) {
if (tagName === "label")
isClickable = (element.control != null) && !element.control.disabled;
else if (tagName === "img")
isClickable = ["zoom-in", "zoom-out"].includes(element.style.cursor);
}
// An element with a class name containing the text "button" might be clickable. However, real
// clickables are often wrapped in elements with such class names. So, when we find clickables
// based only on their class name, we mark them as unreliable.
const className = element.getAttribute("class");
if (!isClickable && className && className.toLowerCase().includes("button")) {
isClickable = true;
}
// Elements with tabindex are sometimes useful, but usually not. We can treat them as second
// class citizens when it improves UX, so take special note of them.
const tabIndexValue = element.getAttribute("tabindex");
const tabIndex = tabIndexValue ? parseInt(tabIndexValue) : -1;
if (!isClickable && !(tabIndex < 0) && !isNaN(tabIndex)) {
isClickable = true;
}
const idValue = element.getAttribute("id");
const id = idValue ? idValue.toLowerCase() : "";
if (isClickable && area == 0) {
const textValue = element.textContent.trim().replace(/\s{2,}/g, ' ');
clickable_msg = `${tagName}[id=${id}] ${isClickable} (${area}) ${textValue}`
}
return {
element: element,
include: isClickable,
area,
rects,
text: element.textContent.trim().replace(/\s{2,}/g, ' ')
};
}).filter(item =>
item.include && (item.area >= 1)
);
items = items.filter(x => !items.some(y => x.element.contains(y.element) && !(x == y)))
items.forEach(item => {
item.element.classList.add('possible-clickable-element');
});
}