Bug 642793 - The focused Tab is not set first in the stack. r=ian
authorAdam Dane [:hobophobe] <unusualtears@gmail.com>
Mon, 25 Apr 2011 13:21:04 -0500
changeset 68847 c8c3e140ebe3e36680b45117185d960ba5606db2
parent 68846 a2db302689584e16ea907511f68eaf156b28e121
child 68848 4e5abe9e5e8dd23a9d5186afc1acadb9568b4e3f
push id19776
push userbzbarsky@mozilla.com
push dateMon, 02 May 2011 13:13:57 +0000
treeherdermozilla-central@79157d41d7bc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersian
bugs642793
milestone6.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 642793 - The focused Tab is not set first in the stack. r=ian
browser/base/content/tabview/groupitems.js
browser/base/content/tabview/tabitems.js
browser/base/content/tabview/ui.js
browser/base/content/test/tabview/Makefile.in
browser/base/content/test/tabview/browser_tabview_bug642793.js
browser/base/content/test/tabview/browser_tabview_expander.js
--- a/browser/base/content/tabview/groupitems.js
+++ b/browser/base/content/tabview/groupitems.js
@@ -73,17 +73,16 @@ function GroupItem(listOfEls, options) {
   this._inited = false;
   this._uninited = false;
   this._children = []; // an array of Items
   this.defaultSize = new Point(TabItems.tabWidth * 1.5, TabItems.tabHeight * 1.5);
   this.isAGroupItem = true;
   this.id = options.id || GroupItems.getNextID();
   this._isStacked = false;
   this.expanded = null;
-  this.topChild = null;
   this.hidden = false;
   this.fadeAwayUndoButtonDelay = 15000;
   this.fadeAwayUndoButtonDuration = 300;
 
   this.keepProportional = false;
   this._frozenItemSizeData = {};
 
   // Double click tracker
@@ -298,16 +297,17 @@ GroupItem.prototype = Utils.extend(new I
   // Function: setActiveTab
   // Sets the active <TabItem> for this groupItem; can be null, but only
   // if there are no children.
   setActiveTab: function GroupItem_setActiveTab(tab) {
     Utils.assertThrow((!tab && this._children.length == 0) || tab.isATabItem,
         "tab must be null (if no children) or a TabItem");
 
     this._activeTab = tab;
+    this.arrange({immediately: true});
   },
 
   // -----------
   // Function: getActiveTab
   // Gets the active <TabItem> for this groupItem; can be null, but only
   // if there are no children.
   getActiveTab: function GroupItem_getActiveTab() {
     return this._activeTab;
@@ -345,18 +345,17 @@ GroupItem.prototype = Utils.extend(new I
   },
 
   // ----------
   // Function: isTopOfStack
   // Returns true if the item is showing on top of this group's stack,
   // determined by whether the tab is this group's topChild, or
   // if it doesn't have one, its first child.
   isTopOfStack: function GroupItem_isTopOfStack(item) {
-    return this.isStacked() && ((this.topChild == item) ||
-      (!this.topChild && this.getChild(0) == item));
+    return this.isStacked() && item == this.getTopChild();
   },
 
   // ----------
   // Function: save
   // Saves this groupItem to persistent storage.
   save: function GroupItem_save() {
     if (!this._inited || this._uninited) // too soon/late to save
       return;
@@ -613,17 +612,17 @@ GroupItem.prototype = Utils.extend(new I
     iQ(this.container).css({zIndex: value});
 
     var count = this._children.length;
     if (count) {
       var topZIndex = value + count + 1;
       var zIndex = topZIndex;
       var self = this;
       this._children.forEach(function(child) {
-        if (child == self.topChild)
+        if (child == self.getTopChild())
           child.setZ(topZIndex + 1);
         else {
           child.setZ(zIndex);
           zIndex--;
         }
       });
     }
   },
@@ -1431,21 +1430,22 @@ GroupItem.prototype = Utils.extend(new I
     // y is the vertical margin
     var x = (bb.width - size.x) / 2;
     var y = Math.min(size.x, (bb.height - size.y) / 2);
     var box = new Rect(bb.left + x, bb.top + y, size.x, size.y);
 
     var self = this;
     var children = [];
 
-    // ensure this.topChild is the first item in childrenToArrange
-    let topChildPos = childrenToArrange.indexOf(this.topChild);
+    // ensure topChild is the first item in childrenToArrange
+    let topChild = this.getTopChild();
+    let topChildPos = childrenToArrange.indexOf(topChild);
     if (topChildPos > 0) {
       childrenToArrange.splice(topChildPos, 1);
-      childrenToArrange.unshift(this.topChild);
+      childrenToArrange.unshift(topChild);
     }
 
     childrenToArrange.forEach(function GroupItem__stackArrange_order(child) {
       // Children are still considered stacked even if they're hidden later.
       child.addClass("stacked");
       child.isStacked = true;
       if (numInPile-- > 0) {
         children.push(child);
@@ -1490,17 +1490,16 @@ GroupItem.prototype = Utils.extend(new I
   _gridArrange: function GroupItem__gridArrange(childrenToArrange, box, options) {
     let arrangeOptions;
     if (this.expanded) {
       // if we're expanded, we actually want to use the expanded tray's bounds.
       box = new Rect(this.expanded.bounds);
       box.inset(8, 8);
       arrangeOptions = Utils.extend({}, options, {z: 99999});
     } else {
-      this.topChild = null;
       this._isStacked = false;
       arrangeOptions = Utils.extend({}, options, {
         columns: this._columns
       });
 
       childrenToArrange.forEach(function(child) {
         child.removeClass("stacked");
         child.isStacked = false;
@@ -1536,18 +1535,17 @@ GroupItem.prototype = Utils.extend(new I
 
     return dropIndex;
   },
 
   expand: function GroupItem_expand() {
     var self = this;
     // ___ we're stacked, and command is held down so expand
     GroupItems.setActiveGroupItem(self);
-    let activeTab = this.topChild || this.getChildren()[0];
-    UI.setActiveTab(activeTab);
+    UI.setActiveTab(this.getTopChild());
     
     var startBounds = this.getChild(0).getBounds();
     var $tray = iQ("<div>").css({
       top: startBounds.top,
       left: startBounds.left,
       width: startBounds.width,
       height: startBounds.height,
       position: "absolute",
@@ -1853,23 +1851,24 @@ GroupItem.prototype = Utils.extend(new I
       if (!targetRange.contains(tab._tPos)) {
         gBrowser.moveTabTo(tab, start);
         indices = null;
       }
     });
   },
 
   // ----------
-  // Function: setTopChild
-  // Sets the <Item> that should be displayed on top when in stack mode.
-  setTopChild: function GroupItem_setTopChild(topChild) {
-    this.topChild = topChild;
+  // Function: getTopChild
+  // Gets the <Item> that should be displayed on top when in stack mode.
+  getTopChild: function GroupItem_getTopChild() {
+    if (!this.getChildren().length) {
+      return null;
+    }
 
-    this.arrange({animate: false});
-    // this.arrange calls this.save for us
+    return this.getActiveTab() || this.getChild(0);
   },
 
   // ----------
   // Function: getChild
   // Returns the nth child tab or null if index is out of range.
   //
   // Parameters:
   //  index - the index of the child tab to return, use negative
--- a/browser/base/content/tabview/tabitems.js
+++ b/browser/base/content/tabview/tabitems.js
@@ -714,21 +714,16 @@ TabItem.prototype = Utils.extend(new Ite
         complete();
     };
 
     UI.setActiveTab(this);
     TabItems._update(this.tab, {force: true});
 
     $tab.addClass("front");
 
-    // If we're in a stacked group, make sure we become the
-    // topChild now so that we show the zoom animation correctly.
-    if (this.parent && this.parent.isStacked())
-      this.parent.setTopChild(this);
-
     let animateZoom = gPrefBranch.getBoolPref("animate_zoom");
     if (animateZoom) {
       // The scaleCheat of 2 here is a clever way to speed up the zoom-out
       // code. See getZoomTransform() below.
       let transform = this.getZoomTransform(2);
       TabItems.pausePainting();
 
       $canvas.css({
--- a/browser/base/content/tabview/ui.js
+++ b/browser/base/content/tabview/ui.js
@@ -492,19 +492,16 @@ let UI = {
 
       // Zoom out!
       item.zoomOut(function() {
         if (!currentTab._tabViewTabItem) // if the tab's been destroyed
           item = null;
 
         self.setActiveTab(item);
 
-        if (activeGroupItem && item.parent)
-          activeGroupItem.setTopChild(item);
-
         self._resize(true);
         dispatchEvent(event);
 
         // Flush pending updates
         GroupItems.flushAppTabUpdates();
 
         TabItems.resumePainting();
       });
--- a/browser/base/content/test/tabview/Makefile.in
+++ b/browser/base/content/test/tabview/Makefile.in
@@ -123,16 +123,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug633788.js \
                  browser_tabview_bug634077.js \
                  browser_tabview_bug634085.js \
                  browser_tabview_bug634158.js \
                  browser_tabview_bug634672.js \
                  browser_tabview_bug635696.js \
                  browser_tabview_bug640765.js \
                  browser_tabview_bug641802.js \
+                 browser_tabview_bug642793.js \
                  browser_tabview_bug644097.js \
                  browser_tabview_bug645653.js \
                  browser_tabview_bug648882.js \
                  browser_tabview_bug649006.js \
                  browser_tabview_bug649307.js \
                  browser_tabview_bug651311.js \
                  browser_tabview_dragdrop.js \
                  browser_tabview_exit_button.js \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug642793.js
@@ -0,0 +1,27 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  waitForExplicitFinish();
+  newWindowWithTabView(testTopOfStack, loadTabs);
+}
+
+function loadTabs (win) {
+  for (let i = 0; i < 4; i++)
+    win.gBrowser.loadOneTab('about:blank', {inBackground: false});
+  win.gBrowser.selectedTab = win.gBrowser.tabs[2];
+}
+
+function testTopOfStack(win) {
+  registerCleanupFunction(function () { win.close(); });
+  let cw = win.TabView.getContentWindow();
+  groupItem = cw.GroupItems.getActiveGroupItem();
+  ok(!groupItem.isStacked(), 'groupItem is not stacked');
+  groupItem.setSize(150, 150);
+  groupItem.setUserSize();
+  ok(groupItem.isStacked(), 'groupItem is now stacked');
+  ok(groupItem.isTopOfStack(groupItem.getChild(2)),
+    'the third tab is on top of stack');
+  finish();
+}
+
--- a/browser/base/content/test/tabview/browser_tabview_expander.js
+++ b/browser/base/content/test/tabview/browser_tabview_expander.js
@@ -116,24 +116,24 @@ function onTabViewWindowLoaded(win) {
       win.removeEventListener("tabviewshown", stage2shown, false);
       ok(!group.expanded, "The group is not expanded.");
       isnot(expander[0].style.display, "none", "The expander is visible!");
       let expanderBounds = expander.bounds();
       ok(group.getBounds().contains(expanderBounds), "The expander still lies in the group.");
       let stackCenter = children[0].getBounds().center();
       ok(stackCenter.y < expanderBounds.center().y, "The expander is below the stack.");
 
-      is(group.topChild, children[1], "The top child in the stack is the second tab item");
+      is(group.getTopChild(), children[1], "The top child in the stack is the second tab item");
       let topChildzIndex = children[1].zIndex;
       // the second tab item should have the largest z-index.
       // only check the first 6 tabs as the stack only contains 6 tab items.
       for (let i = 0; i < 6; i++) {
         if (i != 1)
           ok(children[i].zIndex < topChildzIndex,
-            "The child[" + i + "] has smaller zIndex than second dhild");
+            "The child[" + i + "] has smaller zIndex than second child");
       }
 
       // okay, expand this group one last time
       group.addSubscriber("test stage 3", "expanded", stage3expanded);
       EventUtils.sendMouseEvent({ type: "click" }, expander[0], contentWindow);
     }
 
     // STAGE 3:
@@ -155,17 +155,17 @@ function onTabViewWindowLoaded(win) {
       group.removeSubscriber("test stage 3", "collapsed", stage3collapsed);
 
       ok(!group.expanded, "The group is no longer expanded.");
       isnot(expander[0].style.display, "none", "The expander is visible!");
 
       let stackCenter = children[0].getBounds().center();
       ok(stackCenter.y < expanderBounds.center().y, "The expander is below the stack.");
 
-      is(group.topChild, children[1], 
+      is(group.getTopChild(), children[1], 
          "The top child in the stack is still the second tab item");
       let topChildzIndex = children[1].zIndex;
       // the second tab item should have the largest z-index.
       // only check the first 6 tabs as the stack only contains 6 tab items.
       for (let i = 0; i < 6; i++) {
         if (i != 1)
           ok(children[i].zIndex < topChildzIndex,
             "The child[" + i + "] has smaller zIndex than second dhild after a collapse.");