tor-browser

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

window-global.js (5534B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 "use strict";
      5 
      6 const {
      7  windowGlobalTargetSpec,
      8 } = require("resource://devtools/shared/specs/targets/window-global.js");
      9 const {
     10  FrontClassWithSpec,
     11  registerFront,
     12 } = require("resource://devtools/shared/protocol.js");
     13 const {
     14  TargetMixin,
     15 } = require("resource://devtools/client/fronts/targets/target-mixin.js");
     16 
     17 class WindowGlobalTargetFront extends TargetMixin(
     18  FrontClassWithSpec(windowGlobalTargetSpec)
     19 ) {
     20  constructor(client, targetFront, parentFront) {
     21    super(client, targetFront, parentFront);
     22 
     23    // For targets which support the Watcher and configuration actor, the status
     24    // for the `javascriptEnabled` setting will be available on the configuration
     25    // front, and the target will only be used to read the initial value from older
     26    // servers.
     27    // Note: this property is marked as private but is accessed by the
     28    // TargetCommand to provide the "isJavascriptEnabled" wrapper. It should NOT be
     29    // used anywhere else.
     30    this._javascriptEnabled = null;
     31 
     32    // If this target was retrieved via NodeFront connectToFrame, keep a
     33    // reference to the parent NodeFront.
     34    this._parentNodeFront = null;
     35 
     36    this._onTabNavigated = this._onTabNavigated.bind(this);
     37    this._onFrameUpdate = this._onFrameUpdate.bind(this);
     38 
     39    this.on("tabNavigated", this._onTabNavigated);
     40    this.on("frameUpdate", this._onFrameUpdate);
     41  }
     42 
     43  form(json) {
     44    this.actorID = json.actor;
     45    this.browsingContextID = json.browsingContextID;
     46    this.innerWindowId = json.innerWindowId;
     47    this.processID = json.processID;
     48    this.isFallbackExtensionDocument = json.isFallbackExtensionDocument;
     49    this.addonId = json.addonId;
     50 
     51    // Save the full form for Target class usage.
     52    // Do not use `form` name to avoid colliding with protocol.js's `form` method
     53    this.targetForm = json;
     54 
     55    this.outerWindowID = json.outerWindowID;
     56    this.favicon = json.favicon;
     57 
     58    // Initial value for the page title and url. Since the WindowGlobalTargetActor can
     59    // be created very early, those might not represent the actual value we'd want to
     60    // display for the user (e.g. the <title> might not have been parsed yet, and the
     61    // url could still be about:blank, which is what the platform uses at the very start
     62    // of a navigation to a new location).
     63    // Those values are set again  from the targetCommand when receiving DOCUMENT_EVENT
     64    // resource, at which point both values should be in their expected form.
     65    this.setTitle(json.title);
     66    this.setUrl(json.url);
     67  }
     68 
     69  /**
     70   * Event listener for `frameUpdate` event.
     71   */
     72  _onFrameUpdate(packet) {
     73    this.emit("frame-update", packet);
     74  }
     75 
     76  /**
     77   * Event listener for `tabNavigated` event.
     78   */
     79  _onTabNavigated(packet) {
     80    const event = Object.create(null);
     81    event.url = packet.url;
     82    event.title = packet.title;
     83    event.isFrameSwitching = packet.isFrameSwitching;
     84 
     85    // Keep the title unmodified when a developer toolbox switches frame
     86    // for a tab (Bug 1261687).
     87    if (!packet.isFrameSwitching) {
     88      this.setTitle(packet.title);
     89      this.setUrl(packet.url);
     90    }
     91 
     92    // Send any stored event payload (DOMWindow or nsIRequest) for backwards
     93    // compatibility with non-remotable tools.
     94    if (packet.state == "start") {
     95      this.emit("will-navigate", event);
     96    } else {
     97      this.emit("navigate", event);
     98    }
     99  }
    100 
    101  getParentNodeFront() {
    102    return this._parentNodeFront;
    103  }
    104 
    105  setParentNodeFront(nodeFront) {
    106    this._parentNodeFront = nodeFront;
    107  }
    108 
    109  /**
    110   * Set the targetFront url.
    111   *
    112   * @param {string} url
    113   */
    114  setUrl(url) {
    115    this._url = url;
    116  }
    117 
    118  /**
    119   * Set the targetFront title.
    120   *
    121   * @param {string} title
    122   */
    123  setTitle(title) {
    124    this._title = title;
    125  }
    126 
    127  async detach() {
    128    // When calling this.destroy() at the end of this method,
    129    // we will end up calling detach again from TargetMixin.destroy.
    130    // Avoid invalid loops and do not try to resolve only once the previous call to detach
    131    // is done as it would do async infinite loop that never resolves.
    132    if (this._isDetaching) {
    133      return;
    134    }
    135    this._isDetaching = true;
    136 
    137    // Remove listeners set in constructor
    138    this.off("tabNavigated", this._onTabNavigated);
    139    this.off("frameUpdate", this._onFrameUpdate);
    140 
    141    try {
    142      await super.detach();
    143    } catch (e) {
    144      this.logDetachError(e, "browsing context");
    145    }
    146 
    147    // Detach will destroy the target actor, but the server won't emit any
    148    // target-destroyed-form in such manual, client side destruction.
    149    // So that we have to manually destroy the associated front on the client
    150    //
    151    // If detach was called by TargetFrontMixin.destroy, avoid recalling it from it
    152    // as it would do an async infinite loop which would never resolve.
    153    if (!this.isDestroyedOrBeingDestroyed()) {
    154      this.destroy();
    155    }
    156  }
    157 
    158  destroy() {
    159    const promise = super.destroy();
    160    this._parentNodeFront = null;
    161 
    162    // As detach isn't necessarily called on target's destroy
    163    // (it isn't for local tabs), ensure removing listeners set in constructor.
    164    this.off("tabNavigated", this._onTabNavigated);
    165    this.off("frameUpdate", this._onFrameUpdate);
    166 
    167    return promise;
    168  }
    169 }
    170 
    171 exports.WindowGlobalTargetFront = WindowGlobalTargetFront;
    172 registerFront(exports.WindowGlobalTargetFront);