Bug 1443849 - Part 2: Don't touch gBrowser before gBrowserInit. r=Gijs
MozReview-Commit-ID: 5p0FoxNYGJh
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -299,23 +299,33 @@
</method>
<property name="_isCustomizing" readonly="true">
<getter><![CDATA[
return document.documentElement.getAttribute("customizing") == "true";
]]></getter>
</property>
+ <method name="_getVisibleTabs">
+ <body><![CDATA[
+ // Cannot access gBrowser before it's initialized.
+ if (!gBrowser) {
+ return [ this.firstChild ];
+ }
+
+ return gBrowser.visibleTabs;
+ ]]></body>
+ </method>
+
<method name="_setPositionalAttributes">
<body><![CDATA[
- let visibleTabs = this.tabbrowser.visibleTabs;
-
- if (!visibleTabs.length)
+ let visibleTabs = this._getVisibleTabs();
+ if (!visibleTabs.length) {
return;
-
+ }
let selectedIndex = visibleTabs.indexOf(this.selectedItem);
if (this._beforeSelectedTab) {
this._beforeSelectedTab.removeAttribute("beforeselected-visible");
}
if (this.selectedItem.closing || selectedIndex == 0) {
this._beforeSelectedTab = null;
@@ -432,17 +442,17 @@
// Check if tab widths are below the threshold where we want to
// remove close buttons from background tabs so that people don't
// accidentally close tabs by selecting them.
let rect = ele => {
return window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.getBoundsWithoutFlushing(ele);
};
- let tab = this.tabbrowser.visibleTabs[this.tabbrowser._numPinnedTabs];
+ let tab = this._getVisibleTabs()[gBrowser._numPinnedTabs];
if (tab && rect(tab).width <= this._tabClipWidth) {
this.setAttribute("closebuttons", "activetab");
} else {
this.removeAttribute("closebuttons");
}
});
});
]]></body>
@@ -465,19 +475,20 @@
<field name="_tabDefaultMaxWidth">NaN</field>
<field name="_lastTabClosedByMouse">false</field>
<field name="_hasTabTempMaxWidth">false</field>
<!-- Try to keep the active tab's close button under the mouse cursor -->
<method name="_lockTabSizing">
<parameter name="aTab"/>
<body><![CDATA[
- var tabs = this.tabbrowser.visibleTabs;
- if (!tabs.length)
+ let tabs = this._getVisibleTabs();
+ if (!tabs.length) {
return;
+ }
var isEndTab = (aTab._tPos > tabs[tabs.length - 1]._tPos);
var tabWidth = aTab.getBoundingClientRect().width;
if (!this._tabDefaultMaxWidth)
this._tabDefaultMaxWidth =
parseFloat(window.getComputedStyle(aTab).maxWidth);
this._lastTabClosedByMouse = true;
@@ -540,19 +551,20 @@
<method name="_unlockTabSizing">
<body><![CDATA[
this.tabbrowser.removeEventListener("mousemove", this);
window.removeEventListener("mouseout", this);
if (this._hasTabTempMaxWidth) {
this._hasTabTempMaxWidth = false;
- let tabs = this.tabbrowser.visibleTabs;
- for (let i = 0; i < tabs.length; i++)
+ let tabs = this._getVisibleTabs();
+ for (let i = 0; i < tabs.length; i++) {
tabs[i].style.maxWidth = "";
+ }
}
if (this.hasAttribute("using-closing-tabs-spacer")) {
this.removeAttribute("using-closing-tabs-spacer");
this._closingTabsSpacer.style.width = 0;
}
]]></body>
</method>
@@ -564,19 +576,19 @@
this._handleTabSelect(true);
]]></body>
</method>
<field name="_lastNumPinned">0</field>
<field name="_pinnedTabsLayoutCache">null</field>
<method name="_positionPinnedTabs">
<body><![CDATA[
- var numPinned = this.tabbrowser._numPinnedTabs;
- var doPosition = this.getAttribute("overflow") == "true" &&
- this.tabbrowser.visibleTabs.length > numPinned &&
+ let numPinned = gBrowser._numPinnedTabs;
+ let doPosition = this.getAttribute("overflow") == "true" &&
+ this._getVisibleTabs().length > numPinned &&
numPinned > 0;
if (doPosition) {
this.setAttribute("positionpinnedtabs", "true");
let layoutData = this._pinnedTabsLayoutCache;
let uiDensity = document.documentElement.getAttribute("uidensity");
if (!layoutData ||
@@ -633,33 +645,35 @@
let screenX = event.screenX;
if (screenX == draggedTab._dragData.animLastScreenX)
return;
draggedTab._dragData.animLastScreenX = screenX;
let rtl = (window.getComputedStyle(this).direction == "rtl");
let pinned = draggedTab.pinned;
- let numPinned = this.tabbrowser._numPinnedTabs;
- let tabs = this.tabbrowser.visibleTabs
- .slice(pinned ? 0 : numPinned,
- pinned ? numPinned : undefined);
- if (rtl)
+ let numPinned = gBrowser._numPinnedTabs;
+ let tabs = this._getVisibleTabs()
+ .slice(pinned ? 0 : numPinned,
+ pinned ? numPinned : undefined);
+ if (rtl) {
tabs.reverse();
+ }
let tabWidth = draggedTab.getBoundingClientRect().width;
draggedTab._dragData.tabWidth = tabWidth;
// Move the dragged tab based on the mouse position.
let leftTab = tabs[0];
let rightTab = tabs[tabs.length - 1];
let tabScreenX = draggedTab.boxObject.screenX;
let translateX = screenX - draggedTab._dragData.screenX;
- if (!pinned)
+ if (!pinned) {
translateX += this.arrowScrollbox._scrollbox.scrollLeft - draggedTab._dragData.scrollX;
+ }
let leftBound = leftTab.boxObject.screenX - tabScreenX;
let rightBound = (rightTab.boxObject.screenX + rightTab.boxObject.width) -
(tabScreenX + tabWidth);
translateX = Math.max(translateX, leftBound);
translateX = Math.min(translateX, rightBound);
draggedTab.style.transform = "translateX(" + translateX + "px)";
draggedTab._dragData.translateX = translateX;
@@ -715,21 +729,23 @@
return rtl ? tabWidth : -tabWidth;
return 0;
}
]]></body>
</method>
<method name="_finishAnimateTabMove">
<body><![CDATA[
- if (this.getAttribute("movingtab") != "true")
+ if (this.getAttribute("movingtab") != "true") {
return;
+ }
- for (let tab of this.tabbrowser.visibleTabs)
+ for (let tab of this._getVisibleTabs()) {
tab.style.transform = "";
+ }
this.removeAttribute("movingtab");
this.parentNode.removeAttribute("movingtab");
this._handleTabSelect();
]]></body>
</method>
@@ -916,22 +932,29 @@
]]>
</body>
</method>
<method name="getRelatedElement">
<parameter name="aTab"/>
<body>
<![CDATA[
- if (!aTab)
+ if (!aTab) {
return null;
+ }
+
+ // Cannot access gBrowser before it's initialized.
+ if (!gBrowser) {
+ return this.tabbox.tabpanels.firstChild;
+ }
+
// If the tab's browser is lazy, we need to `_insertBrowser` in order
// to have a linkedPanel. This will also serve to bind the browser
// and make it ready to use when the tab is selected.
- this.tabbrowser._insertBrowser(aTab);
+ gBrowser._insertBrowser(aTab);
return document.getElementById(aTab.linkedPanel);
]]>
</body>
</method>
<method name="_updateNewTabVisibility">
<body><![CDATA[
// Helper functions to help deal with customize mode wrapping some items
@@ -1085,17 +1108,17 @@
// The user middleclicked an open space on the tabstrip. This could
// be because they intend to open a new tab, but it could also be
// because they just removed a tab and they now middleclicked on the
// resulting space while that tab is closing. In that case, we don't
// want to open a tab. So if we're removing one or more tabs, and
// the tab click is before the end of the last visible tab, we do
// nothing.
if (this.tabbrowser._removingTabs.length) {
- let visibleTabs = this.tabbrowser.visibleTabs;
+ let visibleTabs = this._getVisibleTabs();
let ltr = (window.getComputedStyle(this).direction == "ltr");
let lastTab = visibleTabs[visibleTabs.length - 1];
let endOfTab = lastTab.getBoundingClientRect()[ltr ? "right" : "left"];
if ((ltr && event.clientX > endOfTab) ||
(!ltr && event.clientX < endOfTab)) {
BrowserOpenTab();
}
} else {
@@ -1740,21 +1763,22 @@
While it would make sense to track this in a field, the field will get nuked
once the node is gone from the DOM, which causes us to think the tab is not
closed, which causes us to make wrong decisions. So we use an expando instead.
<field name="closing">false</field>
-->
<method name="_mouseenter">
<body><![CDATA[
- if (this.hidden || this.closing)
+ if (this.hidden || this.closing) {
return;
+ }
let tabContainer = this.parentNode;
- let visibleTabs = tabContainer.tabbrowser.visibleTabs;
+ let visibleTabs = tabContainer._getVisibleTabs();
let tabIndex = visibleTabs.indexOf(this);
if (this.selected)
tabContainer._handleTabSelect();
if (tabIndex == 0) {
tabContainer._beforeHoveredTab = null;
} else {