@@ -4,6 +4,9 @@ let data;
44let cspFallbackAttempted = 0 ;
55// track whether event listener added
66let beforeunload = 0 ;
7+ //
8+ const uid = Math . random ( ) . toString ( 36 ) . substr ( 2 , 8 ) ;
9+
710
811function sortByWeight ( o ) {
912 let sorted = { } ;
@@ -22,7 +25,9 @@ function injectCSS(filename, code) {
2225
2326function 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
227269document . addEventListener ( "securitypolicyviolation" , cspFallback ) ;
228270// create context menu items as needed
0 commit comments