зеркало из https://github.com/mozilla/pjs.git
merge panorama-central to mozilla-central [a=blocking, dietrich]
This commit is contained in:
Коммит
5b19f74997
|
@ -7930,6 +7930,9 @@ var TabContextMenu = {
|
||||||
let unpinnedTabs = gBrowser.visibleTabs.length - gBrowser._numPinnedTabs;
|
let unpinnedTabs = gBrowser.visibleTabs.length - gBrowser._numPinnedTabs;
|
||||||
document.getElementById("context_closeOtherTabs").disabled = unpinnedTabs <= 1;
|
document.getElementById("context_closeOtherTabs").disabled = unpinnedTabs <= 1;
|
||||||
document.getElementById("context_closeOtherTabs").hidden = this.contextTab.pinned;
|
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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -118,8 +118,8 @@ Drag.prototype = {
|
||||||
|
|
||||||
// OH SNAP!
|
// OH SNAP!
|
||||||
|
|
||||||
// if we aren't holding down the meta key...
|
// if we aren't holding down the meta key or have trenches disabled...
|
||||||
if (!Keys.meta) {
|
if (!Keys.meta && !Trenches.disabled) {
|
||||||
// snappable = true if we aren't a tab on top of something else, and
|
// snappable = true if we aren't a tab on top of something else, and
|
||||||
// there's no active drop site...
|
// there's no active drop site...
|
||||||
let snappable = !(this.item.isATabItem &&
|
let snappable = !(this.item.isATabItem &&
|
||||||
|
|
|
@ -1386,39 +1386,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||||
// TabItems will have handled the new tab and added the tabItem property.
|
// 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
|
// 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.
|
// TabItem), since we've just created it.
|
||||||
let newItem = newTab.tabItem;
|
newTab.tabItem.zoomIn(!url);
|
||||||
|
|
||||||
var self = this;
|
|
||||||
iQ(newItem.container).css({opacity: 0});
|
|
||||||
let $anim = iQ("<div>")
|
|
||||||
.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();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
|
@ -1542,6 +1510,7 @@ let GroupItems = {
|
||||||
},
|
},
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
|
// Function: _handleAttrModified
|
||||||
// watch for icon changes on app tabs
|
// watch for icon changes on app tabs
|
||||||
_handleAttrModified: function GroupItems__handleAttrModified(xulTab) {
|
_handleAttrModified: function GroupItems__handleAttrModified(xulTab) {
|
||||||
if (xulTab.ownerDocument.defaultView != gWindow || !xulTab.pinned)
|
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
|
// Function: addAppTab
|
||||||
handleTabPin: function GroupItems_handleTabPin(xulTab) {
|
// Adds the given xul:tab to the app tab tray in all groups
|
||||||
|
addAppTab: function GroupItems_addAppTab(xulTab) {
|
||||||
this.groupItems.forEach(function(groupItem) {
|
this.groupItems.forEach(function(groupItem) {
|
||||||
groupItem.addAppTab(xulTab);
|
groupItem.addAppTab(xulTab);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
// when a tab becomes unpinned, remove it from the app tab tray in all groups
|
// Function: removeAppTab
|
||||||
handleTabUnpin: function GroupItems_handleTabUnpin(xulTab) {
|
// Removes the given xul:tab from the app tab tray in all groups
|
||||||
|
removeAppTab: function GroupItems_removeAppTab(xulTab) {
|
||||||
this.groupItems.forEach(function(groupItem) {
|
this.groupItems.forEach(function(groupItem) {
|
||||||
groupItem.removeAppTab(xulTab);
|
groupItem.removeAppTab(xulTab);
|
||||||
});
|
});
|
||||||
|
@ -1582,7 +1553,7 @@ let GroupItems = {
|
||||||
getNextID: function GroupItems_getNextID() {
|
getNextID: function GroupItems_getNextID() {
|
||||||
var result = this.nextID;
|
var result = this.nextID;
|
||||||
this.nextID++;
|
this.nextID++;
|
||||||
this.save();
|
this._save();
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1602,20 +1573,22 @@ let GroupItems = {
|
||||||
// Function: saveAll
|
// Function: saveAll
|
||||||
// Saves GroupItems state, as well as the state of all of the groupItems.
|
// Saves GroupItems state, as well as the state of all of the groupItems.
|
||||||
saveAll: function GroupItems_saveAll() {
|
saveAll: function GroupItems_saveAll() {
|
||||||
this.save();
|
this._save();
|
||||||
this.groupItems.forEach(function(groupItem) {
|
this.groupItems.forEach(function(groupItem) {
|
||||||
groupItem.save();
|
groupItem.save();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
// Function: save
|
// Function: _save
|
||||||
// Saves GroupItems state.
|
// Saves GroupItems state.
|
||||||
save: function GroupItems_save() {
|
_save: function GroupItems__save() {
|
||||||
if (!this._inited) // too soon to save now
|
if (!this._inited) // too soon to save now
|
||||||
return;
|
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).
|
// If no data, sets up blank slate (including "new tabs" groupItem).
|
||||||
reconstitute: function GroupItems_reconstitute(groupItemsData, groupItemData) {
|
reconstitute: function GroupItems_reconstitute(groupItemsData, groupItemData) {
|
||||||
try {
|
try {
|
||||||
if (groupItemsData && groupItemsData.nextID)
|
let activeGroupId;
|
||||||
this.nextID = groupItemsData.nextID;
|
|
||||||
|
if (groupItemsData) {
|
||||||
|
if (groupItemsData.nextID)
|
||||||
|
this.nextID = groupItemsData.nextID;
|
||||||
|
if (groupItemsData.activeGroupId)
|
||||||
|
activeGroupId = groupItemsData.activeGroupId;
|
||||||
|
}
|
||||||
|
|
||||||
if (groupItemData) {
|
if (groupItemData) {
|
||||||
for (var id in 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._inited = true;
|
||||||
this.save(); // for nextID
|
this._save(); // for nextID
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
Utils.log("error in recons: "+e);
|
Utils.log("error in recons: "+e);
|
||||||
}
|
}
|
||||||
|
@ -1763,38 +1748,83 @@ let GroupItems = {
|
||||||
// Given a <TabItem>, files it in the appropriate groupItem.
|
// Given a <TabItem>, files it in the appropriate groupItem.
|
||||||
newTab: function GroupItems_newTab(tabItem) {
|
newTab: function GroupItems_newTab(tabItem) {
|
||||||
let activeGroupItem = this.getActiveGroupItem();
|
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) {
|
if (activeGroupItem) {
|
||||||
activeGroupItem.add(tabItem);
|
activeGroupItem.add(tabItem);
|
||||||
} else if (orphanTab) {
|
return;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
// ----------
|
let orphanTabItem = this.getActiveOrphanTab();
|
||||||
// Function: positionNewTabAtBottom
|
if (!orphanTabItem) {
|
||||||
// Does what it says on the tin.
|
let otherTab;
|
||||||
// TODO: Make more robust and improve documentation,
|
// find first visible non-app tab in the tabbar.
|
||||||
// Also, this probably belongs in tabitems.js
|
gBrowser.visibleTabs.some(function(tab) {
|
||||||
// Bug 586558
|
if (!tab.pinned && tab != tabItem.tab) {
|
||||||
positionNewTabAtBottom: function GroupItems_positionNewTabAtBottom(tabItem) {
|
otherTab = tab;
|
||||||
let windowBounds = Items.getSafeWindowBounds();
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
let itemBounds = new Rect(
|
if (otherTab) {
|
||||||
windowBounds.right - TabItems.tabWidth,
|
// the first visible tab belongs to a group, add the new tabItem into
|
||||||
windowBounds.bottom - TabItems.tabHeight,
|
// that group
|
||||||
TabItems.tabWidth,
|
if (otherTab.tabItem.parent) {
|
||||||
TabItems.tabHeight
|
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._activeGroupItem = groupItem;
|
||||||
|
this._save();
|
||||||
},
|
},
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
|
@ -1909,6 +1940,13 @@ let GroupItems = {
|
||||||
if (groupItems.length > 0) {
|
if (groupItems.length > 0) {
|
||||||
groupItems.some(function(groupItem) {
|
groupItems.some(function(groupItem) {
|
||||||
if (!groupItem.hidden) {
|
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);
|
var child = groupItem.getChild(0);
|
||||||
if (child) {
|
if (child) {
|
||||||
tabItem = child;
|
tabItem = child;
|
||||||
|
@ -1930,6 +1968,13 @@ let GroupItems = {
|
||||||
var firstGroupItems = groupItems.slice(currentIndex + 1);
|
var firstGroupItems = groupItems.slice(currentIndex + 1);
|
||||||
firstGroupItems.some(function(groupItem) {
|
firstGroupItems.some(function(groupItem) {
|
||||||
if (!groupItem.hidden) {
|
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);
|
var child = groupItem.getChild(0);
|
||||||
if (child) {
|
if (child) {
|
||||||
tabItem = child;
|
tabItem = child;
|
||||||
|
@ -1947,6 +1992,13 @@ let GroupItems = {
|
||||||
var secondGroupItems = groupItems.slice(0, currentIndex);
|
var secondGroupItems = groupItems.slice(0, currentIndex);
|
||||||
secondGroupItems.some(function(groupItem) {
|
secondGroupItems.some(function(groupItem) {
|
||||||
if (!groupItem.hidden) {
|
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);
|
var child = groupItem.getChild(0);
|
||||||
if (child) {
|
if (child) {
|
||||||
tabItem = child;
|
tabItem = child;
|
||||||
|
|
|
@ -187,7 +187,10 @@ Item.prototype = {
|
||||||
stop: function() {
|
stop: function() {
|
||||||
drag.info.stop();
|
drag.info.stop();
|
||||||
drag.info = null;
|
drag.info = null;
|
||||||
}
|
},
|
||||||
|
// The minimum the mouse must move after mouseDown in order to move an
|
||||||
|
// item
|
||||||
|
minDragDistance: 3
|
||||||
};
|
};
|
||||||
|
|
||||||
// ___ drop
|
// ___ drop
|
||||||
|
@ -592,64 +595,67 @@ Item.prototype = {
|
||||||
// ___ mousemove
|
// ___ mousemove
|
||||||
var handleMouseMove = function(e) {
|
var handleMouseMove = function(e) {
|
||||||
// positioning
|
// positioning
|
||||||
var mouse = new Point(e.pageX, e.pageY);
|
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
|
|
||||||
if (!startSent) {
|
if (!startSent) {
|
||||||
if (typeof self.dragOptions.start == "function")
|
if(Math.abs(mouse.x - startMouse.x) > self.dragOptions.minDragDistance ||
|
||||||
self.dragOptions.start.apply(self,
|
Math.abs(mouse.y - startMouse.y) > self.dragOptions.minDragDistance) {
|
||||||
[startEvent, {position: {left: startPos.x, top: startPos.y}}]);
|
if (typeof self.dragOptions.start == "function")
|
||||||
|
self.dragOptions.start.apply(self,
|
||||||
startSent = true;
|
[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.setBounds(box, true);
|
||||||
self.dragOptions.drag.apply(self, [e]);
|
|
||||||
|
|
||||||
// drop events
|
if (typeof self.dragOptions.drag == "function")
|
||||||
var best = {
|
self.dragOptions.drag.apply(self, [e]);
|
||||||
dropTarget: null,
|
|
||||||
score: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
droppables.forEach(function(droppable) {
|
// drop events
|
||||||
var intersection = box.intersection(droppable.bounds);
|
var best = {
|
||||||
if (intersection && intersection.area() > best.score) {
|
dropTarget: null,
|
||||||
var possibleDropTarget = droppable.item;
|
score: 0
|
||||||
var accept = true;
|
};
|
||||||
if (possibleDropTarget != dropTarget) {
|
|
||||||
var dropOptions = possibleDropTarget.dropOptions;
|
droppables.forEach(function(droppable) {
|
||||||
if (dropOptions && typeof dropOptions.accept == "function")
|
var intersection = box.intersection(droppable.bounds);
|
||||||
accept = dropOptions.accept.apply(possibleDropTarget, [self]);
|
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) {
|
dropTarget = best.dropTarget;
|
||||||
best.dropTarget = possibleDropTarget;
|
|
||||||
best.score = intersection.area();
|
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();
|
e.preventDefault();
|
||||||
|
|
|
@ -1030,10 +1030,16 @@ let TabItems = {
|
||||||
|
|
||||||
item.reconnected = true;
|
item.reconnected = true;
|
||||||
found = true;
|
found = true;
|
||||||
} else
|
} else {
|
||||||
item.reconnected = item.tab.linkedBrowser.currentURI.spec != 'about:blank';
|
// 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();
|
item.save();
|
||||||
|
|
||||||
|
if (item.reconnected)
|
||||||
|
item._sendToSubscribers("reconnected");
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
Utils.log(e);
|
Utils.log(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -466,9 +466,11 @@ var Trenches = {
|
||||||
// nextId - (integer) a counter for the next <Trench>'s <Trench.id> value.
|
// nextId - (integer) a counter for the next <Trench>'s <Trench.id> value.
|
||||||
// showDebug - (boolean) whether to draw the <Trench>es or not.
|
// showDebug - (boolean) whether to draw the <Trench>es or not.
|
||||||
// defaultRadius - (integer) the default radius for new <Trench>es.
|
// defaultRadius - (integer) the default radius for new <Trench>es.
|
||||||
|
// disabled - (boolean) whether trench-snapping is disabled or not.
|
||||||
nextId: 0,
|
nextId: 0,
|
||||||
showDebug: false,
|
showDebug: false,
|
||||||
defaultRadius: 10,
|
defaultRadius: 10,
|
||||||
|
disabled: false,
|
||||||
|
|
||||||
// ---------
|
// ---------
|
||||||
// Variables: snapping preferences; used to break ties in snapping.
|
// Variables: snapping preferences; used to break ties in snapping.
|
||||||
|
|
|
@ -448,10 +448,25 @@ let UI = {
|
||||||
_addTabActionHandlers: function UI__addTabActionHandlers() {
|
_addTabActionHandlers: function UI__addTabActionHandlers() {
|
||||||
var self = this;
|
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) {
|
this._eventListeners.close = function(tab) {
|
||||||
if (tab.ownerDocument.defaultView != gWindow)
|
if (tab.ownerDocument.defaultView != gWindow)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// if it's an app tab, remove it from all the group items
|
||||||
|
if (tab.pinned)
|
||||||
|
GroupItems.removeAppTab(tab);
|
||||||
|
|
||||||
if (self._isTabViewVisible()) {
|
if (self._isTabViewVisible()) {
|
||||||
// just closed the selected tab in the TabView interface.
|
// just closed the selected tab in the TabView interface.
|
||||||
if (self._currentTab == tab)
|
if (self._currentTab == tab)
|
||||||
|
@ -470,13 +485,17 @@ let UI = {
|
||||||
|
|
||||||
// 1) Only go back to the TabView tab when there you close the last
|
// 1) Only go back to the TabView tab when there you close the last
|
||||||
// tab of a groupItem.
|
// 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
|
// 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
|
// an un-named groupItem, which means that the groupItem is gone (null) and
|
||||||
// there are no visible tabs.
|
// there are no visible tabs.
|
||||||
// Can't use timeout here because user would see a flicker of
|
let closingUnnamedGroup = (groupItem == null &&
|
||||||
// switching to another tab before the TabView interface shows up.
|
gBrowser.visibleTabs.length <= 1);
|
||||||
if ((groupItem && groupItem._children.length == 1) ||
|
|
||||||
(groupItem == null && gBrowser.visibleTabs.length <= 1)) {
|
if (closingLastOfGroup || closingUnnamedGroup) {
|
||||||
// for the tab focus event to pick up.
|
// for the tab focus event to pick up.
|
||||||
self._closedLastVisibleTab = true;
|
self._closedLastVisibleTab = true;
|
||||||
// remove the zoom prep.
|
// remove the zoom prep.
|
||||||
|
@ -488,6 +507,7 @@ let UI = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TabMove
|
||||||
this._eventListeners.move = function(tab) {
|
this._eventListeners.move = function(tab) {
|
||||||
if (tab.ownerDocument.defaultView != gWindow)
|
if (tab.ownerDocument.defaultView != gWindow)
|
||||||
return;
|
return;
|
||||||
|
@ -497,6 +517,7 @@ let UI = {
|
||||||
self.setReorderTabItemsOnShow(activeGroupItem);
|
self.setReorderTabItemsOnShow(activeGroupItem);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TabSelect
|
||||||
this._eventListeners.select = function(tab) {
|
this._eventListeners.select = function(tab) {
|
||||||
if (tab.ownerDocument.defaultView != gWindow)
|
if (tab.ownerDocument.defaultView != gWindow)
|
||||||
return;
|
return;
|
||||||
|
@ -504,13 +525,14 @@ let UI = {
|
||||||
self.onTabSelect(tab);
|
self.onTabSelect(tab);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Actually register the above handlers
|
||||||
for (let name in this._eventListeners)
|
for (let name in this._eventListeners)
|
||||||
AllTabs.register(name, this._eventListeners[name]);
|
AllTabs.register(name, this._eventListeners[name]);
|
||||||
|
|
||||||
// Start watching for tab pin events, and set up our uninit for same.
|
// Start watching for tab pin events, and set up our uninit for same.
|
||||||
function handleTabPin(event) {
|
function handleTabPin(event) {
|
||||||
TabItems.handleTabPin(event.originalTarget);
|
TabItems.handleTabPin(event.originalTarget);
|
||||||
GroupItems.handleTabPin(event.originalTarget);
|
GroupItems.addAppTab(event.originalTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
gBrowser.tabContainer.addEventListener("TabPinned", handleTabPin, false);
|
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.
|
// Start watching for tab unpin events, and set up our uninit for same.
|
||||||
function handleTabUnpin(event) {
|
function handleTabUnpin(event) {
|
||||||
TabItems.handleTabUnpin(event.originalTarget);
|
TabItems.handleTabUnpin(event.originalTarget);
|
||||||
GroupItems.handleTabUnpin(event.originalTarget);
|
GroupItems.removeAppTab(event.originalTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
gBrowser.tabContainer.addEventListener("TabUnpinned", handleTabUnpin, false);
|
gBrowser.tabContainer.addEventListener("TabUnpinned", handleTabUnpin, false);
|
||||||
|
|
|
@ -45,9 +45,12 @@ include $(topsrcdir)/config/rules.mk
|
||||||
|
|
||||||
_BROWSER_FILES = \
|
_BROWSER_FILES = \
|
||||||
browser_tabview_apptabs.js \
|
browser_tabview_apptabs.js \
|
||||||
|
browser_tabview_bug580412.js \
|
||||||
browser_tabview_bug587040.js \
|
browser_tabview_bug587040.js \
|
||||||
browser_tabview_bug587990.js \
|
browser_tabview_bug587990.js \
|
||||||
|
browser_tabview_bug590606.js \
|
||||||
browser_tabview_bug591706.js \
|
browser_tabview_bug591706.js \
|
||||||
|
browser_tabview_bug594176.js \
|
||||||
browser_tabview_bug595191.js \
|
browser_tabview_bug595191.js \
|
||||||
browser_tabview_bug595518.js \
|
browser_tabview_bug595518.js \
|
||||||
browser_tabview_bug595943.js \
|
browser_tabview_bug595943.js \
|
||||||
|
@ -56,6 +59,7 @@ _BROWSER_FILES = \
|
||||||
browser_tabview_group.js \
|
browser_tabview_group.js \
|
||||||
browser_tabview_launch.js \
|
browser_tabview_launch.js \
|
||||||
browser_tabview_multiwindow_search.js \
|
browser_tabview_multiwindow_search.js \
|
||||||
|
browser_tabview_orphaned_tabs.js \
|
||||||
browser_tabview_search.js \
|
browser_tabview_search.js \
|
||||||
browser_tabview_snapping.js \
|
browser_tabview_snapping.js \
|
||||||
browser_tabview_undo_group.js \
|
browser_tabview_undo_group.js \
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
* for the specific language governing rights and limitations under the
|
* for the specific language governing rights and limitations under the
|
||||||
* License.
|
* License.
|
||||||
*
|
*
|
||||||
* The Original Code is tabview group test.
|
* The Original Code is tabview app-tab test.
|
||||||
*
|
*
|
||||||
* The Initial Developer of the Original Code is
|
* The Initial Developer of the Original Code is
|
||||||
* Mozilla Foundation.
|
* Mozilla Foundation.
|
||||||
|
@ -50,51 +50,46 @@ function onTabViewWindowLoaded() {
|
||||||
let contentWindow = document.getElementById("tab-view").contentWindow;
|
let contentWindow = document.getElementById("tab-view").contentWindow;
|
||||||
|
|
||||||
// establish initial state
|
// 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");
|
is(gBrowser.tabs.length, 1, "we start with one tab");
|
||||||
let originalTab = gBrowser.tabs[0];
|
let originalTab = gBrowser.tabs[0];
|
||||||
|
|
||||||
// create a group
|
// create a group
|
||||||
let box = new contentWindow.Rect(20, 20, 180, 180);
|
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");
|
is(contentWindow.GroupItems.groupItems.length, 2, "we now have two groups");
|
||||||
contentWindow.GroupItems.setActiveGroupItem(groupItemOne);
|
contentWindow.GroupItems.setActiveGroupItem(groupItemOne);
|
||||||
|
|
||||||
// create a tab
|
// create a tab
|
||||||
let xulTab = gBrowser.loadOneTab("about:blank");
|
let xulTab = gBrowser.loadOneTab("about:blank");
|
||||||
is(gBrowser.tabs.length, 2, "we now have two tabs");
|
is(gBrowser.tabs.length, 2, "we now have two tabs");
|
||||||
is(groupItemOne._children.length, 1, "the new tab was added to the group");
|
is(groupItemOne._children.length, 1, "the new tab was added to the group");
|
||||||
|
|
||||||
// make sure the group has no app tabs
|
// make sure the group has no app tabs
|
||||||
let appTabIcons = groupItemOne.container.getElementsByClassName("appTabIcon");
|
is(appTabCount(groupItemOne), 0, "there are no app tab icons");
|
||||||
is(appTabIcons.length, 0, "there are no app tab icons");
|
|
||||||
|
|
||||||
// pin the tab, make sure the TabItem goes away and the icon comes on
|
// pin the tab, make sure the TabItem goes away and the icon comes on
|
||||||
gBrowser.pinTab(xulTab);
|
gBrowser.pinTab(xulTab);
|
||||||
|
is(groupItemOne._children.length, 0,
|
||||||
is(groupItemOne._children.length, 0, "the app tab's TabItem was removed from the group");
|
"the app tab's TabItem was removed from the group");
|
||||||
|
is(appTabCount(groupItemOne), 1, "there's now one app tab icon");
|
||||||
appTabIcons = groupItemOne.container.getElementsByClassName("appTabIcon");
|
|
||||||
is(appTabIcons.length, 1, "there's now one app tab icon");
|
|
||||||
|
|
||||||
// create a second group and make sure it gets the icon too
|
// create a second group and make sure it gets the icon too
|
||||||
box.offset(box.width + 20, 0);
|
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");
|
is(contentWindow.GroupItems.groupItems.length, 3, "we now have three groups");
|
||||||
appTabIcons = groupItemTwo.container.getElementsByClassName("appTabIcon");
|
is(appTabCount(groupItemTwo), 1,
|
||||||
is(appTabIcons.length, 1, "there's an app tab icon in the second group");
|
"there's an app tab icon in the second group");
|
||||||
|
|
||||||
// unpin the tab, make sure the icon goes away and the TabItem comes on
|
// unpin the tab, make sure the icon goes away and the TabItem comes on
|
||||||
gBrowser.unpinTab(xulTab);
|
gBrowser.unpinTab(xulTab);
|
||||||
|
|
||||||
is(groupItemOne._children.length, 1, "the app tab's TabItem is back");
|
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
|
// pin the tab again
|
||||||
gBrowser.pinTab(xulTab);
|
gBrowser.pinTab(xulTab);
|
||||||
|
|
||||||
|
@ -104,25 +99,30 @@ function onTabViewWindowLoaded() {
|
||||||
// find app tab in group and hit it
|
// find app tab in group and hit it
|
||||||
let onTabViewHidden = function() {
|
let onTabViewHidden = function() {
|
||||||
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
|
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
|
||||||
ok(!TabView.isVisible(), "Tab View is hidden because we clicked on the app tab");
|
ok(!TabView.isVisible(),
|
||||||
|
"Tab View is hidden because we clicked on the app tab");
|
||||||
// clean up
|
|
||||||
gBrowser.selectedTab = originalTab;
|
// delete the app tab and make sure its icon goes away
|
||||||
|
|
||||||
gBrowser.unpinTab(xulTab);
|
|
||||||
gBrowser.removeTab(xulTab);
|
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();
|
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");
|
ok(!TabView.isVisible(), "we finish with Tab View not visible");
|
||||||
|
|
||||||
finish();
|
finish();
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener("tabviewhidden", onTabViewHidden, false);
|
window.addEventListener("tabviewhidden", onTabViewHidden, false);
|
||||||
|
|
||||||
appTabIcons = groupItemOne.container.getElementsByClassName("appTabIcon");
|
let appTabIcons = groupItemOne.container.getElementsByClassName("appTabIcon");
|
||||||
EventUtils.sendMouseEvent({ type: "click" }, appTabIcons[0], contentWindow);
|
EventUtils.sendMouseEvent({ type: "click" }, appTabIcons[0], contentWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function appTabCount(groupItem) {
|
||||||
|
return groupItem.container.getElementsByClassName("appTabIcon").length;
|
||||||
|
}
|
||||||
|
|
|
@ -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 <mitcho@mitcho.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 ***** */
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
|
@ -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 <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 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;
|
||||||
|
}
|
|
@ -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 <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 ***** */
|
||||||
|
|
||||||
|
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"));
|
||||||
|
}
|
|
@ -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 <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 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);
|
||||||
|
}
|
|
@ -32,6 +32,7 @@ body {
|
||||||
|
|
||||||
.thumb {
|
.thumb {
|
||||||
box-shadow: 1px 2px 0 rgba(0, 0, 0, 0.2);
|
box-shadow: 1px 2px 0 rgba(0, 0, 0, 0.2);
|
||||||
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.favicon {
|
.favicon {
|
||||||
|
|
|
@ -30,6 +30,7 @@ body {
|
||||||
|
|
||||||
.thumb {
|
.thumb {
|
||||||
box-shadow: 1px 2px 0 rgba(0, 0, 0, 0.2);
|
box-shadow: 1px 2px 0 rgba(0, 0, 0, 0.2);
|
||||||
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.favicon {
|
.favicon {
|
||||||
|
|
|
@ -34,6 +34,7 @@ body {
|
||||||
|
|
||||||
.thumb {
|
.thumb {
|
||||||
box-shadow: 1px 2px 0 rgba(0, 0, 0, 0.1);
|
box-shadow: 1px 2px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.favicon {
|
.favicon {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче