tor-browser

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

extension-sidebar.js (6397B)


      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 
      5 "use strict";
      6 
      7 const {
      8  createElement,
      9  createFactory,
     10 } = require("resource://devtools/client/shared/vendor/react.mjs");
     11 const EventEmitter = require("resource://devtools/shared/event-emitter.js");
     12 const {
     13  Provider,
     14 } = require("resource://devtools/client/shared/vendor/react-redux.js");
     15 
     16 const extensionsSidebarReducer = require("resource://devtools/client/inspector/extensions/reducers/sidebar.js");
     17 const {
     18  default: objectInspectorReducer,
     19 } = require("resource://devtools/client/shared/components/object-inspector/reducer.js");
     20 
     21 const {
     22  updateExtensionPage,
     23  updateObjectTreeView,
     24  updateExpressionResultView,
     25  removeExtensionSidebar,
     26 } = require("resource://devtools/client/inspector/extensions/actions/sidebar.js");
     27 
     28 /**
     29 * ExtensionSidebar instances represents Inspector sidebars installed by add-ons
     30 * using the devtools.panels.elements.createSidebarPane WebExtensions API.
     31 *
     32 * The WebExtensions API registers the extensions' sidebars on the toolbox instance
     33 * (using the registerInspectorExtensionSidebar method) and, once the Inspector has been
     34 * created, the toolbox uses the Inpector createExtensionSidebar method to create the
     35 * ExtensionSidebar instances and then it registers them to the Inspector.
     36 *
     37 * @param {Inspector} inspector
     38 *        The inspector where the sidebar should be hooked to.
     39 * @param {object} options
     40 * @param {string} options.id
     41 *        The unique id of the sidebar.
     42 * @param {string} options.title
     43 *        The title of the sidebar.
     44 */
     45 class ExtensionSidebar {
     46  constructor(inspector, { id, title }) {
     47    EventEmitter.decorate(this);
     48    this.inspector = inspector;
     49    this.store = inspector.store;
     50    this.id = id;
     51    this.title = title;
     52    this.destroyed = false;
     53 
     54    this.store.injectReducer("extensionsSidebar", extensionsSidebarReducer);
     55    this.store.injectReducer("objectInspector", objectInspectorReducer);
     56  }
     57 
     58  /**
     59   * Lazily create a React ExtensionSidebarComponent wrapped into a Redux Provider.
     60   */
     61  get provider() {
     62    if (!this._provider) {
     63      // Load the ExtensionSidebar component via the Browser Loader as it ultimately loads Reps and Object Inspector,
     64      // which are expected to be loaded in a document scope.
     65      const ExtensionSidebarComponent = createFactory(
     66        this.inspector.browserRequire(
     67          "resource://devtools/client/inspector/extensions/components/ExtensionSidebar.js"
     68        )
     69      );
     70      this._provider = createElement(
     71        Provider,
     72        {
     73          store: this.store,
     74          key: this.id,
     75          title: this.title,
     76        },
     77        ExtensionSidebarComponent({
     78          id: this.id,
     79          onExtensionPageMount: containerEl => {
     80            this.emit("extension-page-mount", containerEl);
     81          },
     82          onExtensionPageUnmount: containerEl => {
     83            this.emit("extension-page-unmount", containerEl);
     84          },
     85          serviceContainer: {
     86            highlightDomElement: async (grip, options = {}) => {
     87              const nodeFront =
     88                await this.inspector.inspectorFront.getNodeFrontFromNodeGrip(
     89                  grip
     90                );
     91              return this.inspector.highlighters.showHighlighterTypeForNode(
     92                this.inspector.highlighters.TYPES.BOXMODEL,
     93                nodeFront,
     94                options
     95              );
     96            },
     97            unHighlightDomElement: async () => {
     98              return this.inspector.highlighters.hideHighlighterType(
     99                this.inspector.highlighters.TYPES.BOXMODEL
    100              );
    101            },
    102            openNodeInInspector: async grip => {
    103              const nodeFront =
    104                await this.inspector.inspectorFront.getNodeFrontFromNodeGrip(
    105                  grip
    106                );
    107              const onInspectorUpdated =
    108                this.inspector.once("inspector-updated");
    109              const onNodeFrontSet =
    110                this.inspector.toolbox.selection.setNodeFront(nodeFront, {
    111                  reason: "inspector-extension-sidebar",
    112                });
    113 
    114              return Promise.all([onNodeFrontSet, onInspectorUpdated]);
    115            },
    116          },
    117        })
    118      );
    119    }
    120 
    121    return this._provider;
    122  }
    123 
    124  /**
    125   * Destroy the ExtensionSidebar instance, dispatch a removeExtensionSidebar Redux action
    126   * (which removes the related state from the Inspector store) and clear any reference
    127   * to the inspector, the Redux store and the lazily created Redux Provider component.
    128   *
    129   * This method is called by the inspector when the ExtensionSidebar is being removed
    130   * (or when the inspector is being destroyed).
    131   */
    132  destroy() {
    133    if (this.destroyed) {
    134      throw new Error(
    135        `ExtensionSidebar instances cannot be destroyed more than once`
    136      );
    137    }
    138 
    139    // Remove the data related to this extension from the inspector store.
    140    this.store.dispatch(removeExtensionSidebar(this.id));
    141 
    142    this.inspector = null;
    143    this.store = null;
    144    this._provider = null;
    145 
    146    this.destroyed = true;
    147  }
    148 
    149  /**
    150   * Dispatch an objectTreeView action to change the SidebarComponent into an
    151   * ObjectTreeView React Component, which shows the passed javascript object
    152   * in the sidebar.
    153   */
    154  setObject(object) {
    155    if (this.removed) {
    156      throw new Error(
    157        "Unable to set an object preview on a removed ExtensionSidebar"
    158      );
    159    }
    160 
    161    this.store.dispatch(updateObjectTreeView(this.id, object));
    162  }
    163 
    164  /**
    165   * Dispatch an objectPreview action to change the SidebarComponent into an
    166   * ObjectPreview React Component, which shows the passed value grip
    167   * in the sidebar.
    168   */
    169  setExpressionResult(expressionResult, rootTitle) {
    170    if (this.removed) {
    171      throw new Error(
    172        "Unable to set an object preview on a removed ExtensionSidebar"
    173      );
    174    }
    175 
    176    this.store.dispatch(
    177      updateExpressionResultView(this.id, expressionResult, rootTitle)
    178    );
    179  }
    180 
    181  setExtensionPage(iframeURL) {
    182    if (this.removed) {
    183      throw new Error(
    184        "Unable to set an object preview on a removed ExtensionSidebar"
    185      );
    186    }
    187 
    188    this.store.dispatch(updateExtensionPage(this.id, iframeURL));
    189  }
    190 }
    191 
    192 module.exports = ExtensionSidebar;