Skip to content

Commit 97f46e0

Browse files
committed
custom api for openInTab and closeTab, quoid#113 quoid#134
1 parent b09863c commit 97f46e0

2 files changed

Lines changed: 51 additions & 1 deletion

File tree

extension/Userscripts Extension/Resources/background.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
6666
contextMenuItems = contextMenuItems.filter(a => a != menuItemId);
6767
purgeContextMenus();
6868
});
69+
} else if (request.name === "API_OPEN_TAB") {
70+
const active = (request.active == true) ? true : false;
71+
browser.tabs.create({active: active, index: sender.tab.index + 1, url: request.url}, response => {
72+
sendResponse(response);
73+
});
74+
return true;
75+
} else if (request.name === "API_CLOSE_TAB") {
76+
browser.tabs.remove(sender.tab.id, response => {/* */});
6977
}
7078
});
7179

extension/Userscripts Extension/Resources/content.js

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ let data;
44
let cspFallbackAttempted = 0;
55
// track whether event listener added
66
let beforeunload = 0;
7+
//
8+
const uid = Math.random().toString(36).substr(2, 8);
9+
710

811
function sortByWeight(o) {
912
let sorted = {};
@@ -22,7 +25,9 @@ function injectCSS(filename, code) {
2225

2326
function injectJS(filename, code, scope) {
2427
console.info(`Injecting ${filename}`);
25-
code = "(function() {\n" + code + "\n//# sourceURL=" + filename.replace(/\s/g, "-") + "\n})();";
28+
// include api methods
29+
const api = `const uid = "${uid}";\n${openInTab}\n${closeTab}\n${GM}`;
30+
code = `(function() {\n${api}\n${code}\n//# sourceURL=${filename.replace(/\s/g, "-")}\n})();`;
2631
if (scope != "content") {
2732
const tag = document.createElement("script");
2833
tag.textContent = code;
@@ -223,6 +228,43 @@ browser.runtime.onMessage.addListener(request => {
223228
}
224229
});
225230

231+
// api - https://developer.chrome.com/docs/extensions/mv3/content_scripts/#host-page-communication
232+
function openInTab(url, openInBackground) {
233+
return new Promise(resolve => {
234+
const callback = e => {
235+
if (e.data.id != uid || e.data.name !== "RESP_OPEN_TAB") return;
236+
resolve(e.data.response);
237+
window.removeEventListener("message", callback);
238+
};
239+
window.addEventListener("message", callback);
240+
const active = (openInBackground === true) ? false : true;
241+
window.postMessage({id: uid, name: "API_OPEN_TAB", url: url, active: active});
242+
});
243+
}
244+
245+
function closeTab() {
246+
window.postMessage({id: uid, name: "API_CLOSE_TAB"});
247+
}
248+
249+
// create api aliases
250+
const GM = "const GM = {openInTab: openInTab}";
251+
252+
window.addEventListener("message", e => {
253+
// only respond to messages that have matching unique id and have a name value
254+
if (e.data.id != uid || !e.data.name) return;
255+
let message;
256+
if (e.data.name === "API_OPEN_TAB") {
257+
// ignore requests that don't supply a url
258+
if (!e.data.url) return;
259+
message = {name: "API_OPEN_TAB", url: e.data.url, active: e.data.active};
260+
browser.runtime.sendMessage(message, response => {
261+
window.postMessage({id: uid, name: "RESP_OPEN_TAB", response: response});
262+
});
263+
} else if (e.data.name === "API_CLOSE_TAB") {
264+
browser.runtime.sendMessage({name: "API_CLOSE_TAB"}, response => {/* */});
265+
}
266+
});
267+
226268
// when userscript fails due to a CSP and has @inject-into value of auto
227269
document.addEventListener("securitypolicyviolation", cspFallback);
228270
// create context menu items as needed

0 commit comments

Comments
 (0)