--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -77,18 +77,18 @@
document.getAnonymousElementByAttribute(this, "anonid", "panelcontainer");
</field>
<field name="mStringBundle">
document.getAnonymousElementByAttribute(this, "anonid", "tbstringbundle");
</field>
<field name="mCurrentTab">
null
</field>
- <field name="_lastRelatedTab">
- null
+ <field name="_lastRelatedTabMap">
+ new WeakMap();
</field>
<field name="mCurrentBrowser">
null
</field>
<field name="mProgressListeners">
[]
</field>
<field name="mTabsProgressListeners">
@@ -1119,21 +1119,22 @@
}
var oldTab = this.mCurrentTab;
// Preview mode should not reset the owner
if (!this._previewMode && !oldTab.selected)
oldTab.owner = null;
- if (this._lastRelatedTab) {
- if (!this._lastRelatedTab.selected)
- this._lastRelatedTab.owner = null;
- this._lastRelatedTab = null;
- }
+ let lastRelatedTab = this._lastRelatedTabMap.get(oldTab);
+ if (lastRelatedTab) {
+ if (!lastRelatedTab.selected)
+ lastRelatedTab.owner = null;
+ }
+ this._lastRelatedTabMap = new WeakMap();
var oldBrowser = this.mCurrentBrowser;
if (!gMultiProcessBrowser) {
oldBrowser.removeAttribute("primary");
oldBrowser.docShellIsActive = false;
newBrowser.setAttribute("primary", "true");
newBrowser.docShellIsActive =
@@ -2458,18 +2459,41 @@
aFocusUrlBar = params.focusUrlBar;
aName = params.name;
}
// if we're adding tabs, we're past interrupt mode, ditch the owner
if (this.mCurrentTab.owner)
this.mCurrentTab.owner = null;
+ // Find the tab that opened this one, if any. This is used for
+ // determining positioning, and inherited attributes such as the
+ // user context ID.
+ //
+ // If we're passed an explicit owner tab, that takes precedence,
+ // and we treat that as the opener. If not, and we have a browser
+ // opener (which is usually the top-level browser from a remote
+ // window.open() call), use that.
+ //
+ // Finally, if the tab is related to the current tab (e.g.,
+ // because it was opened by a link click), use the selected tab as
+ // the owner. If aReferrerURI is set, and we don't have an
+ // explicit relatedToCurrent arg, we assume that the tab is
+ // related to the current tab, since aReferrerURI is null or
+ // undefined if the tab is opened from an external application or
+ // bookmark (i.e. somewhere other than an existing tab).
+ let relatedToCurrent = aRelatedToCurrent == null ? !!aReferrerURI : aRelatedToCurrent;
+ let openerTab = (aOwner ||
+ (aOpenerBrowser && this.getTabForBrowser(aOpenerBrowser)) ||
+ (relatedToCurrent && this.selectedTab));
+
var t = document.createElementNS(NS_XUL, "tab");
+ t.openerTab = openerTab;
+
aURI = aURI || "about:blank";
let aURIObject = null;
try {
aURIObject = Services.io.newURI(aURI);
} catch (ex) { /* we'll try to fix up this URL later */ }
let lazyBrowserURI;
if (aCreateLazyBrowser && aURI != "about:blank") {
@@ -2489,19 +2513,18 @@
}
if (aIsPrerendered) {
t.setAttribute("hidden", "true");
}
// Related tab inherits current tab's user context unless a different
// usercontextid is specified
- if (aUserContextId == null &&
- (aRelatedToCurrent == null ? aReferrerURI : aRelatedToCurrent)) {
- aUserContextId = this.mCurrentTab.getAttribute("usercontextid") || 0;
+ if (aUserContextId == null && openerTab) {
+ aUserContextId = openerTab.getAttribute("usercontextid") || 0;
}
if (aUserContextId) {
t.setAttribute("usercontextid", aUserContextId);
ContextualIdentityService.setTabStyle(t);
}
t.setAttribute("onerror", "this.removeAttribute('image');");
@@ -2664,31 +2687,29 @@
charset: aCharset,
postData: aPostData,
});
} catch (ex) {
Cu.reportError(ex);
}
}
- // Check if we're opening a tab related to the current tab and
- // move it to after the current tab.
- // aReferrerURI is null or undefined if the tab is opened from
- // an external application or bookmark, i.e. somewhere other
- // than the current tab.
- if ((aRelatedToCurrent == null ? aReferrerURI : aRelatedToCurrent) &&
+ // If we're opening a tab related to the an existing tab, move it
+ // to a position after that tab.
+ if (openerTab &&
Services.prefs.getBoolPref("browser.tabs.insertRelatedAfterCurrent")) {
- let newTabPos = (this._lastRelatedTab ||
- this.selectedTab)._tPos + 1;
- if (this._lastRelatedTab)
- this._lastRelatedTab.owner = null;
+
+ let lastRelatedTab = this._lastRelatedTabMap.get(openerTab);
+ let newTabPos = (lastRelatedTab || openerTab)._tPos + 1;
+ if (lastRelatedTab)
+ lastRelatedTab.owner = null;
else
- t.owner = this.selectedTab;
- this.moveTabTo(t, newTabPos);
- this._lastRelatedTab = t;
+ t.owner = openerTab;
+ this.moveTabTo(t, newTabPos, true);
+ this._lastRelatedTabMap.set(openerTab, t);
}
// This field is updated regardless if we actually animate
// since it's important that we keep this count correct in all cases.
this.tabAnimationsInProgress++;
if (animate) {
requestAnimationFrame(function() {
@@ -3075,17 +3096,17 @@
if (this._windowIsClosing) {
aCloseWindow = false;
aNewTab = false;
}
this.tabAnimationsInProgress--;
- this._lastRelatedTab = null;
+ this._lastRelatedTabMap = new WeakMap();
// update the UI early for responsiveness
aTab.collapsed = true;
this._blurTab(aTab);
this._removingTabs.splice(this._removingTabs.indexOf(aTab), 1);
if (aCloseWindow) {
@@ -3725,31 +3746,34 @@
return window.openDialog("chrome://browser/content/", "_blank", "chrome,all,dialog=no,non-remote", url);
]]>
</body>
</method>
<method name="moveTabTo">
<parameter name="aTab"/>
<parameter name="aIndex"/>
+ <parameter name="aKeepRelatedTabs"/>
<body>
<![CDATA[
var oldPosition = aTab._tPos;
if (oldPosition == aIndex)
return;
// Don't allow mixing pinned and unpinned tabs.
if (aTab.pinned)
aIndex = Math.min(aIndex, this._numPinnedTabs - 1);
else
aIndex = Math.max(aIndex, this._numPinnedTabs);
if (oldPosition == aIndex)
return;
- this._lastRelatedTab = null;
+ if (!aKeepRelatedTabs) {
+ this._lastRelatedTabMap = new WeakMap();
+ }
let wasFocused = (document.activeElement == this.mCurrentTab);
aIndex = aIndex < aTab._tPos ? aIndex : aIndex + 1;
// invalidate cache
this._visibleTabs = null;