diff -r 000000000000 -r 6474c204b198 browser/components/tabview/test/head.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/browser/components/tabview/test/head.js Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,451 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + +// Some tests here assume that all restored tabs are loaded without waiting for +// the user to bring them to the foreground. We ensure this by resetting the +// related preference (see the "firefox.js" defaults file for details). +Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", false); +registerCleanupFunction(function () { + Services.prefs.clearUserPref("browser.sessionstore.restore_on_demand"); +}); + +// ---------- +function createEmptyGroupItem(contentWindow, width, height, padding, animate) { + let pageBounds = contentWindow.Items.getPageBounds(); + pageBounds.inset(padding, padding); + + let box = new contentWindow.Rect(pageBounds); + box.width = width; + box.height = height; + + let emptyGroupItem = + new contentWindow.GroupItem([], { bounds: box, immediately: !animate }); + + return emptyGroupItem; +} + +// ---------- +function createGroupItemWithTabs(win, width, height, padding, urls, animate) { + let contentWindow = win.TabView.getContentWindow(); + let groupItemCount = contentWindow.GroupItems.groupItems.length; + // create empty group item + let groupItem = createEmptyGroupItem(contentWindow, width, height, padding, animate); + ok(groupItem.isEmpty(), "This group is empty"); + is(contentWindow.GroupItems.groupItems.length, ++groupItemCount, + "The number of groups is increased by 1"); + // add blank items + contentWindow.UI.setActive(groupItem); + let t = 0; + urls.forEach( function(url) { + let newItem = win.gBrowser.loadOneTab(url)._tabViewTabItem; + ok(newItem.container, "Created element "+t+":"+newItem.container); + ++t; + }); + // to set one of tabItem to be active since we load tabs into a group + // in a non-standard flow. + contentWindow.UI.setActive(groupItem); + return groupItem; +} + +// ---------- +function createGroupItemWithBlankTabs(win, width, height, padding, numNewTabs, animate) { + let urls = []; + while(numNewTabs--) + urls.push("about:blank"); + return createGroupItemWithTabs(win, width, height, padding, urls, animate); +} + +// ---------- +function closeGroupItem(groupItem, callback) { + if (callback) { + groupItem.addSubscriber("close", function onClose() { + groupItem.removeSubscriber("close", onClose); + executeSoon(callback); + }); + } + + if (groupItem.getChildren().length) { + groupItem.addSubscriber("groupHidden", function onHide() { + groupItem.removeSubscriber("groupHidden", onHide); + groupItem.closeHidden(); + }); + } + + groupItem.closeAll(); +} + +// ---------- +function afterAllTabItemsUpdated(callback, win) { + win = win || window; + let tabItems = win.document.getElementById("tab-view").contentWindow.TabItems; + let counter = 0; + + for (let a = 0; a < win.gBrowser.tabs.length; a++) { + let tabItem = win.gBrowser.tabs[a]._tabViewTabItem; + if (tabItem) { + let tab = win.gBrowser.tabs[a]; + counter++; + tabItem.addSubscriber("updated", function onUpdated() { + tabItem.removeSubscriber("updated", onUpdated); + if (--counter == 0) + callback(); + }); + tabItems.update(tab); + } + } + if (counter == 0) + callback(); +} + +// --------- +function newWindowWithTabView(shownCallback, loadCallback, width, height) { + let winWidth = width || 800; + let winHeight = height || 800; + let win = window.openDialog(getBrowserURL(), "_blank", + "chrome,all,dialog=no,height=" + winHeight + + ",width=" + winWidth, "about:blank"); + + whenWindowLoaded(win, function () { + if (loadCallback) + loadCallback(win); + }); + + whenDelayedStartupFinished(win, function () { + showTabView(function () shownCallback(win), win); + }); +} + +// ---------- +function afterAllTabsLoaded(callback, win) { + const TAB_STATE_NEEDS_RESTORE = 1; + + win = win || window; + + let stillToLoad = 0; + let restoreHiddenTabs = Services.prefs.getBoolPref( + "browser.sessionstore.restore_hidden_tabs"); + + function onLoad() { + this.removeEventListener("load", onLoad, true); + stillToLoad--; + if (!stillToLoad) + executeSoon(callback); + } + + for (let a = 0; a < win.gBrowser.tabs.length; a++) { + let tab = win.gBrowser.tabs[a]; + let browser = tab.linkedBrowser; + + let isRestorable = !(tab.hidden && !restoreHiddenTabs && + browser.__SS_restoreState && + browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE); + + if (isRestorable && browser.webProgress.isLoadingDocument) { + stillToLoad++; + browser.addEventListener("load", onLoad, true); + } + } + + if (!stillToLoad) + executeSoon(callback); +} + +// ---------- +function showTabView(callback, win) { + win = win || window; + + if (win.TabView.isVisible()) { + waitForFocus(callback, win); + return; + } + + whenTabViewIsShown(function () { + waitForFocus(callback, win); + }, win); + + win.TabView.show(); +} + +// ---------- +function hideTabView(callback, win) { + win = win || window; + + if (!win.TabView.isVisible()) { + if (callback) + callback(); + return; + } + + if (callback) + whenTabViewIsHidden(callback, win); + + win.TabView.hide(); +} + +// ---------- +function whenTabViewIsHidden(callback, win) { + win = win || window; + + if (!win.TabView.isVisible()) { + callback(); + return; + } + + win.addEventListener('tabviewhidden', function onHidden() { + win.removeEventListener('tabviewhidden', onHidden, false); + callback(); + }, false); +} + +// ---------- +function whenTabViewIsShown(callback, win) { + win = win || window; + + if (win.TabView.isVisible()) { + callback(); + return; + } + + win.addEventListener('tabviewshown', function onShown() { + win.removeEventListener('tabviewshown', onShown, false); + callback(); + }, false); +} + +// ---------- +function hideSearch(callback, win) { + win = win || window; + + let contentWindow = win.TabView.getContentWindow(); + if (!contentWindow.Search.isEnabled()) { + if (callback) + callback(); + return; + } + + if (callback) + whenSearchIsDisabled(callback, win); + + contentWindow.Search.hide(); +} + +// ---------- +function whenSearchIsEnabled(callback, win) { + win = win || window; + + let contentWindow = win.TabView.getContentWindow(); + if (contentWindow.Search.isEnabled()) { + callback(); + return; + } + + contentWindow.addEventListener("tabviewsearchenabled", function onSearchEnabled() { + contentWindow.removeEventListener("tabviewsearchenabled", onSearchEnabled, false); + callback(); + }, false); +} + +// ---------- +function whenSearchIsDisabled(callback, win) { + win = win || window; + + let contentWindow = win.TabView.getContentWindow(); + if (!contentWindow.Search.isEnabled()) { + callback(); + return; + } + + contentWindow.addEventListener("tabviewsearchdisabled", function onSearchDisabled() { + contentWindow.removeEventListener("tabviewsearchdisabled", onSearchDisabled, false); + callback(); + }, false); +} + +// ---------- +function hideGroupItem(groupItem, callback) { + if (groupItem.hidden) { + if (callback) + callback(); + return; + } + + if (callback) { + groupItem.addSubscriber("groupHidden", function onHide() { + groupItem.removeSubscriber("groupHidden", onHide); + callback(); + }); + } + + groupItem.closeAll(); +} + +// ---------- +function unhideGroupItem(groupItem, callback) { + if (!groupItem.hidden) { + if (callback) + callback(); + return; + } + + if (callback) { + groupItem.addSubscriber("groupShown", function onShown() { + groupItem.removeSubscriber("groupShown", onShown); + callback(); + }); + } + + groupItem._unhide(); +} + +// ---------- +function whenWindowLoaded(win, callback) { + win.addEventListener("load", function onLoad() { + win.removeEventListener("load", onLoad, false); + executeSoon(callback); + }, false); +} + +// ---------- +function whenWindowStateReady(win, callback) { + win.addEventListener("SSWindowStateReady", function onReady() { + win.removeEventListener("SSWindowStateReady", onReady, false); + executeSoon(callback); + }, false); +} + +// ---------- +function whenDelayedStartupFinished(win, callback) { + let topic = "browser-delayed-startup-finished"; + Services.obs.addObserver(function onStartup(aSubject) { + if (win != aSubject) + return; + + Services.obs.removeObserver(onStartup, topic); + executeSoon(callback); + }, topic, false); +} + +// ---------- +function newWindowWithState(state, callback) { + const ss = Cc["@mozilla.org/browser/sessionstore;1"] + .getService(Ci.nsISessionStore); + + let opts = "chrome,all,dialog=no,height=800,width=800"; + let win = window.openDialog(getBrowserURL(), "_blank", opts, "about:blank"); + + let numConditions = 2; + let check = function () { + if (!--numConditions) + callback(win); + }; + + whenDelayedStartupFinished(win, function () { + ss.setWindowState(win, JSON.stringify(state), true); + win.close(); + // Give it time to close + executeSoon(function() { + win = ss.undoCloseWindow(0); + + whenWindowLoaded(win, function () { + afterAllTabsLoaded(check, win); + }); + + whenDelayedStartupFinished(win, check); + }); + }); +} + +// ---------- +function restoreTab(callback, index, win) { + win = win || window; + + let tab = win.undoCloseTab(index || 0); + let tabItem = tab._tabViewTabItem; + + let finalize = function () { + afterAllTabsLoaded(function () callback(tab), win); + }; + + if (tabItem._reconnected) { + finalize(); + return; + } + + tab._tabViewTabItem.addSubscriber("reconnected", function onReconnected() { + tab._tabViewTabItem.removeSubscriber("reconnected", onReconnected); + finalize(); + }); +} + +// ---------- +function goToNextGroup(win) { + win = win || window; + + let utils = + win.QueryInterface(Ci.nsIInterfaceRequestor). + getInterface(Ci.nsIDOMWindowUtils); + + const masks = Ci.nsIDOMNSEvent; + let mval = 0; + mval |= masks.CONTROL_MASK; + + utils.sendKeyEvent("keypress", 0, 96, mval); +} + +// ---------- +function whenAppTabIconAdded(groupItem, callback) { + groupItem.addSubscriber("appTabIconAdded", function onAppTabIconAdded() { + groupItem.removeSubscriber("appTabIconAdded", onAppTabIconAdded); + executeSoon(callback); + }); +} + +/** + * Chrome windows aren't closed synchronously. Provide a helper method to close + * a window and wait until we received the "domwindowclosed" notification for it. + */ +function promiseWindowClosed(win) { + let deferred = Promise.defer(); + + Services.obs.addObserver(function obs(subject, topic) { + if (subject == win) { + Services.obs.removeObserver(obs, topic); + deferred.resolve(); + } + }, "domwindowclosed", false); + + win.close(); + return deferred.promise; +} + +// ---------- +function waitForOnBeforeUnloadDialog(browser, callback) { + browser.addEventListener("DOMWillOpenModalDialog", function onModalDialog() { + browser.removeEventListener("DOMWillOpenModalDialog", onModalDialog, true); + + executeSoon(() => { + let stack = browser.parentNode; + let dialogs = stack.getElementsByTagNameNS(XUL_NS, "tabmodalprompt"); + let {button0, button1} = dialogs[0].ui; + callback(button0, button1); + }); + }, true); +} + +/** + * Overrides browser.js' OpenBrowserWindow() function to enforce an initial + * tab different from about:home to not hit the network. + */ +function OpenBrowserWindow(aOptions) { + let features = ""; + let url = "about:blank"; + + if (aOptions && aOptions.private || false) { + features = ",private"; + url = "about:privatebrowsing"; + } + + return openDialog(getBrowserURL(), "", "chrome,all,dialog=no" + features, url); +}