Skip to content

Instantly share code, notes, and snippets.

@codehag
Last active August 7, 2019 16:29

Revisions

  1. codehag revised this gist Aug 7, 2019. 1 changed file with 6 additions and 6 deletions.
    12 changes: 6 additions & 6 deletions tabdescriptorfront.js
    Original file line number Diff line number Diff line change
    @@ -26,11 +26,11 @@ class TabDescriptorFront extends FrontClassWithSpec(descriptorSpec) {
    * Teardown event listeners.
    */
    teardownListeners() {
    if (tab.ownerDocument.defaultView) {
    tab.ownerDocument.defaultView.removeEventListener("unload", handleEvent);
    if (this.tab.ownerDocument.defaultView) {
    this.tab.ownerDocument.defaultView.removeEventListener("unload", handleEvent);
    }
    tab.removeEventListener("TabClose", handleEvent);
    tab.removeEventListener("TabRemotenessChange", handleEvent);
    this.tab.removeEventListener("TabClose", handleEvent);
    this.tab.removeEventListener("TabRemotenessChange", handleEvent);
    }

    /**
    @@ -42,10 +42,10 @@ class TabDescriptorFront extends FrontClassWithSpec(descriptorSpec) {
    this.destroy();
    break;
    case "unload":
    target.destroy();
    this._target.destroy();
    break;
    case "TabRemotenessChange":
    onRemotenessChange();
    this.onRemotenessChange();
    break;
    }
    }
  2. codehag revised this gist Aug 7, 2019. No changes.
  3. codehag revised this gist Aug 7, 2019. 4 changed files with 82 additions and 84 deletions.
    34 changes: 34 additions & 0 deletions tabdescriptoractor.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,34 @@
    // TabDescriptorActor
    const TabDescriptorActor = ActorClassWithSpec(descriptorSpec, {
    initialize(connection, options = {}) {
    Actor.prototype.initialize.call(this, connection);
    this.tabList = options.tabList;
    this.destroy = this.destroy.bind(this);
    },

    async getTarget() {
    const tabList = this.tabList;
    if (!tabList) {
    return {
    error: "noTabs",
    message: "This root actor has no browser tabs.",
    };
    }
    let targetActor;
    try {
    targetActor = await tabList.getTab(options, { forceUnzombify: true });
    } catch (error) {
    if (error.error) {
    // Pipe expected errors as-is to the client
    return error;
    }
    return {
    error: "noTab",
    message: "Unexpected error while calling getTab(): " + error,
    };
    }
    targetActor.parentID = this.actorID;
    this.manage(targetActor);
    return { tab: targetActor.form() };
    },
    });
    85 changes: 1 addition & 84 deletions tabdescriptor.js → tabdescriptorfront.js
    Original file line number Diff line number Diff line change
    @@ -96,87 +96,4 @@ class TabDescriptorFront extends FrontClassWithSpec(descriptorSpec) {
    this.emit("destroy");
    super.destroy();
    }
    }

    // TabDescriptorActor
    const TabDescriptorActor = ActorClassWithSpec(descriptorSpec, {
    initialize(connection, options = {}) {
    Actor.prototype.initialize.call(this, connection);
    this.tabList = options.tabList;
    this.destroy = this.destroy.bind(this);
    },

    async getTarget() {
    const tabList = this.tabList;
    if (!tabList) {
    return {
    error: "noTabs",
    message: "This root actor has no browser tabs.",
    };
    }
    let targetActor;
    try {
    targetActor = await tabList.getTab(options, { forceUnzombify: true });
    } catch (error) {
    if (error.error) {
    // Pipe expected errors as-is to the client
    return error;
    }
    return {
    error: "noTab",
    message: "Unexpected error while calling getTab(): " + error,
    };
    }
    targetActor.parentID = this.actorID;
    this.manage(targetActor);
    return { tab: targetActor.form() };
    },
    });

    // changes in forTab:
    //
    forTab: async function(tab) {
    let target = targets.get(tab);
    if (target) {
    return target;
    }
    const promise = this.createTargetForTab(tab);
    // Immediately set the target's promise in cache to prevent race
    targets.set(tab, promise);
    target = await promise;
    // Then replace the promise with the target object
    targets.set(tab, target);
    target.attachTab(tab);
    target.once("close", () => {
    targets.delete(tab);
    });
    return target;
    },

    // changes in toolbox instantiation
    function Toolbox(
    targetDescriptor, // pass a top level target descriptor
    selectedTool,
    hostType,
    contentWindow,
    frameId,
    msSinceProcessStart
    ) {
    //...
    this.init();
    }

    Toolbox.prototype = {
    // ...
    get target() {
    return this._targetDescriptor._target;
    }
    init: function() {
    await this._targetDescriptor.getTarget();
    this.target.on(//...
    // etc.
    this._targetDescriptor.on("switch-target", //.. do something
    this._targetDescriptor.on("destroy", this.destroy) // or something, the descriptor representing the top level target has been destroyed
    }
    }

    }
    20 changes: 20 additions & 0 deletions targetfactory-fortab.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,20 @@

    // changes in forTab:
    //
    forTab: async function(tab) {
    let target = targets.get(tab);
    if (target) {
    return target;
    }
    const promise = this.createTargetForTab(tab);
    // Immediately set the target's promise in cache to prevent race
    targets.set(tab, promise);
    target = await promise;
    // Then replace the promise with the target object
    targets.set(tab, target);
    target.attachTab(tab);
    target.once("close", () => {
    targets.delete(tab);
    });
    return target;
    },
    27 changes: 27 additions & 0 deletions toolbox-changes.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,27 @@
    // changes in toolbox instantiation
    function Toolbox(
    targetDescriptor, // pass a top level target descriptor
    selectedTool,
    hostType,
    contentWindow,
    frameId,
    msSinceProcessStart
    ) {
    //...
    this.init();
    }

    Toolbox.prototype = {
    // ...
    get target() {
    return this._targetDescriptor._target;
    }
    init: function() {
    await this._targetDescriptor.getTarget();
    this.target.on(//...
    // etc.
    this._targetDescriptor.on("switch-target", //.. do something
    this._targetDescriptor.on("destroy", this.destroy) // or something, the descriptor representing the top level target has been destroyed
    }
    }

  4. codehag created this gist Aug 7, 2019.
    182 changes: 182 additions & 0 deletions tabdescriptor.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,182 @@
    // TabDescriptorFront
    class TabDescriptorFront extends FrontClassWithSpec(descriptorSpec) {
    constructor(client) {
    super(client)
    }

    attachTab(tab) {
    this._tab = tab;
    this.setupListeners();
    }

    get tab() {
    return this.tab;
    }

    /**
    * Listen to the different events.
    */
    setupListeners() {
    this.tab.addEventListener("TabClose", handleEvent);
    this.tab.ownerDocument.defaultView.addEventListener("unload", handleEvent);
    this.tab.addEventListener("TabRemotenessChange", handleEvent);
    }

    /**
    * Teardown event listeners.
    */
    teardownListeners() {
    if (tab.ownerDocument.defaultView) {
    tab.ownerDocument.defaultView.removeEventListener("unload", handleEvent);
    }
    tab.removeEventListener("TabClose", handleEvent);
    tab.removeEventListener("TabRemotenessChange", handleEvent);
    }

    /**
    * Handle tabs events.
    */
    handleEvent(event) {
    switch (event.type) {
    case "TabClose":
    this.destroy();
    break;
    case "unload":
    target.destroy();
    break;
    case "TabRemotenessChange":
    onRemotenessChange();
    break;
    }
    }

    /**
    * Automatically respawn the toolbox when the tab changes between being
    * loaded within the parent process and loaded from a content process.
    * Process change can go in both ways.
    */
    async onRemotenessChange() {
    // Responsive design do a crazy dance around tabs and triggers
    // remotenesschange events. But we should ignore them as at the end
    // the content doesn't change its remoteness.
    if (tab.isResponsiveDesignMode) {
    return;
    }
    await this._target.destroy();
    this.getTarget();
    this.emit("switch-target");
    }

    getTarget() {
    if (this._target) {
    return this._target;
    }
    if (this._targetPromise) {
    return this._targetPromise;
    }
    this._targetPromise = (async () => {
    try {
    const from = await super.getTarget();
    this._target = new BrowsingContextTargetFront(this.conn);
    this._target.form(form);
    this.manage(this._target);
    this._targetPromise = null;
    return this._target;
    } catch (e) {
    throw new Error(`Could not connect to tab target: ${e}`);
    }
    })();
    }

    destroy() {
    this.tearDownListeners();
    this._tab = null;
    this._target = null;
    this._targetPromise = null;
    this.emit("destroy");
    super.destroy();
    }
    }

    // TabDescriptorActor
    const TabDescriptorActor = ActorClassWithSpec(descriptorSpec, {
    initialize(connection, options = {}) {
    Actor.prototype.initialize.call(this, connection);
    this.tabList = options.tabList;
    this.destroy = this.destroy.bind(this);
    },

    async getTarget() {
    const tabList = this.tabList;
    if (!tabList) {
    return {
    error: "noTabs",
    message: "This root actor has no browser tabs.",
    };
    }
    let targetActor;
    try {
    targetActor = await tabList.getTab(options, { forceUnzombify: true });
    } catch (error) {
    if (error.error) {
    // Pipe expected errors as-is to the client
    return error;
    }
    return {
    error: "noTab",
    message: "Unexpected error while calling getTab(): " + error,
    };
    }
    targetActor.parentID = this.actorID;
    this.manage(targetActor);
    return { tab: targetActor.form() };
    },
    });

    // changes in forTab:
    //
    forTab: async function(tab) {
    let target = targets.get(tab);
    if (target) {
    return target;
    }
    const promise = this.createTargetForTab(tab);
    // Immediately set the target's promise in cache to prevent race
    targets.set(tab, promise);
    target = await promise;
    // Then replace the promise with the target object
    targets.set(tab, target);
    target.attachTab(tab);
    target.once("close", () => {
    targets.delete(tab);
    });
    return target;
    },

    // changes in toolbox instantiation
    function Toolbox(
    targetDescriptor, // pass a top level target descriptor
    selectedTool,
    hostType,
    contentWindow,
    frameId,
    msSinceProcessStart
    ) {
    //...
    this.init();
    }

    Toolbox.prototype = {
    // ...
    get target() {
    return this._targetDescriptor._target;
    }
    init: function() {
    await this._targetDescriptor.getTarget();
    this.target.on(//...
    // etc.
    this._targetDescriptor.on("switch-target", //.. do something
    this._targetDescriptor.on("destroy", this.destroy) // or something, the descriptor representing the top level target has been destroyed
    }
    }