forked from urffsamhunt/visionpair
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontentScript.js
More file actions
166 lines (147 loc) · 5.59 KB
/
Copy pathcontentScript.js
File metadata and controls
166 lines (147 loc) · 5.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// Listens for messages from the background script.
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
// Handles the request for HTML from the background script.
if (message.action === "getPageHtml") {
console.log("Background script requested HTML. Sending it now.");
sendResponse({ html: document });
parseAndSanitize(document);
return true; // Required for asynchronous responses.
}
if (message.key === "ai_result" && message.value) {
console.log(
"Received AI result wrapper - executing inner command:",
message.value // Ask the content script on that tab to send us its HTML content.
);
executeCommand(message.value);
return;
}
// Handles the commands to be executed
if (message.key) {
console.log("Received AI command to execute:", message);
executeCommand(message);
}
// this is a comment this is a prove of my read-write ability
});
// This listener triggers automatically whenever a tab finishes loading.
browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
// We only act when a page has completely loaded and has a web URL.
if (changeInfo.status === 'complete' && tab.url && tab.url.startsWith('http')) {
console.log(`Page loaded: ${tab.url}. Requesting HTML...`);
browser.tabs.sendMessage(tabId, { action: "getPageHtml" })
.then(response => {
if (response && response.html) {
handleRawHtml(response.html);
}
})
.catch(error => console.error(`Could not get HTML from content script: ${error}`));
}
});
function parseAndSanitize(dom) {
// Select all <a> elements that have an <h3> as a direct child
const nodes = dom.querySelectorAll('a:has(> h3)');
let htmlString = '';
nodes.forEach(node => {
htmlString += node.outerHTML;
});
return htmlString; // optionally return the concatenated HTML string
}
function parseAndSanitizePage(dommy) {
const nodes = dommy.querySelector(body);
let htmlString = nodes.innerHTML;
htmlString = htmlString
.replace(/<noscript[\s\S]*?<\/noscript>/gi, '')
.replace(/<script[\s\S]*?<\/script>/gi, '')
.replace(/<style[\s\S]*?<\/style>/gi, '')
.replace(/<iframe[\s\S]*?<\/iframe>/gi, '')
.replace(/<object[\s\S]*?<\/object>/gi, '')
.replace(/<embed[\s\S]*?<\/embed>/gi, '')
.replace(/<svg[\s\S]*?<\/svg>/gi, '')
.replace(/<g[\s\S]*?<\/g>/gi, '')
.replace(/<path[\s\S]*?<\/path>/gi, '')
.replace(/<header[\s\S]*?<\/header>/gi, '')
.replace(/<link[\s\S]*?>/gi, '')
.replace(/<meta[\s\S]*?>/gi, '');
body.innerHTML = htmlString;
}
//Procedure S
function executeCommand(command) {
console.log("Executing command:", command);
document.getElementById("STT").innerText = JSON.stringify(value);
const { key, value } = command;
switch (key) {
case 'click': handleClick(value); break;
case 'hover': handleHover(value); break;
case 'input': handleInput(value[0], value[1]); break;
case 'back': handleBack(value); break;
case 'forward': handleForward(value); break;
case 'search': handleSearch(value); break;
case 'bookmark': handleBookmark(); break;
default: console.error(`Unknown command key: "${key}"`);
}
}
// --- Helper Functions to Find Elements on the Page ---
function findElementByText(text) {
if (!text) return null;
const lowerCaseText = text.trim().toLowerCase();
const candidates = document.querySelectorAll(
'a, button, [role="button"], [role="link"], input[type="submit"]'
);
return Array.from(candidates).find((el) =>
el.textContent.trim().toLowerCase().includes(lowerCaseText)
);
}
function findElementForInput(labelText) {
if (!labelText) return null;
const lowerCaseLabel = labelText.trim().toLowerCase();
for (const label of document.querySelectorAll("label")) {
if (label.textContent.trim().toLowerCase().includes(lowerCaseLabel)) {
const inputId = label.getAttribute("for");
if (inputId) return document.getElementById(inputId);
return label.querySelector("input, textarea, select");
}
}
return null;
}
//Procedure Execution
function handleClick(queryParams) {
const element = findElementByText(queryParams.text);
if (element) element.click();
else
console.error(
`Could not find element to click with text: "${queryParams.text}"`
);
}
function handleHover(queryParams) {
const element = findElementByText(queryParams.text);
if (element)
element.dispatchEvent(new MouseEvent("mouseover", { bubbles: true }));
else
console.error(
`Could not find element to hover with text: "${queryParams.text}"`
);
}
function handleInput(inputValue, queryParams) {
const inputElement = findElementForInput(queryParams.text);
if (inputElement) {
inputElement.value = inputValue;
inputElement.dispatchEvent(new Event("input", { bubbles: true }));
inputElement.dispatchEvent(new Event("change", { bubbles: true }));
} else
console.error(
`Could not find input field with label: "${queryParams.text}"`
);
}
function handleBack(pages) {
history.go(-pages);
}
function handleForward(pages) {
history.go(pages);
}
function handleSearch(searchText) {
// The content script can't create tabs, so it will ask the background script to do it.
browser.runtime.sendMessage({ action: "search", query: searchText });
}
function handleBookmark() {
// The Content script can't create bookmarks, so it will ask the background script.
browser.runtime.sendMessage({ action: "addBookmark" });
}