diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index 49df4df72c9..d9512cb734e 100644
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -7930,6 +7930,9 @@ var TabContextMenu = {
let unpinnedTabs = gBrowser.visibleTabs.length - gBrowser._numPinnedTabs;
document.getElementById("context_closeOtherTabs").disabled = unpinnedTabs <= 1;
document.getElementById("context_closeOtherTabs").hidden = this.contextTab.pinned;
+
+ // Disable "Move to Group" if it's a pinned tab.
+ document.getElementById("context_tabViewMenu").disabled = this.contextTab.pinned;
}
};
diff --git a/browser/base/content/tabview/drag.js b/browser/base/content/tabview/drag.js
index 17b1ac12c67..97000ca7adc 100644
--- a/browser/base/content/tabview/drag.js
+++ b/browser/base/content/tabview/drag.js
@@ -118,8 +118,8 @@ Drag.prototype = {
// OH SNAP!
- // if we aren't holding down the meta key...
- if (!Keys.meta) {
+ // if we aren't holding down the meta key or have trenches disabled...
+ if (!Keys.meta && !Trenches.disabled) {
// snappable = true if we aren't a tab on top of something else, and
// there's no active drop site...
let snappable = !(this.item.isATabItem &&
diff --git a/browser/base/content/tabview/groupitems.js b/browser/base/content/tabview/groupitems.js
index 21a3ab7e984..e2de885ed1b 100644
--- a/browser/base/content/tabview/groupitems.js
+++ b/browser/base/content/tabview/groupitems.js
@@ -1386,39 +1386,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
// TabItems will have handled the new tab and added the tabItem property.
// We don't have to check if it's an app tab (and therefore wouldn't have a
// TabItem), since we've just created it.
- let newItem = newTab.tabItem;
-
- var self = this;
- iQ(newItem.container).css({opacity: 0});
- let $anim = iQ("
")
- .addClass("newTabAnimatee")
- .css({
- top: newItem.bounds.top + 5,
- left: newItem.bounds.left + 5,
- width: newItem.bounds.width - 10,
- height: newItem.bounds.height - 10,
- zIndex: 999,
- opacity: 0
- })
- .appendTo("body")
- .animate({opacity: 1}, {
- duration: 500,
- complete: function() {
- $anim.animate({
- top: 0,
- left: 0,
- width: window.innerWidth,
- height: window.innerHeight
- }, {
- duration: 270,
- complete: function() {
- iQ(newItem.container).css({opacity: 1});
- newItem.zoomIn(!url);
- $anim.remove();
- }
- });
- }
- });
+ newTab.tabItem.zoomIn(!url);
},
// ----------
@@ -1542,6 +1510,7 @@ let GroupItems = {
},
// ----------
+ // Function: _handleAttrModified
// watch for icon changes on app tabs
_handleAttrModified: function GroupItems__handleAttrModified(xulTab) {
if (xulTab.ownerDocument.defaultView != gWindow || !xulTab.pinned)
@@ -1561,16 +1530,18 @@ let GroupItems = {
},
// ----------
- // when a tab becomes pinned, add it to the app tab tray in all groups
- handleTabPin: function GroupItems_handleTabPin(xulTab) {
+ // Function: addAppTab
+ // Adds the given xul:tab to the app tab tray in all groups
+ addAppTab: function GroupItems_addAppTab(xulTab) {
this.groupItems.forEach(function(groupItem) {
groupItem.addAppTab(xulTab);
});
},
// ----------
- // when a tab becomes unpinned, remove it from the app tab tray in all groups
- handleTabUnpin: function GroupItems_handleTabUnpin(xulTab) {
+ // Function: removeAppTab
+ // Removes the given xul:tab from the app tab tray in all groups
+ removeAppTab: function GroupItems_removeAppTab(xulTab) {
this.groupItems.forEach(function(groupItem) {
groupItem.removeAppTab(xulTab);
});
@@ -1582,7 +1553,7 @@ let GroupItems = {
getNextID: function GroupItems_getNextID() {
var result = this.nextID;
this.nextID++;
- this.save();
+ this._save();
return result;
},
@@ -1602,20 +1573,22 @@ let GroupItems = {
// Function: saveAll
// Saves GroupItems state, as well as the state of all of the groupItems.
saveAll: function GroupItems_saveAll() {
- this.save();
+ this._save();
this.groupItems.forEach(function(groupItem) {
groupItem.save();
});
},
// ----------
- // Function: save
+ // Function: _save
// Saves GroupItems state.
- save: function GroupItems_save() {
+ _save: function GroupItems__save() {
if (!this._inited) // too soon to save now
return;
- Storage.saveGroupItemsData(gWindow, {nextID:this.nextID});
+ let activeGroupId = this._activeGroupItem ? this._activeGroupItem.id : null;
+ Storage.saveGroupItemsData(
+ gWindow, { nextID: this.nextID, activeGroupId: activeGroupId });
},
// ----------
@@ -1637,8 +1610,14 @@ let GroupItems = {
// If no data, sets up blank slate (including "new tabs" groupItem).
reconstitute: function GroupItems_reconstitute(groupItemsData, groupItemData) {
try {
- if (groupItemsData && groupItemsData.nextID)
- this.nextID = groupItemsData.nextID;
+ let activeGroupId;
+
+ if (groupItemsData) {
+ if (groupItemsData.nextID)
+ this.nextID = groupItemsData.nextID;
+ if (groupItemsData.activeGroupId)
+ activeGroupId = groupItemsData.activeGroupId;
+ }
if (groupItemData) {
for (var id in groupItemData) {
@@ -1652,9 +1631,15 @@ let GroupItems = {
}
}
}
+ // set active group item
+ if (activeGroupId) {
+ let activeGroupItem = this.groupItem(activeGroupId);
+ if (activeGroupItem)
+ this.setActiveGroupItem(activeGroupItem);
+ }
this._inited = true;
- this.save(); // for nextID
+ this._save(); // for nextID
} catch(e) {
Utils.log("error in recons: "+e);
}
@@ -1763,38 +1748,83 @@ let GroupItems = {
// Given a , files it in the appropriate groupItem.
newTab: function GroupItems_newTab(tabItem) {
let activeGroupItem = this.getActiveGroupItem();
- let orphanTab = this.getActiveOrphanTab();
-// Utils.log('newTab', activeGroupItem, orphanTab);
+
+ // 1. Active group
+ // 2. Active orphan
+ // 3. First visible non-app tab (that's not the tab in question), whether it's an
+ // orphan or not (make a new group if it's an orphan, add it to the group if it's
+ // not)
+ // 4. First group
+ // 5. First orphan that's not the tab in question
+ // 6. At this point there should be no groups or tabs (except for app tabs and the
+ // tab in question): make a new group
+
if (activeGroupItem) {
activeGroupItem.add(tabItem);
- } else if (orphanTab) {
- let newGroupItemBounds = orphanTab.getBoundsWithTitle();
- newGroupItemBounds.inset(-40,-40);
- let newGroupItem = new GroupItem([orphanTab, tabItem], {bounds: newGroupItemBounds});
- newGroupItem.snap();
- this.setActiveGroupItem(newGroupItem);
- } else {
- this.positionNewTabAtBottom(tabItem);
+ return;
}
- },
- // ----------
- // Function: positionNewTabAtBottom
- // Does what it says on the tin.
- // TODO: Make more robust and improve documentation,
- // Also, this probably belongs in tabitems.js
- // Bug 586558
- positionNewTabAtBottom: function GroupItems_positionNewTabAtBottom(tabItem) {
- let windowBounds = Items.getSafeWindowBounds();
+ let orphanTabItem = this.getActiveOrphanTab();
+ if (!orphanTabItem) {
+ let otherTab;
+ // find first visible non-app tab in the tabbar.
+ gBrowser.visibleTabs.some(function(tab) {
+ if (!tab.pinned && tab != tabItem.tab) {
+ otherTab = tab;
+ return true;
+ }
+ return false;
+ });
- let itemBounds = new Rect(
- windowBounds.right - TabItems.tabWidth,
- windowBounds.bottom - TabItems.tabHeight,
- TabItems.tabWidth,
- TabItems.tabHeight
- );
+ if (otherTab) {
+ // the first visible tab belongs to a group, add the new tabItem into
+ // that group
+ if (otherTab.tabItem.parent) {
+ let groupItem = otherTab.tabItem.parent;
+ groupItem.add(tabItem);
+ this.setActiveGroupItem(groupItem);
+ return;
+ }
+ // the first visible tab is an orphan tab, set the orphan tab, and
+ // create a new group for orphan tab and new tabItem
+ orphanTabItem = otherTab.tabItem;
+ }
- tabItem.setBounds(itemBounds);
+ if (!orphanTabItem) {
+ // add the new tabItem to the first group item
+ if (this.groupItems.length > 0) {
+ let groupItem = this.groupItems[0];
+ groupItem.add(tabItem);
+ this.setActiveGroupItem(groupItem);
+ return;
+ }
+ // set the orphan tab, and create a new group for orphan tab and
+ // new tabItem
+ let orphanedTabs = this.getOrphanedTabs();
+ if (orphanedTabs.length > 0)
+ orphanTabItem = orphanedTabs[0];
+ }
+ }
+
+ // create new group for orphan tab and new tabItem
+ let tabItems;
+ let newGroupItemBounds;
+ // the orphan tab would be the same as tabItem when all tabs are app tabs
+ // and a new tab is created.
+ if (orphanTabItem && orphanTabItem.tab != tabItem.tab) {
+ newGroupItemBounds = orphanTabItem.getBoundsWithTitle();
+ tabItems = [orphanTabItem, tabItem];
+ } else {
+ tabItem.setPosition(60, 60, true);
+ newGroupItemBounds = tabItem.getBounds();
+ tabItems = [tabItem];
+ }
+
+ newGroupItemBounds.inset(-40,-40);
+ let newGroupItem =
+ new GroupItem(tabItems, { bounds: newGroupItemBounds });
+ newGroupItem.snap();
+ this.setActiveGroupItem(newGroupItem);
},
// ----------
@@ -1825,6 +1855,7 @@ let GroupItems = {
}
this._activeGroupItem = groupItem;
+ this._save();
},
// ----------
@@ -1909,6 +1940,13 @@ let GroupItems = {
if (groupItems.length > 0) {
groupItems.some(function(groupItem) {
if (!groupItem.hidden) {
+ // restore the last active tab in the group
+ let activeTab = groupItem.getActiveTab();
+ if (activeTab) {
+ tabItem = activeTab;
+ return true;
+ }
+ // if no tab is active, use the first one
var child = groupItem.getChild(0);
if (child) {
tabItem = child;
@@ -1930,6 +1968,13 @@ let GroupItems = {
var firstGroupItems = groupItems.slice(currentIndex + 1);
firstGroupItems.some(function(groupItem) {
if (!groupItem.hidden) {
+ // restore the last active tab in the group
+ let activeTab = groupItem.getActiveTab();
+ if (activeTab) {
+ tabItem = activeTab;
+ return true;
+ }
+ // if no tab is active, use the first one
var child = groupItem.getChild(0);
if (child) {
tabItem = child;
@@ -1947,6 +1992,13 @@ let GroupItems = {
var secondGroupItems = groupItems.slice(0, currentIndex);
secondGroupItems.some(function(groupItem) {
if (!groupItem.hidden) {
+ // restore the last active tab in the group
+ let activeTab = groupItem.getActiveTab();
+ if (activeTab) {
+ tabItem = activeTab;
+ return true;
+ }
+ // if no tab is active, use the first one
var child = groupItem.getChild(0);
if (child) {
tabItem = child;
diff --git a/browser/base/content/tabview/items.js b/browser/base/content/tabview/items.js
index ccd7bbd96d7..88ff81c0d93 100644
--- a/browser/base/content/tabview/items.js
+++ b/browser/base/content/tabview/items.js
@@ -187,7 +187,10 @@ Item.prototype = {
stop: function() {
drag.info.stop();
drag.info = null;
- }
+ },
+ // The minimum the mouse must move after mouseDown in order to move an
+ // item
+ minDragDistance: 3
};
// ___ drop
@@ -592,64 +595,67 @@ Item.prototype = {
// ___ mousemove
var handleMouseMove = function(e) {
// positioning
- var mouse = new Point(e.pageX, e.pageY);
- var box = self.getBounds();
- box.left = startPos.x + (mouse.x - startMouse.x);
- box.top = startPos.y + (mouse.y - startMouse.y);
-
- self.setBounds(box, true);
-
- // drag events
+ var mouse = new Point(e.pageX, e.pageY);
if (!startSent) {
- if (typeof self.dragOptions.start == "function")
- self.dragOptions.start.apply(self,
- [startEvent, {position: {left: startPos.x, top: startPos.y}}]);
-
- startSent = true;
+ if(Math.abs(mouse.x - startMouse.x) > self.dragOptions.minDragDistance ||
+ Math.abs(mouse.y - startMouse.y) > self.dragOptions.minDragDistance) {
+ if (typeof self.dragOptions.start == "function")
+ self.dragOptions.start.apply(self,
+ [startEvent, {position: {left: startPos.x, top: startPos.y}}]);
+ startSent = true;
+ }
}
+ if (startSent) {
+ // drag events
+ var box = self.getBounds();
+ box.left = startPos.x + (mouse.x - startMouse.x);
+ box.top = startPos.y + (mouse.y - startMouse.y);
- if (typeof self.dragOptions.drag == "function")
- self.dragOptions.drag.apply(self, [e]);
+ self.setBounds(box, true);
- // drop events
- var best = {
- dropTarget: null,
- score: 0
- };
+ if (typeof self.dragOptions.drag == "function")
+ self.dragOptions.drag.apply(self, [e]);
- droppables.forEach(function(droppable) {
- var intersection = box.intersection(droppable.bounds);
- if (intersection && intersection.area() > best.score) {
- var possibleDropTarget = droppable.item;
- var accept = true;
- if (possibleDropTarget != dropTarget) {
- var dropOptions = possibleDropTarget.dropOptions;
- if (dropOptions && typeof dropOptions.accept == "function")
- accept = dropOptions.accept.apply(possibleDropTarget, [self]);
+ // drop events
+ var best = {
+ dropTarget: null,
+ score: 0
+ };
+
+ droppables.forEach(function(droppable) {
+ var intersection = box.intersection(droppable.bounds);
+ if (intersection && intersection.area() > best.score) {
+ var possibleDropTarget = droppable.item;
+ var accept = true;
+ if (possibleDropTarget != dropTarget) {
+ var dropOptions = possibleDropTarget.dropOptions;
+ if (dropOptions && typeof dropOptions.accept == "function")
+ accept = dropOptions.accept.apply(possibleDropTarget, [self]);
+ }
+
+ if (accept) {
+ best.dropTarget = possibleDropTarget;
+ best.score = intersection.area();
+ }
+ }
+ });
+
+ if (best.dropTarget != dropTarget) {
+ var dropOptions;
+ if (dropTarget) {
+ dropOptions = dropTarget.dropOptions;
+ if (dropOptions && typeof dropOptions.out == "function")
+ dropOptions.out.apply(dropTarget, [e]);
}
- if (accept) {
- best.dropTarget = possibleDropTarget;
- best.score = intersection.area();
+ dropTarget = best.dropTarget;
+
+ if (dropTarget) {
+ dropOptions = dropTarget.dropOptions;
+ if (dropOptions && typeof dropOptions.over == "function")
+ dropOptions.over.apply(dropTarget, [e]);
}
}
- });
-
- if (best.dropTarget != dropTarget) {
- var dropOptions;
- if (dropTarget) {
- dropOptions = dropTarget.dropOptions;
- if (dropOptions && typeof dropOptions.out == "function")
- dropOptions.out.apply(dropTarget, [e]);
- }
-
- dropTarget = best.dropTarget;
-
- if (dropTarget) {
- dropOptions = dropTarget.dropOptions;
- if (dropOptions && typeof dropOptions.over == "function")
- dropOptions.over.apply(dropTarget, [e]);
- }
}
e.preventDefault();
diff --git a/browser/base/content/tabview/tabitems.js b/browser/base/content/tabview/tabitems.js
index 6c049ca1188..111d03bacb0 100644
--- a/browser/base/content/tabview/tabitems.js
+++ b/browser/base/content/tabview/tabitems.js
@@ -1030,10 +1030,16 @@ let TabItems = {
item.reconnected = true;
found = true;
- } else
- item.reconnected = item.tab.linkedBrowser.currentURI.spec != 'about:blank';
-
+ } else {
+ // if it's not a blank tab or it belongs to a group, it would mean
+ // the item is reconnected.
+ item.reconnected =
+ (item.tab.linkedBrowser.currentURI.spec != 'about:blank' || item.parent);
+ }
item.save();
+
+ if (item.reconnected)
+ item._sendToSubscribers("reconnected");
} catch(e) {
Utils.log(e);
}
diff --git a/browser/base/content/tabview/trench.js b/browser/base/content/tabview/trench.js
index 8e045ae924b..f7ccf37aab3 100644
--- a/browser/base/content/tabview/trench.js
+++ b/browser/base/content/tabview/trench.js
@@ -466,9 +466,11 @@ var Trenches = {
// nextId - (integer) a counter for the next 's value.
// showDebug - (boolean) whether to draw the es or not.
// defaultRadius - (integer) the default radius for new es.
+ // disabled - (boolean) whether trench-snapping is disabled or not.
nextId: 0,
showDebug: false,
defaultRadius: 10,
+ disabled: false,
// ---------
// Variables: snapping preferences; used to break ties in snapping.
diff --git a/browser/base/content/tabview/ui.js b/browser/base/content/tabview/ui.js
index d5f7bb79b75..cb2048de4b4 100644
--- a/browser/base/content/tabview/ui.js
+++ b/browser/base/content/tabview/ui.js
@@ -448,10 +448,25 @@ let UI = {
_addTabActionHandlers: function UI__addTabActionHandlers() {
var self = this;
+ // TabOpen
+ this._eventListeners.open = function(tab) {
+ if (tab.ownerDocument.defaultView != gWindow)
+ return;
+
+ // if it's an app tab, add it to all the group items
+ if (tab.pinned)
+ GroupItems.addAppTab(tab);
+ };
+
+ // TabClose
this._eventListeners.close = function(tab) {
if (tab.ownerDocument.defaultView != gWindow)
return;
+ // if it's an app tab, remove it from all the group items
+ if (tab.pinned)
+ GroupItems.removeAppTab(tab);
+
if (self._isTabViewVisible()) {
// just closed the selected tab in the TabView interface.
if (self._currentTab == tab)
@@ -470,13 +485,17 @@ let UI = {
// 1) Only go back to the TabView tab when there you close the last
// tab of a groupItem.
+ let closingLastOfGroup = (groupItem &&
+ groupItem._children.length == 1 &&
+ groupItem._children[0].tab == tab);
+
// 2) Take care of the case where you've closed the last tab in
// an un-named groupItem, which means that the groupItem is gone (null) and
- // there are no visible tabs.
- // Can't use timeout here because user would see a flicker of
- // switching to another tab before the TabView interface shows up.
- if ((groupItem && groupItem._children.length == 1) ||
- (groupItem == null && gBrowser.visibleTabs.length <= 1)) {
+ // there are no visible tabs.
+ let closingUnnamedGroup = (groupItem == null &&
+ gBrowser.visibleTabs.length <= 1);
+
+ if (closingLastOfGroup || closingUnnamedGroup) {
// for the tab focus event to pick up.
self._closedLastVisibleTab = true;
// remove the zoom prep.
@@ -488,6 +507,7 @@ let UI = {
}
};
+ // TabMove
this._eventListeners.move = function(tab) {
if (tab.ownerDocument.defaultView != gWindow)
return;
@@ -497,6 +517,7 @@ let UI = {
self.setReorderTabItemsOnShow(activeGroupItem);
};
+ // TabSelect
this._eventListeners.select = function(tab) {
if (tab.ownerDocument.defaultView != gWindow)
return;
@@ -504,13 +525,14 @@ let UI = {
self.onTabSelect(tab);
};
+ // Actually register the above handlers
for (let name in this._eventListeners)
AllTabs.register(name, this._eventListeners[name]);
// Start watching for tab pin events, and set up our uninit for same.
function handleTabPin(event) {
TabItems.handleTabPin(event.originalTarget);
- GroupItems.handleTabPin(event.originalTarget);
+ GroupItems.addAppTab(event.originalTarget);
}
gBrowser.tabContainer.addEventListener("TabPinned", handleTabPin, false);
@@ -521,7 +543,7 @@ let UI = {
// Start watching for tab unpin events, and set up our uninit for same.
function handleTabUnpin(event) {
TabItems.handleTabUnpin(event.originalTarget);
- GroupItems.handleTabUnpin(event.originalTarget);
+ GroupItems.removeAppTab(event.originalTarget);
}
gBrowser.tabContainer.addEventListener("TabUnpinned", handleTabUnpin, false);
diff --git a/browser/base/content/test/tabview/Makefile.in b/browser/base/content/test/tabview/Makefile.in
index a30411b1f5c..871c1fe8010 100644
--- a/browser/base/content/test/tabview/Makefile.in
+++ b/browser/base/content/test/tabview/Makefile.in
@@ -45,9 +45,12 @@ include $(topsrcdir)/config/rules.mk
_BROWSER_FILES = \
browser_tabview_apptabs.js \
+ browser_tabview_bug580412.js \
browser_tabview_bug587040.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_bug595943.js \
@@ -56,6 +59,7 @@ _BROWSER_FILES = \
browser_tabview_group.js \
browser_tabview_launch.js \
browser_tabview_multiwindow_search.js \
+ browser_tabview_orphaned_tabs.js \
browser_tabview_search.js \
browser_tabview_snapping.js \
browser_tabview_undo_group.js \
diff --git a/browser/base/content/test/tabview/browser_tabview_apptabs.js b/browser/base/content/test/tabview/browser_tabview_apptabs.js
index 839bb83b1de..8e9cd089409 100644
--- a/browser/base/content/test/tabview/browser_tabview_apptabs.js
+++ b/browser/base/content/test/tabview/browser_tabview_apptabs.js
@@ -11,7 +11,7 @@
* for the specific language governing rights and limitations under the
* License.
*
- * The Original Code is tabview group test.
+ * The Original Code is tabview app-tab test.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
@@ -50,51 +50,46 @@ function onTabViewWindowLoaded() {
let contentWindow = document.getElementById("tab-view").contentWindow;
// establish initial state
- is(contentWindow.GroupItems.groupItems.length, 1, "we start with one group (the default)");
+ is(contentWindow.GroupItems.groupItems.length, 1,
+ "we start with one group (the default)");
is(gBrowser.tabs.length, 1, "we start with one tab");
let originalTab = gBrowser.tabs[0];
-
- // create a group
+
+ // create a group
let box = new contentWindow.Rect(20, 20, 180, 180);
- let groupItemOne = new contentWindow.GroupItem([], { bounds: box, title: "test1" });
+ let groupItemOne = new contentWindow.GroupItem([],
+ { bounds: box, title: "test1" });
is(contentWindow.GroupItems.groupItems.length, 2, "we now have two groups");
contentWindow.GroupItems.setActiveGroupItem(groupItemOne);
-
+
// create a tab
let xulTab = gBrowser.loadOneTab("about:blank");
is(gBrowser.tabs.length, 2, "we now have two tabs");
is(groupItemOne._children.length, 1, "the new tab was added to the group");
-
+
// make sure the group has no app tabs
- let appTabIcons = groupItemOne.container.getElementsByClassName("appTabIcon");
- is(appTabIcons.length, 0, "there are no app tab icons");
-
+ is(appTabCount(groupItemOne), 0, "there are no app tab icons");
+
// pin the tab, make sure the TabItem goes away and the icon comes on
gBrowser.pinTab(xulTab);
-
- is(groupItemOne._children.length, 0, "the app tab's TabItem was removed from the group");
-
- appTabIcons = groupItemOne.container.getElementsByClassName("appTabIcon");
- is(appTabIcons.length, 1, "there's now one app tab icon");
+ is(groupItemOne._children.length, 0,
+ "the app tab's TabItem was removed from the group");
+ is(appTabCount(groupItemOne), 1, "there's now one app tab icon");
// create a second group and make sure it gets the icon too
box.offset(box.width + 20, 0);
- let groupItemTwo = new contentWindow.GroupItem([], { bounds: box, title: "test2" });
+ let groupItemTwo = new contentWindow.GroupItem([],
+ { bounds: box, title: "test2" });
is(contentWindow.GroupItems.groupItems.length, 3, "we now have three groups");
- appTabIcons = groupItemTwo.container.getElementsByClassName("appTabIcon");
- is(appTabIcons.length, 1, "there's an app tab icon in the second group");
-
+ is(appTabCount(groupItemTwo), 1,
+ "there's an app tab icon in the second group");
+
// unpin the tab, make sure the icon goes away and the TabItem comes on
gBrowser.unpinTab(xulTab);
-
is(groupItemOne._children.length, 1, "the app tab's TabItem is back");
+ is(appTabCount(groupItemOne), 0, "the icon is gone from group one");
+ is(appTabCount(groupItemTwo), 0, "the icon is gone from group 2");
- appTabIcons = groupItemOne.container.getElementsByClassName("appTabIcon");
- is(appTabIcons.length, 0, "the icon is gone from group one");
-
- appTabIcons = groupItemTwo.container.getElementsByClassName("appTabIcon");
- is(appTabIcons.length, 0, "the icon is gone from group 2");
-
// pin the tab again
gBrowser.pinTab(xulTab);
@@ -104,25 +99,30 @@ function onTabViewWindowLoaded() {
// find app tab in group and hit it
let onTabViewHidden = function() {
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
- ok(!TabView.isVisible(), "Tab View is hidden because we clicked on the app tab");
-
- // clean up
- gBrowser.selectedTab = originalTab;
-
- gBrowser.unpinTab(xulTab);
+ ok(!TabView.isVisible(),
+ "Tab View is hidden because we clicked on the app tab");
+
+ // delete the app tab and make sure its icon goes away
gBrowser.removeTab(xulTab);
- is(gBrowser.tabs.length, 1, "we finish with one tab");
-
+ is(appTabCount(groupItemOne), 0, "closing app tab removes its icon");
+
+ // clean up
groupItemOne.close();
- is(contentWindow.GroupItems.groupItems.length, 1, "we finish with one group");
-
+
+ is(contentWindow.GroupItems.groupItems.length, 1,
+ "we finish with one group");
+ is(gBrowser.tabs.length, 1, "we finish with one tab");
ok(!TabView.isVisible(), "we finish with Tab View not visible");
-
+
finish();
};
window.addEventListener("tabviewhidden", onTabViewHidden, false);
- appTabIcons = groupItemOne.container.getElementsByClassName("appTabIcon");
+ let appTabIcons = groupItemOne.container.getElementsByClassName("appTabIcon");
EventUtils.sendMouseEvent({ type: "click" }, appTabIcons[0], contentWindow);
}
+
+function appTabCount(groupItem) {
+ return groupItem.container.getElementsByClassName("appTabIcon").length;
+}
diff --git a/browser/base/content/test/tabview/browser_tabview_bug580412.js b/browser/base/content/test/tabview/browser_tabview_bug580412.js
new file mode 100644
index 00000000000..45f2b42efde
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug580412.js
@@ -0,0 +1,154 @@
+/* ***** 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 Tab View bug 580412 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):
+ * Michael Yoshitaka Erlewine
+ *
+ * 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);
+ if (TabView.isVisible())
+ onTabViewWindowLoaded();
+ else
+ TabView.show();
+}
+
+function onTabViewWindowLoaded() {
+ window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
+
+ let contentWindow = document.getElementById("tab-view").contentWindow;
+ let [originalTab] = gBrowser.visibleTabs;
+
+ ok(TabView.isVisible(), "Tab View is visible");
+ is(contentWindow.GroupItems.groupItems.length, 1, "There is only one group");
+ let currentActiveGroup = contentWindow.GroupItems.getActiveGroupItem();
+
+// is(currentActiveGroup.getBounds.bottom(), 40,
+// "There's currently 40 px between the first group and second group");
+
+ let endGame = function() {
+ let onTabViewHidden = function() {
+ window.removeEventListener("tabviewhidden", onTabViewHidden, false);
+ ok(!TabView.isVisible(), "TabView is shown");
+ finish();
+ };
+ window.addEventListener("tabviewhidden", onTabViewHidden, false);
+
+ ok(TabView.isVisible(), "TabView is shown");
+
+ gBrowser.selectedTab = originalTab;
+ TabView.hide();
+ }
+
+ let part1 = function() {
+// contentWindow.UI.reset();
+ // move down 20 so we're far enough away from the top.
+ checkSnap(currentActiveGroup, 0, 20, contentWindow, function(snapped){
+ ok(!snapped,"Move away from the edge");
+
+ // Just pick it up and drop it.
+ checkSnap(currentActiveGroup, 0, 0, contentWindow, function(snapped){
+ ok(!snapped,"Just pick it up and drop it");
+
+ checkSnap(currentActiveGroup, 0, 1, contentWindow, function(snapped){
+ ok(snapped,"Drag one pixel: should snap");
+
+ checkSnap(currentActiveGroup, 0, 5, contentWindow, function(snapped){
+ ok(!snapped,"Moving five pixels: shouldn't snap");
+ endGame();
+ });
+ });
+ });
+ });
+ }
+
+ part1();
+}
+
+function simulateDragDrop(tabItem, offsetX, offsetY, contentWindow) {
+ // enter drag mode
+ let dataTransfer;
+
+ EventUtils.synthesizeMouse(
+ tabItem.container, 1, 1, { type: "mousedown" }, contentWindow);
+ event = contentWindow.document.createEvent("DragEvents");
+ event.initDragEvent(
+ "dragenter", true, true, contentWindow, 0, 0, 0, 0, 0,
+ false, false, false, false, 1, null, dataTransfer);
+ tabItem.container.dispatchEvent(event);
+
+ // drag over
+ if (offsetX || offsetY) {
+ let Ci = Components.interfaces;
+ let utils = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).
+ getInterface(Ci.nsIDOMWindowUtils);
+ let rect = tabItem.getBounds();
+ for (let i = 1; i <= 5; i++) {
+ let left = rect.left + 1 + Math.round(i * offsetX / 5);
+ let top = rect.top + 1 + Math.round(i * offsetY / 5);
+ utils.sendMouseEvent("mousemove", left, top, 0, 1, 0);
+ }
+ event = contentWindow.document.createEvent("DragEvents");
+ event.initDragEvent(
+ "dragover", true, true, contentWindow, 0, 0, 0, 0, 0,
+ false, false, false, false, 0, null, dataTransfer);
+ tabItem.container.dispatchEvent(event);
+ }
+
+ // drop
+ EventUtils.synthesizeMouse(
+ tabItem.container, 0, 0, { type: "mouseup" }, contentWindow);
+ event = contentWindow.document.createEvent("DragEvents");
+ event.initDragEvent(
+ "drop", true, true, contentWindow, 0, 0, 0, 0, 0,
+ false, false, false, false, 0, null, dataTransfer);
+ tabItem.container.dispatchEvent(event);
+}
+
+function checkSnap(item, offsetX, offsetY, contentWindow, callback) {
+ let firstTop = item.getBounds().top;
+ let firstLeft = item.getBounds().left;
+ let onDrop = function() {
+ let snapped = false;
+ item.container.removeEventListener('drop', onDrop, false);
+ if (item.getBounds().top != firstTop + offsetY)
+ snapped = true;
+ if (item.getBounds().left != firstLeft + offsetX)
+ snapped = true;
+ callback(snapped);
+ };
+ item.container.addEventListener('drop', onDrop, false);
+ simulateDragDrop(item, offsetX, offsetY, contentWindow);
+}
diff --git a/browser/base/content/test/tabview/browser_tabview_bug590606.js b/browser/base/content/test/tabview/browser_tabview_bug590606.js
new file mode 100644
index 00000000000..5491cac81d1
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug590606.js
@@ -0,0 +1,126 @@
+/* ***** 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 bug 590606 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 ***** */
+
+let originalTab;
+let newTabOne;
+
+function test() {
+ waitForExplicitFinish();
+
+ originalTab = gBrowser.visibleTabs[0];
+ // add a tab to the existing group.
+ newTabOne = gBrowser.addTab();
+
+ let onTabviewShown = function() {
+ window.removeEventListener("tabviewshown", onTabviewShown, false);
+
+ let contentWindow = document.getElementById("tab-view").contentWindow;
+
+ is(contentWindow.GroupItems.groupItems.length, 1,
+ "There is one group item on startup");
+ let groupItemOne = contentWindow.GroupItems.groupItems[0];
+ is(groupItemOne.getChildren().length, 2,
+ "There should be two tab items in that group.");
+ is(gBrowser.selectedTab, groupItemOne.getChild(0).tab,
+ "The currently selected tab should be the first tab in the groupItemOne");
+
+ // create another group with a tab.
+ let groupItemTwo = createEmptyGroupItem(contentWindow, 200);
+
+ let onTabViewHidden = function() {
+ window.removeEventListener("tabviewhidden", onTabViewHidden, false);
+ // start the test
+ testGroupSwitch(contentWindow, groupItemOne, groupItemTwo);
+ };
+ window.addEventListener("tabviewhidden", onTabViewHidden, false);
+
+ // click on the + button
+ let newTabButton = groupItemTwo.container.getElementsByClassName("newTabButton");
+ ok(newTabButton[0], "New tab button exists");
+ EventUtils.sendMouseEvent({ type: "click" }, newTabButton[0], contentWindow);
+ };
+ window.addEventListener("tabviewshown", onTabviewShown, false);
+ TabView.toggle();
+}
+
+function testGroupSwitch(contentWindow, groupItemOne, groupItemTwo) {
+ is(gBrowser.selectedTab, groupItemTwo.getChild(0).tab,
+ "The currently selected tab should be the only tab in the groupItemTwo");
+
+ // switch to groupItemOne
+ tabItem = contentWindow.GroupItems.getNextGroupItemTab(false);
+ if (tabItem)
+ gBrowser.selectedTab = tabItem.tab;
+ is(gBrowser.selectedTab, groupItemOne.getChild(0).tab,
+ "The currently selected tab should be the first tab in the groupItemOne");
+
+ // switch to the second tab in groupItemOne
+ gBrowser.selectedTab = groupItemOne.getChild(1).tab;
+
+ // switch to groupItemTwo
+ tabItem = contentWindow.GroupItems.getNextGroupItemTab(false);
+ if (tabItem)
+ gBrowser.selectedTab = tabItem.tab;
+ is(gBrowser.selectedTab, groupItemTwo.getChild(0).tab,
+ "The currently selected tab should be the only tab in the groupItemTwo");
+
+ // switch to groupItemOne
+ tabItem = contentWindow.GroupItems.getNextGroupItemTab(false);
+ if (tabItem)
+ gBrowser.selectedTab = tabItem.tab;
+ is(gBrowser.selectedTab, groupItemOne.getChild(1).tab,
+ "The currently selected tab should be the second tab in the groupItemOne");
+
+ // cleanup.
+ gBrowser.removeTab(groupItemTwo.getChild(0).tab);
+ gBrowser.removeTab(newTabOne);
+
+ finish();
+}
+
+function createEmptyGroupItem(contentWindow, padding) {
+ let pageBounds = contentWindow.Items.getPageBounds();
+ pageBounds.inset(padding, padding);
+
+ let box = new contentWindow.Rect(pageBounds);
+ box.width = 300;
+ box.height = 300;
+
+ let emptyGroupItem = new contentWindow.GroupItem([], { bounds: box });
+
+ return emptyGroupItem;
+}
diff --git a/browser/base/content/test/tabview/browser_tabview_bug594176.js b/browser/base/content/test/tabview/browser_tabview_bug594176.js
new file mode 100644
index 00000000000..8a841eb0e20
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug594176.js
@@ -0,0 +1,65 @@
+/* ***** 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 bug 594176 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() {
+ let [origTab] = gBrowser.visibleTabs;
+ ok(!origTab.pinned, "The original tab is not pinned");
+
+ let pinnedTab = gBrowser.addTab();
+ gBrowser.pinTab(pinnedTab);
+ ok(pinnedTab.pinned, "The new tab is pinned");
+
+ popup(origTab);
+ ok(!document.getElementById("context_tabViewMenu").disabled,
+ "The tab view menu is enabled for normal tab");
+
+ popup(pinnedTab);
+ ok(document.getElementById("context_tabViewMenu").disabled,
+ "The tab view menu is disabled for pinned tab");
+
+ gBrowser.unpinTab(pinnedTab);
+ popup(pinnedTab);
+ ok(!document.getElementById("context_tabViewMenu").disabled,
+ "The tab view menu is enabled for unpinned tab");
+
+ gBrowser.removeTab(pinnedTab);
+}
+
+function popup(tab) {
+ document.popupNode = tab;
+ TabContextMenu.updateContextMenu(document.getElementById("tabContextMenu"));
+}
diff --git a/browser/base/content/test/tabview/browser_tabview_orphaned_tabs.js b/browser/base/content/test/tabview/browser_tabview_orphaned_tabs.js
new file mode 100644
index 00000000000..2d591c5b963
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_orphaned_tabs.js
@@ -0,0 +1,136 @@
+/* ***** 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 test for orphaned tabs (bug 595893).
+ *
+ * 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 ***** */
+
+let tabOne;
+let newWin;
+
+function test() {
+ waitForExplicitFinish();
+
+ newWin =
+ window.openDialog(getBrowserURL(), "_blank", "all,dialog=no", "about:blank");
+
+ let onLoad = function() {
+ newWin.removeEventListener("load", onLoad, false);
+
+ tabOne = newWin.gBrowser.addTab();
+
+ newWin.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
+ newWin.TabView.toggle();
+ }
+ newWin.addEventListener("load", onLoad, false);
+}
+
+function onTabViewWindowLoaded() {
+ newWin.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
+
+ ok(newWin.TabView.isVisible(), "Tab View is visible");
+
+ let contentWindow = newWin.document.getElementById("tab-view").contentWindow;
+
+ // 1) the tab should belong to a group, and no orphan tabs
+ ok(tabOne.tabItem.parent, "Tab one belongs to a group");
+ is(contentWindow.GroupItems.getOrphanedTabs().length, 0, "No orphaned tabs");
+
+ // 2) create a group, add a blank tab
+ let groupItem = createEmptyGroupItem(contentWindow, 200);
+
+ let onTabViewHidden = function() {
+ newWin.removeEventListener("tabviewhidden", onTabViewHidden, false);
+
+ // 3) the new group item should have one child and no orphan tab
+ is(groupItem.getChildren().length, 1, "The group item has an item");
+ is(contentWindow.GroupItems.getOrphanedTabs().length, 0, "No orphaned tabs");
+
+ let checkAndFinish = function() {
+ // 4) check existence of stored group data for tab before finishing
+ let tabData = contentWindow.Storage.getTabData(tabItem.tab);
+ ok(tabData && contentWindow.TabItems.storageSanity(tabData) && tabData.groupID,
+ "Tab two has stored group data");
+
+ // clean up and finish the test
+ newWin.gBrowser.removeTab(tabOne);
+ newWin.gBrowser.removeTab(tabItem.tab);
+ whenWindowObservesOnce(newWin, "domwindowclosed", function() {
+ finish();
+ });
+ newWin.close();
+ };
+ let tabItem = groupItem.getChild(0);
+ // the item may not be connected so subscriber would be used in that case.
+ if (tabItem.reconnected) {
+ checkAndFinish();
+ } else {
+ tabItem.addSubscriber(tabItem, "reconnected", function() {
+ tabItem.removeSubscriber(tabItem, "reconnected");
+ checkAndFinish();
+ });
+ }
+ };
+ newWin.addEventListener("tabviewhidden", onTabViewHidden, 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 createEmptyGroupItem(contentWindow, padding) {
+ let pageBounds = contentWindow.Items.getPageBounds();
+ pageBounds.inset(padding, padding);
+
+ let box = new contentWindow.Rect(pageBounds);
+ box.width = 300;
+ box.height = 300;
+
+ let emptyGroupItem = new contentWindow.GroupItem([], { bounds: box });
+
+ return emptyGroupItem;
+}
+
+function whenWindowObservesOnce(win, topic, callback) {
+ let windowWatcher =
+ Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(Ci.nsIWindowWatcher);
+ function windowObserver(subject, topicName, aData) {
+ if (win == subject.QueryInterface(Ci.nsIDOMWindow) && topic == topicName) {
+ windowWatcher.unregisterNotification(windowObserver);
+ callback();
+ }
+ }
+ windowWatcher.registerNotification(windowObserver);
+}
diff --git a/browser/themes/gnomestripe/browser/tabview/tabview.css b/browser/themes/gnomestripe/browser/tabview/tabview.css
index b358056aa5d..5b7f3c76837 100644
--- a/browser/themes/gnomestripe/browser/tabview/tabview.css
+++ b/browser/themes/gnomestripe/browser/tabview/tabview.css
@@ -32,6 +32,7 @@ body {
.thumb {
box-shadow: 1px 2px 0 rgba(0, 0, 0, 0.2);
+ background-color: white;
}
.favicon {
diff --git a/browser/themes/pinstripe/browser/tabview/tabview.css b/browser/themes/pinstripe/browser/tabview/tabview.css
index 0df35b67551..6854500698d 100644
--- a/browser/themes/pinstripe/browser/tabview/tabview.css
+++ b/browser/themes/pinstripe/browser/tabview/tabview.css
@@ -30,6 +30,7 @@ body {
.thumb {
box-shadow: 1px 2px 0 rgba(0, 0, 0, 0.2);
+ background-color: white;
}
.favicon {
diff --git a/browser/themes/winstripe/browser/tabview/tabview.css b/browser/themes/winstripe/browser/tabview/tabview.css
index 78c9863caa1..0f266131351 100644
--- a/browser/themes/winstripe/browser/tabview/tabview.css
+++ b/browser/themes/winstripe/browser/tabview/tabview.css
@@ -34,6 +34,7 @@ body {
.thumb {
box-shadow: 1px 2px 0 rgba(0, 0, 0, 0.1);
+ background-color: white;
}
.favicon {