--- a/browser/components/extensions/parent/ext-browser.js
+++ b/browser/components/extensions/parent/ext-browser.js
@@ -1,16 +1,18 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
// This file provides some useful code for the |tabs| and |windows|
// modules. All of the code is installed on |global|, which is a scope
// shared among the different ext-*.js scripts.
+ChromeUtils.defineModuleGetter(this, "ExtensionParent",
+ "resource://gre/modules/ExtensionParent.jsm");
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
ChromeUtils.defineModuleGetter(this, "RecentWindow",
"resource:///modules/RecentWindow.jsm");
var {
ExtensionError,
defineLazyGetter,
@@ -109,41 +111,43 @@ global.TabContext = class extends EventE
this.tabData = new WeakMap();
windowTracker.addListener("progress", this);
windowTracker.addListener("TabSelect", this);
}
get(nativeTab) {
- if (!this.tabData.has(nativeTab)) {
- this.tabData.set(nativeTab, this.getDefaults(nativeTab));
+ let tab = this.extension.tabManager.getWrapper(nativeTab);
+ if (!this.tabData.has(tab)) {
+ this.tabData.set(tab, this.getDefaults(nativeTab));
}
- return this.tabData.get(nativeTab);
+ return this.tabData.get(tab);
}
clear(nativeTab) {
- this.tabData.delete(nativeTab);
+ let tab = this.extension.tabManager.getWrapper(nativeTab);
+ this.tabData.delete(tab);
}
handleEvent(event) {
if (event.type == "TabSelect") {
let nativeTab = event.target;
this.emit("tab-select", nativeTab);
this.emit("location-change", nativeTab);
}
}
onLocationChange(browser, webProgress, request, locationURI, flags) {
let gBrowser = browser.ownerGlobal.gBrowser;
- let tab = gBrowser.getTabForBrowser(browser);
+ let nativeTab = gBrowser.getTabForBrowser(browser);
// fromBrowse will be false in case of e.g. a hash change or history.pushState
let fromBrowse = !(flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT);
- this.emit("location-change", tab, fromBrowse);
+ this.emit("location-change", nativeTab, fromBrowse);
}
shutdown() {
windowTracker.removeListener("progress", this);
windowTracker.removeListener("TabSelect", this);
}
};
@@ -237,16 +241,23 @@ class TabTracker extends TabTrackerBase
setId(nativeTab, id) {
this._tabs.set(nativeTab, id);
if (nativeTab.linkedBrowser) {
this._browsers.set(nativeTab.linkedBrowser, id);
}
this._tabIds.set(id, nativeTab);
}
+ adopt(nativeTab, adoptedBy) {
+ this.setId(nativeTab, this.getId(adoptedBy));
+ for (let extension of ExtensionParent.GlobalManager.extensionMap.values()) {
+ extension.tabManager.adopt(nativeTab, adoptedBy);
+ }
+ }
+
_handleTabDestroyed(event, {nativeTab}) {
let id = this._tabs.get(nativeTab);
if (id) {
this._tabs.delete(nativeTab);
if (this._tabIds.get(id) === nativeTab) {
this._tabIds.delete(id);
}
}
@@ -300,17 +311,17 @@ class TabTracker extends TabTrackerBase
switch (event.type) {
case "TabOpen":
let {adoptedTab} = event.detail;
if (adoptedTab) {
this.adoptedTabs.set(adoptedTab, event.target);
// This tab is being created to adopt a tab from a different window.
// Copy the ID from the old tab to the new.
- this.setId(nativeTab, this.getId(adoptedTab));
+ this.adopt(nativeTab, adoptedTab);
adoptedTab.linkedBrowser.messageManager.sendAsyncMessage("Extension:SetFrameData", {
windowId: windowTracker.getId(nativeTab.ownerGlobal),
});
}
// Save the current tab, since the newly-created tab will likely be
// active by the time the promise below resolves and the event is
@@ -330,17 +341,17 @@ class TabTracker extends TabTrackerBase
case "TabClose":
let {adoptedBy} = event.detail;
if (adoptedBy) {
// This tab is being closed because it was adopted by a new window.
// Copy its ID to the new tab, in case it was created as the first tab
// of a new window, and did not have an `adoptedTab` detail when it was
// opened.
- this.setId(adoptedBy, this.getId(nativeTab));
+ this.adopt(adoptedBy, nativeTab);
this.emitDetached(nativeTab, adoptedBy);
} else {
this.emitRemoved(nativeTab, false);
}
break;
case "TabSelect":
@@ -386,17 +397,17 @@ class TabTracker extends TabTrackerBase
// delayed startup code in browser.js, which is currently triggered
// by the first MozAfterPaint event. That code handles finally
// adopting the tab, and clears it from the arguments list in the
// process, so if we run later than it, we're too late.
let nativeTab = window.arguments[0];
let adoptedBy = window.gBrowser.tabs[0];
this.adoptedTabs.set(nativeTab, adoptedBy);
- this.setId(adoptedBy, this.getId(nativeTab));
+ this.adopt(adoptedBy, nativeTab);
// We need to be sure to fire this event after the onDetached event
// for the original tab.
let listener = (event, details) => {
if (details.nativeTab === nativeTab) {
this.off("tab-detached", listener);
Promise.resolve().then(() => {
--- a/toolkit/components/extensions/parent/ext-tabs-base.js
+++ b/toolkit/components/extensions/parent/ext-tabs-base.js
@@ -1790,16 +1790,22 @@ class TabManagerBase {
*
* @returns {TabBase}
* The wrapper for this tab.
*/
getWrapper(nativeTab) {
return this._tabs.get(nativeTab);
}
+ adopt(nativeTab, adoptedBy) {
+ let wrapper = this.getWrapper(adoptedBy);
+ wrapper.nativeTab = nativeTab;
+ this._tabs.set(nativeTab, wrapper);
+ }
+
/**
* Converts the given native tab to a JSON-compatible object, in the format
* required to be returned by WebExtension APIs, which may be safely passed to
* extension code.
*
* @param {NativeTab} nativeTab
* The native tab to convert.
* @param {NativeTab} [fallbackTab]