Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add GM.getTab and GM.saveTab #296

Merged
merged 9 commits into from
Aug 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,11 @@ Userscripts currently supports the following api methods. All methods are asynch
- on success returns a promise resolved with an object indicating success
- `GM.listValues()`
- on success returns a promise resolved with an array of the key names of **presently set** values
- `GM.getTab()`
- on success returns a promise resolved with `Any` data that is persistent as long as this tab is open
- `GM.saveTab(tabObj)`
- `tabObj: Any`
- on success returns a promise resolved with an object indicating success
- `GM.openInTab(url, openInBackground)`
- `url: String`, `openInBackground: Bool`
- on success returns a promise resolved with the [tab data](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/Tab) for the tab just opened
Expand Down
82 changes: 82 additions & 0 deletions extension/Userscripts Extension/Resources/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,53 @@ const apis = {
window.postMessage({id: US_uid, name: "API_SET_CLIPBOARD", data: data, type: type});
return undefined;
},
US_getTab() {
const pid = Math.random().toString(36).substring(1, 9);
return new Promise(resolve => {
const callback = e => {
if (
e.data.pid !== pid
|| e.data.id !== US_uid
|| e.data.name !== "RESP_GET_TAB"
|| e.data.filename !== US_filename
) return;
const response = e.data.response;
resolve(response);
window.removeEventListener("message", callback);
};
window.addEventListener("message", callback);
window.postMessage({
id: US_uid,
pid: pid,
name: "API_GET_TAB",
filename: US_filename
});
});
},
US_saveTab(tab) {
const pid = Math.random().toString(36).substring(1, 9);
return new Promise(resolve => {
const callback = e => {
if (
e.data.pid !== pid
|| e.data.id !== US_uid
|| e.data.name !== "RESP_SAVE_TAB"
|| e.data.filename !== US_filename
) return;
const response = e.data.response;
resolve(response);
window.removeEventListener("message", callback);
};
window.addEventListener("message", callback);
window.postMessage({
id: US_uid,
pid: pid,
name: "API_SAVE_TAB",
filename: US_filename,
tab: tab
});
});
},
// when xhr is called it sends a message to the content script
// and adds it's own event listener to get responses from content script
// each xhr has a unique id so it won't respond to different xhr
Expand Down Expand Up @@ -405,6 +452,14 @@ function addApis({userscripts, uid, scriptHandler, scriptHandlerVersion}) {
api += `\n${apis.US_setClipboardSync}`;
api += "\nconst GM_setClipboard = US_setClipboardSync;";
break;
case "GM.getTab":
api += `\n${apis.US_getTab}`;
gmMethods.push("getTab: US_getTab");
break;
case "GM.saveTab":
api += `\n${apis.US_saveTab}`;
gmMethods.push("saveTab: US_saveTab");
break;
case "GM_xmlhttpRequest":
case "GM.xmlHttpRequest":
if (!includedMethods.includes("xhr")) {
Expand Down Expand Up @@ -713,6 +768,33 @@ browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
}
break;
}
case "API_GET_TAB": {
if (typeof sender.tab !== "undefined") {
let tab = null;
const tabData = sessionStorage.getItem(`tab-${sender.tab.id}`);
try {
// if tabData is null, can still parse it and return that
tab = JSON.parse(tabData);
} catch (error) {
console.error("failed to parse tab data for getTab");
}
sendResponse(tab);
} else {
console.error("unable to deliver tab due to empty tab id");
sendResponse(null);
}
break;
}
case "API_SAVE_TAB": {
if (typeof sender.tab !== "undefined" && request.tab) {
sessionStorage.setItem(`tab-${sender.tab.id}`, JSON.stringify(request.tab));
sendResponse({success: true});
} else {
console.error("unable to save tab due to empty tab id or bad arg");
sendResponse(null);
}
break;
}
case "USERSCRIPT_INSTALL_00":
case "USERSCRIPT_INSTALL_01":
case "USERSCRIPT_INSTALL_02": {
Expand Down
25 changes: 25 additions & 0 deletions extension/Userscripts Extension/Resources/content.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,31 @@ function handleApiMessages(e) {
window.postMessage(respMessage);
});
break;
case "API_GET_TAB":
message = {
name: name,
filename: e.data.filename,
pid: pid
};
browser.runtime.sendMessage(message, response => {
respMessage.response = response;
respMessage.filename = e.data.filename;
window.postMessage(respMessage);
});
break;
case "API_SAVE_TAB":
message = {
name: name,
filename: e.data.filename,
pid: pid,
tab: e.data.tab
};
browser.runtime.sendMessage(message, response => {
respMessage.response = response;
respMessage.filename = e.data.filename;
window.postMessage(respMessage);
});
break;
case "API_XHR_ABORT_INJ":
message = {name: "API_XHR_ABORT_CS", xhrId: e.data.xhrId};
browser.runtime.sendMessage(message);
Expand Down
4 changes: 3 additions & 1 deletion extension/Userscripts Extension/Resources/page.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion src/page/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,9 @@ export const validGrants = new Set([
"GM_addStyle",
"GM_info",
"GM_setClipboard",
"GM_xmlhttpRequest"
"GM_xmlhttpRequest",
"GM.getTab",
"GM.saveTab"
]);

export const validKeys = new Set([
Expand Down