@@ -25,19 +25,23 @@ function triageJS(userscript) {
2525 if ( document . readyState !== "loading" ) {
2626 injectJS ( userscript ) ;
2727 } else {
28- document . addEventListener ( "DOMContentLoaded" , ( ) => {
29- injectJS ( userscript ) ;
30- } ) ;
28+ document . addEventListener (
29+ "DOMContentLoaded" ,
30+ ( ) => injectJS ( userscript ) ,
31+ { once : true } ,
32+ ) ;
3133 }
3234 } else if ( runAt === "document-idle" ) {
3335 if ( document . readyState === "complete" ) {
3436 injectJS ( userscript ) ;
3537 } else {
36- document . addEventListener ( "readystatechange" , ( ) => {
38+ const handle = ( ) => {
3739 if ( document . readyState === "complete" ) {
3840 injectJS ( userscript ) ;
41+ document . removeEventListener ( "readystatechange" , handle ) ;
3942 }
40- } ) ;
43+ } ;
44+ document . addEventListener ( "readystatechange" , handle ) ;
4145 }
4246 }
4347}
@@ -233,17 +237,23 @@ async function injection() {
233237}
234238
235239function listeners ( ) {
236- // listens for messages from background, popup, etc...
237- browser . runtime . onMessage . addListener ( ( request ) => {
238- const name = request . name ;
240+ /** listen for CSP violations */
241+ document . addEventListener ( "securitypolicyviolation" , cspFallback , {
242+ once : true ,
243+ } ) ;
244+ /**
245+ * listens for messages from background, popup, etc...
246+ * @type {import("webextension-polyfill").Runtime.OnMessageListener }
247+ */
248+ const handleMessage = ( message ) => {
249+ const name = message . name ;
239250 if ( name === "CONTEXT_RUN" ) {
240251 // from bg script when context-menu item is clicked
241252 // double check to ensure context-menu scripts only run in top windows
242253 if ( window !== window . top ) return ;
243-
244254 // loop through context-menu scripts saved to data object and find match
245255 // if no match found, nothing will execute and error will log
246- const filename = request . menuItemId ;
256+ const filename = message . menuItemId ;
247257 for ( let i = 0 ; i < data . files . menu . length ; i ++ ) {
248258 const item = data . files . menu [ i ] ;
249259 if ( item . scriptObject . filename === filename ) {
@@ -254,9 +264,18 @@ function listeners() {
254264 }
255265 console . error ( `Couldn't find ${ filename } code!` ) ;
256266 }
267+ } ;
268+ /** Dynamically remove listeners to avoid memory leaks */
269+ if ( document . visibilityState === "visible" ) {
270+ browser . runtime . onMessage . addListener ( handleMessage ) ;
271+ }
272+ document . addEventListener ( "visibilitychange" , ( ) => {
273+ if ( document . hidden ) {
274+ browser . runtime . onMessage . removeListener ( handleMessage ) ;
275+ } else {
276+ browser . runtime . onMessage . addListener ( handleMessage ) ;
277+ }
257278 } ) ;
258- // listen for CSP violations
259- document . addEventListener ( "securitypolicyviolation" , cspFallback ) ;
260279}
261280
262281async function initialize ( ) {
0 commit comments