diff --git a/assets/resources/scriptlets.js b/assets/resources/scriptlets.js index be12e54f4..9b8b5bac3 100644 --- a/assets/resources/scriptlets.js +++ b/assets/resources/scriptlets.js @@ -117,6 +117,35 @@ function shouldLog(details) { return scriptletGlobals.has('canDebug') && details.log; } +/******************************************************************************/ + +builtinScriptlets.push({ + name: 'run-at.fn', + fn: runAt, +}); +function runAt(fn, when) { + const intFromReadyState = state => { + return ({ + loading: 1, + interactive: 2, + end: 2, + complete: 3, + idle: 3, + })[`${state}`] || 0; + }; + const runAt = intFromReadyState(when); + if ( intFromReadyState(document.readyState) >= runAt ) { + fn(); return; + } + const options = { capture: true }; + const onStateChange = ( ) => { + if ( intFromReadyState(document.readyState) < runAt ) { return; } + fn(); + document.removeEventListener('readystatechange', onStateChange, options); + }; + document.addEventListener('readystatechange', onStateChange, options); +} + /******************************************************************************* Injectable scriptlets @@ -432,6 +461,7 @@ builtinScriptlets.push({ fn: addEventListenerDefuser, dependencies: [ 'pattern-to-regex.fn', + 'run-at.fn', 'safe-self.fn', 'should-debug.fn', 'should-log.fn', @@ -453,29 +483,45 @@ function addEventListenerDefuser( const rePattern = patternToRegex(pattern); const log = shouldLog(details); const debug = shouldDebug(details); - const proto = self.EventTarget.prototype; - proto.addEventListener = new Proxy(proto.addEventListener, { - apply: function(target, thisArg, args) { - let type, handler; - try { - type = String(args[0]); - handler = String(args[1]); - } catch(ex) { + const trapEddEventListeners = ( ) => { + const eventListenerHandler = { + apply: function(target, thisArg, args) { + let type, handler; + try { + type = String(args[0]); + handler = String(args[1]); + } catch(ex) { + } + const matchesType = safe.RegExp_test.call(reType, type); + const matchesHandler = safe.RegExp_test.call(rePattern, handler); + const matchesEither = matchesType || matchesHandler; + const matchesBoth = matchesType && matchesHandler; + if ( log === 1 && matchesBoth || log === 2 && matchesEither || log === 3 ) { + safe.uboLog(`addEventListener('${type}', ${handler})`); + } + if ( debug === 1 && matchesBoth || debug === 2 && matchesEither ) { + debugger; // jshint ignore:line + } + if ( matchesBoth ) { return; } + return Reflect.apply(target, thisArg, args); } - const matchesType = safe.RegExp_test.call(reType, type); - const matchesHandler = safe.RegExp_test.call(rePattern, handler); - const matchesEither = matchesType || matchesHandler; - const matchesBoth = matchesType && matchesHandler; - if ( log === 1 && matchesBoth || log === 2 && matchesEither || log === 3 ) { - safe.uboLog(`addEventListener('${type}', ${handler})`); - } - if ( debug === 1 && matchesBoth || debug === 2 && matchesEither ) { - debugger; // jshint ignore:line - } - if ( matchesBoth ) { return; } - return Reflect.apply(target, thisArg, args); - } - }); + }; + self.EventTarget.prototype.addEventListener = new Proxy( + self.EventTarget.prototype.addEventListener, + eventListenerHandler + ); + self.document.addEventListener = new Proxy( + self.document.addEventListener, + eventListenerHandler + ); + self.addEventListener = new Proxy( + self.addEventListener, + eventListenerHandler + ); + }; + runAt(( ) => { + trapEddEventListeners(); + }, details.runAt); } /******************************************************************************/ @@ -979,6 +1025,9 @@ builtinScriptlets.push({ name: 'set-constant.js', aliases: [ 'set.js' ], fn: setConstant, + dependencies: [ + 'run-at.fn', + ], }); function setConstant( arg1 = '', @@ -1144,22 +1193,9 @@ function setConstant( }; trapChain(window, chain); } - const runAt = details.runAt; - if ( runAt === 0 ) { - setConstant(chain, cValue); return; - } - const docReadyState = ( ) => { - return ({ loading: 1, interactive: 2, complete: 3, })[document.readyState] || 0; - }; - if ( docReadyState() >= runAt ) { - setConstant(chain, cValue); return; - } - const onReadyStateChange = ( ) => { - if ( docReadyState() < runAt ) { return; } + runAt(( ) => { setConstant(chain, cValue); - document.removeEventListener('readystatechange', onReadyStateChange); - }; - document.addEventListener('readystatechange', onReadyStateChange); + }, details.runAt); } /******************************************************************************/