/******************************************************************************* uBlock Origin - a comprehensive, efficient content blocker Copyright (C) 2019-present Raymond Hill This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see {http://www.gnu.org/licenses/}. Home: https://github.com/gorhill/uBlock The scriptlets below are meant to be injected only into a web page context. */ import { registerScriptlet } from './base.js'; import { safeSelf } from './safe-self.js'; /* eslint no-prototype-builtins: 0 */ /** * @helperScriptlet run-at.fn * * @description * Execute a function at a specific page-load milestone. * * @param fn * The function to call. * * @param when * An identifier which tells when the function should be executed. * See . * * @example * `runAt(( ) => { start(); }, 'interactive')` * * */ export function runAt(fn, when) { const intFromReadyState = state => { const targets = { 'loading': 1, 'asap': 1, 'interactive': 2, 'end': 2, '2': 2, 'complete': 3, 'idle': 3, '3': 3, }; const tokens = Array.isArray(state) ? state : [ state ]; for ( const token of tokens ) { const prop = `${token}`; if ( targets.hasOwnProperty(prop) === false ) { continue; } return targets[prop]; } return 0; }; const runAt = intFromReadyState(when); if ( intFromReadyState(document.readyState) >= runAt ) { fn(); return; } const onStateChange = ( ) => { if ( intFromReadyState(document.readyState) < runAt ) { return; } fn(); safe.removeEventListener.apply(document, args); }; const safe = safeSelf(); const args = [ 'readystatechange', onStateChange, { capture: true } ]; safe.addEventListener.apply(document, args); } registerScriptlet(runAt, { name: 'run-at.fn', dependencies: [ safeSelf, ], }); /******************************************************************************/ function runAtHtmlElementFn(fn) { if ( document.documentElement ) { fn(); return; } const observer = new MutationObserver(( ) => { observer.disconnect(); fn(); }); observer.observe(document, { childList: true }); } registerScriptlet(runAtHtmlElementFn, { name: 'run-at-html-element.fn', });