tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

executor-window.js (2638B)


      1 // Functions available by default in the executor.
      2 
      3 'use strict';
      4 
      5 let executorStartEvent = null;
      6 
      7 function requestExecutor(uuid, startOn) {
      8  if (startOn) {
      9    addEventListener(startOn, (e) => {
     10      executorStartEvent = e;
     11      startExecutor(uuid);
     12    });
     13  } else {
     14    startExecutor(uuid);
     15  }
     16 }
     17 
     18 function addScript(url) {
     19  const script = document.createElement('script');
     20  script.src = url;
     21  const promise = new Promise((resolve, reject) => {
     22    script.onload = () => resolve(url);
     23    script.onerror = (e) => reject(e);
     24  });
     25  document.body.appendChild(script);
     26  return promise;
     27 }
     28 
     29 /**
     30 * Suspends the executor and executes the function in `fnString` when it has
     31 * suspended. Installs a pageshow handler to resume the executor if the
     32 * document is BFCached. Installs a hashchange handler to detect when the
     33 * navigation did not change documents.
     34 *
     35 * This returns nothing because fn is invoke after waiting for the document to
     36 * be suspended. If we were to return a promise, the executor could not suspend
     37 * until that promise resolved but the promise cannot resolve until the executor
     38 * is suspended. This could be avoided by adding support
     39 * directly in the dispatcher for tasks suspend immediately after execution.
     40 *
     41 * @param {string} fnString A stringified function to be executed.
     42 * @param {any[]} args The arguments to pass to the function.
     43 */
     44 function executeScriptToNavigate(fnString, args) {
     45  // Only one of these listeners should run.
     46  const controller = new AbortController();
     47  window.addEventListener('pageshow', (event) => {
     48    controller.abort();
     49    executor.resume();
     50  }, {signal: controller.signal, once: true});
     51  window.addEventListener('hashchange', (event) => {
     52    controller.abort();
     53    const oldURLObject = new URL(event.oldURL);
     54    const newURLObject = new URL(event.newURL);
     55    oldURLObject.hash = '';
     56    newURLObject.hash = '';
     57    // If only the hash-fragment changed then the navigation was
     58    // same-document and we should resume the executor.
     59    if (oldURLObject.toString() == newURLObject.toString()) {
     60      executor.resume();
     61    }
     62  }, {signal: controller.signal, once: true});
     63 
     64  executor.suspend(() => {
     65    eval(fnString).apply(null, args);
     66  });
     67 }
     68 
     69 // If a frameset element exists in the document, return the first one. Otherwise
     70 // create a new one and return that.
     71 function findOrCreateFrameset() {
     72  const framesets = document.getElementsByTagName('frameset');
     73  if (framesets.length > 0) {
     74    return framesets[0];
     75  }
     76  const frameset = document.createElement('frameset');
     77  frameset.cols = '100%';
     78  document.body.append(frameset);
     79  return frameset;
     80 }