merge the last green changeset on fx-team to mozilla-central

This commit is contained in:
Tim Taubert 2011-07-13 15:01:58 -07:00
commit 6bfb9177bc
19 changed files with 191 additions and 214 deletions

View File

@ -435,7 +435,12 @@ let TabView = {
this.sessionRestoreEnabledOnce = true;
// enable session restore
Services.prefs.setIntPref(this.PREF_STARTUP_PAGE, 3);
// enable session restore if necessary
if (Services.prefs.getIntPref(this.PREF_STARTUP_PAGE) != 3) {
Services.prefs.setIntPref(this.PREF_STARTUP_PAGE, 3);
// show banner
this._window.UI.notifySessionRestoreEnabled();
}
}
};

View File

@ -191,6 +191,7 @@ function GroupItem(listOfEls, options) {
self.$titleShield.show();
if (self.getTitle())
gTabView.firstUseExperienced = true;
self.save();
})
.focus(function() {
self._unfreezeItemSize();
@ -825,9 +826,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
} else {
// child.removeSubscriber() must be called before child.close(),
// therefore we call child.addSubscriber() if the tab is not removed.
child.addSubscriber(self, "close", function() {
self.remove(child);
});
child.addSubscriber(self, "close", self._onChildClose.bind(self));
}
});
@ -1010,19 +1009,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
item.droppable(false);
item.groupItemData = {};
item.addSubscriber(this, "close", function() {
let count = self._children.length;
let dontArrange = self.expanded || !self.shouldStack(count);
let dontClose = !item.closedManually && gBrowser._numPinnedTabs > 0;
self.remove(item, {dontArrange: dontArrange, dontClose: dontClose});
if (dontArrange)
self._freezeItemSize(count);
if (self._children.length > 0 && self._activeTab)
UI.setActive(self);
});
item.addSubscriber(this, "close", this._onChildClose.bind(this));
item.setParent(this);
if (typeof item.setResizable == 'function')
@ -1050,6 +1037,25 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
}
},
// ----------
// Function: _onChildClose
// Handles "close" events from the group's children.
//
// Parameters:
// tabItem - The tabItem that is closed.
_onChildClose: function GroupItem__onChildClose(tabItem) {
let count = this._children.length;
let dontArrange = this.expanded || !this.shouldStack(count);
let dontClose = !tabItem.closedManually && gBrowser._numPinnedTabs > 0;
this.remove(tabItem, {dontArrange: dontArrange, dontClose: dontClose});
if (dontArrange)
this._freezeItemSize(count);
if (this._children.length > 0 && this._activeTab)
UI.setActive(this);
},
// ----------
// Function: remove
// Removes an item from the groupItem.

View File

@ -178,6 +178,20 @@ body {
position: absolute;
}
.banner {
left: 0;
bottom: 0;
right: 0;
padding: 10px 0;
position: absolute;
z-index: 1000060;
background: #000;
color: #fff;
opacity: 0;
text-align: center;
font-weight: 700;
}
/* Resizable
----------------------------------*/
.resizer {

View File

@ -135,6 +135,10 @@ let UI = {
// Used to keep track of allowed browser keys.
_browserKeys: null,
// Variable: _browserKeysWithShift
// Used to keep track of allowed browser keys with Shift key combination.
_browserKeysWithShift: null,
// Variable: ignoreKeypressForSearch
// Used to prevent keypress being handled after quitting search mode.
ignoreKeypressForSearch: false,
@ -973,11 +977,15 @@ let UI = {
"selectAll", "find"
].forEach(function(key) {
let element = gWindow.document.getElementById("key_" + key);
keys[key] = element.getAttribute("key").toLocaleLowerCase().charCodeAt(0);
let code = element.getAttribute("key").toLocaleLowerCase().charCodeAt(0);
keys[code] = key;
});
this._browserKeys = keys;
// for key combinations with shift key, the charCode of upper case letters
// are different to the lower case ones so need to handle them differently.
keys = {};
// The lower case letters are passed to processBrowserKeys() even with shift
// key when stimulating a key press using EventUtils.synthesizeKey() so need
// to handle both upper and lower cases here.
[
#ifdef XP_UNIX
"redo",
@ -986,11 +994,10 @@ let UI = {
"privatebrowsing"
].forEach(function(key) {
let element = gWindow.document.getElementById("key_" + key);
keys[key] = element.getAttribute("key").toLocaleUpperCase().charCodeAt(0);
let code = element.getAttribute("key").toLocaleLowerCase().charCodeAt(0);
keys[code] = key;
});
delete this._browserKeys;
this._browserKeys = keys;
this._browserKeysWithShift = keys;
},
// ----------
@ -1022,44 +1029,25 @@ let UI = {
#endif
let preventDefault = true;
if (evt.shiftKey) {
switch (evt.charCode) {
case self._browserKeys.tabview:
// when a user presses ctrl+shift+key, upper case letter charCode
// is passed to processBrowserKeys() so converting back to lower
// case charCode before doing the check
let lowercaseCharCode =
String.fromCharCode(evt.charCode).toLocaleLowerCase().charCodeAt(0);
if (lowercaseCharCode in self._browserKeysWithShift) {
let key = self._browserKeysWithShift[lowercaseCharCode];
if (key == "tabview")
self.exit();
break;
#ifdef XP_UNIX
case self._browserKeys.redo:
#endif
case self._browserKeys.closeWindow:
case self._browserKeys.undoCloseTab:
case self._browserKeys.undoCloseWindow:
case self._browserKeys.privatebrowsing:
else
preventDefault = false;
break;
}
} else {
switch (evt.charCode) {
case self._browserKeys.find:
if (evt.charCode in self._browserKeys) {
let key = self._browserKeys[evt.charCode];
if (key == "find")
self.enableSearch();
break;
#ifdef XP_UNIX
case self._browserKeys.quitApplication:
#else
case self._browserKeys.redo:
#endif
#ifdef XP_MACOSX
case self._browserKeys.preferencesCmdMac:
case self._browserKeys.minimizeWindow:
case self._browserKeys.hideThisAppCmdMac:
#endif
case self._browserKeys.newNavigator:
case self._browserKeys.newNavigatorTab:
case self._browserKeys.undo:
case self._browserKeys.cut:
case self._browserKeys.copy:
case self._browserKeys.paste:
case self._browserKeys.selectAll:
else
preventDefault = false;
break;
}
}
if (preventDefault) {
@ -1568,6 +1556,35 @@ let UI = {
url = gFavIconService.getFaviconImageForPage(tab.linkedBrowser.currentURI).spec;
return url;
},
// ----------
// Function: notifySessionRestoreEnabled
// Notify the user that session restore has been automatically enabled
// by showing a banner that expects no user interaction. It fades out after
// some seconds.
notifySessionRestoreEnabled: function UI_notifySessionRestoreEnabled() {
let brandBundle = gWindow.document.getElementById("bundle_brand");
let brandShortName = brandBundle.getString("brandShortName");
let notificationText = tabviewBundle.formatStringFromName(
"tabview.notification.sessionStore", [brandShortName], 1);
let banner = iQ("<div>")
.text(notificationText)
.addClass("banner")
.appendTo("body");
let onFadeOut = function () {
banner.remove();
};
let onFadeIn = function () {
setTimeout(function () {
banner.animate({opacity: 0}, {duration: 1500, complete: onFadeOut});
}, 5000);
};
banner.animate({opacity: 0.7}, {duration: 1500, complete: onFadeIn});
}
};

View File

@ -110,7 +110,6 @@ _BROWSER_FILES = \
browser_tabview_bug625195.js \
browser_tabview_bug625269.js \
browser_tabview_bug625424.js \
browser_tabview_bug625666.js \
browser_tabview_bug626368.js \
browser_tabview_bug626525.js \
browser_tabview_bug626791.js \

View File

@ -3,124 +3,78 @@
function test() {
waitForExplicitFinish();
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
if (TabView.isVisible())
onTabViewWindowLoaded();
else
TabView.show();
showTabView(onTabViewShown);
}
function onTabViewWindowLoaded() {
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
let contentWindow = document.getElementById("tab-view").contentWindow;
function onTabViewShown() {
let contentWindow = TabView.getContentWindow();
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();
// set double click interval to negative so quick drag and drop doesn't
// trigger the double click code.
let origDBlClickInterval = contentWindow.UI.DBLCLICK_INTERVAL;
contentWindow.UI.DBLCLICK_INTERVAL = -1;
let endGame = function() {
contentWindow.UI.reset();
contentWindow.UI.DBLCLICK_INTERVAL = origDBlClickInterval;
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() {
// 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();
});
});
});
hideTabView(function () {
ok(!TabView.isVisible(), "TabView is hidden");
finish();
});
}
// we need to stop the setBounds() css animation or else the test will
// fail in single-mode because the group is newly created "ontabshown".
let $container = contentWindow.iQ(currentActiveGroup.container);
$container.css("-moz-transition-property", "none");
currentActiveGroup.setPosition(40, 40, true);
currentActiveGroup.arrange({animate: false});
part1();
// move down 20 so we're far enough away from the top.
checkSnap(currentActiveGroup, 0, 20, contentWindow, function(snapped){
is(currentActiveGroup.getBounds().top, 60, "group.top is 60px");
ok(!snapped,"Move away from the edge");
// Just pick it up and drop it.
checkSnap(currentActiveGroup, 0, 0, contentWindow, function(snapped){
is(currentActiveGroup.getBounds().top, 60, "group.top is 60px");
ok(!snapped,"Just pick it up and drop it");
checkSnap(currentActiveGroup, 0, 1, contentWindow, function(snapped){
is(currentActiveGroup.getBounds().top, 60, "group.top is 60px");
ok(snapped,"Drag one pixel: should snap");
checkSnap(currentActiveGroup, 0, 5, contentWindow, function(snapped){
is(currentActiveGroup.getBounds().top, 65, "group.top is 65px");
ok(!snapped,"Moving five pixels: shouldn't snap");
endGame();
});
});
});
});
}
function simulateDragDrop(tabItem, offsetX, offsetY, contentWindow) {
// enter drag mode
let dataTransfer;
function simulateDragDrop(item, offsetX, offsetY, contentWindow) {
let target = item.container;
EventUtils.synthesizeMouse(
tabItem.container, 1, 1, { type: "mousedown" }, contentWindow);
let 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);
EventUtils.synthesizeMouse(target, 1, 1, {type: "mousedown"}, contentWindow);
EventUtils.synthesizeMouse(target, 1 + offsetX, 1 + offsetY, {type: "mousemove"}, contentWindow);
EventUtils.synthesizeMouse(target, 1, 1, {type: "mouseup"}, contentWindow);
}
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);
let snapped = false;
if (item.getBounds().top != firstTop + offsetY)
snapped = true;
if (item.getBounds().left != firstLeft + offsetX)
snapped = true;
callback(snapped);
}

View File

@ -17,7 +17,7 @@ function test1() {
ok(!TabView.isVisible(), "Tab View is not visible");
showTabView(test2);
});
EventUtils.synthesizeKey("E", { accelKey: true, shiftKey: true }, contentWindow);
EventUtils.synthesizeKey("e", { accelKey: true, shiftKey: true }, contentWindow);
}
function test2() {
@ -58,7 +58,7 @@ function test4() {
executeSoon(function() {
is(gBrowser.tabs.length, 1, "There is one tab after removing one");
EventUtils.synthesizeKey("T", { accelKey: true, shiftKey: true }, contentWindow);
EventUtils.synthesizeKey("t", { accelKey: true, shiftKey: true }, contentWindow);
is(gBrowser.tabs.length, 2, "There are two tabs after restoring one");
gBrowser.tabs[0].linkedBrowser.loadURI("about:blank");
@ -96,7 +96,7 @@ function test9() {
function test10() {
is(gBrowser.tabs.length, 1, "There is one tab before cmd/ctrl + shift + a is pressed");
// it would open about:addons on a new tab if it passes through the white list.
EventUtils.synthesizeKey("A", { accelKey: true, shiftKey: true }, contentWindow);
EventUtils.synthesizeKey("a", { accelKey: true, shiftKey: true }, contentWindow);
executeSoon(function() {
is(gBrowser.tabs.length, 1, "There is still one tab after cmd/ctrl + shift + a is pressed");

View File

@ -11,6 +11,8 @@ function test() {
let assertWindowTitle = function (win, title) {
let browser = win.gBrowser.tabs[0].linkedBrowser;
let winTitle = win.gBrowser.getWindowTitleForBrowser(browser);
info('window title is: "' + winTitle + '"');
is(winTitle.indexOf(title), 0, "title starts with '" + title + "'");
};

View File

@ -57,5 +57,5 @@ function toggleTabViewTest(contentWindow) {
}
contentWindow.addEventListener("tabviewhidden", onTabViewHidden, false);
// Use keyboard shortcut to toggle back to browser view
EventUtils.synthesizeKey("E", { accelKey: true, shiftKey: true });
EventUtils.synthesizeKey("e", { accelKey: true, shiftKey: true });
}

View File

@ -28,7 +28,7 @@ function onTabViewWindowLoaded() {
// verify that the keyboard combo works (this is the crux of bug 595518)
// Prepare the key combo
window.addEventListener("tabviewshown", onTabViewShown, false);
EventUtils.synthesizeKey("E", { accelKey: true, shiftKey: true }, contentWindow);
EventUtils.synthesizeKey("e", { accelKey: true, shiftKey: true }, contentWindow);
}
let onTabViewShown = function() {

View File

@ -41,7 +41,7 @@ function onTabViewWindowLoaded() {
// the appropriate group would get selected when the key
// combination is pressed
executeSoon(function() {
EventUtils.synthesizeKey("E", {accelKey : true, shiftKey: true}, contentWindow);
EventUtils.synthesizeKey("e", {accelKey : true, shiftKey: true}, contentWindow);
});
});

View File

@ -78,8 +78,8 @@ function part2(win) {
finish();
}, false);
// show tabview
EventUtils.synthesizeKey("E", { accelKey: true, shiftKey: true }, win);
EventUtils.synthesizeKey("e", { accelKey: true, shiftKey: true }, win);
// hide tabview
EventUtils.synthesizeKey("E", { accelKey: true, shiftKey: true }, win);
EventUtils.synthesizeKey("e", { accelKey: true, shiftKey: true }, win);
})
}

View File

@ -1,49 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
let cw;
let getTabItemAspect = function (tabItem) {
let bounds = cw.iQ('.thumb', tabItem.container).bounds();
let padding = cw.TabItems.tabItemPadding;
return (bounds.height + padding.y) / (bounds.width + padding.x);
}
let getAspectRange = function () {
let aspect = cw.TabItems.tabAspect;
let variance = aspect / 100 * 1.5;
return new cw.Range(aspect - variance, aspect + variance);
}
waitForExplicitFinish();
newWindowWithTabView(function (win) {
registerCleanupFunction(function () win.close());
cw = win.TabView.getContentWindow();
// prepare orphan tab
let tabItem = win.gBrowser.tabs[0]._tabViewTabItem;
tabItem.parent.remove(tabItem, {immediately: true});
tabItem.setBounds(new cw.Rect(20, 20, 200, 165), true);
let bounds = tabItem.getBounds();
// prepare group item
let box = new cw.Rect(20, 300, 400, 200);
let groupItem = new cw.GroupItem([], {bounds: box, immediately: true});
groupItem.setBounds(new cw.Rect(20, 100, 400, 200));
groupItem.pushAway(true);
let newBounds = tabItem.getBounds();
ok(newBounds.width < bounds.width, "The new width of item is smaller than the old one.");
ok(newBounds.height < bounds.height, "The new height of item is smaller than the old one.");
let aspectRange = getAspectRange();
let aspect = getTabItemAspect(tabItem);
ok(aspectRange.contains(aspect), "orphaned tabItem's aspect is correct");
finish();
});
}

View File

@ -30,6 +30,16 @@ function test() {
assertBoolPref(TabView.PREF_RESTORE_ENABLED_ONCE, enabledOnce);
};
let assertNotificationBannerVisible = function (win) {
let cw = win.TabView.getContentWindow();
is(cw.iQ(".banner").length, 1, "notification banner is visible");
};
let assertNotificationBannerNotVisible = function (win) {
let cw = win.TabView.getContentWindow();
is(cw.iQ(".banner").length, 0, "notification banner is not visible");
};
let next = function () {
if (tests.length == 0) {
waitForFocus(finish);
@ -52,6 +62,7 @@ function test() {
setPreferences(1, true, false);
newWindowWithTabView(function (win) {
assertNotificationBannerVisible(win);
assertPreferences(3, true, true);
win.close();
@ -72,10 +83,12 @@ function test() {
setPreferences(1, false, false);
newWindowWithTabView(function (win) {
assertNotificationBannerNotVisible(win);
assertPreferences(1, false, false);
win.TabView.firstUseExperienced = true;
assertNotificationBannerVisible(win);
assertPreferences(3, true, true);
win.close();
@ -94,6 +107,7 @@ function test() {
setPreferences(3, true, false);
newWindowWithTabView(function (win) {
assertNotificationBannerNotVisible(win);
assertPreferences(3, true, true);
win.close();
@ -111,6 +125,7 @@ function test() {
setPreferences(3, true, true);
newWindowWithTabView(function (win) {
assertNotificationBannerNotVisible(win);
assertPreferences(3, true, true);
win.close();
@ -129,6 +144,7 @@ function test() {
setPreferences(1, true, true);
newWindowWithTabView(function (win) {
assertNotificationBannerNotVisible(win);
assertPreferences(1, true, true);
win.close();

View File

@ -28,7 +28,7 @@ function test() {
newWin.document.getElementById("menu_tabview").doCommand();
}, function() {
testMethodToHideAndShowTabView(function() {
EventUtils.synthesizeKey("E", { accelKey: true, shiftKey: true }, newWin);
EventUtils.synthesizeKey("e", { accelKey: true, shiftKey: true }, newWin);
}, finish);
});
});

View File

@ -83,9 +83,11 @@ function newWindowWithTabView(shownCallback, loadCallback, width, height) {
",width=" + winWidth);
whenWindowLoaded(win, function () {
if (typeof loadCallback == "function")
if (loadCallback)
loadCallback(win);
});
whenDelayedStartupFinished(win, function () {
showTabView(function () shownCallback(win), win);
});
}

View File

@ -289,6 +289,7 @@ var treeView = {
isSeparator: function(idx) { return false; },
isSorted: function() { return false; },
isEditable: function(idx, column) { return false; },
canDrop: function(idx, orientation, dt) { return false; },
getLevel: function(idx) { return this.isContainer(idx) ? 0 : 1; },
getParentIndex: function(idx) {

View File

@ -2222,8 +2222,14 @@ SessionStoreService.prototype = {
if (!aWindow._hosts)
return;
for (var [host, isPinned] in Iterator(aWindow._hosts)) {
var list = CookieSvc.getCookiesFromHost(host);
while (list.hasMoreElements()) {
let list;
try {
list = CookieSvc.getCookiesFromHost(host);
}
catch (ex) {
debug("getCookiesFromHost failed. Host: " + host);
}
while (list && list.hasMoreElements()) {
var cookie = list.getNext().QueryInterface(Ci.nsICookie2);
// aWindow._hosts will only have hosts with the right privacy rules,
// so there is no need to do anything special with this call to
@ -2952,8 +2958,11 @@ SessionStoreService.prototype = {
// so we can just set the URL to null.
browser.__SS_restore_data = { url: null };
browser.__SS_restore_tab = aTab;
if (didStartLoad)
browser.stop();
didStartLoad = true;
browser.loadURI(tabData.userTypedValue, null, null, true);
browser.loadURIWithFlags(tabData.userTypedValue,
Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP);
}
}

View File

@ -2,3 +2,4 @@ tabview.groupItem.newTabButton=New tab
tabview.groupItem.defaultName=Name this tab group…
tabview.groupItem.undoCloseGroup=Undo Close Group
tabview.search.otherWindowTabs=Tabs from other windows
tabview.notification.sessionStore=Tabs and groups will automatically be restored the next time you start %S.