From 04bf56d9ad367f7df5bf0bcf5164146f46eafc68 Mon Sep 17 00:00:00 2001 From: Raymond Lee Date: Fri, 10 Sep 2010 22:40:27 +0800 Subject: [PATCH] Bug 587341 - Implement Undo Close Group inside of Tab Candy [r+a=dietrich] --HG-- extra : rebase_source : c7b690918220b912add182cd0aea2aedf5b05e9f --- browser/base/content/browser-tabview.js | 7 +- browser/base/content/tabview/groupitems.js | 204 +++++++++++++++--- browser/base/content/tabview/tabitems.js | 5 +- browser/base/content/tabview/tabview.css | 9 + browser/base/content/tabview/ui.js | 8 +- browser/base/content/test/tabview/Makefile.in | 1 + .../test/tabview/browser_tabview_bug591706.js | 41 ++-- .../test/tabview/browser_tabview_dragdrop.js | 6 +- .../tabview/browser_tabview_undo_group.js | 168 +++++++++++++++ .../gnomestripe/browser/tabview/tabview.css | 29 +++ .../pinstripe/browser/tabview/tabview.css | 28 +++ .../winstripe/browser/tabview/tabview.css | 28 +++ 12 files changed, 488 insertions(+), 46 deletions(-) create mode 100644 browser/base/content/test/tabview/browser_tabview_undo_group.js diff --git a/browser/base/content/browser-tabview.js b/browser/base/content/browser-tabview.js index 81d69cad3f8..5e1facde695 100644 --- a/browser/base/content/browser-tabview.js +++ b/browser/base/content/browser-tabview.js @@ -150,8 +150,11 @@ let TabView = { let activeGroup = tab.tabItem.parent; let groupItems = self._window.GroupItems.groupItems; - groupItems.forEach(function(groupItem) { - if (groupItem.getTitle().length > 0 && + groupItems.forEach(function(groupItem) { + // if group has title, it's not hidden and there is no active group or + // the active group id doesn't match the group id, a group menu item + // would be added. + if (groupItem.getTitle().length > 0 && !groupItem.hidden && (!activeGroup || activeGroup.id != groupItem.id)) { let menuItem = self._createGroupMenuItem(groupItem); popup.insertBefore(menuItem, separator); diff --git a/browser/base/content/tabview/groupitems.js b/browser/base/content/tabview/groupitems.js index c8a4bf1f34c..4a8394bb04d 100644 --- a/browser/base/content/tabview/groupitems.js +++ b/browser/base/content/tabview/groupitems.js @@ -77,6 +77,7 @@ function GroupItem(listOfEls, options) { this.expanded = null; this.locked = (options.locked ? Utils.copy(options.locked) : {}); this.topChild = null; + this.hidden = false; this.keepProportional = false; @@ -269,6 +270,9 @@ function GroupItem(listOfEls, options) { if (this.locked.close) $close.hide(); + // ___ Undo Close + this.$undoContainer = null; + // ___ Superclass initialization this._init($container[0]); @@ -541,9 +545,16 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), { GroupItems.unregister(this); this._sendToSubscribers("close"); this.removeTrenches(); - iQ(this.container).fadeOut(function() { - iQ(this).remove(); - Items.unsquish(); + + iQ(this.container).animate({ + opacity: 0, + "-moz-transform": "scale(.3)", + }, { + duration: 170, + complete: function() { + iQ(this).remove(); + Items.unsquish(); + } }); Storage.deleteGroupItem(gWindow, this.id); @@ -553,17 +564,137 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), { // Function: closeAll // Closes the groupItem and all of its children. closeAll: function GroupItem_closeAll() { - var self = this; - if (this._children.length) { - var toClose = this._children.concat(); + if (this._children.length > 0) { + this._children.forEach(function(child) { + iQ(child.container).hide(); + }); + + iQ(this.container).animate({ + opacity: 0, + "-moz-transform": "scale(.3)", + }, { + duration: 170, + complete: function() { + iQ(this).hide(); + } + }); + + this._createUndoButton(); + } else { + if (!this.locked.close) + this.close(); + } + }, + + // ---------- + // Function: _createUndoButton + // Makes the affordance for undo a close group action + _createUndoButton: function() { + let self = this; + this.$undoContainer = iQ("
") + .addClass("undo") + .attr("type", "button") + .text("Undo Close Group") + .appendTo("body"); + let undoClose = iQ("") + .addClass("close") + .appendTo(this.$undoContainer); + + this.$undoContainer.css({ + left: this.bounds.left + this.bounds.width/2 - iQ(self.$undoContainer).width()/2, + top: this.bounds.top + this.bounds.height/2 - iQ(self.$undoContainer).height()/2, + "-moz-transform": "scale(.1)", + opacity: 0 + }); + this.hidden = true; + + setTimeout(function() { + self.$undoContainer.animate({ + "-moz-transform": "scale(1)", + "opacity": 1 + }, { + 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(); - if (!this.locked.close) - this.close(); + iQ(self.container).remove(); + self.$undoContainer.remove(); + self.$undoContainer = null; + Items.unsquish(); + + Storage.deleteGroupItem(gWindow, self.id); + }; + + 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.$undoContainer = null; + + iQ(self.container).show().animate({ + "-moz-transform": "scale(1)", + "opacity": 1 + }, { + duration: 170, + complete: function() { + self._children.forEach(function(child) { + iQ(child.container).show(); + }); + } + }); + + self._sendToSubscribers("groupShown", { groupItemId: self.id }); + }); + }); + + undoClose.click(function() { + self.$undoContainer.fadeOut(remove); + }); + + // After 15 seconds, fade away. + const WAIT = 15000; + const FADE = 300; + + let fadeaway = function() { + if (self.$undoContainer) + self.$undoContainer.animate({ + color: "transparent", + opacity: 0 + }, { + duration: FADE, + complete: remove + }); + }; + + 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); + }); }, // ---------- @@ -1594,14 +1725,13 @@ let GroupItems = { // ---------- // Function: setActiveGroupItem - // Sets the active groupItem, thereby showing only the relevent tabs, and + // Sets the active groupItem, thereby showing only the relevant tabs and // setting the groupItem which will receive new tabs. // // Paramaters: // groupItem - the active or if no groupItem is active // (which means we have an orphaned tab selected) setActiveGroupItem: function GroupItems_setActiveGroupItem(groupItem) { - if (this._activeGroupItem) iQ(this._activeGroupItem.container).removeClass('activeGroupItem'); @@ -1696,10 +1826,12 @@ let GroupItems = { if (!activeGroupItem) { if (groupItems.length > 0) { groupItems.some(function(groupItem) { - var child = groupItem.getChild(0); - if (child) { - tabItem = child; - return true; + if (!groupItem.hidden) { + var child = groupItem.getChild(0); + if (child) { + tabItem = child; + return true; + } } return false; }); @@ -1707,7 +1839,7 @@ let GroupItems = { } else { var currentIndex; groupItems.some(function(groupItem, index) { - if (groupItem == activeGroupItem) { + if (!groupItem.hidden && groupItem == activeGroupItem) { currentIndex = index; return true; } @@ -1715,10 +1847,12 @@ let GroupItems = { }); var firstGroupItems = groupItems.slice(currentIndex + 1); firstGroupItems.some(function(groupItem) { - var child = groupItem.getChild(0); - if (child) { - tabItem = child; - return true; + if (!groupItem.hidden) { + var child = groupItem.getChild(0); + if (child) { + tabItem = child; + return true; + } } return false; }); @@ -1730,10 +1864,12 @@ let GroupItems = { if (!tabItem) { var secondGroupItems = groupItems.slice(0, currentIndex); secondGroupItems.some(function(groupItem) { - var child = groupItem.getChild(0); - if (child) { - tabItem = child; - return true; + if (!groupItem.hidden) { + var child = groupItem.getChild(0); + if (child) { + tabItem = child; + return true; + } } return false; }); @@ -1818,5 +1954,25 @@ let GroupItems = { groupItem.close(); } }); + }, + + // ---------- + // Function: removeHiddenGroups + // Removes all hidden groups' data and its browser tabs. + removeHiddenGroups: function GroupItems_removeHiddenGroups() { + iQ(".undo").remove(); + + // ToDo: encapsulate this in the group item. bug 594863 + this.groupItems.forEach(function(groupItem) { + if (groupItem.hidden) { + let toClose = groupItem._children.concat(); + toClose.forEach(function(child) { + child.removeSubscriber(groupItem, "close"); + child.close(); + }); + + Storage.deleteGroupItem(gWindow, groupItem.id); + } + }); } }; diff --git a/browser/base/content/tabview/tabitems.js b/browser/base/content/tabview/tabitems.js index 2b4a03807e4..94b87424f42 100644 --- a/browser/base/content/tabview/tabitems.js +++ b/browser/base/content/tabview/tabitems.js @@ -49,7 +49,6 @@ // Parameters: // tab - a xul:tab function TabItem(tab) { - Utils.assert(tab, "tab"); this.tab = tab; @@ -506,6 +505,10 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), { // Parameters: // isNewBlankTab - boolean indicates whether it is a newly opened blank tab. zoomIn: function TabItem_zoomIn(isNewBlankTab) { + // don't allow zoom in if its group is hidden + if (this.parent && this.parent.hidden) + return; + var self = this; var $tabEl = iQ(this.container); var childHitResult = { shouldZoom: true }; diff --git a/browser/base/content/tabview/tabview.css b/browser/base/content/tabview/tabview.css index b7ae4ca708d..27f0d45e5ac 100644 --- a/browser/base/content/tabview/tabview.css +++ b/browser/base/content/tabview/tabview.css @@ -102,6 +102,15 @@ body { /* Other Items ----------------------------------*/ +.undo { + position: absolute; +} + +.undo .close { + display: inline-block; + position: relative; +} + .info-item { position: absolute; } diff --git a/browser/base/content/tabview/ui.js b/browser/base/content/tabview/ui.js index ce6f91c3f6f..cbf5893ef12 100644 --- a/browser/base/content/tabview/ui.js +++ b/browser/base/content/tabview/ui.js @@ -214,8 +214,10 @@ let UI = { var observer = { observe : function(subject, topic, data) { if (topic == "quit-application-requested") { - if (self._isTabViewVisible()) + if (self._isTabViewVisible()) { + GroupItems.removeHiddenGroups(); TabItems.saveAll(true); + } self._save(); } } @@ -353,6 +355,7 @@ let UI = { if (!this._isTabViewVisible()) return; + GroupItems.removeHiddenGroups(); TabItems.pausePainting(); this._reorderTabsOnHide.forEach(function(groupItem) { @@ -572,7 +575,8 @@ let UI = { function getClosestTabBy(norm) { var centers = - [[item.bounds.center(), item] for each(item in TabItems.getItems())]; + [[item.bounds.center(), item] + for each(item in TabItems.getItems()) if (!item.parent || !item.parent.hidden)]; var myCenter = self.getActiveTab().bounds.center(); var matches = centers .filter(function(item){return norm(item[0], myCenter)}) diff --git a/browser/base/content/test/tabview/Makefile.in b/browser/base/content/test/tabview/Makefile.in index 92f333d944b..b1a4d4a3ff8 100644 --- a/browser/base/content/test/tabview/Makefile.in +++ b/browser/base/content/test/tabview/Makefile.in @@ -51,6 +51,7 @@ _BROWSER_FILES = \ browser_tabview_snapping.js \ browser_tabview_bug591706.js \ browser_tabview_apptabs.js \ + browser_tabview_undo_group.js \ $(NULL) libs:: $(_BROWSER_FILES) diff --git a/browser/base/content/test/tabview/browser_tabview_bug591706.js b/browser/base/content/test/tabview/browser_tabview_bug591706.js index af8116354c1..b1e4642ac26 100644 --- a/browser/base/content/test/tabview/browser_tabview_bug591706.js +++ b/browser/base/content/test/tabview/browser_tabview_bug591706.js @@ -80,24 +80,33 @@ function onTabViewWindowLoaded() { is(group.getChildren()[0].tab.linkedBrowser.contentWindow.location, secondTab.linkedBrowser.contentWindow.location, "The second tab was there first"); is(group.getChildren()[1].tab.linkedBrowser.contentWindow.location, firstTab.linkedBrowser.contentWindow.location, "The first tab was just added and went to the end of the line"); + group.addSubscriber(group, "close", function() { + group.removeSubscriber(group, "close"); + + ok(group.isEmpty(), "The group is empty again"); + + is(contentWindow.GroupItems.getActiveGroupItem(), null, "The active group is gone"); + contentWindow.GroupItems.setActiveGroupItem(currentGroup); + isnot(contentWindow.GroupItems.getActiveGroupItem(), null, "There is an active group"); + is(gBrowser.tabs.length, 1, "There is only one tab left"); + is(gBrowser.visibleTabs.length, 1, "There is also only one visible tab"); + + let onTabViewHidden = function() { + window.removeEventListener("tabviewhidden", onTabViewHidden, false); + finish(); + }; + window.addEventListener("tabviewhidden", onTabViewHidden, false); + gBrowser.selectedTab = originalTab; + + TabView.hide(); + }); + // Get rid of the group and its children group.closeAll(); - ok(group.isEmpty(), "The group is empty again"); - - is(contentWindow.GroupItems.getActiveGroupItem(), null, "The active group is gone"); - contentWindow.GroupItems.setActiveGroupItem(currentGroup); - isnot(contentWindow.GroupItems.getActiveGroupItem(), null, "There is an active group"); - is(gBrowser.tabs.length, 1, "There is only one tab left"); - is(gBrowser.visibleTabs.length, 1, "There is also only one visible tab"); - - let onTabViewHidden = function() { - window.removeEventListener("tabviewhidden", onTabViewHidden, false); - finish(); - }; - window.addEventListener("tabviewhidden", onTabViewHidden, false); - gBrowser.selectedTab = originalTab; - - TabView.hide(); + // close undo group + let closeButton = group.$undoContainer.find(".close"); + EventUtils.sendMouseEvent( + { type: "click" }, closeButton[0], contentWindow); } function simulateDragDrop(srcElement, offsetX, offsetY, contentWindow) { diff --git a/browser/base/content/test/tabview/browser_tabview_dragdrop.js b/browser/base/content/test/tabview/browser_tabview_dragdrop.js index 7075dab358a..ce634dc131a 100644 --- a/browser/base/content/test/tabview/browser_tabview_dragdrop.js +++ b/browser/base/content/test/tabview/browser_tabview_dragdrop.js @@ -114,7 +114,11 @@ function addTest(contentWindow, groupOneId, groupTwoId, originalTab) { let onTabViewHidden = function() { window.removeEventListener("tabviewhidden", onTabViewHidden, false); - groupTwo.closeAll(); + groupTwo.closeAll(); + // close undo group + let closeButton = groupTwo.$undoContainer.find(".close"); + EventUtils.sendMouseEvent( + { type: "click" }, closeButton[0], contentWindow); }; groupTwo.addSubscriber(groupTwo, "close", function() { groupTwo.removeSubscriber(groupTwo, "close"); diff --git a/browser/base/content/test/tabview/browser_tabview_undo_group.js b/browser/base/content/test/tabview/browser_tabview_undo_group.js new file mode 100644 index 00000000000..02fcea9dc80 --- /dev/null +++ b/browser/base/content/test/tabview/browser_tabview_undo_group.js @@ -0,0 +1,168 @@ +/* ***** 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 tabview undo group test. + * + * 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 + * + * 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 ***** */ + +function test() { + waitForExplicitFinish(); + + window.addEventListener("tabviewshown", onTabViewWindowLoaded, false); + TabView.toggle(); +} + +function onTabViewWindowLoaded() { + window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false); + ok(TabView.isVisible(), "Tab View is visible"); + + let contentWindow = document.getElementById("tab-view").contentWindow; + + // create a group item + let box = new contentWindow.Rect(20, 400, 300, 300); + let groupItem = new contentWindow.GroupItem([], { bounds: box }); + + // create a tab item in the new group + let onTabViewHidden = function() { + window.removeEventListener("tabviewhidden", onTabViewHidden, false); + + ok(!TabView.isVisible(), "Tab View is hidden because we just opened a tab"); + // show tab view + TabView.toggle(); + }; + let onTabViewShown = function() { + window.removeEventListener("tabviewshown", onTabViewShown, false); + + is(groupItem.getChildren().length, 1, "The new group has a tab item"); + // start the tests + testUndoGroup(contentWindow, groupItem); + }; + window.addEventListener("tabviewhidden", onTabViewHidden, false); + window.addEventListener("tabviewshown", onTabViewShown, false); + + // click on the + button + let newTabButton = groupItem.container.getElementsByClassName("newTabButton"); + ok(newTabButton[0], "New tab button exists"); + + EventUtils.sendMouseEvent({ type: "click" }, newTabButton[0], contentWindow); +} + +function testUndoGroup(contentWindow, groupItem) { + groupItem.addSubscriber(groupItem, "groupHidden", function() { + groupItem.removeSubscriber(groupItem, "groupHidden"); + + // check the data of the group + let theGroupItem = contentWindow.GroupItems.groupItem(groupItem.id); + ok(theGroupItem, "The group item still exists"); + is(theGroupItem.getChildren().length, 1, + "The tab item in the group still exists"); + + // check the visibility of the group element and undo element + is(theGroupItem.container.style.display, "none", + "The group element is hidden"); + ok(theGroupItem.$undoContainer, "Undo container is avaliable"); + + EventUtils.sendMouseEvent( + { type: "click" }, theGroupItem.$undoContainer[0], contentWindow); + }); + + groupItem.addSubscriber(groupItem, "groupShown", function() { + groupItem.removeSubscriber(groupItem, "groupShown"); + + // check the data of the group + let theGroupItem = contentWindow.GroupItems.groupItem(groupItem.id); + ok(theGroupItem, "The group item still exists"); + is(theGroupItem.getChildren().length, 1, + "The tab item in the group still exists"); + + // check the visibility of the group element and undo element + is(theGroupItem.container.style.display, "", "The group element is visible"); + ok(!theGroupItem.$undoContainer, "Undo container is not avaliable"); + + // start the next test + testCloseUndoGroup(contentWindow, groupItem); + }); + + let closeButton = groupItem.container.getElementsByClassName("close"); + ok(closeButton, "Group item close button exists"); + EventUtils.sendMouseEvent({ type: "click" }, closeButton[0], contentWindow); +} + +function testCloseUndoGroup(contentWindow, groupItem) { + groupItem.addSubscriber(groupItem, "groupHidden", function() { + groupItem.removeSubscriber(groupItem, "groupHidden"); + + // check the data of the group + let theGroupItem = contentWindow.GroupItems.groupItem(groupItem.id); + ok(theGroupItem, "The group item still exists"); + is(theGroupItem.getChildren().length, 1, + "The tab item in the group still exists"); + + // check the visibility of the group element and undo element + is(theGroupItem.container.style.display, "none", + "The group element is hidden"); + ok(theGroupItem.$undoContainer, "Undo container is avaliable"); + + // click on close + let closeButton = theGroupItem.$undoContainer.find(".close"); + EventUtils.sendMouseEvent( + { type: "click" }, closeButton[0], contentWindow); + }); + + groupItem.addSubscriber(groupItem, "close", function() { + groupItem.removeSubscriber(groupItem, "close"); + + let theGroupItem = contentWindow.GroupItems.groupItem(groupItem.id); + ok(!theGroupItem, "The group item doesn't exists"); + + let endGame = function() { + window.removeEventListener("tabviewhidden", endGame, false); + ok(!TabView.isVisible(), "Tab View is hidden"); + finish(); + }; + window.addEventListener("tabviewhidden", endGame, false); + + // after the last selected tabitem is closed, there would be not active + // tabitem on the UI so we set the active tabitem before toggling the + // visibility of tabview + let tabItems = contentWindow.TabItems.getItems(); + ok(tabItems[0], "A tab item exists"); + contentWindow.UI.setActiveTab(tabItems[0]); + + TabView.toggle(); + }); + + let closeButton = groupItem.container.getElementsByClassName("close"); + ok(closeButton, "Group item close button exists"); + EventUtils.sendMouseEvent({ type: "click" }, closeButton[0], contentWindow); +} diff --git a/browser/themes/gnomestripe/browser/tabview/tabview.css b/browser/themes/gnomestripe/browser/tabview/tabview.css index 244b2b185a0..7c744288dfd 100644 --- a/browser/themes/gnomestripe/browser/tabview/tabview.css +++ b/browser/themes/gnomestripe/browser/tabview/tabview.css @@ -194,6 +194,35 @@ body { cursor: pointer; } +.undo { + background-color: #A0A0A0; + width: 150px; + height: 30px; + line-height: 30px; + -moz-box-shadow: 0px 1px 0px rgba(255,255,255,.5), 0px -1px 0px rgba(0,0,0,.24); + text-shadow: 0px -1px 0px rgba(255,255,255,.2); + color: rgba( 0,0,0, .8); + border-radius: 0.4em; + text-align: center; + border: none; + cursor: pointer; +} + +.undo:hover { + background-color: #949494; +} + +.undo .close { + top: 4px; + left: 4px; + opacity: 0.5; +} + +.undo .close:hover{ + opacity: 1.0; +} + + /* InfoItems ----------------------------------*/ diff --git a/browser/themes/pinstripe/browser/tabview/tabview.css b/browser/themes/pinstripe/browser/tabview/tabview.css index d7a5f857d94..53cb0c64566 100644 --- a/browser/themes/pinstripe/browser/tabview/tabview.css +++ b/browser/themes/pinstripe/browser/tabview/tabview.css @@ -201,6 +201,34 @@ body { cursor: pointer; } +.undo { + background-color: #A0A0A0; + width: 150px; + height: 30px; + line-height: 30px; + -moz-box-shadow: 0px 1px 0px rgba(255,255,255,.5), 0px -1px 0px rgba(0,0,0,.24); + text-shadow: 0px -1px 0px rgba(255,255,255,.2); + color: rgba( 0,0,0, .8); + border-radius: 0.4em; + text-align: center; + border: none; + cursor: pointer; +} + +.undo:hover { + background-color: #949494; +} + +.undo .close { + top: 4px; + left: 4px; + opacity: 0.5; +} + +.undo .close:hover{ + opacity: 1.0; +} + /* InfoItems ----------------------------------*/ diff --git a/browser/themes/winstripe/browser/tabview/tabview.css b/browser/themes/winstripe/browser/tabview/tabview.css index 7b952b24191..2b763f863ce 100644 --- a/browser/themes/winstripe/browser/tabview/tabview.css +++ b/browser/themes/winstripe/browser/tabview/tabview.css @@ -206,6 +206,34 @@ body { cursor: pointer; } +.undo { + background-color: #A0A0A0; + width: 150px; + height: 30px; + line-height: 30px; + -moz-box-shadow: 0px 1px 0px rgba(255,255,255,.5), 0px -1px 0px rgba(0,0,0,.24); + text-shadow: 0px -1px 0px rgba(255,255,255,.2); + color: rgba( 0,0,0, .8); + border-radius: 0.4em; + text-align: center; + border: none; + cursor: pointer; +} + +.undo:hover { + background-color: #949494; +} + +.undo .close { + top: 4px; + left: 4px; + opacity: 0.5; +} + +.undo .close:hover{ + opacity: 1.0; +} + /* InfoItems ----------------------------------*/