Bug 595521 - When closing the last group, the undo button should stay indefinitely r=dolske, a=blocking
authorRaymond Lee <raymond@raysquare.com>
Fri, 29 Oct 2010 12:55:18 +0800
changeset 56965 03a3ee4ece3566ff4fc67d2afd36de37c9f57365
parent 56964 e08e1f42bf117533861ed39eed02977528f92837
child 56966 04088d699f56729cc86ea04ec4f3f9965a16df64
push id16740
push userian@iangilman.com
push dateFri, 05 Nov 2010 21:02:17 +0000
treeherdermozilla-central@03a3ee4ece35 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdolske, blocking
bugs595521
milestone2.0b8pre
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 595521 - When closing the last group, the undo button should stay indefinitely r=dolske, a=blocking
browser/base/content/tabview/groupitems.js
browser/base/content/test/tabview/Makefile.in
browser/base/content/test/tabview/browser_tabview_bug595521.js
--- a/browser/base/content/tabview/groupitems.js
+++ b/browser/base/content/tabview/groupitems.js
@@ -76,16 +76,18 @@ function GroupItem(listOfEls, options) {
   this.isAGroupItem = true;
   this.id = options.id || GroupItems.getNextID();
   this._isStacked = false;
   this._stackAngles = [0];
   this.expanded = null;
   this.locked = (options.locked ? Utils.copy(options.locked) : {});
   this.topChild = null;
   this.hidden = false;
+  this.fadeAwayUndoButtonDelay = 15000;
+  this.fadeAwayUndoButtonDuration = 300;
 
   this.keepProportional = false;
 
   // Variable: _activeTab
   // The <TabItem> for the groupItem's active tab.
   this._activeTab = null;
 
   // Variables: xDensity, yDensity
@@ -272,16 +274,17 @@ function GroupItem(listOfEls, options) {
   if (this.locked.bounds)
     $container.css({cursor: 'default'});
 
   if (this.locked.close)
     $close.hide();
 
   // ___ Undo Close
   this.$undoContainer = null;
+  this._undoButtonTimeoutId = null;
 
   // ___ Superclass initialization
   this._init($container[0]);
 
   if (this.$debug)
     this.$debug.css({zIndex: -1000});
 
   // ___ Children
@@ -632,46 +635,25 @@ GroupItem.prototype = Utils.extend(new I
         easing: "tabviewBounce",
         duration: 170,
         complete: function() {
           self._sendToSubscribers("groupHidden", { groupItemId: self.id });
         }
       });
     }, 50);
 
-    let remove = function() {
-      // close all children
-      let toClose = self._children.concat();
-      toClose.forEach(function(child) {
-        child.removeSubscriber(self, "close");
-        child.close();
-      });
- 
-      // remove all children
-      self.removeAll();
-      GroupItems.unregister(self);
-      self._sendToSubscribers("close");
-      self.removeTrenches();
-
-      iQ(self.container).remove();
-      self.$undoContainer.remove();
-      self.$undoContainer = null;
-      Items.unsquish();
-
-      self.deleteData();
-    };
-
     this.$undoContainer.click(function(e) {
       // Only do this for clicks on this actual element.
       if (e.target.nodeName != self.$undoContainer[0].nodeName)
         return;
 
       self.$undoContainer.fadeOut(function() {
         iQ(this).remove();
         self.hidden = false;
+        self._cancelFadeAwayUndoButtonTimer();
         self.$undoContainer = null;
 
         iQ(self.container).show().animate({
           "-moz-transform": "scale(1)",
           "opacity": 1
         }, {
           duration: 170,
           complete: function() {
@@ -681,41 +663,102 @@ GroupItem.prototype = Utils.extend(new I
           }
         });
 
         self._sendToSubscribers("groupShown", { groupItemId: self.id });
       });
     });
 
     undoClose.click(function() {
-      self.$undoContainer.fadeOut(remove);
+      self._cancelFadeAwayUndoButtonTimer();
+      self.$undoContainer.fadeOut(function() { self._removeHiddenGroupItem(); });
     });
 
-    // After 15 seconds, fade away.
-    const WAIT = 15000;
-    const FADE = 300;
+    this.setupFadeAwayUndoButtonTimer();
+    // Cancel the fadeaway if you move the mouse over the undo
+    // button, and restart the countdown once you move out of it.
+    this.$undoContainer.mouseover(function() { 
+      self._cancelFadeAwayUndoButtonTimer();
+    });
+    this.$undoContainer.mouseout(function() {
+      self.setupFadeAwayUndoButtonTimer();
+    });
+  },
+
+  // ----------
+  // Sets up fade away undo button timeout. 
+  setupFadeAwayUndoButtonTimer: function() {
+    let self = this;
 
-    let fadeaway = function() {
-      if (self.$undoContainer)
+    if (!this._undoButtonTimeoutId) {
+      this._undoButtonTimeoutId = setTimeout(function() { 
+        self._fadeAwayUndoButton(); 
+      }, this.fadeAwayUndoButtonDelay);
+    }
+  },
+  
+  // ----------
+  // Cancels the fade away undo button timeout. 
+  _cancelFadeAwayUndoButtonTimer: function() {
+    clearTimeout(this._undoButtonTimeoutId);
+    this._undoButtonTimeoutId = null;
+  }, 
+
+  // ----------
+  // Fades away the undo button
+  _fadeAwayUndoButton: function() {
+    let self = this;
+
+    if (this.$undoContainer) {
+      // if there is one or more orphan tabs or there is more than one group 
+      // and other groupS are not empty, fade away the undo button.
+      let shouldFadeAway = GroupItems.getOrphanedTabs().length > 0;
+      
+      if (!shouldFadeAway && GroupItems.groupItems.length > 1) {
+        shouldFadeAway = 
+          GroupItems.groupItems.some(function(groupItem) {
+            return (groupItem != self && groupItem.getChildren().length > 0);
+          });
+      }
+      if (shouldFadeAway) {
         self.$undoContainer.animate({
           color: "transparent",
           opacity: 0
         }, {
-          duration: FADE,
-          complete: remove
+          duration: this.fadeAwayUndoButtonDuration,
+          complete: function() { self._removeHiddenGroupItem(); }
         });
-    };
+      }
+    }
+  },
+
+  // ----------
+  // Removes the group item, its children and its container.
+  _removeHiddenGroupItem: function() {
+    let self = this;
 
-    let timeoutId = setTimeout(fadeaway, WAIT);
-    // Cancel the fadeaway if you move the mouse over the undo
-    // button, and restart the countdown once you move out of it.
-    this.$undoContainer.mouseover(function() clearTimeout(timeoutId));
-    this.$undoContainer.mouseout(function() {
-      timeoutId = setTimeout(fadeaway, WAIT);
+    // close all children
+    let toClose = this._children.concat();
+    toClose.forEach(function(child) {
+      child.removeSubscriber(self, "close");
+      child.close();
     });
+ 
+    // remove all children
+    this.removeAll();
+    GroupItems.unregister(this);
+    this._sendToSubscribers("close");
+    this.removeTrenches();
+
+    iQ(this.container).remove();
+    this.$undoContainer.remove();
+    this.$undoContainer = null;
+    Items.unsquish();
+
+    this.deleteData();
   },
 
   // ----------
   // Function: add
   // Adds an item to the groupItem.
   // Parameters:
   //
   //   a - The item to add. Can be an <Item>, a DOM element or an iQ object.
--- a/browser/base/content/test/tabview/Makefile.in
+++ b/browser/base/content/test/tabview/Makefile.in
@@ -48,16 +48,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug580412.js \
                  browser_tabview_bug587043.js \
                  browser_tabview_bug587990.js \
                  browser_tabview_bug590606.js \
                  browser_tabview_bug591706.js \
                  browser_tabview_bug594176.js \
                  browser_tabview_bug595191.js \
                  browser_tabview_bug595518.js \
+                 browser_tabview_bug595521.js \
                  browser_tabview_bug595804.js \
                  browser_tabview_bug595930.js \
                  browser_tabview_bug595943.js \
                  browser_tabview_bug598600.js \
                  browser_tabview_dragdrop.js \
                  browser_tabview_exit_button.js \
                  browser_tabview_group.js \
                  browser_tabview_launch.js \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug595521.js
@@ -0,0 +1,101 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is a test for bug 595521.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Raymond Lee <raymond@appcoast.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+let fadeAwayUndoButtonDelay;
+let fadeAwayUndoButtonDuration;
+
+function test() {
+  waitForExplicitFinish();
+
+  window.addEventListener("tabviewshown", testCloseLastGroup, false);
+  TabView.toggle();
+}
+
+function testCloseLastGroup() {
+  window.removeEventListener("tabviewshown", testCloseLastGroup, false);
+  ok(TabView.isVisible(), "Tab View is visible");
+
+  let contentWindow = document.getElementById("tab-view").contentWindow;
+
+  is(contentWindow.GroupItems.groupItems.length, 1, "Has one group only");
+
+  let groupItem = contentWindow.GroupItems.groupItems[0];
+  
+  let checkExistence = function() {
+    is(contentWindow.GroupItems.groupItems.length, 1, 
+       "Still has one group after delay");
+
+    EventUtils.sendMouseEvent(
+      { type: "click" }, groupItem.$undoContainer[0], contentWindow);
+  };
+
+  groupItem.addSubscriber(groupItem, "groupHidden", function() {
+    groupItem.removeSubscriber(groupItem, "groupHidden");
+    // it should still stay after 3 ms.
+    setTimeout(checkExistence, 3);
+  });
+
+  groupItem.addSubscriber(groupItem, "groupShown", function() {
+    groupItem.removeSubscriber(groupItem, "groupShown");
+
+    let endGame = function() {
+      window.removeEventListener("tabviewhidden", endGame, false);
+      ok(!TabView.isVisible(), "Tab View is hidden");
+
+      groupItem.fadeAwayUndoButtonDelay = fadeAwayUndoButtonDelay;
+      groupItem.fadeAwayUndoButtonDuration = fadeAwayUndoButtonDuration;
+
+      finish();
+    };
+    window.addEventListener("tabviewhidden", endGame, false);
+
+    TabView.toggle();
+  });
+
+  let closeButton = groupItem.container.getElementsByClassName("close");
+  ok(closeButton, "Group item close button exists");
+
+  // store the original values
+  fadeAwayUndoButtonDelay = groupItem.fadeAwayUndoButtonDelay;
+  fadeAwayUndoButtonDuration = groupItem.fadeAwayUndoButtonDuration;
+
+  // set both fade away delay and duration to 1ms
+  groupItem.fadeAwayUndoButtonDelay = 1;
+  groupItem.fadeAwayUndoButtonDuration = 1;
+
+  EventUtils.sendMouseEvent({ type: "click" }, closeButton[0], contentWindow);
+}