Merge fx-team to central, a=merge

--HG--
extra : commitid : GoUn7UzWJCi
This commit is contained in:
Wes Kocher 2015-12-01 16:07:14 -08:00
Родитель 50e8f21d5b c3c17919f1
Коммит 541c7a5b69
297 изменённых файлов: 3238 добавлений и 25782 удалений

Просмотреть файл

@ -94,7 +94,7 @@ browser/extensions/loop/content/preferences/prefs.js
# Libs we don't need to check
browser/extensions/loop/content/panels/vendor
browser/extensions/loop/content/shared/vendor
browser/extensions/loop/standalone/content/libs
browser/extensions/loop/standalone/content/vendor
# Libs we don't need to check
browser/extensions/loop/test/shared/vendor
# Coverage files

Просмотреть файл

@ -210,7 +210,6 @@ DEFAULT_TEST_PREFS = {
'security.default_personal_cert': 'Select Automatically',
'network.http.prompt-temp-redirect': False,
'security.warn_viewing_mixed': False,
'browser.panorama.experienced_first_run': True,
# Set a future policy version to avoid the telemetry prompt.
'toolkit.telemetry.prompted': 999,
'toolkit.telemetry.notifiedOptOut': 999,

Просмотреть файл

@ -26,7 +26,6 @@
"security.default_personal_cert": "Select Automatically",
"network.http.prompt-temp-redirect": false,
"security.warn_viewing_mixed": false,
"browser.panorama.experienced_first_run": true,
"toolkit.telemetry.prompted": 999,
"toolkit.telemetry.notifiedOptOut": 999,
"extensions.defaultProviders.enabled": true,

Просмотреть файл

@ -0,0 +1,63 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
Cu.import("resource:///modules/TabGroupsMigrator.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
const SUPPORT_URL = "https://support.mozilla.org/kb/tab-groups-removal";
function fillInDescription() {
let descElement = document.getElementById("mainDescription");
let text = descElement.getAttribute("_description_label");
let learnMoreText = descElement.getAttribute("_learnmore_label");
let link = document.createElement("a");
link.href = SUPPORT_URL;
link.target = "_blank";
link.textContent = learnMoreText;
// We don't want to assign the label (plaintext, because we took it out of
// getAttribute, so html entities have been resolved) directly to innerHTML.
// Using a separate element and then using innerHTML on that would mean we
// depend on the HTML encoding (or lack thereof) of %S, which l10n tools
// might change.
// So instead, split the plaintext we have and create textNodes:
let nodes = text.split(/%S/).map(document.createTextNode.bind(document));
// then insert the link:
nodes.splice(1, 0, link);
// then append all of these in turn:
for (let node of nodes) {
descElement.appendChild(node);
}
}
let loadPromise = new Promise(resolve => {
let loadHandler = e => {
window.removeEventListener("DOMContentLoaded", loadHandler);
fillInDescription();
resolve();
};
window.addEventListener("DOMContentLoaded", loadHandler, false);
});
let tabGroupsBookmarkItemId;
// If the session wasn't restored this run/session, this might be null.
// Then we shouldn't show the button:
if (TabGroupsMigrator.bookmarkedGroupsPromise) {
let bookmarkPromise = TabGroupsMigrator.bookmarkedGroupsPromise.then(bm => {
return PlacesUtils.promiseItemId(bm.guid);
}).then(itemId => { tabGroupsBookmarkItemId = itemId });
Promise.all([bookmarkPromise, loadPromise]).then(function() {
document.getElementById("show-migrated-bookmarks-button").style.removeProperty("display");
});
}
function showMigratedGroups() {
let browserWin = getBrowserWindow();
browserWin.PlacesCommandHook.showPlacesOrganizer(["BookmarksMenu", tabGroupsBookmarkItemId]);
}

Просмотреть файл

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-->
<!DOCTYPE html [
<!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
%htmlDTD;
<!ENTITY % netErrorDTD SYSTEM "chrome://global/locale/netError.dtd">
%netErrorDTD;
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
%globalDTD;
<!ENTITY % restorepageDTD SYSTEM "chrome://browser/locale/aboutSessionRestore.dtd">
%restorepageDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<head>
<title>&tabgroupsmigration.tabtitle;</title>
<link rel="stylesheet" href="chrome://global/skin/in-content/info-pages.css" type="text/css" media="all"/>
<link rel="stylesheet" href="chrome://browser/skin/aboutSessionRestore.css" type="text/css" media="all"/>
<link rel="icon" type="image/png" href="chrome://global/skin/icons/warning-16.png"/>
<script type="application/javascript;version=1.8" src="chrome://browser/content/aboutSessionRestore.js"/>
<script type="application/javascript;version=1.8" src="chrome://browser/content/aboutTabGroupsMigration.js"/>
</head>
<body dir="&locale.dir;">
<div class="container restore-chosen">
<div class="title">
<h1 class="title-text">&tabgroupsmigration.pagetitle;</h1>
</div>
<div class="description">
<p id="mainDescription"
_learnmore_label="&tabgroupsmigration.learnMoreLink;"
_description_label="&tabgroupsmigration.description;"></p>
<button id="show-migrated-bookmarks-button" style="display:none" onclick="showMigratedGroups()">&tabgroupsmigration.bookmarkbutton;</button>
<p>&tabgroupsmigration.restoredescription;</p>
</div>
<div class="tree-container" available="true">
<xul:tree id="tabList" seltype="single" hidecolumnpicker="true"
onclick="onListClick(event);" onkeydown="onListKeyDown(event);"
_window_label="&restorepage.windowLabel;">
<xul:treecols>
<xul:treecol cycler="true" id="restore" type="checkbox" label="&restorepage.restoreHeader;"/>
<xul:splitter class="tree-splitter"/>
<xul:treecol primary="true" id="title" label="&restorepage.listHeader;" flex="1"/>
</xul:treecols>
<xul:treechildren flex="1"/>
</xul:tree>
</div>
<div class="button-container">
#ifdef XP_UNIX
<xul:button id="errorCancel"
label="&restorepage.closeButton;"
accesskey="&restorepage.close.access;"
oncommand="startNewSession();"/>
<xul:button class="primary"
id="errorTryAgain"
label="&restorepage.tryagainButton;"
accesskey="&restorepage.restore.access;"
oncommand="restoreSession();"/>
#else
<xul:button class="primary"
id="errorTryAgain"
label="&restorepage.tryagainButton;"
accesskey="&restorepage.restore.access;"
oncommand="restoreSession();"/>
<xul:button id="errorCancel"
label="&restorepage.closeButton;"
accesskey="&restorepage.close.access;"
oncommand="startNewSession();"/>
#endif
</div>
<!-- holds the session data for when the tab is closed -->
<input type="text" id="sessionData" style="display: none;"/>
</div>
</body>
</html>

Просмотреть файл

@ -82,7 +82,6 @@
<command id="Browser:NextTab" oncommand="gBrowser.tabContainer.advanceSelectedTab(1, true);" reserved="true"/>
<command id="Browser:PrevTab" oncommand="gBrowser.tabContainer.advanceSelectedTab(-1, true);" reserved="true"/>
<command id="Browser:ShowAllTabs" oncommand="allTabs.open();"/>
<command id="Browser:ToggleTabView" oncommand="TabView.toggle();"/>
<command id="cmd_fullZoomReduce" oncommand="FullZoom.reduce()"/>
<command id="cmd_fullZoomEnlarge" oncommand="FullZoom.enlarge()"/>
<command id="cmd_fullZoomReset" oncommand="FullZoom.reset()"/>
@ -178,7 +177,6 @@
<broadcaster id="isFrameImage"/>
<broadcaster id="singleFeedMenuitemState" disabled="true"/>
<broadcaster id="multipleFeedsMenuState" hidden="true"/>
<broadcaster id="tabviewGroupsNumber" groups="1"/>
<broadcaster id="sync-setup-state"/>
<broadcaster id="sync-syncnow-state" hidden="true"/>
<broadcaster id="sync-reauth-state" hidden="true"/>
@ -428,8 +426,6 @@
<key id="key_switchTextDirection" key="&bidiSwitchTextDirectionItem.commandkey;" command="cmd_switchTextDirection" modifiers="accel,shift" />
<key id="key_tabview" key="&tabView.commandkey;" command="Browser:ToggleTabView" modifiers="accel,shift"/>
<key id="key_privatebrowsing" command="Tools:PrivateBrowsing" key="&privateBrowsingCmd.commandkey;" modifiers="accel,shift"/>
<key id="key_sanitize" command="Tools:Sanitize" keycode="VK_DELETE" modifiers="accel,shift"/>
#ifdef XP_MACOSX

Просмотреть файл

@ -1,490 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var TabView = {
_deck: null,
_iframe: null,
_window: null,
_initialized: false,
_browserKeyHandlerInitialized: false,
_closedLastVisibleTabBeforeFrameInitialized: false,
_isFrameLoading: false,
_initFrameCallbacks: [],
PREF_BRANCH: "browser.panorama.",
PREF_FIRST_RUN: "browser.panorama.experienced_first_run",
PREF_STARTUP_PAGE: "browser.startup.page",
PREF_RESTORE_ENABLED_ONCE: "browser.panorama.session_restore_enabled_once",
GROUPS_IDENTIFIER: "tabview-groups",
VISIBILITY_IDENTIFIER: "tabview-visibility",
// ----------
get windowTitle() {
delete this.windowTitle;
let brandBundle = document.getElementById("bundle_brand");
let brandShortName = brandBundle.getString("brandShortName");
let title = gNavigatorBundle.getFormattedString("tabview.title", [brandShortName]);
return this.windowTitle = title;
},
// ----------
get firstUseExperienced() {
let pref = this.PREF_FIRST_RUN;
if (Services.prefs.prefHasUserValue(pref))
return Services.prefs.getBoolPref(pref);
return false;
},
// ----------
set firstUseExperienced(val) {
Services.prefs.setBoolPref(this.PREF_FIRST_RUN, val);
},
// ----------
get sessionRestoreEnabledOnce() {
let pref = this.PREF_RESTORE_ENABLED_ONCE;
if (Services.prefs.prefHasUserValue(pref))
return Services.prefs.getBoolPref(pref);
return false;
},
// ----------
set sessionRestoreEnabledOnce(val) {
Services.prefs.setBoolPref(this.PREF_RESTORE_ENABLED_ONCE, val);
},
// ----------
init: function TabView_init() {
// disable the ToggleTabView command for popup windows
goSetCommandEnabled("Browser:ToggleTabView", window.toolbar.visible);
if (!window.toolbar.visible)
return;
if (this._initialized)
return;
if (this.firstUseExperienced) {
// ___ visibility
let data = SessionStore.getWindowValue(window, this.VISIBILITY_IDENTIFIER);
if (data && data == "true") {
this.show();
} else {
try {
data = SessionStore.getWindowValue(window, this.GROUPS_IDENTIFIER);
if (data) {
let parsedData = JSON.parse(data);
this.updateGroupNumberBroadcaster(parsedData.totalNumber || 1);
}
} catch (e) { }
let self = this;
// if a tab is changed from hidden to unhidden and the iframe is not
// initialized, load the iframe and setup the tab.
this._tabShowEventListener = function(event) {
if (!self._window)
self._initFrame(function() {
self._window.UI.onTabSelect(gBrowser.selectedTab);
if (self._closedLastVisibleTabBeforeFrameInitialized) {
self._closedLastVisibleTabBeforeFrameInitialized = false;
self._window.UI.showTabView(false);
}
});
};
this._tabCloseEventListener = function(event) {
if (!self._window && gBrowser.visibleTabs.length == 0)
self._closedLastVisibleTabBeforeFrameInitialized = true;
};
gBrowser.tabContainer.addEventListener(
"TabShow", this._tabShowEventListener, false);
gBrowser.tabContainer.addEventListener(
"TabClose", this._tabCloseEventListener, false);
if (this._tabBrowserHasHiddenTabs()) {
this._setBrowserKeyHandlers();
} else {
// for restoring last session and undoing recently closed window
this._SSWindowStateReadyListener = function (event) {
if (this._tabBrowserHasHiddenTabs())
this._setBrowserKeyHandlers();
}.bind(this);
window.addEventListener(
"SSWindowStateReady", this._SSWindowStateReadyListener, false);
}
}
}
Services.prefs.addObserver(this.PREF_BRANCH, this, false);
this._initialized = true;
},
// ----------
// Observes topic changes.
observe: function TabView_observe(subject, topic, data) {
if (data == this.PREF_FIRST_RUN && this.firstUseExperienced) {
this._addToolbarButton();
this.enableSessionRestore();
}
},
// ----------
// Uninitializes TabView.
uninit: function TabView_uninit() {
if (!this._initialized)
return;
Services.prefs.removeObserver(this.PREF_BRANCH, this);
if (this._tabShowEventListener)
gBrowser.tabContainer.removeEventListener(
"TabShow", this._tabShowEventListener, false);
if (this._tabCloseEventListener)
gBrowser.tabContainer.removeEventListener(
"TabClose", this._tabCloseEventListener, false);
if (this._SSWindowStateReadyListener)
window.removeEventListener(
"SSWindowStateReady", this._SSWindowStateReadyListener, false);
this._initialized = false;
if (this._window) {
this._window = null;
}
if (this._iframe) {
this._iframe.remove();
this._iframe = null;
}
},
// ----------
// Creates the frame and calls the callback once it's loaded.
// If the frame already exists, calls the callback immediately.
_initFrame: function TabView__initFrame(callback) {
let hasCallback = typeof callback == "function";
// prevent frame to be initialized for popup windows
if (!window.toolbar.visible)
return;
if (this._window) {
if (hasCallback)
callback();
return;
}
if (hasCallback)
this._initFrameCallbacks.push(callback);
if (this._isFrameLoading)
return;
this._isFrameLoading = true;
TelemetryStopwatch.start("PANORAMA_INITIALIZATION_TIME_MS");
// ___ find the deck
this._deck = document.getElementById("tab-view-deck");
// ___ create the frame
this._iframe = document.createElement("iframe");
this._iframe.id = "tab-view";
this._iframe.setAttribute("transparent", "true");
this._iframe.setAttribute("tooltip", "tab-view-tooltip");
this._iframe.flex = 1;
let self = this;
window.addEventListener("tabviewframeinitialized", function onInit() {
window.removeEventListener("tabviewframeinitialized", onInit, false);
TelemetryStopwatch.finish("PANORAMA_INITIALIZATION_TIME_MS");
self._isFrameLoading = false;
self._window = self._iframe.contentWindow;
self._setBrowserKeyHandlers();
if (self._tabShowEventListener) {
gBrowser.tabContainer.removeEventListener(
"TabShow", self._tabShowEventListener, false);
self._tabShowEventListener = null;
}
if (self._tabCloseEventListener) {
gBrowser.tabContainer.removeEventListener(
"TabClose", self._tabCloseEventListener, false);
self._tabCloseEventListener = null;
}
if (self._SSWindowStateReadyListener) {
window.removeEventListener(
"SSWindowStateReady", self._SSWindowStateReadyListener, false);
self._SSWindowStateReadyListener = null;
}
self._initFrameCallbacks.forEach(cb => cb());
self._initFrameCallbacks = [];
}, false);
this._iframe.setAttribute("src", "chrome://browser/content/tabview.html");
this._deck.appendChild(this._iframe);
// ___ create tooltip
let tooltip = document.createElement("tooltip");
tooltip.id = "tab-view-tooltip";
tooltip.setAttribute("onpopupshowing", "return TabView.fillInTooltip(document.tooltipNode);");
document.getElementById("mainPopupSet").appendChild(tooltip);
},
// ----------
getContentWindow: function TabView_getContentWindow() {
return this._window;
},
// ----------
isVisible: function TabView_isVisible() {
return (this._deck ? this._deck.selectedPanel == this._iframe : false);
},
// ----------
show: function TabView_show() {
if (this.isVisible())
return;
let self = this;
this._initFrame(function() {
self._window.UI.showTabView(true);
});
},
// ----------
hide: function TabView_hide() {
if (this.isVisible() && this._window) {
this._window.UI.exit();
}
},
// ----------
toggle: function TabView_toggle() {
if (this.isVisible())
this.hide();
else
this.show();
},
// ----------
_tabBrowserHasHiddenTabs: function TabView_tabBrowserHasHiddenTabs() {
return (gBrowser.tabs.length - gBrowser.visibleTabs.length) > 0;
},
// ----------
updateContextMenu: function TabView_updateContextMenu(tab, popup) {
let separator = document.getElementById("context_tabViewNamedGroups");
let isEmpty = true;
while (popup.firstChild && popup.firstChild != separator)
popup.removeChild(popup.firstChild);
let self = this;
this._initFrame(function() {
let activeGroup = tab._tabViewTabItem.parent;
let groupItems = self._window.GroupItems.groupItems;
groupItems.forEach(function(groupItem) {
// if group has title, it's not hidden and there is no active group or
// the active group id doesn't match the group id, a group menu item
// would be added.
if (!groupItem.hidden &&
(groupItem.getTitle().trim() || groupItem.getChildren().length) &&
(!activeGroup || activeGroup.id != groupItem.id)) {
let menuItem = self._createGroupMenuItem(groupItem);
popup.insertBefore(menuItem, separator);
isEmpty = false;
}
});
separator.hidden = isEmpty;
});
},
// ----------
_createGroupMenuItem: function TabView__createGroupMenuItem(groupItem) {
let menuItem = document.createElement("menuitem");
let title = groupItem.getTitle();
if (!title.trim()) {
let topChildLabel = groupItem.getTopChild().tab.label;
let childNum = groupItem.getChildren().length;
if (childNum > 1) {
let num = childNum - 1;
title =
gNavigatorBundle.getString("tabview.moveToUnnamedGroup.label");
title = PluralForm.get(num, title).replace("#1", topChildLabel).replace("#2", num);
} else {
title = topChildLabel;
}
}
menuItem.setAttribute("label", title);
menuItem.setAttribute("tooltiptext", title);
menuItem.setAttribute("crop", "center");
menuItem.setAttribute("class", "tabview-menuitem");
menuItem.setAttribute(
"oncommand",
"TabView.moveTabTo(TabContextMenu.contextTab,'" + groupItem.id + "')");
return menuItem;
},
// ----------
moveTabTo: function TabView_moveTabTo(tab, groupItemId) {
if (this._window) {
this._window.GroupItems.moveTabToGroupItem(tab, groupItemId);
} else {
let self = this;
this._initFrame(function() {
self._window.GroupItems.moveTabToGroupItem(tab, groupItemId);
});
}
},
// ----------
// Adds new key commands to the browser, for invoking the Tab Candy UI
// and for switching between groups of tabs when outside of the Tab Candy UI.
_setBrowserKeyHandlers: function TabView__setBrowserKeyHandlers() {
if (this._browserKeyHandlerInitialized)
return;
this._browserKeyHandlerInitialized = true;
let self = this;
window.addEventListener("keypress", function(event) {
if (self.isVisible() || !self._tabBrowserHasHiddenTabs())
return;
let charCode = event.charCode;
// Control (+ Shift) + `
if (event.ctrlKey && !event.metaKey && !event.altKey &&
(charCode == 96 || charCode == 126)) {
event.stopPropagation();
event.preventDefault();
self._initFrame(function() {
let groupItems = self._window.GroupItems;
let tabItem = groupItems.getNextGroupItemTab(event.shiftKey);
if (!tabItem)
return;
if (gBrowser.selectedTab.pinned)
groupItems.updateActiveGroupItemAndTabBar(tabItem, {dontSetActiveTabInGroup: true});
else
gBrowser.selectedTab = tabItem.tab;
});
}
}, true);
},
// ----------
// Prepares the tab view for undo close tab.
prepareUndoCloseTab: function TabView_prepareUndoCloseTab(blankTabToRemove) {
if (this._window) {
this._window.UI.restoredClosedTab = true;
if (blankTabToRemove && blankTabToRemove._tabViewTabItem)
blankTabToRemove._tabViewTabItem.isRemovedAfterRestore = true;
}
},
// ----------
// Cleans up the tab view after undo close tab.
afterUndoCloseTab: function TabView_afterUndoCloseTab() {
if (this._window)
this._window.UI.restoredClosedTab = false;
},
// ----------
// On move to group pop showing.
moveToGroupPopupShowing: function TabView_moveToGroupPopupShowing(event) {
// Update the context menu only if Panorama was already initialized or if
// there are hidden tabs.
let numHiddenTabs = gBrowser.tabs.length - gBrowser.visibleTabs.length;
if (this._window || numHiddenTabs > 0)
this.updateContextMenu(TabContextMenu.contextTab, event.target);
},
// ----------
// Function: _addToolbarButton
// Adds the TabView button to the TabsToolbar.
_addToolbarButton: function TabView__addToolbarButton() {
let buttonId = "tabview-button";
if (CustomizableUI.getPlacementOfWidget(buttonId))
return;
let allTabsBtnPlacement = CustomizableUI.getPlacementOfWidget("alltabs-button");
// allTabsBtnPlacement can never be null because the button isn't removable
let desiredPosition = allTabsBtnPlacement.position + 1;
CustomizableUI.addWidgetToArea(buttonId, "TabsToolbar", desiredPosition);
// NB: this is for backwards compatibility, and should be removed by
// https://bugzilla.mozilla.org/show_bug.cgi?id=976041
document.persist("TabsToolbar", "currentset");
},
// ----------
// Function: updateGroupNumberBroadcaster
// Updates the group number broadcaster.
updateGroupNumberBroadcaster: function TabView_updateGroupNumberBroadcaster(number) {
let groupsNumber = document.getElementById("tabviewGroupsNumber");
groupsNumber.setAttribute("groups", number);
},
// ----------
// Function: enableSessionRestore
// Enables automatic session restore when the browser is started. Does
// nothing if we already did that once in the past.
enableSessionRestore: function TabView_enableSessionRestore() {
if (!this._window || !this.firstUseExperienced)
return;
// do nothing if we already enabled session restore once
if (this.sessionRestoreEnabledOnce)
return;
this.sessionRestoreEnabledOnce = true;
// 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();
}
},
// ----------
// Function: fillInTooltip
// Fills in the tooltip text.
fillInTooltip: function fillInTooltip(tipElement) {
let retVal = false;
let titleText = null;
let direction = tipElement.ownerDocument.dir;
while (!titleText && tipElement) {
if (tipElement.nodeType == Node.ELEMENT_NODE)
titleText = tipElement.getAttribute("title");
tipElement = tipElement.parentNode;
}
let tipNode = document.getElementById("tab-view-tooltip");
tipNode.style.direction = direction;
if (titleText) {
tipNode.setAttribute("label", titleText);
retVal = true;
}
return retVal;
}
};

Просмотреть файл

@ -836,11 +836,6 @@ statuspanel[inactive][previoustype=overLink] {
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#promobox");
}
/* tabview menus */
.tabview-menuitem {
max-width: 32em;
}
/* gcli */
html|*#gcli-tooltip-frame,

Просмотреть файл

@ -1388,7 +1388,6 @@ var gBrowserInit = {
RestoreLastSessionObserver.init();
SocialUI.init();
TabView.init();
// Telemetry for master-password - we do this after 5 seconds as it
// can cause IO if NSS/PSM has not already initialized.
@ -1509,7 +1508,6 @@ var gBrowserInit = {
gPrefService.removeObserver(ctrlTab.prefName, ctrlTab);
ctrlTab.uninit();
TabView.uninit();
SocialUI.uninit();
gBrowserThumbnails.uninit();
FullZoom.destroy();
@ -1564,7 +1562,7 @@ var gBrowserInit = {
'viewToolbarsMenu', 'viewSidebarMenuMenu', 'Browser:Reload',
'viewFullZoomMenu', 'pageStyleMenu', 'charsetMenu', 'View:PageSource', 'View:FullScreen',
'viewHistorySidebar', 'Browser:AddBookmarkAs', 'Browser:BookmarkAllTabs',
'View:PageInfo', 'Browser:ToggleTabView'];
'View:PageInfo'];
var element;
for (let disabledItem of disabledItems) {
@ -5521,7 +5519,6 @@ const nodeToTooltipMap = {
"new-tab-button": "newTabButton.tooltip",
"tabs-newtab-button": "newTabButton.tooltip",
"fullscreen-button": "fullscreenButton.tooltip",
"tabview-button": "tabviewButton.tooltip",
"downloads-button": "downloads.tooltip",
};
const nodeToShortcutMap = {
@ -5533,7 +5530,6 @@ const nodeToShortcutMap = {
"new-tab-button": "key_newNavigatorTab",
"tabs-newtab-button": "key_newNavigatorTab",
"fullscreen-button": "key_fullScreen",
"tabview-button": "key_tabview",
"downloads-button": "key_openDownloads"
};
const gDynamicTooltipCache = new Map();
@ -6534,11 +6530,6 @@ function CanCloseWindow()
function WindowIsClosing()
{
if (TabView.isVisible()) {
TabView.hide();
return false;
}
if (!closeWindow(false, warnAboutClosingWindow))
return false;
@ -6758,9 +6749,7 @@ function undoCloseTab(aIndex) {
var tab = null;
if (SessionStore.getClosedTabCount(window) > (aIndex || 0)) {
TabView.prepareUndoCloseTab(blankTabToRemove);
tab = SessionStore.undoCloseTab(window, aIndex || 0);
TabView.afterUndoCloseTab();
if (blankTabToRemove)
gBrowser.removeTab(blankTabToRemove);
@ -7854,10 +7843,6 @@ var TabContextMenu = {
if (!bookmarkAllTabs.hidden)
PlacesCommandHook.updateBookmarkAllTabsCommand();
// Hide "Move to Group" if it's a pinned tab.
document.getElementById("context_tabViewMenu").hidden =
(this.contextTab.pinned || !TabView.firstUseExperienced);
// Adjust the state of the toggle mute menu item.
let toggleMute = document.getElementById("context_toggleMuteTab");
if (this.contextTab.hasAttribute("muted")) {

Просмотреть файл

@ -91,15 +91,6 @@
<menuitem id="context_unpinTab" label="&unpinTab.label;" hidden="true"
accesskey="&unpinTab.accesskey;"
oncommand="gBrowser.unpinTab(TabContextMenu.contextTab);"/>
<menu id="context_tabViewMenu" label="&moveToGroup.label;"
accesskey="&moveToGroup.accesskey;">
<menupopup id="context_tabViewMenuPopup"
onpopupshowing="if (event.target == this) TabView.moveToGroupPopupShowing(event);">
<menuseparator id="context_tabViewNamedGroups" hidden="true"/>
<menuitem id="context_tabViewNewGroup" label="&moveToNewGroup.label;"
oncommand="TabView.moveTabTo(TabContextMenu.contextTab, null);"/>
</menupopup>
</menu>
<menuitem id="context_openTabInWindow" label="&moveToNewWindow.label;"
accesskey="&moveToNewWindow.accesskey;"
tbattr="tabbrowser-multiple"
@ -590,12 +581,6 @@
removable="false">
<menupopup id="alltabs-popup"
position="after_end">
<menuitem id="menu_tabview"
class="menuitem-iconic"
key="key_tabview"
label="&viewTabGroups.label;"
command="Browser:ToggleTabView"
observes="tabviewGroupsNumber"/>
<menuitem id="alltabs_undoCloseTab"
class="menuitem-iconic"
key="key_undoCloseTab"
@ -1058,12 +1043,6 @@
class="toolbarbutton-1 chromeclass-toolbar-additional"
label="&syncToolbarButton.label;"
oncommand="gSyncUI.handleToolbarButton()"/>
<toolbarbutton id="tabview-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
label="&tabGroupsButton.label;"
command="Browser:ToggleTabView"
tooltip="dynamic-shortcut-tooltip"
observes="tabviewGroupsNumber"/>
</toolbarpalette>
</toolbox>

Просмотреть файл

@ -56,8 +56,7 @@ var gChatWindow = {
'key_selectTab4', 'key_selectTab5', 'key_selectTab6',
'key_selectTab7', 'key_selectTab8', 'key_selectLastTab',
'viewHistorySidebar', 'viewBookmarksSidebar',
'Browser:AddBookmarkAs', 'Browser:BookmarkAllTabs',
'Browser:ToggleTabView'];
'Browser:AddBookmarkAs', 'Browser:BookmarkAllTabs'];
for (let disabledItem of disabledItems) {
document.getElementById(disabledItem).setAttribute("disabled", "true");

Просмотреть файл

@ -1007,14 +1007,7 @@
<method name="updateTitlebar">
<body>
<![CDATA[
if ("TabView" in window && TabView.isVisible()) {
// ToDo: this will be removed when we gain ability to draw to the menu bar.
// Bug 586175
this.ownerDocument.title = TabView.windowTitle;
}
else {
this.ownerDocument.title = this.getWindowTitleForBrowser(this.mCurrentBrowser);
}
this.ownerDocument.title = this.getWindowTitleForBrowser(this.mCurrentBrowser);
]]>
</body>
</method>
@ -4374,11 +4367,9 @@
if (tabForEvent.selected)
return;
// If this is a tabprompt, and we're not in tabview/panorama with
// the prompt being a beforeunload one, we won't switch tabs
// (unless this behaviour has been disabled entirely using the pref).
// If this is a tabprompt, we won't switch tabs
// (unless this behaviour has been disabled entirely using the pref)
if (event.detail && event.detail.tabPrompt &&
!(event.detail.inPermitUnload && ("TabView" in window) && TabView.isVisible()) &&
Services.prefs.getBoolPref("browser.tabs.dontfocusfordialogs")) {
let docPrincipal = targetIsWindow ? event.target.document.nodePrincipal : null;
// At least one of these should/will be non-null:
@ -6224,7 +6215,7 @@
var tabstripBO = tabContainer.mTabstrip.scrollBoxObject;
for (var i = 0; i < this.childNodes.length; i++) {
let curTab = this.childNodes[i].tab;
if (!curTab) // "Tab Groups" menuitem and its menuseparator
if (!curTab) // "Undo close tab", menuseparator, or entries put here by addons.
continue;
let curTabBO = curTab.boxObject;
if (curTabBO.screenX >= tabstripBO.screenX &&

Просмотреть файл

@ -15,12 +15,6 @@ function testAttrib(elem, attrib, attribValue, msg) {
function test() {
waitForExplicitFinish();
// Ensure TabView has been initialized already. Otherwise it could
// activate at an unexpected time and show/hide tabs.
TabView._initFrame(runTest);
}
function runTest() {
is(gBrowser.tabs.length, 1, "one tab is open initially");
// Add several new tabs in sequence, hiding some, to ensure that the

Просмотреть файл

@ -5,12 +5,6 @@
function test() {
waitForExplicitFinish();
// Ensure TabView has been initialized already. Otherwise it could
// activate at an unexpected time and show/hide tabs.
TabView._initFrame(runTest);
}
function runTest() {
// establish initial state
is(gBrowser.tabs.length, 1, "we start with one tab");

Просмотреть файл

@ -7,12 +7,6 @@
function test() {
waitForExplicitFinish();
// Ensure TabView has been initialized already. Otherwise it could
// activate at an unexpected time and show/hide tabs.
TabView._initFrame(runTest);
}
function runTest() {
// Add a tab that will get removed and hidden
let testTab = gBrowser.addTab("about:blank", {skipAnimation: true});
is(gBrowser.visibleTabs.length, 2, "just added a tab, so 2 tabs");

Просмотреть файл

@ -29,18 +29,6 @@ const EXPECTED_REFLOWS = [
"_handleNewTab@chrome://browser/content/tabbrowser.xml|" +
"onxbltransitionend@chrome://browser/content/tabbrowser.xml|",
// The TabView iframe causes reflows in the parent document.
"iQClass_height@chrome://browser/content/tabview.js|" +
"GroupItem_getContentBounds@chrome://browser/content/tabview.js|" +
"GroupItem_shouldStack@chrome://browser/content/tabview.js|" +
"GroupItem_arrange@chrome://browser/content/tabview.js|" +
"GroupItem_add@chrome://browser/content/tabview.js|" +
"GroupItems_newTab@chrome://browser/content/tabview.js|" +
"TabItem__reconnect@chrome://browser/content/tabview.js|" +
"TabItem@chrome://browser/content/tabview.js|" +
"TabItems_link@chrome://browser/content/tabview.js|" +
"TabItems_init/this._eventListeners.open@chrome://browser/content/tabview.js|",
// SessionStore.getWindowDimensions()
"ssi_getWindowDimension@resource:///modules/sessionstore/SessionStore.jsm|" +
"ssi_updateWindowFeatures/<@resource:///modules/sessionstore/SessionStore.jsm|" +

Просмотреть файл

@ -3,10 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
add_task(function* () {
// Ensure TabView has been initialized already. Otherwise it could
// activate at an unexpected time and show/hide tabs.
yield new Promise(resolve => TabView._initFrame(resolve));
// There should be one tab when we start the test
let [origTab] = gBrowser.visibleTabs;
@ -31,13 +27,6 @@ add_task(function* () {
gBrowser.selectedTab = testTab;
gBrowser.showOnlyTheseTabs([testTab]);
// if the tabview frame is initialized, we need to move the orignal tab to
// another group; otherwise, selecting a tab would make all three tabs in
// the same group to display.
let tabViewWindow = TabView.getContentWindow();
if (tabViewWindow)
tabViewWindow.GroupItems.moveTabToGroupItem(origTab, null);
visible = gBrowser.visibleTabs;
is(visible.length, 2, "2 tabs should be visible including the pinned");
is(visible[0], pinned, "first is pinned");
@ -101,8 +90,5 @@ add_task(function* () {
is(gBrowser.tabs.length, 1, "sanity check that it matches");
is(gBrowser.selectedTab, origTab, "got the orig tab");
is(origTab.hidden, false, "and it's not hidden -- visible!");
if (tabViewWindow)
tabViewWindow.GroupItems.groupItems[0].close();
});

Просмотреть файл

@ -5,12 +5,6 @@
function test() {
waitForExplicitFinish();
// Ensure TabView has been initialized already. Otherwise it could
// activate at an unexpected time and show/hide tabs.
TabView._initFrame(runTest);
}
function runTest() {
let tabOne = gBrowser.addTab("about:blank");
let tabTwo = gBrowser.addTab("http://mochi.test:8888/");
gBrowser.selectedTab = tabTwo;

Просмотреть файл

@ -5,12 +5,6 @@
function test() {
waitForExplicitFinish();
// Ensure TabView has been initialized already. Otherwise it could
// activate at an unexpected time and show/hide tabs.
TabView._initFrame(runTest);
}
function runTest() {
// There should be one tab when we start the test
let [origTab] = gBrowser.visibleTabs;
is(gBrowser.visibleTabs.length, 1, "1 tab should be open");

Просмотреть файл

@ -3,10 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
add_task(function* test() {
// Ensure TabView has been initialized already. Otherwise it could
// activate at an unexpected time and show/hide tabs.
yield new Promise(resolve => TabView._initFrame(resolve));
// There should be one tab when we start the test
let [origTab] = gBrowser.visibleTabs;
is(gBrowser.visibleTabs.length, 1, "there is one visible tab");

Просмотреть файл

@ -3,10 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
add_task(function* test() {
// Ensure TabView has been initialized already. Otherwise it could
// activate at an unexpected time and show/hide tabs.
yield new Promise(resolve => TabView._initFrame(resolve));
gPrefService.setBoolPref("browser.ctrlTab.previews", true);
let [origTab] = gBrowser.visibleTabs;

Просмотреть файл

@ -72,6 +72,8 @@ browser.jar:
content/browser/aboutTabCrashed.css (content/aboutTabCrashed.css)
content/browser/aboutTabCrashed.js (content/aboutTabCrashed.js)
content/browser/aboutTabCrashed.xhtml (content/aboutTabCrashed.xhtml)
* content/browser/aboutTabGroupsMigration.xhtml (content/aboutTabGroupsMigration.xhtml)
content/browser/aboutTabGroupsMigration.js (content/aboutTabGroupsMigration.js)
* content/browser/browser.css (content/browser.css)
* content/browser/browser.js (content/browser.js)
* content/browser/browser.xul (content/browser.xul)
@ -93,7 +95,6 @@ browser.jar:
content/browser/browser-social.js (content/browser-social.js)
* content/browser/browser-syncui.js (content/browser-syncui.js)
* content/browser/browser-tabPreviews.xml (content/browser-tabPreviews.xml)
content/browser/browser-tabview.js (content/browser-tabview.js)
content/browser/browser-thumbnails.js (content/browser-thumbnails.js)
content/browser/browser-trackingprotection.js (content/browser-trackingprotection.js)
* content/browser/chatWindow.xul (content/chatWindow.xul)

Просмотреть файл

@ -104,7 +104,6 @@ skip-if = os == "linux" # Intermittent failures
skip-if = e10s # Bug 1088710
[browser_967000_button_feeds.js]
[browser_967000_button_sync.js]
[browser_967000_button_tabView.js]
[browser_968447_bookmarks_toolbar_items_in_panel.js]
skip-if = os == "linux" # Intemittent failures - bug 979207
[browser_968565_insert_before_hidden_items.js]

Просмотреть файл

@ -1,55 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
add_task(function() {
info("Check Tab Groups button functionality");
let deferred = Promise.defer();
let timeout = null;
// add the Tab View button to the panel
CustomizableUI.addWidgetToArea("tabview-button", CustomizableUI.AREA_PANEL);
window.addEventListener("tabviewhidden", function tabViewHidden() {
clearTimeout(timeout);
window.removeEventListener("tabviewhidden", tabViewHidden, false);
ok(true, "Tab View is closed");
deferred.resolve();
}, false);
window.addEventListener("tabviewshown", function tabViewShown() {
window.removeEventListener("tabviewshown", tabViewShown, false);
ok(true, "Tab Groups are loaded");
// close tabs view
window.TabView.hide();
timeout = setTimeout(() => {
window.removeEventListener("tabviewhidden", tabViewHidden, false);
deferred.reject("Tabs view wasn't hidden within 20000ms");
}, 20000);
}, false);
// check the button's functionality
yield PanelUI.show();
let tabViewButton = document.getElementById("tabview-button");
ok(tabViewButton, "Tab Groups button was added to the Panel Menu");
tabViewButton.click();
yield deferred.promise;
ok(!isPanelUIOpen(), "The panel is closed");
if(isPanelUIOpen()) {
let panelHidePromise = promisePanelHidden(window);
PanelUI.hide();
yield panelHidePromise;
}
});
add_task(function asyncCleanup() {
// reset the panel to the default state
yield resetCustomization();
ok(CustomizableUI.inDefaultState, "UI is in default state again.");
});

Просмотреть файл

@ -21,7 +21,6 @@ DIRS += [
'sessionstore',
'shell',
'selfsupport',
'tabview',
'uitour',
'translation',
]

Просмотреть файл

@ -93,6 +93,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
"resource:///modules/RecentWindow.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "TabGroupsMigrator",
"resource:///modules/TabGroupsMigrator.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
@ -1350,21 +1353,6 @@ BrowserGlue.prototype = {
}
}
if (this._mayNeedToWarnAboutTabGroups) {
let haveTabGroups = false;
let wins = Services.wm.getEnumerator("navigator:browser");
while (wins.hasMoreElements()) {
let win = wins.getNext();
if (win.TabView._tabBrowserHasHiddenTabs() && win.TabView.firstUseExperienced) {
haveTabGroups = true;
break;
}
}
if (haveTabGroups) {
this._showTabGroupsDeprecationNotification();
}
}
#ifdef E10S_TESTING_ONLY
E10SUINotification.checkStatus();
#else
@ -1405,25 +1393,12 @@ BrowserGlue.prototype = {
},
#endif
_showTabGroupsDeprecationNotification() {
let brandShortName = gBrandBundle.GetStringFromName("brandShortName");
let text = gBrowserBundle.formatStringFromName("tabgroups.deprecationwarning.description",
[brandShortName], 1);
let learnMore = gBrowserBundle.GetStringFromName("tabgroups.deprecationwarning.learnMore.label");
let learnMoreKey = gBrowserBundle.GetStringFromName("tabgroups.deprecationwarning.learnMore.accesskey");
let win = RecentWindow.getMostRecentBrowserWindow();
let notifyBox = win.document.getElementById("high-priority-global-notificationbox");
let button = {
label: learnMore,
accessKey: learnMoreKey,
callback: function(aNotificationBar, aButton) {
win.openUILinkIn("https://support.mozilla.org/kb/tab-groups-removal", "tab");
},
_maybeMigrateTabGroups() {
let migrationObserver = (stateAsSupportsString, topic) => {
Services.obs.removeObserver(migrationObserver, "sessionstore-state-read");
TabGroupsMigrator.migrate(stateAsSupportsString);
};
notifyBox.appendNotification(text, "tabgroups-removal-notification", null,
notifyBox.PRIORITY_WARNING_MEDIUM, [button]);
Services.obs.addObserver(migrationObserver, "sessionstore-state-read", false);
},
_onQuitRequest: function BG__onQuitRequest(aCancelQuit, aQuitType) {
@ -1933,7 +1908,7 @@ BrowserGlue.prototype = {
},
_migrateUI: function BG__migrateUI() {
const UI_VERSION = 34;
const UI_VERSION = 35;
const BROWSER_DOCURL = "chrome://browser/content/browser.xul";
let currentUIVersion = 0;
try {
@ -2278,9 +2253,8 @@ BrowserGlue.prototype = {
this._notifyNotificationsUpgrade().catch(Cu.reportError);
}
if (currentUIVersion < 34) {
// We'll do something once windows are open:
this._mayNeedToWarnAboutTabGroups = true;
if (currentUIVersion < 35) {
this._maybeMigrateTabGroups();
}
// Update the migration version.

Просмотреть файл

@ -32,7 +32,6 @@ var SessionMigrationInternal = {
* - with tab group info (hidden + group id)
* - with selected tab info
* - with selected window info
* - with tabgroups info
*
* The complete state is then wrapped into the "about:welcomeback" page as
* form field info to be restored when restoring the state.
@ -53,21 +52,8 @@ var SessionMigrationInternal = {
tab.index = oldTab.index;
tab.hidden = oldTab.hidden;
tab.pinned = oldTab.pinned;
// The tabgroup info is in the extData, so we need to get it out.
if (oldTab.extData && "tabview-tab" in oldTab.extData) {
tab.extData = {"tabview-tab": oldTab.extData["tabview-tab"]};
}
return tab;
});
// There are various tabgroup-related attributes that we need to get out
// of the session restore data for the window, too.
if (oldWin.extData) {
for (let k of Object.keys(oldWin.extData)) {
if (k.startsWith("tabview-")) {
win.extData[k] = oldWin.extData[k];
}
}
}
win.selected = oldWin.selected;
win._closedTabs = [];
return win;

Просмотреть файл

@ -1770,7 +1770,8 @@ var SessionStoreInternal = {
}
// Default delay of 2 seconds gives enough time to catch multiple TabShow
// events due to changing groups in Panorama.
// events. This used to be due to changing groups in 'tab groups'. We
// might be able to get rid of this now?
this.saveStateDelayed(aWindow);
},
@ -1782,7 +1783,8 @@ var SessionStoreInternal = {
}
// Default delay of 2 seconds gives enough time to catch multiple TabHide
// events due to changing groups in Panorama.
// events. This used to be due to changing groups in 'tab groups'. We
// might be able to get rid of this now?
this.saveStateDelayed(aWindow);
},
@ -2290,10 +2292,7 @@ var SessionStoreInternal = {
// Restore into that window - pretend it's a followup since we'll already
// have a focused window.
//XXXzpao This is going to merge extData together (taking what was in
// winState over what is in the window already. The hack we have
// in _preWindowToRestoreInto will prevent most (all?) Panorama
// weirdness but we will still merge other extData.
// Bug 588217 should make this go away by merging the group data.
// winState over what is in the window already.
let options = {overwriteTabs: canOverwriteTabs, isFollowUp: true};
this.restoreWindow(windowToUse, winState, options);
}
@ -2501,25 +2500,10 @@ var SessionStoreInternal = {
// the previous session's tabs to the end. This will be set if possible.
let canOverwriteTabs = false;
// Step 1 of processing:
// Inspect extData for Panorama identifiers. If found, then we want to
// inspect further. If there is a single group, then we can use this
// window. If there are multiple groups then we won't use this window.
let groupsData = this.getWindowValue(aWindow, "tabview-groups");
if (groupsData) {
groupsData = JSON.parse(groupsData);
// If there are multiple groups, we don't want to use this window.
if (groupsData.totalNumber > 1)
return [false, false];
}
// Step 2 of processing:
// If we're still here, then the window is usable. Look at the open tabs in
// comparison to home pages. If all the tabs are home pages then we'll end
// up overwriting all of them. Otherwise we'll just close the tabs that
// match home pages. Tabs with the about:blank URI will always be
// overwritten.
// Look at the open tabs in comparison to home pages. If all the tabs are
// home pages then we'll end up overwriting all of them. Otherwise we'll
// just close the tabs that match home pages. Tabs with the about:blank
// URI will always be overwritten.
let homePages = ["about:blank"];
let removableTabs = [];
let tabbrowser = aWindow.gBrowser;

Просмотреть файл

@ -70,7 +70,7 @@ function initTreeView() {
gTreeData = [];
gStateObject.windows.forEach(function(aWinData, aIx) {
var winState = {
label: winLabel.replace("%S", (aIx + 1)),
label: aWinData.tabGroupsMigrationTitle || winLabel.replace("%S", (aIx + 1)),
open: true,
checked: true,
ix: aIx

Просмотреть файл

@ -13,13 +13,6 @@ function observeOneRestore(callback) {
function test() {
waitForExplicitFinish();
// Disable Panorama, since it conflicts with this test.
let tabview = document.getElementById("tab-view");
if (tabview) {
document.getElementById("tab-view").contentWindow.UI.uninit();
TabView.uninit();
}
// There should be one tab when we start the test
let [origTab] = gBrowser.visibleTabs;
let hiddenTab = gBrowser.addTab();
@ -53,11 +46,6 @@ function test() {
gBrowser.removeTab(hiddenTab);
gBrowser.removeTab(extraTab);
// Re-enable Panorama.
if (tabview) {
TabView.init();
}
finish();
});
ss.setBrowserState(JSON.stringify(stateObj));

Просмотреть файл

@ -6,10 +6,6 @@ add_task(function* () {
/** Bug 607016 - If a tab is never restored, attributes (eg. hidden) aren't updated correctly **/
ignoreAllUncaughtExceptions();
// Ensure TabView has been initialized already. Otherwise it could
// activate at an unexpected time and show/hide tabs.
yield new Promise(resolve => TabView._initFrame(resolve));
// Set the pref to true so we know exactly how many tabs should be restoring at
// any given time. This guarantees that a finishing load won't start another.
Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", true);

Просмотреть файл

@ -7,12 +7,7 @@
function test() {
waitForExplicitFinish();
// Ensure TabView has been initialized already. Otherwise it could
// activate at an unexpected time and show/hide tabs.
TabView._initFrame(runTest);
}
function runTest() {
// We speed up the interval between session saves to ensure that the test
// runs quickly.
Services.prefs.setIntPref("browser.sessionstore.interval", 2000);

Просмотреть файл

@ -1,92 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var Cu = Components.utils;
var Ci = Components.interfaces;
Cu.import("resource:///modules/tabview/utils.jsm");
// Bug 671101 - directly using webProgress in this context
// causes docShells to leak
this.__defineGetter__("webProgress", function () {
let ifaceReq = docShell.QueryInterface(Ci.nsIInterfaceRequestor);
return ifaceReq.getInterface(Ci.nsIWebProgress);
});
// ----------
// WindowEventHandler
//
// Handles events dispatched by the content window.
var WindowEventHandler = {
// ----------
// Function: onDOMWillOpenModalDialog
// Sends a synchronous message when the "onDOMWillOpenModalDialog" event
// is fired right before a modal dialog will be opened by the current page.
onDOMWillOpenModalDialog: function WEH_onDOMWillOpenModalDialog(event) {
// (event.isTrusted == true) when the event is generated by a user action
// and does not originate from a script.
if (!event.isTrusted)
return;
// we're intentionally sending a synchronous message to handle this event
// as quick as possible, switch the selected tab and hide the tabview
// before the modal dialog is shown
sendSyncMessage("Panorama:DOMWillOpenModalDialog");
},
// ----------
// Function: onMozAfterPaint
// Sends an asynchronous message when the "onMozAfterPaint" event
// is fired.
onMozAfterPaint: function WEH_onMozAfterPaint(event) {
if (event.clientRects.length > 0) {
sendAsyncMessage("Panorama:MozAfterPaint");
}
}
};
// add event listeners
addEventListener("DOMWillOpenModalDialog", WindowEventHandler.onDOMWillOpenModalDialog, false);
addEventListener("MozAfterPaint", WindowEventHandler.onMozAfterPaint, false);
// ----------
// WindowMessageHandler
//
// Handles messages sent by the chrome process.
var WindowMessageHandler = {
// ----------
// Function: isDocumentLoaded
// Checks if the currently active document is loaded.
isDocumentLoaded: function WMH_isDocumentLoaded(cx) {
let isLoaded = (content &&
content.document.readyState != "uninitialized" &&
!webProgress.isLoadingDocument);
sendAsyncMessage(cx.name, {isLoaded: isLoaded});
},
// ----------
// Function: isImageDocument
// Checks if the currently active document is an image document or not.
isImageDocument: function WMH_isImageDocument(cx) {
let isImageDocument = (content &&
content.document instanceof Ci.nsIImageDocument);
sendAsyncMessage(cx.name, {isImageDocument: isImageDocument});
},
waitForDocumentLoad: function WMH_waitForDocumentLoad() {
addEventListener("load", function listener() {
removeEventListener("load", listener, true);
sendAsyncMessage("Panorama:documentLoaded");
}, true);
},
};
// add message listeners
addMessageListener("Panorama:isDocumentLoaded", WindowMessageHandler.isDocumentLoaded);
addMessageListener("Panorama:isImageDocument", WindowMessageHandler.isImageDocument);
addMessageListener("Panorama:waitForDocumentLoad", WindowMessageHandler.waitForDocumentLoad);

Просмотреть файл

@ -1,269 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// **********
// Title: drag.js
// ----------
// Variable: drag
// The Drag that's currently in process.
var drag = {
info: null,
zIndex: 100,
lastMoveTime: 0
};
//----------
//Variable: resize
//The resize (actually a Drag) that is currently in process
var resize = {
info: null,
lastMoveTime: 0
};
// ##########
// Class: Drag (formerly DragInfo)
// Helper class for dragging <Item>s
//
// ----------
// Constructor: Drag
// Called to create a Drag in response to an <Item> draggable "start" event.
// Note that it is also used partially during <Item>'s resizable method as well.
//
// Parameters:
// item - The <Item> being dragged
// event - The DOM event that kicks off the drag
function Drag(item, event) {
Utils.assert(item && (item.isAnItem || item.isAFauxItem),
'must be an item, or at least a faux item');
this.item = item;
this.el = item.container;
this.$el = iQ(this.el);
this.parent = this.item.parent;
this.startPosition = new Point(event.clientX, event.clientY);
this.startTime = Date.now();
this.item.isDragging = true;
this.item.setZ(999999);
this.safeWindowBounds = Items.getSafeWindowBounds();
Trenches.activateOthersTrenches(this.el);
};
Drag.prototype = {
// ----------
// Function: toString
// Prints [Drag (item)] for debug use
toString: function Drag_toString() {
return "[Drag (" + this.item + ")]";
},
// ----------
// Function: snapBounds
// Adjusts the given bounds according to the currently active trenches. Used by <Drag.snap>
//
// Parameters:
// bounds - (<Rect>) bounds
// stationaryCorner - which corner is stationary? by default, the top left in LTR mode,
// and top right in RTL mode.
// "topleft", "bottomleft", "topright", "bottomright"
// assumeConstantSize - (boolean) whether the bounds' dimensions are sacred or not.
// keepProportional - (boolean) if assumeConstantSize is false, whether we should resize
// proportionally or not
// checkItemStatus - (boolean) make sure this is a valid item which should be snapped
snapBounds: function Drag_snapBounds(bounds, stationaryCorner, assumeConstantSize, keepProportional, checkItemStatus) {
if (!stationaryCorner)
stationaryCorner = UI.rtl ? 'topright' : 'topleft';
var update = false; // need to update
var updateX = false;
var updateY = false;
var newRect;
var snappedTrenches = {};
// OH SNAP!
// 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 &&
this.item.overlapsWithOtherItems()) &&
!iQ(".acceptsDrop").length;
if (!checkItemStatus || snappable) {
newRect = Trenches.snap(bounds, stationaryCorner, assumeConstantSize,
keepProportional);
if (newRect) { // might be false if no changes were made
update = true;
snappedTrenches = newRect.snappedTrenches || {};
bounds = newRect;
}
}
}
// make sure the bounds are in the window.
newRect = this.snapToEdge(bounds, stationaryCorner, assumeConstantSize,
keepProportional);
if (newRect) {
update = true;
bounds = newRect;
Utils.extend(snappedTrenches, newRect.snappedTrenches);
}
Trenches.hideGuides();
for (var edge in snappedTrenches) {
var trench = snappedTrenches[edge];
if (typeof trench == 'object') {
trench.showGuide = true;
trench.show();
}
}
return update ? bounds : false;
},
// ----------
// Function: snap
// Called when a drag or mousemove occurs. Set the bounds based on the mouse move first, then
// call snap and it will adjust the item's bounds if appropriate. Also triggers the display of
// trenches that it snapped to.
//
// Parameters:
// stationaryCorner - which corner is stationary? by default, the top left in LTR mode,
// and top right in RTL mode.
// "topleft", "bottomleft", "topright", "bottomright"
// assumeConstantSize - (boolean) whether the bounds' dimensions are sacred or not.
// keepProportional - (boolean) if assumeConstantSize is false, whether we should resize
// proportionally or not
snap: function Drag_snap(stationaryCorner, assumeConstantSize, keepProportional) {
var bounds = this.item.getBounds();
bounds = this.snapBounds(bounds, stationaryCorner, assumeConstantSize, keepProportional, true);
if (bounds) {
this.item.setBounds(bounds, true);
return true;
}
return false;
},
// --------
// Function: snapToEdge
// Returns a version of the bounds snapped to the edge if it is close enough. If not,
// returns false. If <Keys.meta> is true, this function will simply enforce the
// window edges.
//
// Parameters:
// rect - (<Rect>) current bounds of the object
// stationaryCorner - which corner is stationary? by default, the top left in LTR mode,
// and top right in RTL mode.
// "topleft", "bottomleft", "topright", "bottomright"
// assumeConstantSize - (boolean) whether the rect's dimensions are sacred or not
// keepProportional - (boolean) if we are allowed to change the rect's size, whether the
// dimensions should scaled proportionally or not.
snapToEdge: function Drag_snapToEdge(rect, stationaryCorner, assumeConstantSize, keepProportional) {
var swb = this.safeWindowBounds;
var update = false;
var updateX = false;
var updateY = false;
var snappedTrenches = {};
var snapRadius = (Keys.meta ? 0 : Trenches.defaultRadius);
if (rect.left < swb.left + snapRadius ) {
if (stationaryCorner.indexOf('right') > -1 && !assumeConstantSize)
rect.width = rect.right - swb.left;
rect.left = swb.left;
update = true;
updateX = true;
snappedTrenches.left = 'edge';
}
if (rect.right > swb.right - snapRadius) {
if (updateX || !assumeConstantSize) {
var newWidth = swb.right - rect.left;
if (keepProportional)
rect.height = rect.height * newWidth / rect.width;
rect.width = newWidth;
update = true;
} else if (!updateX || !Trenches.preferLeft) {
rect.left = swb.right - rect.width;
update = true;
}
snappedTrenches.right = 'edge';
delete snappedTrenches.left;
}
if (rect.top < swb.top + snapRadius) {
if (stationaryCorner.indexOf('bottom') > -1 && !assumeConstantSize)
rect.height = rect.bottom - swb.top;
rect.top = swb.top;
update = true;
updateY = true;
snappedTrenches.top = 'edge';
}
if (rect.bottom > swb.bottom - snapRadius) {
if (updateY || !assumeConstantSize) {
var newHeight = swb.bottom - rect.top;
if (keepProportional)
rect.width = rect.width * newHeight / rect.height;
rect.height = newHeight;
update = true;
} else if (!updateY || !Trenches.preferTop) {
rect.top = swb.bottom - rect.height;
update = true;
}
snappedTrenches.top = 'edge';
delete snappedTrenches.bottom;
}
if (update) {
rect.snappedTrenches = snappedTrenches;
return rect;
}
return false;
},
// ----------
// Function: drag
// Called in response to an <Item> draggable "drag" event.
drag: function Drag_drag(event) {
this.snap(UI.rtl ? 'topright' : 'topleft', true);
if (this.parent && this.parent.expanded) {
var distance = this.startPosition.distance(new Point(event.clientX, event.clientY));
if (distance > 100) {
this.parent.remove(this.item);
this.parent.collapse();
}
}
},
// ----------
// Function: stop
// Called in response to an <Item> draggable "stop" event.
//
// Parameters:
// immediately - bool for doing the pushAway immediately, without animation
stop: function Drag_stop(immediately) {
Trenches.hideGuides();
this.item.isDragging = false;
if (this.parent && this.parent != this.item.parent)
this.parent.closeIfEmpty();
if (this.parent && this.parent.expanded)
this.parent.arrange();
if (this.item.parent)
this.item.parent.arrange();
if (this.item.isAGroupItem) {
this.item.setZ(drag.zIndex);
drag.zIndex++;
this.item.pushAway(immediately);
}
Trenches.disactivate();
}
};

Просмотреть файл

@ -1,146 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
Components.utils.import('resource://gre/modules/PlacesUtils.jsm');
var FavIcons = {
// Pref that controls whether to display site icons.
PREF_CHROME_SITE_ICONS: "browser.chrome.site_icons",
// Pref that controls whether to display fav icons.
PREF_CHROME_FAVICONS: "browser.chrome.favicons",
// Lazy getter for pref browser.chrome.site_icons.
get _prefSiteIcons() {
delete this._prefSiteIcons;
this._prefSiteIcons = Services.prefs.getBoolPref(this.PREF_CHROME_SITE_ICONS);
},
// Lazy getter for pref browser.chrome.favicons.
get _prefFavicons() {
delete this._prefFavicons;
this._prefFavicons = Services.prefs.getBoolPref(this.PREF_CHROME_FAVICONS);
},
get defaultFavicon() {
return this._favIconService.defaultFavicon.spec;
},
init: function FavIcons_init() {
XPCOMUtils.defineLazyServiceGetter(this, "_favIconService",
"@mozilla.org/browser/favicon-service;1", "nsIFaviconService");
Services.prefs.addObserver(this.PREF_CHROME_SITE_ICONS, this, false);
Services.prefs.addObserver(this.PREF_CHROME_FAVICONS, this, false);
},
uninit: function FavIcons_uninit() {
Services.prefs.removeObserver(this.PREF_CHROME_SITE_ICONS, this);
Services.prefs.removeObserver(this.PREF_CHROME_FAVICONS, this);
},
observe: function FavIcons_observe(subject, topic, data) {
let value = Services.prefs.getBoolPref(data);
if (data == this.PREF_CHROME_SITE_ICONS)
this._prefSiteIcons = value;
else if (data == this.PREF_CHROME_FAVICONS)
this._prefFavicons = value;
},
// ----------
// Function: getFavIconUrlForTab
// Gets the "favicon link URI" for the given xul:tab, or null if unavailable.
getFavIconUrlForTab: function FavIcons_getFavIconUrlForTab(tab, callback) {
this._isImageDocument(tab, function (isImageDoc) {
if (isImageDoc) {
callback(tab.pinned ? tab.image : null);
} else {
this._getFavIconForNonImageDocument(tab, callback);
}
}.bind(this));
},
// ----------
// Function: _getFavIconForNonImageDocument
// Retrieves the favicon for a tab containing a non-image document.
_getFavIconForNonImageDocument:
function FavIcons_getFavIconForNonImageDocument(tab, callback) {
if (tab.image)
this._getFavIconFromTabImage(tab, callback);
else if (this._shouldLoadFavIcon(tab))
this._getFavIconForHttpDocument(tab, callback);
else
callback(null);
},
// ----------
// Function: _getFavIconFromTabImage
// Retrieves the favicon for tab with a tab image.
_getFavIconFromTabImage:
function FavIcons_getFavIconFromTabImage(tab, callback) {
let tabImage = gBrowser.getIcon(tab);
// If the tab image's url starts with http(s), fetch icon from favicon
// service via the moz-anno protocol.
if (/^https?:/.test(tabImage)) {
let tabImageURI = gWindow.makeURI(tabImage);
tabImage = this._favIconService.getFaviconLinkForIcon(tabImageURI).spec;
}
callback(tabImage);
},
// ----------
// Function: _getFavIconForHttpDocument
// Retrieves the favicon for tab containg a http(s) document.
_getFavIconForHttpDocument:
function FavIcons_getFavIconForHttpDocument(tab, callback) {
let {currentURI} = tab.linkedBrowser;
this._favIconService.getFaviconURLForPage(currentURI, function (uri) {
if (uri) {
let icon = this._favIconService.getFaviconLinkForIcon(uri).spec;
callback(icon);
} else {
callback(this.defaultFavicon);
}
}.bind(this));
},
// ----------
// Function: _isImageDocument
// Checks whether an image is loaded into the given tab.
_isImageDocument: function UI__isImageDocument(tab, callback) {
let mm = tab.linkedBrowser.messageManager;
let message = "Panorama:isImageDocument";
mm.addMessageListener(message, function onMessage(cx) {
mm.removeMessageListener(cx.name, onMessage);
callback(cx.json.isImageDocument);
});
mm.sendAsyncMessage(message);
},
// ----------
// Function: _shouldLoadFavIcon
// Checks whether fav icon should be loaded for a given tab.
_shouldLoadFavIcon: function FavIcons_shouldLoadFavIcon(tab) {
// No need to load a favicon if the user doesn't want site or favicons.
if (!this._prefSiteIcons || !this._prefFavicons)
return false;
let uri = tab.linkedBrowser.currentURI;
// Stop here if we don't have a valid nsIURI.
if (!uri || !(uri instanceof Ci.nsIURI))
return false;
// Load favicons for http(s) pages only.
return uri.schemeIs("http") || uri.schemeIs("https");
}
};

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,765 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// **********
// Title: iq.js
// Various helper functions, in the vein of jQuery.
// ----------
// Function: iQ
// Returns an iQClass object which represents an individual element or a group
// of elements. It works pretty much like jQuery(), with a few exceptions,
// most notably that you can't use strings with complex html,
// just simple tags like '<div>'.
function iQ(selector, context) {
// The iQ object is actually just the init constructor 'enhanced'
return new iQClass(selector, context);
};
// A simple way to check for HTML strings or ID strings
// (both of which we optimize for)
var quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/;
// Match a standalone tag
var rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/;
// ##########
// Class: iQClass
// The actual class of iQ result objects, representing an individual element
// or a group of elements.
//
// ----------
// Function: iQClass
// You don't call this directly; this is what's called by iQ().
function iQClass(selector, context) {
// Handle $(""), $(null), or $(undefined)
if (!selector) {
return this;
}
// Handle $(DOMElement)
if (selector.nodeType) {
this.context = selector;
this[0] = selector;
this.length = 1;
return this;
}
// The body element only exists once, optimize finding it
if (selector === "body" && !context) {
this.context = document;
this[0] = document.body;
this.selector = "body";
this.length = 1;
return this;
}
// Handle HTML strings
if (typeof selector === "string") {
// Are we dealing with HTML string or an ID?
let match = quickExpr.exec(selector);
// Verify a match, and that no context was specified for #id
if (match && (match[1] || !context)) {
// HANDLE $(html) -> $(array)
if (match[1]) {
let doc = (context ? context.ownerDocument || context : document);
// If a single string is passed in and it's a single tag
// just do a createElement and skip the rest
let ret = rsingleTag.exec(selector);
if (ret) {
if (Utils.isPlainObject(context)) {
Utils.assert(false, 'does not support HTML creation with context');
} else {
selector = [doc.createElement(ret[1])];
}
} else {
Utils.assert(false, 'does not support complex HTML creation');
}
return Utils.merge(this, selector);
// HANDLE $("#id")
} else {
let elem = document.getElementById(match[2]);
if (elem) {
this.length = 1;
this[0] = elem;
}
this.context = document;
this.selector = selector;
return this;
}
// HANDLE $("TAG")
} else if (!context && /^\w+$/.test(selector)) {
this.selector = selector;
this.context = document;
selector = document.getElementsByTagName(selector);
return Utils.merge(this, selector);
// HANDLE $(expr, $(...))
} else if (!context || context.iq) {
return (context || iQ(document)).find(selector);
// HANDLE $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
return iQ(context).find(selector);
}
// HANDLE $(function)
// Shortcut for document ready
} else if (typeof selector == "function") {
Utils.log('iQ does not support ready functions');
return null;
}
if ("selector" in selector) {
this.selector = selector.selector;
this.context = selector.context;
}
let ret = this || [];
if (selector != null) {
// The window, strings (and functions) also have 'length'
if (selector.length == null || typeof selector == "string" || selector.setInterval) {
Array.push(ret, selector);
} else {
Utils.merge(ret, selector);
}
}
return ret;
};
iQClass.prototype = {
// ----------
// Function: toString
// Prints [iQ...] for debug use
toString: function iQClass_toString() {
if (this.length > 1) {
if (this.selector)
return "[iQ (" + this.selector + ")]";
else
return "[iQ multi-object]";
}
if (this.length == 1)
return "[iQ (" + this[0].toString() + ")]";
return "[iQ non-object]";
},
// Start with an empty selector
selector: "",
// The default length of a iQ object is 0
length: 0,
// ----------
// Function: each
// Execute a callback for every element in the matched set.
each: function iQClass_each(callback) {
if (typeof callback != "function") {
Utils.assert(false, "each's argument must be a function");
return null;
}
for (let i = 0; this[i] != null && callback(this[i]) !== false; i++) {}
return this;
},
// ----------
// Function: addClass
// Adds the given class(es) to the receiver.
addClass: function iQClass_addClass(value) {
Utils.assertThrow(typeof value == "string" && value,
'requires a valid string argument');
let length = this.length;
for (let i = 0; i < length; i++) {
let elem = this[i];
if (elem.nodeType === 1) {
value.split(/\s+/).forEach(function(className) {
elem.classList.add(className);
});
}
}
return this;
},
// ----------
// Function: removeClass
// Removes the given class(es) from the receiver.
removeClass: function iQClass_removeClass(value) {
if (typeof value != "string" || !value) {
Utils.assert(false, 'does not support function argument');
return null;
}
let length = this.length;
for (let i = 0; i < length; i++) {
let elem = this[i];
if (elem.nodeType === 1 && elem.className) {
value.split(/\s+/).forEach(function(className) {
elem.classList.remove(className);
});
}
}
return this;
},
// ----------
// Function: hasClass
// Returns true is the receiver has the given css class.
hasClass: function iQClass_hasClass(singleClassName) {
let length = this.length;
for (let i = 0; i < length; i++) {
if (this[i].classList.contains(singleClassName)) {
return true;
}
}
return false;
},
// ----------
// Function: find
// Searches the receiver and its children, returning a new iQ object with
// elements that match the given selector.
find: function iQClass_find(selector) {
let ret = [];
let length = 0;
let l = this.length;
for (let i = 0; i < l; i++) {
length = ret.length;
try {
Utils.merge(ret, this[i].querySelectorAll(selector));
} catch(e) {
Utils.log('iQ.find error (bad selector)', e);
}
if (i > 0) {
// Make sure that the results are unique
for (let n = length; n < ret.length; n++) {
for (let r = 0; r < length; r++) {
if (ret[r] === ret[n]) {
ret.splice(n--, 1);
break;
}
}
}
}
}
return iQ(ret);
},
// ----------
// Function: contains
// Check to see if a given DOM node descends from the receiver.
contains: function iQClass_contains(selector) {
Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)');
// fast path when querySelector() can be used
if ('string' == typeof selector)
return null != this[0].querySelector(selector);
let object = iQ(selector);
Utils.assert(object.length <= 1, 'does not yet support multi-objects');
let elem = object[0];
if (!elem || !elem.parentNode)
return false;
do {
elem = elem.parentNode;
} while (elem && this[0] != elem);
return this[0] == elem;
},
// ----------
// Function: remove
// Removes the receiver from the DOM.
remove: function iQClass_remove(options) {
if (!options || !options.preserveEventHandlers)
this.unbindAll();
for (let i = 0; this[i] != null; i++) {
let elem = this[i];
if (elem.parentNode) {
elem.parentNode.removeChild(elem);
}
}
return this;
},
// ----------
// Function: empty
// Removes all of the reciever's children and HTML content from the DOM.
empty: function iQClass_empty() {
for (let i = 0; this[i] != null; i++) {
let elem = this[i];
while (elem.firstChild) {
iQ(elem.firstChild).unbindAll();
elem.removeChild(elem.firstChild);
}
}
return this;
},
// ----------
// Function: width
// Returns the width of the receiver, including padding and border.
width: function iQClass_width() {
return Math.floor(this[0].offsetWidth);
},
// ----------
// Function: height
// Returns the height of the receiver, including padding and border.
height: function iQClass_height() {
return Math.floor(this[0].offsetHeight);
},
// ----------
// Function: position
// Returns an object with the receiver's position in left and top
// properties.
position: function iQClass_position() {
let bounds = this.bounds();
return new Point(bounds.left, bounds.top);
},
// ----------
// Function: bounds
// Returns a <Rect> with the receiver's bounds.
bounds: function iQClass_bounds() {
Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)');
let rect = this[0].getBoundingClientRect();
return new Rect(Math.floor(rect.left), Math.floor(rect.top),
Math.floor(rect.width), Math.floor(rect.height));
},
// ----------
// Function: data
// Pass in both key and value to attach some data to the receiver;
// pass in just key to retrieve it.
data: function iQClass_data(key, value) {
let data = null;
if (value === undefined) {
Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)');
data = this[0].iQData;
if (data)
return data[key];
else
return null;
}
for (let i = 0; this[i] != null; i++) {
let elem = this[i];
data = elem.iQData;
if (!data)
data = elem.iQData = {};
data[key] = value;
}
return this;
},
// ----------
// Function: html
// Given a value, sets the receiver's innerHTML to it; otherwise returns
// what's already there.
html: function iQClass_html(value) {
Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)');
if (value === undefined)
return this[0].innerHTML;
this[0].innerHTML = value;
return this;
},
// ----------
// Function: text
// Given a value, sets the receiver's textContent to it; otherwise returns
// what's already there.
text: function iQClass_text(value) {
Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)');
if (value === undefined) {
return this[0].textContent;
}
return this.empty().append((this[0] && this[0].ownerDocument || document).createTextNode(value));
},
// ----------
// Function: val
// Given a value, sets the receiver's value to it; otherwise returns what's already there.
val: function iQClass_val(value) {
Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)');
if (value === undefined) {
return this[0].value;
}
this[0].value = value;
return this;
},
// ----------
// Function: appendTo
// Appends the receiver to the result of iQ(selector).
appendTo: function iQClass_appendTo(selector) {
Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)');
iQ(selector).append(this);
return this;
},
// ----------
// Function: append
// Appends the result of iQ(selector) to the receiver.
append: function iQClass_append(selector) {
let object = iQ(selector);
Utils.assert(object.length == 1 && this.length == 1,
'does not yet support multi-objects (or null objects)');
this[0].appendChild(object[0]);
return this;
},
// ----------
// Function: attr
// Sets or gets an attribute on the element(s).
attr: function iQClass_attr(key, value) {
Utils.assert(typeof key === 'string', 'string key');
if (value === undefined) {
Utils.assert(this.length == 1, 'retrieval does not support multi-objects (or null objects)');
return this[0].getAttribute(key);
}
for (let i = 0; this[i] != null; i++)
this[i].setAttribute(key, value);
return this;
},
// ----------
// Function: css
// Sets or gets CSS properties on the receiver. When setting certain numerical properties,
// will automatically add "px". A property can be removed by setting it to null.
//
// Possible call patterns:
// a: object, b: undefined - sets with properties from a
// a: string, b: undefined - gets property specified by a
// a: string, b: string/number - sets property specified by a to b
css: function iQClass_css(a, b) {
let properties = null;
if (typeof a === 'string') {
let key = a;
if (b === undefined) {
Utils.assert(this.length == 1, 'retrieval does not support multi-objects (or null objects)');
return window.getComputedStyle(this[0], null).getPropertyValue(key);
}
properties = {};
properties[key] = b;
} else if (a instanceof Rect) {
properties = {
left: a.left,
top: a.top,
width: a.width,
height: a.height
};
} else {
properties = a;
}
let pixels = {
'left': true,
'top': true,
'right': true,
'bottom': true,
'width': true,
'height': true
};
for (let i = 0; this[i] != null; i++) {
let elem = this[i];
for (let key in properties) {
let value = properties[key];
if (pixels[key] && typeof value != 'string')
value += 'px';
if (value == null) {
elem.style.removeProperty(key);
} else if (key.indexOf('-') != -1)
elem.style.setProperty(key, value, '');
else
elem.style[key] = value;
}
}
return this;
},
// ----------
// Function: animate
// Uses CSS transitions to animate the element.
//
// Parameters:
// css - an object map of the CSS properties to change
// options - an object with various properites (see below)
//
// Possible "options" properties:
// duration - how long to animate, in milliseconds
// easing - easing function to use. Possibilities include
// "tabviewBounce", "easeInQuad". Default is "ease".
// complete - function to call once the animation is done, takes nothing
// in, but "this" is set to the element that was animated.
animate: function iQClass_animate(css, options) {
Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)');
if (!options)
options = {};
let easings = {
tabviewBounce: "cubic-bezier(0.0, 0.63, .6, 1.29)",
easeInQuad: 'ease-in', // TODO: make it a real easeInQuad, or decide we don't care
fast: 'cubic-bezier(0.7,0,1,1)'
};
let duration = (options.duration || 400);
let easing = (easings[options.easing] || 'ease');
if (css instanceof Rect) {
css = {
left: css.left,
top: css.top,
width: css.width,
height: css.height
};
}
// The latest versions of Firefox do not animate from a non-explicitly
// set css properties. So for each element to be animated, go through
// and explicitly define 'em.
let rupper = /([A-Z])/g;
this.each(function(elem) {
let cStyle = window.getComputedStyle(elem, null);
for (let prop in css) {
prop = prop.replace(rupper, "-$1").toLowerCase();
iQ(elem).css(prop, cStyle.getPropertyValue(prop));
}
});
this.css({
'transition-property': Object.keys(css).join(", "),
'transition-duration': (duration / 1000) + 's',
'transition-timing-function': easing
});
this.css(css);
let self = this;
setTimeout(function() {
self.css({
'transition-property': 'none',
'transition-duration': '',
'transition-timing-function': ''
});
if (typeof options.complete == "function")
options.complete.apply(self);
}, duration);
return this;
},
// ----------
// Function: fadeOut
// Animates the receiver to full transparency. Calls callback on completion.
fadeOut: function iQClass_fadeOut(callback) {
Utils.assert(typeof callback == "function" || callback === undefined,
'does not yet support duration');
this.animate({
opacity: 0
}, {
duration: 400,
complete: function() {
iQ(this).css({display: 'none'});
if (typeof callback == "function")
callback.apply(this);
}
});
return this;
},
// ----------
// Function: fadeIn
// Animates the receiver to full opacity.
fadeIn: function iQClass_fadeIn() {
this.css({display: ''});
this.animate({
opacity: 1
}, {
duration: 400
});
return this;
},
// ----------
// Function: hide
// Hides the receiver.
hide: function iQClass_hide() {
this.css({display: 'none', opacity: 0});
return this;
},
// ----------
// Function: show
// Shows the receiver.
show: function iQClass_show() {
this.css({display: '', opacity: 1});
return this;
},
// ----------
// Function: bind
// Binds the given function to the given event type. Also wraps the function
// in a try/catch block that does a Utils.log on any errors.
bind: function iQClass_bind(type, func) {
let handler = function(event) {
return func.apply(this, [event]);
};
for (let i = 0; this[i] != null; i++) {
let elem = this[i];
if (!elem.iQEventData)
elem.iQEventData = {};
if (!elem.iQEventData[type])
elem.iQEventData[type] = [];
elem.iQEventData[type].push({
original: func,
modified: handler
});
elem.addEventListener(type, handler, false);
}
return this;
},
// ----------
// Function: one
// Binds the given function to the given event type, but only for one call;
// automatically unbinds after the event fires once.
one: function iQClass_one(type, func) {
Utils.assert(typeof func == "function", 'does not support eventData argument');
let handler = function(e) {
iQ(this).unbind(type, handler);
return func.apply(this, [e]);
};
return this.bind(type, handler);
},
// ----------
// Function: unbind
// Unbinds the given function from the given event type.
unbind: function iQClass_unbind(type, func) {
Utils.assert(typeof func == "function", 'Must provide a function');
for (let i = 0; this[i] != null; i++) {
let elem = this[i];
let handler = func;
if (elem.iQEventData && elem.iQEventData[type]) {
let count = elem.iQEventData[type].length;
for (let a = 0; a < count; a++) {
let pair = elem.iQEventData[type][a];
if (pair.original == func) {
handler = pair.modified;
elem.iQEventData[type].splice(a, 1);
if (!elem.iQEventData[type].length) {
delete elem.iQEventData[type];
if (!Object.keys(elem.iQEventData).length)
delete elem.iQEventData;
}
break;
}
}
}
elem.removeEventListener(type, handler, false);
}
return this;
},
// ----------
// Function: unbindAll
// Unbinds all event handlers.
unbindAll: function iQClass_unbindAll() {
for (let i = 0; this[i] != null; i++) {
let elem = this[i];
for (let j = 0; j < elem.childElementCount; j++)
iQ(elem.children[j]).unbindAll();
if (!elem.iQEventData)
continue;
Object.keys(elem.iQEventData).forEach(function (type) {
while (elem.iQEventData && elem.iQEventData[type])
this.unbind(type, elem.iQEventData[type][0].original);
}, this);
}
return this;
}
};
// ----------
// Create various event aliases
var events = [
'keyup',
'keydown',
'keypress',
'mouseup',
'mousedown',
'mouseover',
'mouseout',
'mousemove',
'click',
'dblclick',
'resize',
'change',
'blur',
'focus'
];
events.forEach(function(event) {
iQClass.prototype[event] = function(func) {
return this.bind(event, func);
};
});

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,9 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
browser.jar:
content/browser/tabview.css
* content/browser/tabview.js
content/browser/tabview.html
content/browser/tabview-content.js (content.js)

Просмотреть файл

@ -1,831 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// **********
// Title: utils.js
this.EXPORTED_SYMBOLS = ["Point", "Rect", "Range", "Subscribable", "Utils", "MRUList"];
// #########
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
// ##########
// Class: Point
// A simple point.
//
// Constructor: Point
// If a is a Point, creates a copy of it. Otherwise, expects a to be x,
// and creates a Point with it along with y. If either a or y are omitted,
// 0 is used in their place.
this.Point = function Point(a, y) {
if (Utils.isPoint(a)) {
this.x = a.x;
this.y = a.y;
} else {
this.x = (Utils.isNumber(a) ? a : 0);
this.y = (Utils.isNumber(y) ? y : 0);
}
};
Point.prototype = {
// ----------
// Function: toString
// Prints [Point (x,y)] for debug use
toString: function Point_toString() {
return "[Point (" + this.x + "," + this.y + ")]";
},
// ----------
// Function: distance
// Returns the distance from this point to the given <Point>.
distance: function Point_distance(point) {
var ax = this.x - point.x;
var ay = this.y - point.y;
return Math.sqrt((ax * ax) + (ay * ay));
}
};
// ##########
// Class: Rect
// A simple rectangle. Note that in addition to the left and width, it also has
// a right property; changing one affects the others appropriately. Same for the
// vertical properties.
//
// Constructor: Rect
// If a is a Rect, creates a copy of it. Otherwise, expects a to be left,
// and creates a Rect with it along with top, width, and height.
this.Rect = function Rect(a, top, width, height) {
// Note: perhaps 'a' should really be called 'rectOrLeft'
if (Utils.isRect(a)) {
this.left = a.left;
this.top = a.top;
this.width = a.width;
this.height = a.height;
} else {
this.left = a;
this.top = top;
this.width = width;
this.height = height;
}
};
Rect.prototype = {
// ----------
// Function: toString
// Prints [Rect (left,top,width,height)] for debug use
toString: function Rect_toString() {
return "[Rect (" + this.left + "," + this.top + "," +
this.width + "," + this.height + ")]";
},
get right() {
return this.left + this.width;
},
set right(value) {
this.width = value - this.left;
},
get bottom() {
return this.top + this.height;
},
set bottom(value) {
this.height = value - this.top;
},
// ----------
// Variable: xRange
// Gives you a new <Range> for the horizontal dimension.
get xRange() {
return new Range(this.left, this.right);
},
// ----------
// Variable: yRange
// Gives you a new <Range> for the vertical dimension.
get yRange() {
return new Range(this.top, this.bottom);
},
// ----------
// Function: intersects
// Returns true if this rectangle intersects the given <Rect>.
intersects: function Rect_intersects(rect) {
return (rect.right > this.left &&
rect.left < this.right &&
rect.bottom > this.top &&
rect.top < this.bottom);
},
// ----------
// Function: intersection
// Returns a new <Rect> with the intersection of this rectangle and the give <Rect>,
// or null if they don't intersect.
intersection: function Rect_intersection(rect) {
var box = new Rect(Math.max(rect.left, this.left), Math.max(rect.top, this.top), 0, 0);
box.right = Math.min(rect.right, this.right);
box.bottom = Math.min(rect.bottom, this.bottom);
if (box.width > 0 && box.height > 0)
return box;
return null;
},
// ----------
// Function: contains
// Returns a boolean denoting if the <Rect> or <Point> is contained inside
// this rectangle.
//
// Parameters
// - A <Rect> or a <Point>
contains: function Rect_contains(a) {
if (Utils.isPoint(a))
return (a.x > this.left &&
a.x < this.right &&
a.y > this.top &&
a.y < this.bottom);
return (a.left >= this.left &&
a.right <= this.right &&
a.top >= this.top &&
a.bottom <= this.bottom);
},
// ----------
// Function: center
// Returns a new <Point> with the center location of this rectangle.
center: function Rect_center() {
return new Point(this.left + (this.width / 2), this.top + (this.height / 2));
},
// ----------
// Function: size
// Returns a new <Point> with the dimensions of this rectangle.
size: function Rect_size() {
return new Point(this.width, this.height);
},
// ----------
// Function: position
// Returns a new <Point> with the top left of this rectangle.
position: function Rect_position() {
return new Point(this.left, this.top);
},
// ----------
// Function: area
// Returns the area of this rectangle.
area: function Rect_area() {
return this.width * this.height;
},
// ----------
// Function: inset
// Makes the rect smaller (if the arguments are positive) as if a margin is added all around
// the initial rect, with the margin widths (symmetric) being specified by the arguments.
//
// Paramaters
// - A <Point> or two arguments: x and y
inset: function Rect_inset(a, b) {
if (Utils.isPoint(a)) {
b = a.y;
a = a.x;
}
this.left += a;
this.width -= a * 2;
this.top += b;
this.height -= b * 2;
},
// ----------
// Function: offset
// Moves (translates) the rect by the given vector.
//
// Paramaters
// - A <Point> or two arguments: x and y
offset: function Rect_offset(a, b) {
if (Utils.isPoint(a)) {
this.left += a.x;
this.top += a.y;
} else {
this.left += a;
this.top += b;
}
},
// ----------
// Function: equals
// Returns true if this rectangle is identical to the given <Rect>.
equals: function Rect_equals(rect) {
return (rect.left == this.left &&
rect.top == this.top &&
rect.width == this.width &&
rect.height == this.height);
},
// ----------
// Function: union
// Returns a new <Rect> with the union of this rectangle and the given <Rect>.
union: function Rect_union(a) {
var newLeft = Math.min(a.left, this.left);
var newTop = Math.min(a.top, this.top);
var newWidth = Math.max(a.right, this.right) - newLeft;
var newHeight = Math.max(a.bottom, this.bottom) - newTop;
var newRect = new Rect(newLeft, newTop, newWidth, newHeight);
return newRect;
},
// ----------
// Function: copy
// Copies the values of the given <Rect> into this rectangle.
copy: function Rect_copy(a) {
this.left = a.left;
this.top = a.top;
this.width = a.width;
this.height = a.height;
}
};
// ##########
// Class: Range
// A physical interval, with a min and max.
//
// Constructor: Range
// Creates a Range with the given min and max
this.Range = function Range(min, max) {
if (Utils.isRange(min) && !max) { // if the one variable given is a range, copy it.
this.min = min.min;
this.max = min.max;
} else {
this.min = min || 0;
this.max = max || 0;
}
};
Range.prototype = {
// ----------
// Function: toString
// Prints [Range (min,max)] for debug use
toString: function Range_toString() {
return "[Range (" + this.min + "," + this.max + ")]";
},
// Variable: extent
// Equivalent to max-min
get extent() {
return (this.max - this.min);
},
set extent(extent) {
this.max = extent - this.min;
},
// ----------
// Function: contains
// Whether the <Range> contains the given <Range> or value or not.
//
// Parameters
// - a number or <Range>
contains: function Range_contains(value) {
if (Utils.isNumber(value))
return value >= this.min && value <= this.max;
if (Utils.isRange(value))
return value.min >= this.min && value.max <= this.max;
return false;
},
// ----------
// Function: overlaps
// Whether the <Range> overlaps with the given <Range> value or not.
//
// Parameters
// - a number or <Range>
overlaps: function Range_overlaps(value) {
if (Utils.isNumber(value))
return this.contains(value);
if (Utils.isRange(value))
return !(value.max < this.min || this.max < value.min);
return false;
},
// ----------
// Function: proportion
// Maps the given value to the range [0,1], so that it returns 0 if the value is <= the min,
// returns 1 if the value >= the max, and returns an interpolated "proportion" in (min, max).
//
// Parameters
// - a number
// - (bool) smooth? If true, a smooth tanh-based function will be used instead of the linear.
proportion: function Range_proportion(value, smooth) {
if (value <= this.min)
return 0;
if (this.max <= value)
return 1;
var proportion = (value - this.min) / this.extent;
if (smooth) {
// The ease function ".5+.5*Math.tanh(4*x-2)" is a pretty
// little graph. It goes from near 0 at x=0 to near 1 at x=1
// smoothly and beautifully.
// http://www.wolframalpha.com/input/?i=.5+%2B+.5+*+tanh%28%284+*+x%29+-+2%29
let tanh = function tanh(x) {
var e = Math.exp(x);
return (e - 1/e) / (e + 1/e);
};
return .5 - .5 * tanh(2 - 4 * proportion);
}
return proportion;
},
// ----------
// Function: scale
// Takes the given value in [0,1] and maps it to the associated value on the Range.
//
// Parameters
// - a number in [0,1]
scale: function Range_scale(value) {
if (value > 1)
value = 1;
if (value < 0)
value = 0;
return this.min + this.extent * value;
}
};
// ##########
// Class: Subscribable
// A mix-in for allowing objects to collect subscribers for custom events.
this.Subscribable = function Subscribable() {
this.subscribers = null;
};
Subscribable.prototype = {
// ----------
// Function: addSubscriber
// The given callback will be called when the Subscribable fires the given event.
addSubscriber: function Subscribable_addSubscriber(eventName, callback) {
try {
Utils.assertThrow(typeof callback == "function", "callback must be a function");
Utils.assertThrow(eventName && typeof eventName == "string",
"eventName must be a non-empty string");
} catch(e) {
Utils.log(e);
return;
}
if (!this.subscribers)
this.subscribers = {};
if (!this.subscribers[eventName])
this.subscribers[eventName] = [];
let subscribers = this.subscribers[eventName];
if (subscribers.indexOf(callback) == -1)
subscribers.push(callback);
},
// ----------
// Function: removeSubscriber
// Removes the subscriber associated with the event for the given callback.
removeSubscriber: function Subscribable_removeSubscriber(eventName, callback) {
try {
Utils.assertThrow(typeof callback == "function", "callback must be a function");
Utils.assertThrow(eventName && typeof eventName == "string",
"eventName must be a non-empty string");
} catch(e) {
Utils.log(e);
return;
}
if (!this.subscribers || !this.subscribers[eventName])
return;
let subscribers = this.subscribers[eventName];
let index = subscribers.indexOf(callback);
if (index > -1)
subscribers.splice(index, 1);
},
// ----------
// Function: _sendToSubscribers
// Internal routine. Used by the Subscribable to fire events.
_sendToSubscribers: function Subscribable__sendToSubscribers(eventName, eventInfo) {
try {
Utils.assertThrow(eventName && typeof eventName == "string",
"eventName must be a non-empty string");
} catch(e) {
Utils.log(e);
return;
}
if (!this.subscribers || !this.subscribers[eventName])
return;
let subsCopy = this.subscribers[eventName].concat();
subsCopy.forEach(function (callback) {
try {
callback(this, eventInfo);
} catch(e) {
Utils.log(e);
}
}, this);
}
};
// ##########
// Class: Utils
// Singelton with common utility functions.
this.Utils = {
// ----------
// Function: toString
// Prints [Utils] for debug use
toString: function Utils_toString() {
return "[Utils]";
},
// ___ Logging
useConsole: true, // as opposed to dump
showTime: false,
// ----------
// Function: log
// Prints the given arguments to the JavaScript error console as a message.
// Pass as many arguments as you want, it'll print them all.
log: function Utils_log() {
var text = this.expandArgumentsForLog(arguments);
var prefix = this.showTime ? Date.now() + ': ' : '';
if (this.useConsole)
Services.console.logStringMessage(prefix + text);
else
dump(prefix + text + '\n');
},
// ----------
// Function: error
// Prints the given arguments to the JavaScript error console as an error.
// Pass as many arguments as you want, it'll print them all.
error: function Utils_error() {
var text = this.expandArgumentsForLog(arguments);
var prefix = this.showTime ? Date.now() + ': ' : '';
if (this.useConsole)
Cu.reportError(prefix + "tabview error: " + text);
else
dump(prefix + "TABVIEW ERROR: " + text + '\n');
},
// ----------
// Function: trace
// Prints the given arguments to the JavaScript error console as a message,
// along with a full stack trace.
// Pass as many arguments as you want, it'll print them all.
trace: function Utils_trace() {
var text = this.expandArgumentsForLog(arguments);
// cut off the first line of the stack trace, because that's just this function.
let stack = Error().stack.split("\n").slice(1);
// if the caller was assert, cut out the line for the assert function as well.
if (stack[0].indexOf("Utils_assert(") == 0)
stack.splice(0, 1);
this.log('trace: ' + text + '\n' + stack.join("\n"));
},
// ----------
// Function: assert
// Prints a stack trace along with label (as a console message) if condition is false.
assert: function Utils_assert(condition, label) {
if (!condition) {
let text;
if (typeof label != 'string')
text = 'badly formed assert';
else
text = "tabview assert: " + label;
this.trace(text);
}
},
// ----------
// Function: assertThrow
// Throws label as an exception if condition is false.
assertThrow: function Utils_assertThrow(condition, label) {
if (!condition) {
let text;
if (typeof label != 'string')
text = 'badly formed assert';
else
text = "tabview assert: " + label;
// cut off the first line of the stack trace, because that's just this function.
let stack = Error().stack.split("\n").slice(1);
throw text + "\n" + stack.join("\n");
}
},
// ----------
// Function: expandObject
// Prints the given object to a string, including all of its properties.
expandObject: function Utils_expandObject(obj) {
var s = obj + ' = {';
for (let prop in obj) {
let value;
try {
value = obj[prop];
} catch(e) {
value = '[!!error retrieving property]';
}
s += prop + ': ';
if (typeof value == 'string')
s += '\'' + value + '\'';
else if (typeof value == 'function')
s += 'function';
else
s += value;
s += ', ';
}
return s + '}';
},
// ----------
// Function: expandArgumentsForLog
// Expands all of the given args (an array) into a single string.
expandArgumentsForLog: function Utils_expandArgumentsForLog(args) {
var that = this;
return Array.map(args, function(arg) {
return typeof arg == 'object' ? that.expandObject(arg) : arg;
}).join('; ');
},
// ___ Misc
// ----------
// Function: isLeftClick
// Given a DOM mouse event, returns true if it was for the left mouse button.
isLeftClick: function Utils_isLeftClick(event) {
return event.button == 0;
},
// ----------
// Function: isMiddleClick
// Given a DOM mouse event, returns true if it was for the middle mouse button.
isMiddleClick: function Utils_isMiddleClick(event) {
return event.button == 1;
},
// ----------
// Function: isRightClick
// Given a DOM mouse event, returns true if it was for the right mouse button.
isRightClick: function Utils_isRightClick(event) {
return event.button == 2;
},
// ----------
// Function: isDOMElement
// Returns true if the given object is a DOM element.
isDOMElement: function Utils_isDOMElement(object) {
return object instanceof Ci.nsIDOMElement;
},
// ----------
// Function: isValidXULTab
// A xulTab is valid if it has not been closed,
// and it has not been removed from the DOM
// Returns true if the tab is valid.
isValidXULTab: function Utils_isValidXULTab(xulTab) {
return !xulTab.closing && xulTab.parentNode;
},
// ----------
// Function: isNumber
// Returns true if the argument is a valid number.
isNumber: function Utils_isNumber(n) {
return typeof n == 'number' && !isNaN(n);
},
// ----------
// Function: isRect
// Returns true if the given object (r) looks like a <Rect>.
isRect: function Utils_isRect(r) {
return (r &&
this.isNumber(r.left) &&
this.isNumber(r.top) &&
this.isNumber(r.width) &&
this.isNumber(r.height));
},
// ----------
// Function: isRange
// Returns true if the given object (r) looks like a <Range>.
isRange: function Utils_isRange(r) {
return (r &&
this.isNumber(r.min) &&
this.isNumber(r.max));
},
// ----------
// Function: isPoint
// Returns true if the given object (p) looks like a <Point>.
isPoint: function Utils_isPoint(p) {
return (p && this.isNumber(p.x) && this.isNumber(p.y));
},
// ----------
// Function: isPlainObject
// Check to see if an object is a plain object (created using "{}" or "new Object").
isPlainObject: function Utils_isPlainObject(obj) {
// Must be an Object.
// Make sure that DOM nodes and window objects don't pass through, as well
if (!obj || Object.prototype.toString.call(obj) !== "[object Object]" ||
obj.nodeType || obj.setInterval) {
return false;
}
// Not own constructor property must be Object
const hasOwnProperty = Object.prototype.hasOwnProperty;
if (obj.constructor &&
!hasOwnProperty.call(obj, "constructor") &&
!hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf")) {
return false;
}
// Own properties are enumerated firstly, so to speed up,
// if last one is own, then all properties are own.
var key;
for (key in obj) {}
return key === undefined || hasOwnProperty.call(obj, key);
},
// ----------
// Function: isEmptyObject
// Returns true if the given object has no members.
isEmptyObject: function Utils_isEmptyObject(obj) {
for (let name in obj)
return false;
return true;
},
// ----------
// Function: copy
// Returns a copy of the argument. Note that this is a shallow copy; if the argument
// has properties that are themselves objects, those properties will be copied by reference.
copy: function Utils_copy(value) {
if (value && typeof value == 'object') {
if (Array.isArray(value))
return this.extend([], value);
return this.extend({}, value);
}
return value;
},
// ----------
// Function: merge
// Merge two array-like objects into the first and return it.
merge: function Utils_merge(first, second) {
Array.forEach(second, el => Array.push(first, el));
return first;
},
// ----------
// Function: extend
// Pass several objects in and it will combine them all into the first object and return it.
extend: function Utils_extend() {
// copy reference to target object
let target = arguments[0] || {};
// Deep copy is not supported
if (typeof target === "boolean") {
this.assert(false, "The first argument of extend cannot be a boolean." +
"Deep copy is not supported.");
return target;
}
// Back when this was in iQ + iQ.fn, so you could extend iQ objects with it.
// This is no longer supported.
let length = arguments.length;
if (length === 1) {
this.assert(false, "Extending the iQ prototype using extend is not supported.");
return target;
}
// Handle case when target is a string or something
if (typeof target != "object" && typeof target != "function") {
target = {};
}
for (let i = 1; i < length; i++) {
// Only deal with non-null/undefined values
let options = arguments[i];
if (options != null) {
// Extend the base object
for (let name in options) {
let copy = options[name];
// Prevent never-ending loop
if (target === copy)
continue;
if (copy !== undefined)
target[name] = copy;
}
}
}
// Return the modified object
return target;
},
// ----------
// Function: attempt
// Tries to execute a number of functions. Returns immediately the return
// value of the first non-failed function without executing successive
// functions, or null.
attempt: function Utils_attempt() {
let args = arguments;
for (let i = 0; i < args.length; i++) {
try {
return args[i]();
} catch (e) {}
}
return null;
}
};
// ##########
// Class: MRUList
// A most recently used list.
//
// Constructor: MRUList
// If a is an array of entries, creates a copy of it.
this.MRUList = function MRUList(a) {
if (Array.isArray(a))
this._list = a.concat();
else
this._list = [];
};
MRUList.prototype = {
// ----------
// Function: toString
// Prints [List (entry1, entry2, ...)] for debug use
toString: function MRUList_toString() {
return "[List (" + this._list.join(", ") + ")]";
},
// ----------
// Function: update
// Updates/inserts the given entry as the most recently used one in the list.
update: function MRUList_update(entry) {
this.remove(entry);
this._list.unshift(entry);
},
// ----------
// Function: remove
// Removes the given entry from the list.
remove: function MRUList_remove(entry) {
let index = this._list.indexOf(entry);
if (index > -1)
this._list.splice(index, 1);
},
// ----------
// Function: peek
// Returns the most recently used entry. If a filter exists, gets the most
// recently used entry which matches the filter.
peek: function MRUList_peek(filter) {
let match = null;
if (filter && typeof filter == "function")
this._list.some(function MRUList_peek_getEntry(entry) {
if (filter(entry)) {
match = entry
return true;
}
return false;
});
else
match = this._list.length > 0 ? this._list[0] : null;
return match;
},
};

Просмотреть файл

@ -1,15 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXTRA_JS_MODULES.tabview = ['modules/utils.jsm']
BROWSER_CHROME_MANIFESTS += [
'test/browser.ini',
]
JAR_MANIFESTS += ['jar.mn']
with Files('**'):
BUG_COMPONENT = ('Firefox', 'Panorama')

Просмотреть файл

@ -1,614 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* ******************************
*
* This file incorporates work from:
* Quicksilver Score (qs_score):
* http://rails-oceania.googlecode.com/svn/lachiecox/qs_score/trunk/qs_score.js
* This incorporated work is covered by the following copyright and
* permission notice:
* Copyright 2008 Lachie Cox
* Licensed under the MIT license.
* http://jquery.org/license
*
* ***************************** */
// **********
// Title: search.js
// Implementation for the search functionality of Firefox Panorama.
// ##########
// Class: TabUtils
//
// A collection of helper functions for dealing with both <TabItem>s and
// <xul:tab>s without having to worry which one is which.
var TabUtils = {
// ----------
// Function: toString
// Prints [TabUtils] for debug use.
toString: function TabUtils_toString() {
return "[TabUtils]";
},
// ---------
// Function: nameOfTab
// Given a <TabItem> or a <xul:tab> returns the tab's name.
nameOf: function TabUtils_nameOf(tab) {
// We can have two types of tabs: A <TabItem> or a <xul:tab>
// because we have to deal with both tabs represented inside
// of active Panoramas as well as for windows in which
// Panorama has yet to be activated. We uses object sniffing to
// determine the type of tab and then returns its name.
return tab.label != undefined ? tab.label : tab.$tabTitle[0].textContent;
},
// ---------
// Function: URLOf
// Given a <TabItem> or a <xul:tab> returns the URL of tab.
URLOf: function TabUtils_URLOf(tab) {
// Convert a <TabItem> to <xul:tab>
if ("tab" in tab)
tab = tab.tab;
return tab.linkedBrowser.currentURI.spec;
},
// ---------
// Function: faviconURLOf
// Given a <TabItem> or a <xul:tab> returns the URL of tab's favicon.
faviconURLOf: function TabUtils_faviconURLOf(tab) {
return tab.image != undefined ? tab.image : tab.$favImage[0].src;
},
// ---------
// Function: focus
// Given a <TabItem> or a <xul:tab>, focuses it and it's window.
focus: function TabUtils_focus(tab) {
// Convert a <TabItem> to a <xul:tab>
if ("tab" in tab)
tab = tab.tab;
tab.ownerDocument.defaultView.gBrowser.selectedTab = tab;
tab.ownerDocument.defaultView.focus();
}
};
// ##########
// Class: TabMatcher
//
// A class that allows you to iterate over matching and not-matching tabs,
// given a case-insensitive search term.
function TabMatcher(term) {
this.term = term;
}
TabMatcher.prototype = {
// ----------
// Function: toString
// Prints [TabMatcher (term)] for debug use.
toString: function TabMatcher_toString() {
return "[TabMatcher (" + this.term + ")]";
},
// ---------
// Function: _filterAndSortForMatches
// Given an array of <TabItem>s and <xul:tab>s returns a new array
// of tabs whose name matched the search term, sorted by lexical
// closeness.
_filterAndSortForMatches: function TabMatcher__filterAndSortForMatches(tabs) {
let self = this;
tabs = tabs.filter(function TabMatcher__filterAndSortForMatches_filter(tab) {
let name = TabUtils.nameOf(tab);
let url = TabUtils.URLOf(tab);
return name.match(new RegExp(self.term, "i")) || url.match(new RegExp(self.term, "i"));
});
tabs.sort(function TabMatcher__filterAndSortForMatches_sort(x, y) {
let yScore = self._scorePatternMatch(self.term, TabUtils.nameOf(y));
let xScore = self._scorePatternMatch(self.term, TabUtils.nameOf(x));
return yScore - xScore;
});
return tabs;
},
// ---------
// Function: _filterForUnmatches
// Given an array of <TabItem>s returns an unsorted array of tabs whose name
// does not match the the search term.
_filterForUnmatches: function TabMatcher__filterForUnmatches(tabs) {
let self = this;
return tabs.filter(function TabMatcher__filterForUnmatches_filter(tab) {
let name = tab.$tabTitle[0].textContent;
let url = TabUtils.URLOf(tab);
return !name.match(new RegExp(self.term, "i")) && !url.match(new RegExp(self.term, "i"));
});
},
// ---------
// Function: _getTabsForOtherWindows
// Returns an array of <TabItem>s and <xul:tabs>s representing tabs
// from all windows but the current window. <TabItem>s will be returned
// for windows in which Panorama has been activated at least once, while
// <xul:tab>s will be returned for windows in which Panorama has never
// been activated.
_getTabsForOtherWindows: function TabMatcher__getTabsForOtherWindows() {
let enumerator = Services.wm.getEnumerator("navigator:browser");
let allTabs = [];
while (enumerator.hasMoreElements()) {
let win = enumerator.getNext();
// This function gets tabs from other windows, not from the current window
if (win != gWindow)
allTabs.push.apply(allTabs, win.gBrowser.tabs);
}
return allTabs;
},
// ----------
// Function: matchedTabsFromOtherWindows
// Returns an array of <TabItem>s and <xul:tab>s that match the search term
// from all windows but the current window. <TabItem>s will be returned for
// windows in which Panorama has been activated at least once, while
// <xul:tab>s will be returned for windows in which Panorama has never
// been activated.
// (new TabMatcher("app")).matchedTabsFromOtherWindows();
matchedTabsFromOtherWindows: function TabMatcher_matchedTabsFromOtherWindows() {
if (this.term.length < 2)
return [];
let tabs = this._getTabsForOtherWindows();
return this._filterAndSortForMatches(tabs);
},
// ----------
// Function: matched
// Returns an array of <TabItem>s which match the current search term.
// If the term is less than 2 characters in length, it returns nothing.
matched: function TabMatcher_matched() {
if (this.term.length < 2)
return [];
let tabs = TabItems.getItems();
return this._filterAndSortForMatches(tabs);
},
// ----------
// Function: unmatched
// Returns all of <TabItem>s that .matched() doesn't return.
unmatched: function TabMatcher_unmatched() {
let tabs = TabItems.getItems();
if (this.term.length < 2)
return tabs;
return this._filterForUnmatches(tabs);
},
// ----------
// Function: doSearch
// Performs the search. Lets you provide three functions.
// The first is on all matched tabs in the window, the second on all unmatched
// tabs in the window, and the third on all matched tabs in other windows.
// The first two functions take two parameters: A <TabItem> and its integer index
// indicating the absolute rank of the <TabItem> in terms of match to
// the search term. The last function also takes two paramaters, but can be
// passed both <TabItem>s and <xul:tab>s and the index is offset by the
// number of matched tabs inside the window.
doSearch: function TabMatcher_doSearch(matchFunc, unmatchFunc, otherFunc) {
let matches = this.matched();
let unmatched = this.unmatched();
let otherMatches = this.matchedTabsFromOtherWindows();
matches.forEach(function(tab, i) {
matchFunc(tab, i);
});
otherMatches.forEach(function(tab,i) {
otherFunc(tab, i+matches.length);
});
unmatched.forEach(function(tab, i) {
unmatchFunc(tab, i);
});
},
// ----------
// Function: _scorePatternMatch
// Given a pattern string, returns a score between 0 and 1 of how well
// that pattern matches the original string. It mimics the heuristics
// of the Mac application launcher Quicksilver.
_scorePatternMatch: function TabMatcher__scorePatternMatch(pattern, matched, offset) {
offset = offset || 0;
pattern = pattern.toLowerCase();
matched = matched.toLowerCase();
if (pattern.length == 0)
return 0.9;
if (pattern.length > matched.length)
return 0.0;
for (let i = pattern.length; i > 0; i--) {
let sub_pattern = pattern.substring(0,i);
let index = matched.indexOf(sub_pattern);
if (index < 0)
continue;
if (index + pattern.length > matched.length + offset)
continue;
let next_string = matched.substring(index+sub_pattern.length);
let next_pattern = null;
if (i >= pattern.length)
next_pattern = '';
else
next_pattern = pattern.substring(i);
let remaining_score = this._scorePatternMatch(next_pattern, next_string, offset + index);
if (remaining_score > 0) {
let score = matched.length-next_string.length;
if (index != 0) {
let c = matched.charCodeAt(index-1);
if (c == 32 || c == 9) {
for (let j = (index - 2); j >= 0; j--) {
c = matched.charCodeAt(j);
score -= ((c == 32 || c == 9) ? 1 : 0.15);
}
} else {
score -= index;
}
}
score += remaining_score * next_string.length;
score /= matched.length;
return score;
}
}
return 0.0;
}
};
// ##########
// Class: TabHandlers
//
// A object that handles all of the event handlers.
var TabHandlers = {
_mouseDownLocation: null,
// ---------
// Function: onMatch
// Adds styles and event listeners to the matched tab items.
onMatch: function TabHandlers_onMatch(tab, index) {
tab.addClass("onTop");
index != 0 ? tab.addClass("notMainMatch") : tab.removeClass("notMainMatch");
// Remove any existing handlers before adding the new ones.
// If we don't do this, then we may add more handlers than
// we remove.
tab.$canvas
.unbind("mousedown", TabHandlers._hideHandler)
.unbind("mouseup", TabHandlers._showHandler);
tab.$canvas
.mousedown(TabHandlers._hideHandler)
.mouseup(TabHandlers._showHandler);
},
// ---------
// Function: onUnmatch
// Removes styles and event listeners from the unmatched tab items.
onUnmatch: function TabHandlers_onUnmatch(tab, index) {
tab.$container.removeClass("onTop");
tab.removeClass("notMainMatch");
tab.$canvas
.unbind("mousedown", TabHandlers._hideHandler)
.unbind("mouseup", TabHandlers._showHandler);
},
// ---------
// Function: onOther
// Removes styles and event listeners from the unmatched tabs.
onOther: function TabHandlers_onOther(tab, index) {
// Unlike the other on* functions, in this function tab can
// either be a <TabItem> or a <xul:tab>. In other functions
// it is always a <TabItem>. Also note that index is offset
// by the number of matches within the window.
let item = iQ("<div/>")
.addClass("inlineMatch")
.click(function TabHandlers_onOther_click(event) {
Search.hide(event);
TabUtils.focus(tab);
});
iQ("<img/>")
.attr("src", TabUtils.faviconURLOf(tab))
.appendTo(item);
iQ("<span/>")
.text(TabUtils.nameOf(tab))
.appendTo(item);
index != 0 ? item.addClass("notMainMatch") : item.removeClass("notMainMatch");
item.appendTo("#results");
iQ("#otherresults").show();
},
// ---------
// Function: _hideHandler
// Performs when mouse down on a canvas of tab item.
_hideHandler: function TabHandlers_hideHandler(event) {
iQ("#search").fadeOut();
iQ("#searchshade").fadeOut();
TabHandlers._mouseDownLocation = {x:event.clientX, y:event.clientY};
},
// ---------
// Function: _showHandler
// Performs when mouse up on a canvas of tab item.
_showHandler: function TabHandlers_showHandler(event) {
// If the user clicks on a tab without moving the mouse then
// they are zooming into the tab and we need to exit search
// mode.
if (TabHandlers._mouseDownLocation.x == event.clientX &&
TabHandlers._mouseDownLocation.y == event.clientY) {
Search.hide();
return;
}
iQ("#searchshade").show();
iQ("#search").show();
iQ("#searchbox")[0].focus();
// Marshal the search.
setTimeout(Search.perform, 0);
}
};
// ##########
// Class: Search
//
// A object that handles the search feature.
var Search = {
_initiatedBy: "",
_blockClick: false,
_currentHandler: null,
// ----------
// Function: toString
// Prints [Search] for debug use.
toString: function Search_toString() {
return "[Search]";
},
// ----------
// Function: init
// Initializes the searchbox to be focused, and everything else to be hidden,
// and to have everything have the appropriate event handlers.
init: function Search_init() {
let self = this;
iQ("#search").hide();
iQ("#searchshade").hide().mousedown(function Search_init_shade_mousedown(event) {
if (event.target.id != "searchbox" && !self._blockClick)
self.hide();
});
iQ("#searchbox").keyup(function Search_init_box_keyup() {
self.perform();
})
.attr("title", tabviewString("button.searchTabs"));
iQ("#searchbutton").mousedown(function Search_init_button_mousedown() {
self._initiatedBy = "buttonclick";
self.ensureShown();
self.switchToInMode();
})
.attr("title", tabviewString("button.searchTabs"));
window.addEventListener("focus", function Search_init_window_focus() {
if (self.isEnabled()) {
self._blockClick = true;
setTimeout(function() {
self._blockClick = false;
}, 0);
}
}, false);
this.switchToBeforeMode();
},
// ----------
// Function: _beforeSearchKeyHandler
// Handles all keydown before the search interface is brought up.
_beforeSearchKeyHandler: function Search__beforeSearchKeyHandler(event) {
// Only match reasonable text-like characters for quick search.
if (event.altKey || event.ctrlKey || event.metaKey)
return;
if ((event.keyCode > 0 && event.keyCode <= event.DOM_VK_DELETE) ||
event.keyCode == event.DOM_VK_CONTEXT_MENU ||
event.keyCode == event.DOM_VK_SLEEP ||
(event.keyCode >= event.DOM_VK_F1 &&
event.keyCode <= event.DOM_VK_SCROLL_LOCK) ||
event.keyCode == event.DOM_VK_META ||
event.keyCode == 91 || // 91 = left windows key
event.keyCode == 92 || // 92 = right windows key
(!event.keyCode && !event.charCode)) {
return;
}
// If we are already in an input field, allow typing as normal.
if (event.target.nodeName == "INPUT")
return;
// / is used to activate the search feature so the key shouldn't be entered
// into the search box.
if (event.keyCode == KeyEvent.DOM_VK_SLASH) {
event.stopPropagation();
event.preventDefault();
}
this.switchToInMode();
this._initiatedBy = "keydown";
this.ensureShown(true);
},
// ----------
// Function: _inSearchKeyHandler
// Handles all keydown while search mode.
_inSearchKeyHandler: function Search__inSearchKeyHandler(event) {
let term = iQ("#searchbox").val();
if ((event.keyCode == event.DOM_VK_ESCAPE) ||
(event.keyCode == event.DOM_VK_BACK_SPACE && term.length <= 1 &&
this._initiatedBy == "keydown")) {
this.hide(event);
return;
}
let matcher = this.createSearchTabMatcher();
let matches = matcher.matched();
let others = matcher.matchedTabsFromOtherWindows();
if (event.keyCode == event.DOM_VK_RETURN &&
(matches.length > 0 || others.length > 0)) {
this.hide(event);
if (matches.length > 0)
matches[0].zoomIn();
else
TabUtils.focus(others[0]);
}
},
// ----------
// Function: switchToBeforeMode
// Make sure the event handlers are appropriate for the before-search mode.
switchToBeforeMode: function Search_switchToBeforeMode() {
let self = this;
if (this._currentHandler)
iQ(window).unbind("keydown", this._currentHandler);
this._currentHandler = function Search_switchToBeforeMode_handler(event) {
self._beforeSearchKeyHandler(event);
}
iQ(window).keydown(this._currentHandler);
},
// ----------
// Function: switchToInMode
// Make sure the event handlers are appropriate for the in-search mode.
switchToInMode: function Search_switchToInMode() {
let self = this;
if (this._currentHandler)
iQ(window).unbind("keydown", this._currentHandler);
this._currentHandler = function Search_switchToInMode_handler(event) {
self._inSearchKeyHandler(event);
}
iQ(window).keydown(this._currentHandler);
},
createSearchTabMatcher: function Search_createSearchTabMatcher() {
return new TabMatcher(iQ("#searchbox").val());
},
// ----------
// Function: isEnabled
// Checks whether search mode is enabled or not.
isEnabled: function Search_isEnabled() {
return iQ("#search").css("display") != "none";
},
// ----------
// Function: hide
// Hides search mode.
hide: function Search_hide(event) {
if (!this.isEnabled())
return;
iQ("#searchbox").val("");
iQ("#searchshade").hide();
iQ("#search").hide();
iQ("#searchbutton").css({ opacity:.8 });
if (AppConstants.platform == "macosx")
UI.setTitlebarColors(true);
this.perform();
this.switchToBeforeMode();
if (event) {
// when hiding the search mode, we need to prevent the keypress handler
// in UI__setTabViewFrameKeyHandlers to handle the key press again. e.g. Esc
// which is already handled by the key down in this class.
if (event.type == "keydown")
UI.ignoreKeypressForSearch = true;
event.preventDefault();
event.stopPropagation();
}
// Return focus to the tab window
UI.blurAll();
gTabViewFrame.contentWindow.focus();
let newEvent = document.createEvent("Events");
newEvent.initEvent("tabviewsearchdisabled", false, false);
dispatchEvent(newEvent);
},
// ----------
// Function: perform
// Performs a search.
perform: function Search_perform() {
let matcher = this.createSearchTabMatcher();
// Remove any previous other-window search results and
// hide the display area.
iQ("#results").empty();
iQ("#otherresults").hide();
iQ("#otherresults>.label").text(tabviewString("search.otherWindowTabs"));
matcher.doSearch(TabHandlers.onMatch, TabHandlers.onUnmatch, TabHandlers.onOther);
},
// ----------
// Function: ensureShown
// Ensures the search feature is displayed. If not, display it.
// Parameters:
// - a boolean indicates whether this is triggered by a keypress or not
ensureShown: function Search_ensureShown(activatedByKeypress) {
let $search = iQ("#search");
let $searchShade = iQ("#searchshade");
let $searchbox = iQ("#searchbox");
iQ("#searchbutton").css({ opacity: 1 });
// NOTE: when this function is called by keydown handler, next keypress
// event or composition events of IME will be fired on the focused editor.
function dispatchTabViewSearchEnabledEvent() {
let newEvent = document.createEvent("Events");
newEvent.initEvent("tabviewsearchenabled", false, false);
dispatchEvent(newEvent);
};
if (!this.isEnabled()) {
$searchShade.show();
$search.show();
if (AppConstants.platform == "macosx")
UI.setTitlebarColors({active: "#717171", inactive: "#EDEDED"});
if (activatedByKeypress) {
// set the focus so key strokes are entered into the textbox.
$searchbox[0].focus();
dispatchTabViewSearchEnabledEvent();
} else {
// marshal the focusing, otherwise it ends up with searchbox[0].focus gets
// called before the search button gets the focus after being pressed.
setTimeout(function setFocusAndDispatchSearchEnabledEvent() {
$searchbox[0].focus();
dispatchTabViewSearchEnabledEvent();
}, 0);
}
}
}
};

Просмотреть файл

@ -1,201 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// **********
// Title: storage.js
// ##########
// Class: Storage
// Singleton for permanent storage of TabView data.
var Storage = {
GROUP_DATA_IDENTIFIER: "tabview-group",
GROUPS_DATA_IDENTIFIER: "tabview-groups",
TAB_DATA_IDENTIFIER: "tabview-tab",
UI_DATA_IDENTIFIER: "tabview-ui",
// ----------
// Function: toString
// Prints [Storage] for debug use
toString: function Storage_toString() {
return "[Storage]";
},
// ----------
// Function: init
// Sets up the object.
init: function Storage_init() {
this._sessionStore =
Cc["@mozilla.org/browser/sessionstore;1"].
getService(Ci.nsISessionStore);
},
// ----------
// Function: uninit
uninit: function Storage_uninit () {
this._sessionStore = null;
},
// ----------
// Function: saveTab
// Saves the data for a single tab.
saveTab: function Storage_saveTab(tab, data) {
Utils.assert(tab, "tab");
this._sessionStore.setTabValue(tab, this.TAB_DATA_IDENTIFIER,
JSON.stringify(data));
},
// ----------
// Function: getTabData
// Load tab data from session store and return it.
getTabData: function Storage_getTabData(tab) {
Utils.assert(tab, "tab");
let existingData = null;
try {
let tabData = this._sessionStore.getTabValue(tab, this.TAB_DATA_IDENTIFIER);
if (tabData != "")
existingData = JSON.parse(tabData);
} catch (e) {
// getTabValue will fail if the property doesn't exist.
Utils.log(e);
}
return existingData;
},
// ----------
// Function: getTabState
// Returns the current state of the given tab.
getTabState: function Storage_getTabState(tab) {
Utils.assert(tab, "tab");
let tabState;
try {
tabState = JSON.parse(this._sessionStore.getTabState(tab));
} catch (e) {}
return tabState;
},
// ----------
// Function: saveGroupItem
// Saves the data for a single groupItem, associated with a specific window.
saveGroupItem: function Storage_saveGroupItem(win, data) {
var id = data.id;
var existingData = this.readGroupItemData(win);
existingData[id] = data;
this._sessionStore.setWindowValue(win, this.GROUP_DATA_IDENTIFIER,
JSON.stringify(existingData));
},
// ----------
// Function: deleteGroupItem
// Deletes the data for a single groupItem from the given window.
deleteGroupItem: function Storage_deleteGroupItem(win, id) {
var existingData = this.readGroupItemData(win);
delete existingData[id];
this._sessionStore.setWindowValue(win, this.GROUP_DATA_IDENTIFIER,
JSON.stringify(existingData));
},
// ----------
// Function: readGroupItemData
// Returns the data for all groupItems associated with the given window.
readGroupItemData: function Storage_readGroupItemData(win) {
var existingData = {};
let data;
try {
data = this._sessionStore.getWindowValue(win, this.GROUP_DATA_IDENTIFIER);
if (data)
existingData = JSON.parse(data);
} catch (e) {
// getWindowValue will fail if the property doesn't exist
Utils.log("Error in readGroupItemData: "+e, data);
}
return existingData;
},
// ----------
// Function: readWindowBusyState
// Returns the current busyState for the given window.
readWindowBusyState: function Storage_readWindowBusyState(win) {
let state;
try {
let data = this._sessionStore.getWindowState(win);
if (data)
state = JSON.parse(data);
} catch (e) {
Utils.log("Error while parsing window state");
}
return (state && state.windows[0].busy);
},
// ----------
// Function: saveGroupItemsData
// Saves the global data for the <GroupItems> singleton for the given window.
saveGroupItemsData: function Storage_saveGroupItemsData(win, data) {
this.saveData(win, this.GROUPS_DATA_IDENTIFIER, data);
},
// ----------
// Function: readGroupItemsData
// Reads the global data for the <GroupItems> singleton for the given window.
readGroupItemsData: function Storage_readGroupItemsData(win) {
return this.readData(win, this.GROUPS_DATA_IDENTIFIER);
},
// ----------
// Function: saveUIData
// Saves the global data for the <UIManager> singleton for the given window.
saveUIData: function Storage_saveUIData(win, data) {
this.saveData(win, this.UI_DATA_IDENTIFIER, data);
},
// ----------
// Function: readUIData
// Reads the global data for the <UIManager> singleton for the given window.
readUIData: function Storage_readUIData(win) {
return this.readData(win, this.UI_DATA_IDENTIFIER);
},
// ----------
// Function: saveVisibilityData
// Saves visibility for the given window.
saveVisibilityData: function Storage_saveVisibilityData(win, data) {
this._sessionStore.setWindowValue(
win, win.TabView.VISIBILITY_IDENTIFIER, data);
},
// ----------
// Function: saveData
// Generic routine for saving data to a window.
saveData: function Storage_saveData(win, id, data) {
try {
this._sessionStore.setWindowValue(win, id, JSON.stringify(data));
} catch (e) {
Utils.log("Error in saveData: "+e);
}
},
// ----------
// Function: readData
// Generic routine for reading data from a window.
readData: function Storage_readData(win, id) {
var existingData = {};
try {
var data = this._sessionStore.getWindowValue(win, id);
if (data)
existingData = JSON.parse(data);
} catch (e) {
Utils.log("Error in readData: "+e);
}
return existingData;
}
};

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,294 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Platform-independent structural styling for
* <strike>Tab Candy</strike> Panorama
----------------------------------*/
html {
overflow: hidden;
/* image-rendering: -moz-crisp-edges; */
}
body {
padding: 0px;
margin: 0 auto;
}
#content {
overflow: -moz-hidden-unscrollable;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -999999;
}
/* Tabs
----------------------------------*/
.tab {
position: absolute;
overflow: visible !important;
}
.tab canvas,
.cached-thumb {
width: 100%;
height: 100%;
position: absolute;
top: 0px;
left: 0px;
}
.tabHidden {
display: none;
}
.thumb {
position: relative;
width: 100%;
height: 100%;
}
.favicon {
position: absolute;
}
/* Apply crisp rendering for favicons at exactly 2dppx resolution */
@media (resolution: 2dppx) {
.favicon > img {
image-rendering: -moz-crisp-edges;
}
}
.close {
position: absolute;
cursor: pointer;
}
.expander {
position: absolute;
}
.tab-title {
position: absolute;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.stacked .tab-title {
display: none;
}
.stack-trayed .tab-title {
display: block !important;
}
/* Tab: Zooming
----------------------------------*/
.front {
z-index: 999999 !important;
image-rendering: -moz-crisp-edges;
}
.front canvas {
border: none !important;
padding: 1px !important;
}
/* Groups
----------------------------------*/
.groupItem {
position: absolute;
}
.appTabTrayContainer {
position: absolute;
}
.title-container {
/* We want the title container to leave out width, position of the .close
button and space between input and .close button. Keep an eye on LTR and
RTL differences in .close. */
width: calc(100% - 16px - 6px - 6px);
}
input.name {
text-overflow: ellipsis;
width: -moz-available;
}
input.name:focus {
text-overflow: clip;
}
/* Other Items
----------------------------------*/
.undo {
position: absolute;
}
/* Trenches
----------------------------------*/
.guideTrench,
.visibleTrench,
.activeVisibleTrench {
position: absolute;
}
.guideTrench {
z-index: -101;
}
.visibleTrench {
z-index: -103;
}
.activeVisibleTrench {
z-index: -102;
}
/* Other
----------------------------------*/
.titlebar {
position: absolute;
}
.title-shield {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 10;
}
.transparentBorder {
border: 1px solid transparent !important;
}
.stackExpander {
position: absolute;
}
.shield {
left: 0;
top: 0;
width: 100%;
height: 100%;
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 {
position: absolute;
}
.iq-resizable-handle {
position: absolute;
z-index: 99999;
display: block;
}
.iq-resizable-disabled .iq-resizable-handle,
.iq-resizable-autohide .iq-resizable-handle {
display: none;
}
/* Search
----------------------------------*/
#searchshade{
position: absolute;
top: 0px;
left: 0px;
z-index: 1000001;
}
#search{
position: absolute;
top: 0px;
left: 0px;
pointer-events: none;
z-index: 1000050;
}
html[dir=rtl] #search {
left: auto;
right: 0;
}
#searchbox{
position: absolute;
right: 20px;
top: 20px;
pointer-events: auto;
}
html[dir=rtl] #searchbox {
right: auto;
left: 20px;
}
#actions{
position: absolute;
top: 0px;
right: -3px;
z-index: 1000000;
}
html[dir=rtl] #actions {
right: auto;
left: -3px;
}
#otherresults{
position: absolute;
opacity: 0;
overflow: hidden;
}
.onTop{
z-index: 1000010 !important;
}
.inlineMatch{
display: inline-block;
pointer-events: auto;
}
.inlineMatch>span{
display: inline-block;
overflow: hidden;
}

Просмотреть файл

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
<head>
<title>&nbsp;</title>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
<link rel="stylesheet" href="tabview.css" type="text/css"/>
<link rel="stylesheet" href="chrome://browser/skin/tabview/tabview.css" type="text/css"/>
</head>
<body transparent="true">
<div id="content">
<div id="bg">
</div>
<div id="actions">
<input id="exit-button" type="button" alt="" groups="0" />
<input id="searchbutton" type="button"/>
</div>
</div>
<div id="searchshade"></div>
<div id="search">
<input id="searchbox" type="text"/>
<div id="otherresults">
<span class="label"></span>
<span id="results"></span>
</div>
</div>
<script type="text/javascript;version=1.8" src="tabview.js"></script>
</body>
</html>

Просмотреть файл

@ -1,83 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
var Cr = Components.results;
Cu.import("resource:///modules/tabview/utils.jsm");
Cu.import("resource://gre/modules/AppConstants.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyGetter(this, "tabviewBundle", function() {
return Services.strings.
createBundle("chrome://browser/locale/tabview.properties");
});
XPCOMUtils.defineLazyGetter(this, "tabbrowserBundle", function() {
return Services.strings.
createBundle("chrome://browser/locale/tabbrowser.properties");
});
function tabviewString(name) {
return tabviewBundle.GetStringFromName('tabview.' + name);
}
function tabbrowserString(name) {
return tabbrowserBundle.GetStringFromName(name);
}
XPCOMUtils.defineLazyGetter(this, "gPrefBranch", function() {
return Services.prefs.getBranch("browser.panorama.");
});
XPCOMUtils.defineLazyModuleGetter(this, "gPageThumbnails",
"resource://gre/modules/PageThumbs.jsm", "PageThumbs");
var gWindow = window.parent;
var gBrowser = gWindow.gBrowser;
var gTabView = gWindow.TabView;
var gTabViewDeck = gWindow.document.getElementById("tab-view-deck");
var gBrowserPanel = gWindow.document.getElementById("browser-panel");
var gTabViewFrame = gWindow.document.getElementById("tab-view");
var AllTabs = {
_events: {
attrModified: "TabAttrModified",
close: "TabClose",
move: "TabMove",
open: "TabOpen",
select: "TabSelect",
pinned: "TabPinned",
unpinned: "TabUnpinned"
},
get tabs() {
return Array.filter(gBrowser.tabs, tab => Utils.isValidXULTab(tab));
},
register: function AllTabs_register(eventName, callback) {
gBrowser.tabContainer.addEventListener(this._events[eventName], callback, false);
},
unregister: function AllTabs_unregister(eventName, callback) {
gBrowser.tabContainer.removeEventListener(this._events[eventName], callback, false);
}
};
# NB: Certain files need to evaluate before others
#include iq.js
#include storage.js
#include items.js
#include groupitems.js
#include tabitems.js
#include favicons.js
#include drag.js
#include trench.js
#include search.js
#include telemetry.js
#include ui.js

Просмотреть файл

@ -1,63 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Collects telemetry data for Tabview.
*/
var Telemetry = {
TOPIC_GATHER_TELEMETRY: "gather-telemetry",
/**
* Initializes the object.
*/
init: function Telemetry_init() {
Services.obs.addObserver(this, this.TOPIC_GATHER_TELEMETRY, false);
},
/**
* Uninitializes the object.
*/
uninit: function Telemetry_uninit() {
Services.obs.removeObserver(this, this.TOPIC_GATHER_TELEMETRY);
},
/**
* Adds telemetry values to gather usage statistics.
*/
_collect: function Telemetry_collect() {
let stackedGroupsCount = 0;
let childCounts = [];
GroupItems.groupItems.forEach(function (groupItem) {
if (!groupItem.isEmpty()) {
childCounts.push(groupItem.getChildren().length);
if (groupItem.isStacked())
stackedGroupsCount++;
}
});
function addTelemetryValue(aId, aValue) {
Services.telemetry.getHistogramById("PANORAMA_" + aId).add(aValue);
}
function median(aChildCounts) {
aChildCounts.sort(function(x, y) { return x - y; });
let middle = Math.floor(aChildCounts.length / 2);
return aChildCounts[middle];
}
addTelemetryValue("GROUPS_COUNT", GroupItems.groupItems.length);
addTelemetryValue("STACKED_GROUPS_COUNT", stackedGroupsCount);
addTelemetryValue("MEDIAN_TABS_IN_GROUPS_COUNT", median(childCounts));
},
/**
* Observes for gather telemetry topic.
*/
observe: function Telemetry_observe(aSubject, aTopic, aData) {
if (!gWindow.PrivateBrowsingUtils.isWindowPrivate(gWindow))
this._collect();
}
}

Просмотреть файл

@ -1,196 +0,0 @@
[DEFAULT]
skip-if = e10s # Bug 1092281
support-files =
dummy_page.html
head.js
search1.html
search2.html
test_bug600645.html
test_bug644097.html
test_bug678374.html
test_bug678374_icon16.png
[browser_tabview_alltabs.js]
[browser_tabview_apptabs.js]
[browser_tabview_bug580412.js]
[browser_tabview_bug586553.js]
[browser_tabview_bug587043.js]
[browser_tabview_bug587231.js]
skip-if = buildapp == 'mulet'
[browser_tabview_bug587276.js]
skip-if = e10s || true # Bug 1091200, bug 1096285
[browser_tabview_bug587351.js]
[browser_tabview_bug587503.js]
[browser_tabview_bug587990.js]
[browser_tabview_bug588265.js]
[browser_tabview_bug589324.js]
skip-if = e10s # Bug 1086190
[browser_tabview_bug590606.js]
[browser_tabview_bug591706.js]
[browser_tabview_bug593283.js]
[browser_tabview_bug595191.js]
[browser_tabview_bug595436.js]
[browser_tabview_bug595518.js]
[browser_tabview_bug595521.js]
[browser_tabview_bug595560.js]
[browser_tabview_bug595601.js]
[browser_tabview_bug595804.js]
[browser_tabview_bug595930.js]
[browser_tabview_bug595943.js]
[browser_tabview_bug595965.js]
skip-if = e10s # Bug 1086190
[browser_tabview_bug596781.js]
[browser_tabview_bug597360.js]
[browser_tabview_bug597399.js]
[browser_tabview_bug597980.js]
skip-if = true # Bug 711907
[browser_tabview_bug598375.js]
[browser_tabview_bug598600.js]
[browser_tabview_bug599048.js]
[browser_tabview_bug599626.js]
skip-if = os == 'linux' || e10s # Disabled on Linux: Bug 939620, much fail, so amaze; Disabled for e10s: Bug ??????
[browser_tabview_bug600645.js]
[browser_tabview_bug600812.js]
skip-if = e10s # Bug 1086190
[browser_tabview_bug602432.js]
skip-if = true # Bug 704417
[browser_tabview_bug604098.js]
[browser_tabview_bug606657.js]
[browser_tabview_bug606905.js]
[browser_tabview_bug607108.js]
skip-if = os == 'linux' # Bug 947521
[browser_tabview_bug608037.js]
skip-if = e10s # Bug 1086190
[browser_tabview_bug608153.js]
[browser_tabview_bug608158.js]
[browser_tabview_bug608184.js]
[browser_tabview_bug608405.js]
[browser_tabview_bug610208.js]
[browser_tabview_bug610242.js]
skip-if = true # Bug 736036
[browser_tabview_bug612470.js]
[browser_tabview_bug613541.js]
skip-if = os == "win" # Bug 951477
[browser_tabview_bug616729.js]
skip-if = e10s # Bug 1086190
[browser_tabview_bug616967.js]
[browser_tabview_bug618816.js]
[browser_tabview_bug618828.js]
skip-if = buildapp == 'mulet'
[browser_tabview_bug619937.js]
[browser_tabview_bug622835.js]
[browser_tabview_bug623768.js]
skip-if = e10s # Bug 1086190
[browser_tabview_bug624265_perwindowpb.js]
skip-if = true # Bug 921984, hopefully fixed by bug 930202
[browser_tabview_bug624692.js]
[browser_tabview_bug624727_perwindowpb.js]
skip-if = buildapp == 'mulet'
[browser_tabview_bug624847.js]
skip-if = e10s # Bug 1086190
[browser_tabview_bug624931.js]
[browser_tabview_bug624953.js]
[browser_tabview_bug625195.js]
[browser_tabview_bug625269.js]
[browser_tabview_bug625424.js]
[browser_tabview_bug625955.js]
[browser_tabview_bug626368.js]
skip-if = e10s # Bug 1086190
[browser_tabview_bug626455.js]
skip-if = e10s # Bug 1086190
[browser_tabview_bug626525.js]
[browser_tabview_bug626791.js]
skip-if = buildapp == 'mulet'
[browser_tabview_bug627736.js]
[browser_tabview_bug628061.js]
[browser_tabview_bug628165.js]
[browser_tabview_bug628270.js]
[browser_tabview_bug628887.js]
[browser_tabview_bug629189.js]
[browser_tabview_bug629195.js]
skip-if = os == 'linux'&&debug # bug 981703
[browser_tabview_bug630102.js]
[browser_tabview_bug630157.js]
skip-if = true # Bug 922422
[browser_tabview_bug631662.js]
skip-if = true # Bug 922422
[browser_tabview_bug631752.js]
[browser_tabview_bug633788.js]
[browser_tabview_bug634077.js]
[browser_tabview_bug634085.js]
[browser_tabview_bug634672.js]
[browser_tabview_bug635696.js]
[browser_tabview_bug637840.js]
skip-if = buildapp == 'mulet'
[browser_tabview_bug640765.js]
[browser_tabview_bug641802.js]
[browser_tabview_bug642793.js]
[browser_tabview_bug643392.js]
[browser_tabview_bug644097.js]
[browser_tabview_bug648882.js]
skip-if = true # Bug 752862
[browser_tabview_bug649006.js]
[browser_tabview_bug649307.js]
[browser_tabview_bug649319.js]
[browser_tabview_bug650280_perwindowpb.js]
[browser_tabview_bug650573.js]
[browser_tabview_bug651311.js]
[browser_tabview_bug654295.js]
[browser_tabview_bug654721.js]
[browser_tabview_bug654941.js]
skip-if = true # Bug 754222
[browser_tabview_bug655269.js]
[browser_tabview_bug656778.js]
skip-if = os == "mac" # Bug 946918
[browser_tabview_bug656913.js]
skip-if = e10s # Bug 1086190
[browser_tabview_bug659594.js]
skip-if = os == "mac" || e10s # mac: Bug 939617; e10s - Bug ?????? - "leaked until shutdown [nsGlobalWindow #82 about:blank]"
[browser_tabview_bug662266.js]
[browser_tabview_bug663421.js]
[browser_tabview_bug665502.js]
skip-if = buildapp == 'mulet'
[browser_tabview_bug669694.js]
[browser_tabview_bug673196.js]
[browser_tabview_bug673729.js]
skip-if = true # Bug 749980
[browser_tabview_bug678374.js]
skip-if = true # Bug 795265
[browser_tabview_bug681599.js]
[browser_tabview_bug685476.js]
[browser_tabview_bug685692.js]
[browser_tabview_bug686654.js]
[browser_tabview_bug696602.js]
skip-if = true # Bug 736425
[browser_tabview_bug697390.js]
[browser_tabview_bug705621.js]
[browser_tabview_bug706430.js]
[browser_tabview_bug706736.js]
skip-if = buildapp == 'mulet'
[browser_tabview_bug707466.js]
[browser_tabview_bug712203.js]
[browser_tabview_bug715454.js]
[browser_tabview_bug716880.js]
[browser_tabview_bug728887.js]
[browser_tabview_bug733115.js]
[browser_tabview_bug749658.js]
[browser_tabview_bug766597.js]
[browser_tabview_click_group.js]
[browser_tabview_dragdrop.js]
[browser_tabview_exit_button.js]
[browser_tabview_expander.js]
[browser_tabview_firstrun_pref.js]
[browser_tabview_group.js]
skip-if = os == "mac" || os == "win" # Bug 945687
[browser_tabview_launch.js]
[browser_tabview_multiwindow_search.js]
skip-if = e10s # Bug 1086190
[browser_tabview_pending_tabs.js]
[browser_tabview_privatebrowsing_perwindowpb.js]
skip-if = os == 'linux' || e10s # linux: Bug 944300; e10s: bug ?????? - "leaked until shutdown [nsGlobalWindow #82 about:blank]"
[browser_tabview_rtl.js]
[browser_tabview_search.js]
[browser_tabview_snapping.js]
[browser_tabview_startup_transitions.js]
[browser_tabview_undo_group.js]

Просмотреть файл

@ -1,45 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
let AllTabs;
let newTab = gBrowser.addTab();
// TabPinned
let pinned = function (event) {
let tab = event.target;
is(tab, newTab, "The tabs are the same after the tab is pinned");
ok(tab.pinned, "The tab gets pinned");
gBrowser.unpinTab(tab);
};
// TabUnpinned
let unpinned = function (event) {
let tab = event.target;
AllTabs.unregister("pinned", pinned);
AllTabs.unregister("unpinned", unpinned);
is(tab, newTab, "The tabs are the same after the tab is unpinned");
ok(!tab.pinned, "The tab gets unpinned");
// clean up and finish
gBrowser.removeTab(tab);
hideTabView(finish);
};
showTabView(function () {
AllTabs = TabView.getContentWindow().AllTabs;
AllTabs.register("pinned", pinned);
AllTabs.register("unpinned", unpinned);
ok(!newTab.pinned, "The tab is not pinned");
gBrowser.pinTab(newTab);
});
}

Просмотреть файл

@ -1,96 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
showTabView(onTabViewWindowLoaded);
}
function onTabViewWindowLoaded() {
ok(TabView.isVisible(), "Tab View is visible");
let contentWindow = TabView.getContentWindow();
// establish initial state
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
let box = new contentWindow.Rect(20, 20, 180, 180);
let groupItemOne = new contentWindow.GroupItem([],
{ bounds: box, title: "test1" });
is(contentWindow.GroupItems.groupItems.length, 2, "we now have two groups");
contentWindow.UI.setActive(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
is(appTabCount(groupItemOne), 0, "there are no app tab icons");
// pin the tab, make sure the TabItem goes away and the icon comes on
whenAppTabIconAdded(groupItemOne, function () {
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" });
whenAppTabIconAdded(groupItemTwo, function() {
is(contentWindow.GroupItems.groupItems.length, 3, "we now have three groups");
is(appTabCount(groupItemTwo), 1,
"there's an app tab icon in the second group");
// When the tab was pinned, the last active group with an item got the focus.
// Therefore, switching the focus back to group item one.
contentWindow.UI.setActive(groupItemOne);
// 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 two");
whenAppTabIconAdded(groupItemOne, function() {
// close the second group
groupItemTwo.close();
// find app tab in group and hit it
whenTabViewIsHidden(function() {
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(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(gBrowser.tabs.length, 1, "we finish with one tab");
ok(!TabView.isVisible(), "we finish with Tab View not visible");
finish();
});
let appTabIcons = groupItemOne.container.getElementsByClassName("appTabIcon");
EventUtils.sendMouseEvent({ type: "click" }, appTabIcons[0], contentWindow);
});
gBrowser.pinTab(xulTab);
});
});
gBrowser.pinTab(xulTab);
}
function appTabCount(groupItem) {
return groupItem.container.getElementsByClassName("appTabIcon").length;
}

Просмотреть файл

@ -1,80 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
showTabView(onTabViewShown);
}
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();
let endGame = function() {
ok(TabView.isVisible(), "TabView is shown");
gBrowser.selectedTab = originalTab;
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("transition-property", "none");
currentActiveGroup.setPosition(40, 40, true);
currentActiveGroup.arrange({animate: false});
// 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(item, offsetX, offsetY, contentWindow) {
let target = item.container;
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;
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);
}

Просмотреть файл

@ -1,61 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
TabView.toggle();
}
var moves = 0;
var contentWindow = null;
var newTabs = [];
var originalTab = null;
function onTabMove(e) {
let tab = e.target;
moves++;
}
function onTabViewWindowLoaded() {
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
contentWindow = document.getElementById("tab-view").contentWindow;
originalTab = gBrowser.selectedTab;
newTabs = [gBrowser.addTab("about:rights"), gBrowser.addTab("about:mozilla"), gBrowser.addTab("about:license")];
is(originalTab._tPos, 0, "Original tab is in position 0");
is(newTabs[0]._tPos, 1, "Rights is in position 1");
is(newTabs[1]._tPos, 2, "Mozilla is in position 2");
is(newTabs[2]._tPos, 3, "License is in position 3");
gBrowser.tabContainer.addEventListener("TabMove", onTabMove, false);
let groupItem = contentWindow.GroupItems.getActiveGroupItem();
// move 3 > 0 (and therefore 0 > 1, 1 > 2, 2 > 3)
groupItem._children.splice(0, 0, groupItem._children.splice(3, 1)[0]);
groupItem.arrange();
window.addEventListener("tabviewhidden", onTabViewWindowHidden, false);
TabView.toggle();
}
function onTabViewWindowHidden() {
window.removeEventListener("tabviewhidden", onTabViewWindowHidden, false);
gBrowser.tabContainer.removeEventListener("TabMove", onTabMove, false);
is(moves, 1, "Only one move should be necessary for this basic move.");
is(newTabs[2]._tPos, 0, "License is in position 0");
is(originalTab._tPos, 1, "Original tab is in position 1");
is(newTabs[0]._tPos, 2, "Rights is in position 2");
is(newTabs[1]._tPos, 3, "Mozilla is in position 3");
gBrowser.removeTab(newTabs[0]);
gBrowser.removeTab(newTabs[1]);
gBrowser.removeTab(newTabs[2]);
finish();
}

Просмотреть файл

@ -1,24 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
TabView.toggle();
}
function onTabViewWindowLoaded() {
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
ok(TabView.isVisible(), "Tab View is visible");
let onTabViewHidden = function() {
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
ok(!TabView.isVisible(), "Tab View is hidden");
finish();
};
window.addEventListener("tabviewhidden", onTabViewHidden, false);
document.getElementById("cmd_closeWindow").doCommand();
}

Просмотреть файл

@ -1,96 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var activeTab;
var testTab;
var testGroup;
var contentWindow;
function test() {
waitForExplicitFinish();
// create new tab
testTab = gBrowser.addTab("about:blank");
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
TabView.toggle();
}
function onTabViewWindowLoaded() {
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
ok(TabView.isVisible(), "Tab View is visible");
contentWindow = document.getElementById("tab-view").contentWindow;
// create group
let testGroupRect = new contentWindow.Rect(20, 20, 300, 300);
testGroup = new contentWindow.GroupItem([], { bounds: testGroupRect });
ok(testGroup.isEmpty(), "This group is empty");
ok(testTab._tabViewTabItem, "tab item exists");
// place tab in group
let testTabItem = testTab._tabViewTabItem;
if (testTabItem.parent)
testTabItem.parent.remove(testTabItem);
testGroup.add(testTabItem);
ok(testTab._tabViewTabItem, "tab item exists after adding to group");
// record last update time of tab canvas
let initialUpdateTime = testTabItem._lastTabUpdateTime;
// simulate resize
let resizer = contentWindow.iQ('.iq-resizable-handle', testGroup.container)[0];
let offsetX = 100;
let offsetY = 100;
let delay = 500;
let funcChain = new Array();
funcChain.push(function() {
EventUtils.synthesizeMouse(
resizer, 1, 1, { type: "mousedown" }, contentWindow);
setTimeout(funcChain.shift(), delay);
});
// drag
for (let i = 4; i >= 0; i--) {
funcChain.push(function() {
EventUtils.synthesizeMouse(
resizer, Math.round(offsetX/4), Math.round(offsetY/4),
{ type: "mousemove" }, contentWindow);
setTimeout(funcChain.shift(), delay);
});
}
funcChain.push(function() {
EventUtils.synthesizeMouse(resizer, 0, 0, { type: "mouseup" },
contentWindow);
setTimeout(funcChain.shift(), delay);
});
funcChain.push(function() {
// verify that update time has changed after last update
let lastTime = testTabItem._lastTabUpdateTime;
let hbTiming = contentWindow.TabItems._heartbeatTiming;
ok((lastTime - initialUpdateTime) > hbTiming, "Tab has been updated:"+lastTime+"-"+initialUpdateTime+">"+hbTiming);
// clean up
testGroup.remove(testTab._tabViewTabItem);
testTab._tabViewTabItem.close();
testGroup.close();
let currentTabs = contentWindow.TabItems.getItems();
ok(currentTabs[0], "A tab item exists to make active");
contentWindow.UI.setActive(currentTabs[0]);
window.addEventListener("tabviewhidden", finishTest, false);
TabView.toggle();
});
setTimeout(funcChain.shift(), delay);
}
function finishTest() {
window.removeEventListener("tabviewhidden", finishTest, false);
ok(!TabView.isVisible(), "Tab View is not visible");
finish();
}

Просмотреть файл

@ -1,110 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var contentWindow;
function test() {
requestLongerTimeout(2);
waitForExplicitFinish();
showTabView(test1);
}
function test1() {
ok(TabView.isVisible(), "Tab View is visible");
contentWindow = document.getElementById("tab-view").contentWindow;
whenTabViewIsHidden(function() {
ok(!TabView.isVisible(), "Tab View is not visible");
showTabView(test2);
});
EventUtils.synthesizeKey("e", { accelKey: true, shiftKey: true }, contentWindow);
}
function test2() {
ok(TabView.isVisible(), "Tab View is visible");
whenSearchIsEnabled(function() {
ok(contentWindow.Search.isEnabled(), "The search is enabled")
whenSearchIsDisabled(test3);
hideSearch();
});
EventUtils.synthesizeKey("f", { accelKey: true }, contentWindow);
}
function test3() {
ok(!contentWindow.Search.isEnabled(), "The search is disabled")
is(gBrowser.tabs.length, 1, "There is one tab before cmd/ctrl + t is pressed");
whenTabViewIsHidden(function() {
is(gBrowser.tabs.length, 2, "There are two tabs after cmd/ctrl + t is pressed");
gBrowser.tabs[0].linkedBrowser.loadURI("about:mozilla");
gBrowser.tabs[1].linkedBrowser.loadURI("http://example.com/");
afterAllTabsLoaded(function () {
showTabView(test4);
});
});
EventUtils.synthesizeKey("t", { accelKey: true }, contentWindow);
}
function test4() {
is(gBrowser.tabs.length, 2, "There are two tabs");
let onTabClose = function() {
gBrowser.tabContainer.removeEventListener("TabClose", onTabClose, true);
executeSoon(function() {
is(gBrowser.tabs.length, 1, "There is one tab after removing one");
EventUtils.synthesizeKey("t", { accelKey: true, shiftKey: true }, contentWindow);
is(gBrowser.tabs.length, 2, "There are two tabs after restoring one");
gBrowser.tabs[1].linkedBrowser.addEventListener("load", function listener() {
gBrowser.tabs[1].linkedBrowser.removeEventListener("load", listener, true);
gBrowser.tabs[0].linkedBrowser.loadURI("about:blank");
gBrowser.selectedTab = gBrowser.tabs[0];
test8();
}, true);
});
};
gBrowser.tabContainer.addEventListener("TabClose", onTabClose, true);
gBrowser.removeTab(gBrowser.tabs[1]);
}
// below key combination shouldn't trigger actions in tabview UI
function test8() {
showTabView(function() {
is(gBrowser.tabs.length, 2, "There are two tabs before cmd/ctrl + w is pressed");
EventUtils.synthesizeKey("w", { accelKey: true }, contentWindow);
is(gBrowser.tabs.length, 2, "There are two tabs after cmd/ctrl + w is pressed");
gBrowser.removeTab(gBrowser.tabs[1]);
test9();
});
}
function test9() {
let zoomLevel = ZoomManager.zoom;
EventUtils.synthesizeKey("+", { accelKey: true }, contentWindow);
is(ZoomManager.zoom, zoomLevel, "The zoom level remains unchanged after cmd/ctrl + + is pressed");
EventUtils.synthesizeKey("-", { accelKey: true }, contentWindow);
is(ZoomManager.zoom, zoomLevel, "The zoom level remains unchanged after cmd/ctrl + - is pressed");
test10();
}
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);
executeSoon(function() {
is(gBrowser.tabs.length, 1, "There is still one tab after cmd/ctrl + shift + a is pressed");
hideTabView(finish);
})
}

Просмотреть файл

@ -1,38 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var newTab;
function test() {
waitForExplicitFinish();
newTab = gBrowser.addTab();
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
TabView.toggle();
}
function onTabViewWindowLoaded() {
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
let contentWindow = document.getElementById("tab-view").contentWindow;
is(contentWindow.GroupItems.groupItems.length, 1, "Has one group only");
let tabItems = contentWindow.GroupItems.groupItems[0].getChildren();
ok(tabItems.length, 2, "There are two tabItems in the group");
is(tabItems[1].tab, newTab, "The second tabItem is linked to the new tab");
EventUtils.sendMouseEvent({ type: "mousedown", button: 1 }, tabItems[1].container, contentWindow);
EventUtils.sendMouseEvent({ type: "mouseup", button: 1 }, tabItems[1].container, contentWindow);
ok(tabItems.length, 1, "There is only one tabItem in the group");
let endGame = function() {
window.removeEventListener("tabviewhidden", endGame, false);
finish();
};
window.addEventListener("tabviewhidden", endGame, false);
TabView.toggle();
}

Просмотреть файл

@ -1,112 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
function moveTabOutOfGroup(aTab, aGroup, aCW, aCallback) {
let tabPos = aTab.getBounds().center();
let groupPos = aGroup.getBounds();
let groupPosX = (groupPos.left + groupPos.right) / 2;
let groupPosY = groupPos.bottom + 200;
let offsetX = Math.round(groupPosX - tabPos.x);
let offsetY = Math.round(groupPosY - tabPos.y);
simulateDragDrop(aTab, offsetX, offsetY, aCW);
}
function moveTabInGroup(aTab, aIndexTo, aGroup, aCW) {
let tabTo = aGroup.getChild(aIndexTo);
let tabPos = aTab.getBounds().center();
let tabToPos = tabTo.getBounds().center();
let offsetX = Math.round(tabToPos.x - tabPos.x);
let offsetY = Math.round(tabToPos.y - tabPos.y);
simulateDragDrop(aTab, offsetX, offsetY, aCW);
}
function getTabNumbers(aGroup) {
return aGroup.getChildren().map(function (child) {
let url = child.tab.linkedBrowser.currentURI.spec;
return url.replace("about:blank#", "");
}).join(",");
}
function moveTabs(aGroup, aCW) {
// Test 1: Move the last tab to the third position.
let tab = aGroup.getChild(6);
moveTabInGroup(tab, 2, aGroup, aCW);
is(getTabNumbers(aGroup), "0,1,6,2,3,4,5", "Validate tab positions in test 1.");
// Test 2: Move the second tab to the end of the list.
tab = aGroup.getChild(1);
moveTabInGroup(tab, 6, aGroup, aCW);
is(getTabNumbers(aGroup), "0,6,2,3,4,5,1", "Validate tab positions in test 2.");
// Test 3: Move the fifth tab outside the group.
tab = aGroup.getChild(4);
moveTabOutOfGroup(tab, aGroup, aCW);
is(getTabNumbers(aGroup), "0,6,2,3,5,1", "Validate tab positions in test 3.");
is(aCW.GroupItems.groupItems.length, 3, "Validate group count in test 3.");
// This test is disabled because it is fragile -- see bug 797975
if (false) {
// Test 4: Move the fifth tab back into the group, on the second row.
waitForTransition(tab, function() {
moveTabInGroup(tab, 4, aGroup, aCW);
is(getTabNumbers(aGroup), "0,6,2,3,4,5,1", "Validate tab positions in test 4.");
is(aCW.GroupItems.groupItems.length, 2, "Validate group count in test 4.");
closeGroupItem(aGroup, function() { hideTabView(finish) });
});
} else {
closeGroupItem(aGroup, function() { hideTabView(finish) });
}
}
function createGroup(win) {
registerCleanupFunction(() => win.close());
let cw = win.TabView.getContentWindow();
let group = createGroupItemWithTabs(win, 400, 430, 100, [
"about:blank#0", "about:blank#1", "about:blank#2", "about:blank#3",
"about:blank#4", "about:blank#5", "about:blank#6"
]);
let groupSize = group.getChildren().length;
is(cw.GroupItems.groupItems.length, 2, "Validate group count in tab view.");
ok(!group.shouldStack(groupSize), "Check that group should not stack.");
is(group._columns, 3, "Check the there should be three columns.");
moveTabs(group, cw);
}
newWindowWithTabView(createGroup);
}
function simulateDragDrop(aTab, aOffsetX, aOffsetY, aCW) {
let target = aTab.container;
let rect = target.getBoundingClientRect();
let startX = (rect.right - rect.left) / 2;
let startY = (rect.bottom - rect.top) / 2;
let steps = 2;
let incrementX = aOffsetX / steps;
let incrementY = aOffsetY / steps;
EventUtils.synthesizeMouse(
target, startX, startY, { type: "mousedown" }, aCW);
for (let i = 1; i <= steps; i++) {
EventUtils.synthesizeMouse(
target, incrementX + startX, incrementY + startY,
{ type: "mousemove" }, aCW);
};
EventUtils.synthesizeMouseAtCenter(target, { type: "mouseup" }, aCW);
}
function waitForTransition(aTab, aCallback) {
let groupContainer = aTab.parent.container;
groupContainer.addEventListener("transitionend", function onTransitionEnd(aEvent) {
if (aEvent.target == groupContainer) {
groupContainer.removeEventListener("transitionend", onTransitionEnd);
executeSoon(aCallback);
}
});
}

Просмотреть файл

@ -1,31 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
let newTab;
let onLoad = function (win) {
registerCleanupFunction(() => win.close());
newTab = win.gBrowser.addTab();
let popup = win.document.getElementById("context_tabViewMenuPopup");
win.TabView.updateContextMenu(newTab, popup);
};
let onShow = function (win) {
let cw = win.TabView.getContentWindow();
is(cw.GroupItems.groupItems.length, 1, "Has only one group");
let groupItem = cw.GroupItems.groupItems[0];
let tabItems = groupItem.getChildren();
let tab = tabItems[tabItems.length - 1].tab;
is(tab, newTab, "The new tab exists in the group");
finish();
};
waitForExplicitFinish();
newWindowWithTabView(onShow, onLoad);
}

Просмотреть файл

@ -1,76 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var contentWindow;
var groupItemTwoId;
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
while (gBrowser.tabs[1])
gBrowser.removeTab(gBrowser.tabs[1]);
hideTabView();
});
gBrowser.loadOneTab("about:blank", { inBackground: true });
showTabView(setup);
}
function setup() {
registerCleanupFunction(function() {
let groupItem = contentWindow.GroupItems.groupItem(groupItemTwoId);
if (groupItem)
closeGroupItem(groupItem);
});
let contentWindow = TabView.getContentWindow();
is(contentWindow.GroupItems.groupItems.length, 1, "Has only one group");
let groupItemOne = contentWindow.GroupItems.groupItems[0];
is(groupItemOne.getChildren().length, 2, "Group one has 2 tab items");
let groupItemTwo = createGroupItemWithBlankTabs(window, 250, 250, 40, 1);
groupItemTwoId = groupItemTwo.id;
testGroups(groupItemOne, groupItemTwo, contentWindow);
}
function testGroups(groupItemOne, groupItemTwo, contentWindow) {
// check active tab and group
is(contentWindow.GroupItems.getActiveGroupItem(), groupItemTwo,
"The group two is the active group");
is(contentWindow.UI.getActiveTab(), groupItemTwo.getChild(0),
"The first tab item in group two is active");
let tabItem = groupItemOne.getChild(1);
tabItem.addSubscriber("tabRemoved", function onTabRemoved() {
tabItem.removeSubscriber("tabRemoved", onTabRemoved);
is(groupItemOne.getChildren().length, 1,
"The num of childen in group one is 1");
// check active group and active tab
is(contentWindow.GroupItems.getActiveGroupItem(), groupItemOne,
"The group one is the active group");
is(contentWindow.UI.getActiveTab(), groupItemOne.getChild(0),
"The first tab item in group one is active");
whenTabViewIsHidden(function() {
is(groupItemOne.getChildren().length, 2,
"The num of childen in group one is 2");
// clean up and finish
closeGroupItem(groupItemTwo, function() {
gBrowser.removeTab(groupItemOne.getChild(1).tab);
is(contentWindow.GroupItems.groupItems.length, 1, "Has only one group");
is(groupItemOne.getChildren().length, 1,
"The num of childen in group one is 1");
is(gBrowser.tabs.length, 1, "Has only one tab");
finish();
});
});
EventUtils.synthesizeKey("t", { accelKey: true });
});
// close a tab item in group one
EventUtils.synthesizeMouseAtCenter(tabItem.$close[0], {}, contentWindow);
}

Просмотреть файл

@ -1,89 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const DUMMY_PAGE_URL = "http://mochi.test:8888/browser/browser/components/tabview/test/dummy_page.html";
const DUMMY_PAGE_URL_2 = "http://mochi.test:8888/";
var state = {
windows: [{
tabs: [{
entries: [{ url: DUMMY_PAGE_URL }],
hidden: true,
attributes: {},
extData: {
"tabview-tab":
'{"bounds":{"left":21,"top":29,"width":204,"height":153},' +
'"userSize":null,"url":"' + DUMMY_PAGE_URL + '","groupID":1,' +
'"imageData":null,"title":null}'
}
},{
entries: [{ url: DUMMY_PAGE_URL_2 }],
hidden: false,
attributes: {},
extData: {
"tabview-tab":
'{"bounds":{"left":315,"top":29,"width":111,"height":84},' +
'"userSize":null,"url":"' + DUMMY_PAGE_URL_2 + '","groupID":2,' +
'"imageData":null,"title":null}'
},
}],
selected:2,
_closedTabs: [],
extData: {
"tabview-groups": '{"nextID":3,"activeGroupId":2}',
"tabview-group":
'{"1":{"bounds":{"left":15,"top":5,"width":280,"height":232},' +
'"userSize":null,"title":"","id":1},' +
'"2":{"bounds":{"left":309,"top":5,"width":267,"height":226},' +
'"userSize":null,"title":"","id":2}}',
"tabview-ui": '{"pageBounds":{"left":0,"top":0,"width":788,"height":548}}'
}, sizemode:"normal"
}]
};
function test() {
waitForExplicitFinish();
registerCleanupFunction(function () {
Services.prefs.clearUserPref("browser.sessionstore.restore_hidden_tabs");
});
Services.prefs.setBoolPref("browser.sessionstore.restore_hidden_tabs", false);
testTabSwitchAfterRestore(function () {
Services.prefs.setBoolPref("browser.sessionstore.restore_hidden_tabs", true);
testTabSwitchAfterRestore(finish);
});
}
function testTabSwitchAfterRestore(callback) {
newWindowWithState(state, function (win) {
registerCleanupFunction(() => win.close());
let [firstTab, secondTab] = win.gBrowser.tabs;
is(firstTab.linkedBrowser.currentURI.spec, DUMMY_PAGE_URL,
"The url of first tab url is dummy_page.html");
// check the hidden state of both tabs.
ok(firstTab.hidden, "The first tab is hidden");
ok(!secondTab.hidden, "The second tab is not hidden");
is(secondTab, win.gBrowser.selectedTab, "The second tab is selected");
// when the second tab is hidden, Panorama should be initialized and
// the first tab should be visible.
let container = win.gBrowser.tabContainer;
container.addEventListener("TabHide", function onTabHide() {
container.removeEventListener("TabHide", onTabHide, false);
ok(win.TabView.getContentWindow(), "Panorama is loaded");
ok(!firstTab.hidden, "The first tab is not hidden");
is(firstTab, win.gBrowser.selectedTab, "The first tab is selected");
ok(secondTab.hidden, "The second tab is hidden");
callback();
}, false);
// switch to another tab
win.switchToTabHavingURI(DUMMY_PAGE_URL);
});
}

Просмотреть файл

@ -1,81 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var originalTab;
var newTabOne;
var groupItemTwoId;
function test() {
waitForExplicitFinish();
originalTab = gBrowser.visibleTabs[0];
// add a tab to the existing group.
newTabOne = gBrowser.addTab();
registerCleanupFunction(function() {
while (gBrowser.tabs[1])
gBrowser.removeTab(gBrowser.tabs[1]);
hideTabView();
});
showTabView(function() {
let contentWindow = TabView.getContentWindow();
registerCleanupFunction(function() {
let groupItem = contentWindow.GroupItems.groupItem(groupItemTwoId);
if (groupItem)
closeGroupItem(groupItem);
});
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 = createGroupItemWithBlankTabs(window, 300, 300, 200, 1);
groupItemTwoId = groupItemTwoId;
hideTabView(function() {
// start the test
testGroupSwitch(contentWindow, groupItemOne, groupItemTwo);
});
});
}
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
let 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();
}

Просмотреть файл

@ -1,107 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
if (TabView.isVisible())
onTabViewWindowLoaded();
else
TabView.show();
}
function onTabViewWindowLoaded() {
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
ok(TabView.isVisible(), "Tab View is visible");
let contentWindow = document.getElementById("tab-view").contentWindow;
let [originalTab] = gBrowser.visibleTabs;
// Create a first tab and orphan it
let firstTab = gBrowser.loadOneTab("about:blank#1", {inBackground: true});
let firstTabItem = firstTab._tabViewTabItem;
let currentGroup = contentWindow.GroupItems.getActiveGroupItem();
ok(currentGroup.getChildren().some(child => child == firstTabItem),"The first tab was made in the current group");
contentWindow.GroupItems.getActiveGroupItem().remove(firstTabItem);
ok(!currentGroup.getChildren().some(child => child == firstTabItem),"The first tab was orphaned");
// Create a group and make it active
let box = new contentWindow.Rect(10, 10, 300, 300);
let group = new contentWindow.GroupItem([], { bounds: box });
ok(group.isEmpty(), "This group is empty");
contentWindow.UI.setActive(group);
// Create a second tab in this new group
let secondTab = gBrowser.loadOneTab("about:blank#2", {inBackground: true});
let secondTabItem = secondTab._tabViewTabItem;
ok(group.getChildren().some(child => child == secondTabItem),"The second tab was made in our new group");
is(group.getChildren().length, 1, "Only one tab in the first group");
isnot(firstTab.linkedBrowser.currentURI.spec, secondTab.linkedBrowser.currentURI.spec, "The two tabs must have different locations");
// Add the first tab to the group *programmatically*, without specifying a dropPos
group.add(firstTabItem);
is(group.getChildren().length, 2, "Two tabs in the group");
is(group.getChildren()[0].tab.linkedBrowser.currentURI.spec, secondTab.linkedBrowser.currentURI.spec, "The second tab was there first");
is(group.getChildren()[1].tab.linkedBrowser.currentURI.spec, firstTab.linkedBrowser.currentURI.spec, "The first tab was just added and went to the end of the line");
group.addSubscriber("close", function onClose() {
group.removeSubscriber("close", onClose);
ok(group.isEmpty(), "The group is empty again");
is(contentWindow.GroupItems.getActiveGroupItem(), currentGroup, "There is an active group");
is(gBrowser.tabs.length, 1, "There is only one tab left");
is(gBrowser.visibleTabs.length, 1, "There is also only one visible tab");
let onTabViewHidden = function() {
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
finish();
};
window.addEventListener("tabviewhidden", onTabViewHidden, false);
gBrowser.selectedTab = originalTab;
TabView.hide();
});
// Get rid of the group and its children
group.closeAll();
// close undo group
let closeButton = group.$undoContainer.find(".close");
EventUtils.sendMouseEvent(
{ type: "click" }, closeButton[0], contentWindow);
}
function simulateDragDrop(srcElement, offsetX, offsetY, contentWindow) {
// enter drag mode
let dataTransfer;
EventUtils.synthesizeMouse(
srcElement, 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);
srcElement.dispatchEvent(event);
// drag over
for (let i = 4; i >= 0; i--)
EventUtils.synthesizeMouse(
srcElement, Math.round(offsetX/5), Math.round(offsetY/4),
{ type: "mousemove" }, contentWindow);
event = contentWindow.document.createEvent("DragEvents");
event.initDragEvent(
"dragover", true, true, contentWindow, 0, 0, 0, 0, 0,
false, false, false, false, 0, null, dataTransfer);
srcElement.dispatchEvent(event);
// drop
EventUtils.synthesizeMouse(srcElement, 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);
srcElement.dispatchEvent(event);
}

Просмотреть файл

@ -1,75 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const DUMMY_PAGE_URL = "http://example.com/";
var state = {
windows: [{
tabs: [{
entries: [{ url: DUMMY_PAGE_URL }],
hidden: false,
attributes: {},
extData: {
"tabview-tab": '{"url":"' + DUMMY_PAGE_URL + '","groupID":1,"title":null,"active":true}'
}
},{
entries: [{ url: DUMMY_PAGE_URL }],
hidden: false,
attributes: {},
extData: {
"tabview-tab": '{"url":"' + DUMMY_PAGE_URL + '","groupID":1,"title":null}'
}
},{
entries: [{ url: DUMMY_PAGE_URL }],
hidden: true,
attributes: {},
extData: {
"tabview-tab": '{"url":"' + DUMMY_PAGE_URL + '","groupID":2,"title":null}'
},
},{
entries: [{ url: DUMMY_PAGE_URL }],
hidden: true,
attributes: {},
extData: {
"tabview-tab": '{"url":"' + DUMMY_PAGE_URL + '","groupID":2,"title":null,"active":true}'
},
}],
selected:1,
_closedTabs: [],
extData: {
"tabview-groups": '{"nextID":3,"activeGroupId":2,"totalNumber":2}',
"tabview-group":
'{"1":{"bounds":{"left":15,"top":28,"width":546,"height":218},' +
'"userSize":{"x":546,"y":218},"title":"","id":1},' +
'"2":{"bounds":{"left":15,"top":261,"width":546,"height":199},' +
'"userSize":{"x":546,"y":199},"title":"","id":2}}',
"tabview-ui": '{"pageBounds":{"left":0,"top":0,"width":976,"height":663}}'
}, sizemode:"normal"
}]
};
function test() {
waitForExplicitFinish();
newWindowWithState(state, function (win) {
registerCleanupFunction(() => win.close());
showTabView(function() {
let cw = win.TabView.getContentWindow();
let groupItems = cw.GroupItems.groupItems;
let groupOne = groupItems[0];
let groupTwo = groupItems[1];
// check the active tab of each group
is(groupOne.getActiveTab(), groupOne.getChild(0), "The active tab item of group one is the first one");
is(groupTwo.getActiveTab(), groupTwo.getChild(1), "The active tab item of group two is the second one");
is(cw.UI.getActiveTab(), groupOne.getChild(0), "The hightlighted tab item is the first one in group one");
// select a group and the second tab should be hightlighted
cw.UI.setActive(groupTwo);
is(cw.UI.getActiveTab(), groupTwo.getChild(1), "The hightlighted tab item is the second one in group two");
finish();
}, win);
});
}

Просмотреть файл

@ -1,62 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
// show the tab view
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
ok(!TabView.isVisible(), "Tab View is hidden");
TabView.toggle();
}
function onTabViewWindowLoaded() {
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
ok(TabView.isVisible(), "Tab View is visible");
let contentWindow = document.getElementById("tab-view").contentWindow;
let searchButton = contentWindow.document.getElementById("searchbutton");
ok(searchButton, "Search button exists");
let onSearchEnabled = function() {
contentWindow.removeEventListener(
"tabviewsearchenabled", onSearchEnabled, false);
let search = contentWindow.document.getElementById("search");
ok(search.style.display != "none", "Search is enabled");
escapeTest(contentWindow);
}
contentWindow.addEventListener("tabviewsearchenabled", onSearchEnabled,
false);
// enter search mode
EventUtils.sendMouseEvent({ type: "mousedown" }, searchButton,
contentWindow);
}
function escapeTest(contentWindow) {
let onSearchDisabled = function() {
contentWindow.removeEventListener(
"tabviewsearchdisabled", onSearchDisabled, false);
let search = contentWindow.document.getElementById("search");
ok(search.style.display == "none", "Search is disabled");
toggleTabViewTest(contentWindow);
}
contentWindow.addEventListener("tabviewsearchdisabled", onSearchDisabled,
false);
EventUtils.synthesizeKey("KEY_Escape", { code: "Escape" }, contentWindow);
}
function toggleTabViewTest(contentWindow) {
let onTabViewHidden = function() {
contentWindow.removeEventListener("tabviewhidden", onTabViewHidden, false);
ok(!TabView.isVisible(), "Tab View is hidden");
finish();
}
contentWindow.addEventListener("tabviewhidden", onTabViewHidden, false);
// Use keyboard shortcut to toggle back to browser view
EventUtils.synthesizeKey("e", { accelKey: true, shiftKey: true,
code: "KeyE", keyCode: KeyboardEvent.DOM_VK_E }, contentWindow);
}

Просмотреть файл

@ -1,54 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
let cw, search, searchButton;
let assertSearchIsEnabled = function () {
isnot(search.style.display, "none", "search is enabled");
}
let assertSearchIsDisabled = function () {
is(search.style.display, "none", "search is disabled");
}
let testSearchInitiatedByKeyPress = function () {
EventUtils.synthesizeKey("a", {}, cw);
assertSearchIsEnabled();
EventUtils.synthesizeKey("VK_BACK_SPACE", {}, cw);
assertSearchIsDisabled();
}
let testSearchInitiatedByMouseClick = function () {
EventUtils.sendMouseEvent({type: "mousedown"}, searchButton, cw);
assertSearchIsEnabled();
EventUtils.synthesizeKey("a", {}, cw);
EventUtils.synthesizeKey("VK_BACK_SPACE", {}, cw);
EventUtils.synthesizeKey("VK_BACK_SPACE", {}, cw);
assertSearchIsEnabled();
EventUtils.synthesizeKey("VK_ESCAPE", {}, cw);
assertSearchIsDisabled();
}
waitForExplicitFinish();
newWindowWithTabView(function (win) {
registerCleanupFunction(() => win.close());
cw = win.TabView.getContentWindow();
search = cw.document.getElementById("search");
searchButton = cw.document.getElementById("searchbutton");
SimpleTest.waitForFocus(function () {
assertSearchIsDisabled();
testSearchInitiatedByKeyPress();
testSearchInitiatedByMouseClick();
finish();
}, cw);
});
}

Просмотреть файл

@ -1,60 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
// show tab view
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
TabView.toggle();
}
function onTabViewWindowLoaded() {
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
ok(TabView.isVisible(), "Tab View is visible");
let contentWindow = document.getElementById("tab-view").contentWindow;
let onTabViewHidden = function() {
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
// verify exit button worked
ok(!TabView.isVisible(), "Tab View is hidden");
// verify that the exit button no longer has focus
is(contentWindow.iQ("#exit-button:focus").length, 0,
"The exit button doesn't have the focus");
// 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, code: "KeyE", keyCode: KeyboardEvent.DOM_VK_E }, contentWindow);
}
let onTabViewShown = function() {
window.removeEventListener("tabviewshown", onTabViewShown, false);
// test if the key combo worked
ok(TabView.isVisible(), "Tab View is visible");
// clean up
let endGame = function() {
window.removeEventListener("tabviewhidden", endGame, false);
ok(!TabView.isVisible(), "Tab View is hidden");
finish();
}
window.addEventListener("tabviewhidden", endGame, false);
TabView.toggle();
}
window.addEventListener("tabviewhidden", onTabViewHidden, false);
// locate exit button
let button = contentWindow.document.getElementById("exit-button");
ok(button, "Exit button exists");
// click exit button
button.focus();
EventUtils.sendMouseEvent({ type: "click" }, button, contentWindow);
}

Просмотреть файл

@ -1,67 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var fadeAwayUndoButtonDelay;
var fadeAwayUndoButtonDuration;
function test() {
waitForExplicitFinish();
window.addEventListener("tabviewshown", testCloseLastGroup, false);
TabView.toggle();
}
function testCloseLastGroup() {
window.removeEventListener("tabviewshown", testCloseLastGroup, false);
ok(TabView.isVisible(), "Tab View is visible");
let contentWindow = document.getElementById("tab-view").contentWindow;
is(contentWindow.GroupItems.groupItems.length, 1, "Has one group only");
let groupItem = contentWindow.GroupItems.groupItems[0];
let checkExistence = function() {
is(contentWindow.GroupItems.groupItems.length, 1,
"Still has one group after delay");
EventUtils.sendMouseEvent(
{ type: "click" }, groupItem.$undoContainer[0], contentWindow);
};
groupItem.addSubscriber("groupHidden", function onHidden() {
groupItem.removeSubscriber("groupHidden", onHidden);
// it should still stay after 3 ms.
setTimeout(checkExistence, 3);
});
groupItem.addSubscriber("groupShown", function onShown() {
groupItem.removeSubscriber("groupShown", onShown);
let endGame = function() {
window.removeEventListener("tabviewhidden", endGame, false);
ok(!TabView.isVisible(), "Tab View is hidden");
groupItem.fadeAwayUndoButtonDelay = fadeAwayUndoButtonDelay;
groupItem.fadeAwayUndoButtonDuration = fadeAwayUndoButtonDuration;
finish();
};
window.addEventListener("tabviewhidden", endGame, false);
TabView.toggle();
});
let closeButton = groupItem.container.getElementsByClassName("close");
ok(closeButton, "Group item close button exists");
// store the original values
fadeAwayUndoButtonDelay = groupItem.fadeAwayUndoButtonDelay;
fadeAwayUndoButtonDuration = groupItem.fadeAwayUndoButtonDuration;
// set both fade away delay and duration to 1ms
groupItem.fadeAwayUndoButtonDelay = 1;
groupItem.fadeAwayUndoButtonDuration = 1;
EventUtils.sendMouseEvent({ type: "click" }, closeButton[0], contentWindow);
}

Просмотреть файл

@ -1,71 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var win;
var cw;
function test() {
waitForExplicitFinish();
let onLoad = function (tvwin) {
win = tvwin;
registerCleanupFunction(() => win.close());
win.gBrowser.loadOneTab("http://mochi.test:8888/", {inBackground: true});
};
let onShow = function () {
cw = win.TabView.getContentWindow();
ok(win.TabView.isVisible(), "Tab View is visible");
afterAllTabItemsUpdated(testOne, win);
};
newWindowWithTabView(onShow, onLoad);
}
function testOne() {
hideSearchWhenSearchEnabled(testTwo);
// press cmd/ctrl F
EventUtils.synthesizeKey("f", {accelKey: true}, cw);
}
function testTwo() {
hideSearchWhenSearchEnabled(testThree);
// press /
EventUtils.synthesizeKey("VK_SLASH", {}, cw);
}
function testThree() {
ok(win.TabView.isVisible(), "Tab View is visible");
// create another group with a tab.
let groupItem = createGroupItemWithBlankTabs(win, 300, 300, 200, 1);
is(cw.UI.getActiveTab(), groupItem.getChild(0),
"The active tab is newly created tab item");
whenSearchIsEnabled(function () {
let doc = cw.document;
let searchBox = cw.iQ("#searchbox");
let hasFocus = doc.hasFocus() && doc.activeElement == searchBox[0];
ok(hasFocus, "The search box has focus");
let tab = win.gBrowser.tabs[1];
searchBox.val(tab._tabViewTabItem.$tabTitle[0].innerHTML);
cw.Search.perform();
whenTabViewIsHidden(function () {
is(tab, win.gBrowser.selectedTab, "The search result tab is shown");
finish()
}, win);
// use the tabview menu (the same as pressing cmd/ctrl + e)
win.document.getElementById("menu_tabview").doCommand();
}, win);
EventUtils.synthesizeKey("VK_SLASH", {}, cw);
}
function hideSearchWhenSearchEnabled(callback) {
whenSearchIsEnabled(function() {
hideSearch(callback, win);
}, win);
}

Просмотреть файл

@ -1,167 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
const TAB_STATE_NEEDS_RESTORE = 1;
const TAB_STATE_RESTORING = 2;
var stateBackup = ss.getBrowserState();
var state = {windows:[{tabs:[
// first group
{entries:[{url:"http://example.com#1"}],extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#1\",\"groupID\":2}"}},
{entries:[{url:"http://example.com#2"}],extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#2\",\"groupID\":2}"}},
{entries:[{url:"http://example.com#3"}],extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#3\",\"groupID\":2}"}},
{entries:[{url:"http://example.com#4"}],extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#4\",\"groupID\":2}"}},
// second group
{entries:[{url:"http://example.com#5"}],hidden:true,extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#5\",\"groupID\":1}"}},
{entries:[{url:"http://example.com#6"}],hidden:true,extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#6\",\"groupID\":1}"}},
{entries:[{url:"http://example.com#7"}],hidden:true,extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#7\",\"groupID\":1}"}},
{entries:[{url:"http://example.com#8"}],hidden:true,extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#8\",\"groupID\":1}"}}
],selected:4,extData:{
"tabview-groups":"{\"nextID\":8,\"activeGroupId\":1}","tabview-group":"{\"1\":{\"bounds\":{\"left\":15,\"top\":10,\"width\":415,\"height\":367},\"userSize\":{\"x\":415,\"y\":367},\"title\":\"\",\"id\":1},\"2\":{\"bounds\":{\"left\":286,\"top\":488,\"width\":418,\"height\":313},\"title\":\"\",\"id\":2}}",
"tabview-ui":"{\"pageBounds\":{\"left\":0,\"top\":0,\"width\":940,\"height\":1075}}"
}}]};
function test() {
waitForExplicitFinish();
Services.prefs.setBoolPref("browser.sessionstore.restore_hidden_tabs", false);
TabsProgressListener.init();
registerCleanupFunction(function () {
TabsProgressListener.uninit();
Services.prefs.clearUserPref("browser.sessionstore.restore_hidden_tabs");
gBrowser.selectedTab = gBrowser.tabs[0];
ss.setBrowserState(stateBackup);
});
TabView._initFrame(function () {
executeSoon(testRestoreWithHiddenTabs);
});
}
function testRestoreWithHiddenTabs() {
TabsProgressListener.setCallback(function (needsRestore, isRestoring) {
if (needsRestore <= 4) {
TabsProgressListener.unsetCallback();
is(needsRestore, 4, "4/8 tabs restored");
}
});
waitForBrowserState(state, 4, function () {
is(gBrowser.tabs.length, 8, "there are now eight tabs");
is(gBrowser.visibleTabs.length, 4, "four visible tabs");
let cw = TabView.getContentWindow();
is(cw.GroupItems.groupItems.length, 2, "there are now two groupItems");
testSwitchToInactiveGroup();
});
}
function testSwitchToInactiveGroup() {
let firstProgress = true;
TabsProgressListener.setCallback(function (needsRestore, isRestoring) {
if (firstProgress) {
firstProgress = false;
is(isRestoring, 3, "restoring 3 tabs concurrently");
} else {
ok(isRestoring < 4, "restoring max. 3 tabs concurrently");
}
if (needsRestore)
return;
TabsProgressListener.unsetCallback();
is(gBrowser.visibleTabs.length, 4, "four visible tabs");
waitForFocus(finish);
});
gBrowser.selectedTab = gBrowser.tabs[4];
}
function waitForBrowserState(state, numTabs, callback) {
let tabContainer = gBrowser.tabContainer;
tabContainer.addEventListener("SSTabRestored", function onRestored() {
if (--numTabs <= 0) {
tabContainer.removeEventListener("SSTabRestored", onRestored, true);
executeSoon(callback);
}
}, true);
ss.setBrowserState(JSON.stringify(state));
}
function countTabs() {
let needsRestore = 0, isRestoring = 0;
let windowsEnum = Services.wm.getEnumerator("navigator:browser");
while (windowsEnum.hasMoreElements()) {
let window = windowsEnum.getNext();
if (window.closed)
continue;
for (let i = 0; i < window.gBrowser.tabs.length; i++) {
let browser = window.gBrowser.tabs[i].linkedBrowser;
if (browser.__SS_restoreState == TAB_STATE_RESTORING)
isRestoring++;
else if (browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE)
needsRestore++;
}
}
return [needsRestore, isRestoring];
}
var TabsProgressListener = {
init: function () {
gBrowser.addTabsProgressListener(this);
},
uninit: function () {
this.unsetCallback();
gBrowser.removeTabsProgressListener(this);
},
setCallback: function (callback) {
this.callback = callback;
},
unsetCallback: function () {
delete this.callback;
},
onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
let isNetwork = aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK;
let isWindow = aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
if (!(this.callback && isNetwork && isWindow))
return;
let self = this;
let finalize = function () {
if (wasRestoring)
delete aBrowser.__wasRestoring;
self.callback.apply(null, countTabs());
};
let isRestoring = aBrowser.__SS_restoreState == TAB_STATE_RESTORING;
let wasRestoring = !aBrowser.__SS_restoreState && aBrowser.__wasRestoring;
let hasStopped = aStateFlags & Ci.nsIWebProgressListener.STATE_STOP;
if (isRestoring && !hasStopped)
aBrowser.__wasRestoring = true;
if (hasStopped && (isRestoring || wasRestoring))
finalize();
}
}

Просмотреть файл

@ -1,98 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var prefsBranch = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefService).
getBranch("browser.panorama.");
function animateZoom() {
return prefsBranch.getBoolPref("animate_zoom");
}
var contentWindow = null;
registerCleanupFunction(function() {
// reset to default: true
prefsBranch.setBoolPref("animate_zoom", true);
});
function test() {
requestLongerTimeout(2);
waitForExplicitFinish();
ok(!TabView.isVisible(), "Tab View is not visible");
window.addEventListener("tabviewshown", startTesting, false);
TabView.toggle();
}
function startTesting() {
window.removeEventListener("tabviewshown", startTesting, false);
contentWindow = document.getElementById("tab-view").contentWindow;
ok(TabView.isVisible(), "Tab View is visible");
ok(animateZoom(), "By default, we want to animate");
function finishOnHidden() {
contentWindow.removeEventListener("tabviewhidden", finishOnHidden, false);
ok(!TabView.isVisible(), "Tab View is not visible");
finish();
}
function wrapup() {
contentWindow.addEventListener("tabviewhidden", finishOnHidden, false);
TabView.hide();
}
function part2() {
prefsBranch.setBoolPref("animate_zoom", false);
ok(!animateZoom(), "animate_zoom = false");
zoomInAndOut(false, wrapup);
}
function part1() {
prefsBranch.setBoolPref("animate_zoom",true);
ok(animateZoom(), "animate_zoom = true");
zoomInAndOut(true, part2);
}
// start it up!
part1();
}
function zoomInAndOut(transitionsExpected, callback) {
let transitioned = 0;
contentWindow.document.addEventListener("transitionend", onTransitionEnd, false);
function onTransitionEnd(event) {
transitioned++;
}
let onHidden = function() {
contentWindow.removeEventListener("tabviewhidden", onHidden, false);
if (transitionsExpected)
ok(transitioned >= 0, "There can be transitions");
else
ok(!transitioned, "There should have been no transitions");
TabView.toggle();
};
let onShownAgain = function() {
contentWindow.removeEventListener("tabviewshown", onShownAgain, false);
if (transitionsExpected)
ok(transitioned >= 0, "There can be transitions");
else
ok(!transitioned, "There should have been no transitions");
contentWindow.document.removeEventListener("transitionend", onTransitionEnd, false);
callback();
};
contentWindow.addEventListener("tabviewhidden", onHidden, false);
contentWindow.addEventListener("tabviewshown", onShownAgain, false);
// get this party started by hiding tab view
TabView.toggle();
}

Просмотреть файл

@ -1,55 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
TabView.toggle();
}
function onTabViewWindowLoaded() {
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
ok(TabView.isVisible(), "Tab View is visible");
let [originalTab] = gBrowser.visibleTabs;
let contentWindow = document.getElementById("tab-view").contentWindow;
// create group which we'll close
let box1 = new contentWindow.Rect(310, 10, 300, 300);
let group1 = new contentWindow.GroupItem([], { bounds: box1 });
ok(group1.isEmpty(), "This group is empty");
contentWindow.UI.setActive(group1);
let tab1 = gBrowser.loadOneTab("about:blank#1", {inBackground: true});
let tab1Item = tab1._tabViewTabItem;
ok(group1.getChildren().some(child => child == tab1Item), "The tab was made in our new group");
is(group1.getChildren().length, 1, "Only one tab in the first group");
group1.addSubscriber("close", function onClose() {
group1.removeSubscriber("close", onClose);
let onTabViewHidden = function() {
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
// assert that we're no longer in tab view
ok(!TabView.isVisible(), "Tab View is hidden");
finish();
};
window.addEventListener("tabviewhidden", onTabViewHidden, false);
// delay to give time for hidden group DOM element to be removed so
// the appropriate group would get selected when the key
// combination is pressed
executeSoon(function() {
EventUtils.synthesizeKey("e", {accelKey : true, shiftKey: true}, contentWindow);
});
});
hideGroupItem(group1, function () {
// close undo group
let closeButton = group1.$undoContainer.find(".close");
EventUtils.sendMouseEvent(
{ type: "click" }, closeButton[0], contentWindow);
});
}

Просмотреть файл

@ -1,75 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
// Show TabView
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
TabView.toggle();
}
function onTabViewWindowLoaded() {
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
ok(TabView.isVisible(), "Tab View is visible");
let contentWindow = document.getElementById("tab-view").contentWindow;
// establish initial state
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];
ok(contentWindow.GroupItems.groupItems[0]._children[0].tab == originalTab,
"the original tab is in the original group");
// create a second group
let box = new contentWindow.Rect(20, 20, 180, 180);
let groupItem = new contentWindow.GroupItem([], { bounds: box });
is(contentWindow.GroupItems.groupItems.length, 2, "we now have two groups");
contentWindow.UI.setActive(groupItem);
// create a second tab
let normalXulTab = gBrowser.loadOneTab("about:blank");
is(gBrowser.tabs.length, 2, "we now have two tabs");
is(groupItem._children.length, 1, "the new tab was added to the group");
// create a third tab
let appXulTab = gBrowser.loadOneTab("about:blank");
is(gBrowser.tabs.length, 3, "we now have three tabs");
gBrowser.pinTab(appXulTab);
is(groupItem._children.length, 1, "the app tab is not in the group");
// We now have two groups with one tab each, plus an app tab.
// Click into one of the tabs, close it and make sure we don't go back to Tab View.
function onTabViewHidden() {
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
ok(!TabView.isVisible(), "Tab View is hidden because we clicked on the app tab");
// Remove the tab we're looking at.
gBrowser.removeTab(normalXulTab);
// Make sure we haven't returned to TabView; this is the crux of this test
ok(!TabView.isVisible(), "Tab View remains hidden");
// clean up
gBrowser.selectedTab = originalTab;
gBrowser.unpinTab(appXulTab);
gBrowser.removeTab(appXulTab);
ok(groupItem.closeIfEmpty(), "the second group was empty");
// Verify ending state
is(gBrowser.tabs.length, 1, "we finish with one tab");
is(contentWindow.GroupItems.groupItems.length, 1,
"we finish with one group");
ok(!TabView.isVisible(), "we finish with Tab View hidden");
finish();
}
window.addEventListener("tabviewhidden", onTabViewHidden, false);
EventUtils.sendMouseEvent({ type: "mousedown" }, normalXulTab._tabViewTabItem.container, contentWindow);
EventUtils.sendMouseEvent({ type: "mouseup" }, normalXulTab._tabViewTabItem.container, contentWindow);
}

Просмотреть файл

@ -1,154 +0,0 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* Contributor(s):
* Mihai Sucan <mihai.sucan@gmail.com>
* Raymond Lee <raymond@appcoast.com>
* Ian Gilman <ian@iangilman.com>
*/
function test() {
requestLongerTimeout(2);
waitForExplicitFinish();
newWindowWithTabView(onTabViewShown);
}
function onTabViewShown(win) {
let TabView = win.TabView;
let gBrowser = win.gBrowser;
let document = win.document;
ok(TabView.isVisible(), "Tab View is visible");
let contentWindow = document.getElementById("tab-view").contentWindow;
let iQ = contentWindow.iQ;
// establish initial state
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
let box = new contentWindow.Rect(20, 20, 210, 200);
let groupItem = new contentWindow.GroupItem([],
{ bounds: box, title: "test1" });
is(contentWindow.GroupItems.groupItems.length, 2, "we now have two groups");
contentWindow.UI.setActive(groupItem);
// create a tab
let xulTabs = [];
xulTabs.push(gBrowser.loadOneTab("about:blank"));
is(gBrowser.tabs.length, 2, "we now have two tabs");
is(groupItem._children.length, 1, "the new tab was added to the group");
// make sure the group has no app tabs
is(appTabCount(groupItem), 0, "there are no app tab icons");
let tray = groupItem.$appTabTray;
let trayContainer = iQ(tray[0].parentNode);
is(parseInt(trayContainer.css("width")), 0,
"$appTabTray container is not visible");
// pin the tab, make sure the TabItem goes away and the icon comes on
whenAppTabIconAdded(groupItem, function () {
is(groupItem._children.length, 0,
"the app tab's TabItem was removed from the group");
is(appTabCount(groupItem), 1, "there's now one app tab icon");
is(tray.css("-moz-column-count"), 1,
"$appTabTray column count is 1");
isnot(parseInt(trayContainer.css("width")), 0,
"$appTabTray container is visible");
let iconHeight = iQ(iQ(".appTabIcon", tray)[0]).height();
let trayHeight = parseInt(trayContainer.css("height"));
let rows = Math.floor(trayHeight / iconHeight);
let icons = rows * 2;
function pinnedSomeTabs() {
is(appTabCount(groupItem), icons, "number of app tab icons is correct");
is(tray.css("-moz-column-count"), 2,
"$appTabTray column count is 2");
ok(!trayContainer.hasClass("appTabTrayContainerTruncated"),
"$appTabTray container does not have .appTabTrayContainerTruncated");
// add one more tab
xulTabs.push(gBrowser.loadOneTab("about:blank"));
whenAppTabIconAdded(groupItem, function () {
is(tray.css("-moz-column-count"), 3,
"$appTabTray column count is 3");
ok(trayContainer.hasClass("appTabTrayContainerTruncated"),
"$appTabTray container hasClass .appTabTrayContainerTruncated");
// remove all but one app tabs
for (let i = 1; i < xulTabs.length; i++)
gBrowser.removeTab(xulTabs[i]);
is(tray.css("-moz-column-count"), 1,
"$appTabTray column count is 1");
is(appTabCount(groupItem), 1, "there's now one app tab icon");
ok(!trayContainer.hasClass("appTabTrayContainerTruncated"),
"$appTabTray container does not have .appTabTrayContainerTruncated");
// unpin the last remaining tab
gBrowser.unpinTab(xulTabs[0]);
is(parseInt(trayContainer.css("width")), 0,
"$appTabTray container is not visible");
// When the tab was pinned, the last active group with an item got the focus.
// Therefore, switching the focus back to group item one.
contentWindow.UI.setActive(groupItem);
is(appTabCount(groupItem), 0, "there are no app tab icons");
is(groupItem._children.length, 1, "the normal tab shows in the group");
gBrowser.removeTab(xulTabs[0]);
// close the group
groupItem.close();
hideTabView(function() {
ok(!TabView.isVisible(), "Tab View is hidden");
is(contentWindow.GroupItems.groupItems.length, 1,
"we finish with one group");
is(gBrowser.tabs.length, 1, "we finish with one tab");
win.close();
executeSoon(finish);
}, win);
});
win.gBrowser.pinTab(xulTabs[xulTabs.length-1]);
};
// add enough tabs to have two columns
let returnCount = 0;
for (let i = 1; i < icons; i++) {
xulTabs.push(gBrowser.loadOneTab("about:blank"));
whenAppTabIconAdded(groupItem, function () {
if (++returnCount == (icons - 1))
executeSoon(pinnedSomeTabs);
});
win.gBrowser.pinTab(xulTabs[i]);
}
});
win.gBrowser.pinTab(xulTabs[0]);
}
function appTabCount(groupItem) {
return groupItem.container.getElementsByClassName("appTabIcon").length;
}

Просмотреть файл

@ -1,41 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var newTab;
function test() {
waitForExplicitFinish();
newTab = gBrowser.addTab();
gBrowser.pinTab(newTab);
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
TabView.toggle();
}
function onTabViewWindowLoaded() {
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
ok(TabView.isVisible(), "Tab View is visible");
let contentWindow = document.getElementById("tab-view").contentWindow;
is(contentWindow.GroupItems.groupItems.length, 1, "Only one group exists");
is(gBrowser.tabs.length, 2, "Only one tab exists");
ok(newTab.pinned, "The original tab is pinned");
let groupItem = contentWindow.GroupItems.groupItems[0];
is(groupItem.$closeButton[0].style.display, "none",
"The close button is hidden");
gBrowser.unpinTab(newTab);
is(groupItem.$closeButton[0].style.display, "",
"The close button is visible");
let onTabViewHidden = function() {
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
gBrowser.removeTab(newTab);
finish();
}
window.addEventListener("tabviewhidden", onTabViewHidden, false);
TabView.toggle();
}

Просмотреть файл

@ -1,30 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
newWindowWithTabView(function (win) {
registerCleanupFunction(() => win.close());
let cw = win.TabView.getContentWindow();
let groupItems = cw.GroupItems.groupItems;
let groupItem = groupItems[0];
is(groupItems.length, 1, "There is one group item on startup");
whenTabViewIsHidden(function () {
is(groupItems.length, 1, "There is still one group item");
isnot(groupItem.id, groupItems[0].id,
"The initial group item is not the same as the final group item");
is(win.gBrowser.tabs.length, 1, "There is only one tab");
finish();
}, win);
hideGroupItem(groupItem, function () {
// create a new tab
EventUtils.synthesizeKey("t", { accelKey: true }, cw);
});
});
}

Просмотреть файл

@ -1,52 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
TabView.toggle();
}
function onTabViewWindowLoaded() {
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
let contentWindow = document.getElementById("tab-view").contentWindow;
let number = -1;
let onSearchEnabled = function() {
// ensure the dom changes (textbox get focused with number entered) complete
// before doing a check.
executeSoon(function() {
let searchBox = contentWindow.document.getElementById("searchbox");
is(searchBox.value, number, "The seach box matches the number: " + number);
contentWindow.Search.hide(null);
});
}
let onSearchDisabled = function() {
if (++number <= 9) {
EventUtils.synthesizeKey(String(number), { }, contentWindow);
} else {
contentWindow.removeEventListener(
"tabviewsearchenabled", onSearchEnabled, false);
contentWindow.removeEventListener(
"tabviewsearchdisabled", onSearchDisabled, false);
let endGame = function() {
window.removeEventListener("tabviewhidden", endGame, false);
ok(!TabView.isVisible(), "Tab View is hidden");
finish();
}
window.addEventListener("tabviewhidden", endGame, false);
TabView.toggle();
}
}
contentWindow.addEventListener(
"tabviewsearchenabled", onSearchEnabled, false);
contentWindow.addEventListener(
"tabviewsearchdisabled", onSearchDisabled, false);
onSearchDisabled();
}

Просмотреть файл

@ -1,82 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
newWindowWithTabView(part1);
}
function part1(win) {
registerCleanupFunction(() => win.close());
let contentWindow = win.TabView.getContentWindow();
is(contentWindow.GroupItems.groupItems.length, 1, "Has only one group");
let originalTab = win.gBrowser.selectedTab;
let originalGroup = contentWindow.GroupItems.groupItems[0];
let newTab = win.gBrowser.loadOneTab("about:blank", {inBackground: true});
is(originalGroup.getChildren().length, 2, "The original group now has two tabs");
// create group two with the new tab
let box = new contentWindow.Rect(300,300,150,150);
let newGroup = new contentWindow.GroupItem([], {bounds: box, immediately: true});
newGroup.add(newTab._tabViewTabItem, {immediately: true});
// ensure active group item and tab
contentWindow.UI.setActive(originalGroup);
is(contentWindow.GroupItems.getActiveGroupItem(), originalGroup,
"The original group is active");
is(contentWindow.UI.getActiveTab(), originalTab._tabViewTabItem,
"The original tab is active");
function checkActive(callback, time) {
is(contentWindow.GroupItems.getActiveGroupItem(), newGroup,
"The new group is active");
is(contentWindow.UI.getActiveTab(), newTab._tabViewTabItem,
"The new tab is active");
if (time)
setTimeout(callback, time);
else
callback();
}
// click on the new tab, and check that the new tab and group are active
// at two times: 10 ms after (still during the animation) and
// 500 ms after (after the animation, hopefully). Either way, the new
// tab and group should be active.
EventUtils.sendMouseEvent({ type: "mousedown" },
newTab._tabViewTabItem.container, contentWindow);
EventUtils.sendMouseEvent({ type: "mouseup" },
newTab._tabViewTabItem.container, contentWindow);
setTimeout(function() {
checkActive(function() {
checkActive(function() {
win.close();
newWindowWithTabView(part2);
});
}, 490);
}, 10)
}
function part2(win) {
registerCleanupFunction(() => win.close());
let newTab = win.gBrowser.loadOneTab("about:blank", {inBackground: true});
hideTabView(function() {
let selectedTab = win.gBrowser.selectedTab;
isnot(selectedTab, newTab, "They are different tabs");
// switch the selected tab to new tab
win.gBrowser.selectedTab = newTab;
showTabView(function () {
hideTabView(function () {
is(win.gBrowser.selectedTab, newTab,
"The selected tab should be the same as before (new tab)");
waitForFocus(finish);
}, win);
}, win);
}, win);
}

Просмотреть файл

@ -1,25 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
newWindowWithTabView(function (win) {
registerCleanupFunction(() => win.close());
let cw = win.TabView.getContentWindow();
let groupItem = cw.GroupItems.groupItems[0];
groupItem.setBounds(new cw.Rect(cw.innerWidth - 200, 0, 200, 200));
whenTabViewIsHidden(() => waitForFocus(finish), win);
waitForFocus(function () {
let button = cw.document.getElementById("exit-button");
EventUtils.synthesizeMouseAtCenter(button, {}, cw);
}, cw);
});
// This test relies on the test timing out in order to indicate failure so
// let's add a dummy pass.
ok(true, "Each test requires at least one pass, fail or todo so here is a pass.");
}

Просмотреть файл

@ -1,71 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var newWin;
function test() {
let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
requestLongerTimeout(2);
waitForExplicitFinish();
// open a new window and setup the window state.
newWin = openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no", "about:blank");
whenWindowLoaded(newWin, function () {
let newState = {
windows: [{
tabs: [{
entries: [{ "url": "about:blank" }],
hidden: true,
attributes: {},
extData: {
"tabview-tab":
'{"bounds":{"left":20,"top":35,"width":280,"height":210},' +
'"userSize":null,"url":"about:blank","groupID":1,' +
'"imageData":null,"title":null}'
}
},{
entries: [{ url: "about:blank" }],
index: 1,
hidden: false,
attributes: {},
extData: {
"tabview-tab":
'{"bounds":{"left":375,"top":35,"width":280,"height":210},' +
'"userSize":null,"url":"about:blank","groupID":2,' +
'"imageData":null,"title":null}'
}
}],
selected:2,
_closedTabs: [],
extData: {
"tabview-groups": '{"nextID":3,"activeGroupId":2}',
"tabview-group":
'{"1":{"bounds":{"left":15,"top":10,"width":320,"height":375},' +
'"userSize":null,"title":"","id":1},' +
'"2":{"bounds":{"left":380,"top":5,"width":320,"height":375},' +
'"userSize":null,"title":"","id":2}}',
"tabview-ui": '{"pageBounds":{"left":0,"top":0,"width":875,"height":650}}'
}, sizemode:"normal"
}]
};
ss.setWindowState(newWin, JSON.stringify(newState), true);
// add a new tab.
newWin.gBrowser.addTab();
is(newWin.gBrowser.tabs.length, 3, "There are 3 browser tabs");
let onTabViewShow = function() {
newWin.removeEventListener("tabviewshown", onTabViewShow, false);
let contentWindow = newWin.TabView.getContentWindow();
is(contentWindow.GroupItems.groupItems.length, 2, "Has two group items");
// clean up and finish
newWin.close();
finish();
}
newWin.addEventListener("tabviewshown", onTabViewShow, false);
waitForFocus(function() { newWin.TabView.toggle(); });
});
}

Просмотреть файл

@ -1,57 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var cw;
function test() {
waitForExplicitFinish();
showTabView(function() {
cw = TabView.getContentWindow();
whenSearchIsEnabled(function() {
ok(cw.Search.isEnabled(), "The search is disabled");
// open a new window and it would have the focus
newWindowWithTabView(function(win) {
registerCleanupFunction(function() {
win.close();
hideTabView();
});
testClickOnSearchShade(win);
});
});
EventUtils.synthesizeKey("VK_SLASH", {}, cw);
});
}
function testClickOnSearchShade(win) {
// click on the window with search enabled.
let searchshade = cw.document.getElementById("searchshade");
EventUtils.sendMouseEvent({ type: "click" }, searchshade, cw);
waitForFocus(function() {
ok(cw.Search.isEnabled(), "The search is still enabled after the search shade is clicked");
testFocusInactiveWindow(win, cw);
});
}
function testFocusInactiveWindow(win) {
win.focus();
// focus inactive window
window.focus();
// need to use exeuteSoon as the _blockClick would be set to false after a setTimeout(,0)
executeSoon(function() {
ok(cw.Search.isEnabled(), "The search is still enabled when inactive window has focus");
whenSearchIsDisabled(function() {
hideTabView(finish);
});
let searchshade = cw.document.getElementById("searchshade");
EventUtils.synthesizeMouseAtCenter(searchshade, {}, cw);
});
}

Просмотреть файл

@ -1,72 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const TEST_URL = 'data:text/html,<script>window.onbeforeunload=' +
'function(e){e.returnValue="?"}</script>';
SpecialPowers.pushPrefEnv({"set": [["dom.require_user_interaction_for_beforeunload", false]]});
function test() {
waitForExplicitFinish();
showTabView(onTabViewShown);
}
function onTabViewShown() {
let contentWindow = TabView.getContentWindow();
let groupItemOne = contentWindow.GroupItems.getActiveGroupItem();
let groupItemTwo = createGroupItemWithTabs(window, 300, 300, 10, [TEST_URL]);
afterAllTabsLoaded(function () {
testStayOnPage(contentWindow, groupItemOne, groupItemTwo);
});
}
function testStayOnPage(contentWindow, groupItemOne, groupItemTwo) {
// We created a new tab group with a second tab above, so let's
// pick that second tab here and wait for its onbeforeunload dialog.
let browser = gBrowser.browsers[1];
waitForOnBeforeUnloadDialog(browser, function (btnLeave, btnStay) {
executeSoon(function () {
is(gBrowser.tabs.length, 2,
"The total number of tab is 2 when staying on the page");
is(contentWindow.TabItems.getItems().length, 2,
"The total number of tab items is 2 when staying on the page");
showTabView(function () {
// start the next test
testLeavePage(contentWindow, groupItemOne, groupItemTwo);
});
});
// stay on page
btnStay.click();
});
closeGroupItem(groupItemTwo);
}
function testLeavePage(contentWindow, groupItemOne, groupItemTwo) {
// The second tab hasn't been closed yet because we chose to stay. Wait
// for the onbeforeunload dialog again and leave the page this time.
let browser = gBrowser.browsers[1];
waitForOnBeforeUnloadDialog(browser, function (btnLeave, btnStay) {
// clean up and finish the test
groupItemTwo.addSubscriber("close", function onClose() {
groupItemTwo.removeSubscriber("close", onClose);
is(gBrowser.tabs.length, 1,
"The total number of tab is 1 after leaving the page");
is(contentWindow.TabItems.getItems().length, 1,
"The total number of tab items is 1 after leaving the page");
hideTabView(finish);
});
// Leave page
btnLeave.click();
});
closeGroupItem(groupItemTwo);
}

Просмотреть файл

@ -1,80 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* This file tests that, when there is an app tab that references an invalid
* favicon, the default favicon appears the group app tab tray, instead of an
* empty image that would not be visible.
*/
const fi = Cc["@mozilla.org/browser/favicon-service;1"].
getService(Ci.nsIFaviconService);
var newTab;
function test() {
waitForExplicitFinish();
newTab = gBrowser.addTab();
showTabView(function() {
let cw = TabView.getContentWindow();
whenAppTabIconAdded(cw.GroupItems.groupItems[0], onTabPinned);
gBrowser.pinTab(newTab);
})
}
function onTabPinned() {
let contentWindow = TabView.getContentWindow();
is(contentWindow.GroupItems.groupItems.length, 1,
"There is one group item on startup");
let groupItem = contentWindow.GroupItems.groupItems[0];
let icon = contentWindow.iQ(".appTabIcon", groupItem.$appTabTray)[0];
let $icon = contentWindow.iQ(icon);
is($icon.data("xulTab"), newTab,
"The app tab icon has the right tab reference")
// check to see whether it's showing the default one or not.
is($icon.attr("src"), fi.defaultFavicon.spec,
"The icon is showing the default fav icon for blank tab");
let errorHandler = function(event) {
newTab.removeEventListener("error", errorHandler, false);
// since the browser code and test code are invoked when an error event is
// fired, a delay is used here to avoid the test code run before the browser
// code.
executeSoon(function() {
let iconSrc = $icon.attr("src");
// with moz-anno:favicon automatically redirects to the default favIcon
// if the given url is invalid
ok(iconSrc.startsWith("moz-anno:favicon:"),
"The icon url starts with moz-anno:favicon so the default fav icon would be displayed");
// At this point, as an additional integrity check we could also verify
// that the iconSrc URI does not have any associated favicon data. This
// kind of check, however, is not easily supported by the asynchronous
// favicon API. Fortunately, the fact that we received the error event
// already indicates that the original favicon was not available.
// Morevover, since we are using a "moz-anno:favicon:" URI, we know that
// we'll not display an empty icon, but the default favicon.
// clean up
gBrowser.removeTab(newTab);
let endGame = function() {
window.removeEventListener("tabviewhidden", endGame, false);
ok(!TabView.isVisible(), "Tab View is hidden");
finish();
}
window.addEventListener("tabviewhidden", endGame, false);
TabView.toggle();
});
};
newTab.addEventListener("error", errorHandler, false);
newTab.linkedBrowser.loadURI(
"http://mochi.test:8888/browser/browser/components/tabview/test/test_bug600645.html");
}

Просмотреть файл

@ -1,45 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
let cw;
let createGroupItem = function () {
let bounds = new cw.Rect(20, 20, 150, 150);
let groupItem = new cw.GroupItem([], {bounds: bounds, immediately: true});
cw.UI.setActive(groupItem);
gBrowser.loadOneTab('about:blank', {inBackground: true});
return groupItem;
}
let testVeryQuickDragAndDrop = function () {
let sourceGroup = createGroupItem();
let targetGroup = cw.GroupItems.groupItems[0];
sourceGroup.pushAway(true);
targetGroup.pushAway(true);
let sourceTab = sourceGroup.getChild(0).container;
EventUtils.synthesizeMouseAtCenter(sourceTab, {type: 'mousedown'}, cw);
let targetTab = targetGroup.getChild(0).container;
EventUtils.synthesizeMouseAtCenter(targetTab, {type: 'mousemove'}, cw);
EventUtils.synthesizeMouseAtCenter(targetTab, {type: 'mouseup'}, cw);
is(targetGroup.getChildren().length, 2, 'target group has two tabs');
is(cw.GroupItems.groupItems.length, 1, 'sourceGroup was closed');
isnot(cw.GroupItems.groupItems[0], sourceGroup, 'sourceGroup was closed');
targetGroup.getChild(0).close();
hideTabView(finish);
}
waitForExplicitFinish();
showTabView(function () {
cw = TabView.getContentWindow();
afterAllTabsLoaded(testVeryQuickDragAndDrop);
});
}

Просмотреть файл

@ -1,45 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
let checkUpdateTimes = function (groupItem) {
let children = groupItem.getChildren();
let earliestUpdateTime = children.shift()._testLastTabUpdateTime;
children.forEach(function (tabItem) {
let updateTime = tabItem._testLastTabUpdateTime;
ok(earliestUpdateTime <= updateTime, "Stacked group item update (" +
updateTime + ") > first item (" + earliestUpdateTime + ")");
});
}
waitForExplicitFinish();
newWindowWithTabView(function (win) {
registerCleanupFunction(() => win.close());
let numTabsToUpdate = 10;
let groupItem = createGroupItemWithBlankTabs(win, 150, 150, 100, numTabsToUpdate, false);
ok(groupItem.isStacked(), "groupItem is stacked");
let cw = win.TabView.getContentWindow();
cw.TabItems.pausePainting();
groupItem.getChildren().forEach(function (tabItem) {
tabItem.addSubscriber("updated", function onUpdated() {
tabItem.removeSubscriber("updated", onUpdated);
tabItem._testLastTabUpdateTime = tabItem._lastTabUpdateTime;
if (--numTabsToUpdate)
return;
checkUpdateTimes(groupItem);
finish();
});
cw.TabItems.update(tabItem.tab);
});
cw.TabItems.resumePainting();
});
}

Просмотреть файл

@ -1,41 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var contentWindow;
var contentElement;
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
if (gBrowser.tabs.length > 1)
gBrowser.removeTab(gBrowser.tabs[1]);
hideTabView();
});
showTabView(function() {
contentWindow = TabView.getContentWindow();
contentElement = contentWindow.document.getElementById("content");
test1();
});
}
function test1() {
let groupItems = contentWindow.GroupItems.groupItems;
is(groupItems.length, 1, "there is one groupItem");
whenTabViewIsHidden(function() {
gBrowser.selectedTab = gBrowser.tabs[0];
is(groupItems.length, 2, "there are two groupItems");
closeGroupItem(groupItems[1], finish);
});
// double click
doubleClick(contentElement, 0);
}
function doubleClick(targetElement, buttonCode) {
EventUtils.sendMouseEvent(
{ type: "dblclick", button: buttonCode }, targetElement, contentWindow);
}

Просмотреть файл

@ -1,16 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
showTabView(function () {
let [tab] = gBrowser.tabs;
let groupId = tab._tabViewTabItem.parent.id;
TabView.moveTabTo(tab, groupId);
is(tab._tabViewTabItem.parent.id, groupId, 'tab did not change its group');
hideTabView(finish);
});
}

Просмотреть файл

@ -1,32 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
let newTabs = []
// add enough tabs so the close buttons are hidden and then check the closebuttons attribute
do {
let newTab = gBrowser.addTab("about:blank", {skipAnimation: true});
newTabs.push(newTab);
} while (gBrowser.visibleTabs[0].getBoundingClientRect().width > gBrowser.tabContainer.mTabClipWidth)
// a setTimeout() in addTab is used to trigger adjustTabstrip() so we need a delay here as well.
executeSoon(function() {
is(gBrowser.tabContainer.getAttribute("closebuttons"), "activetab", "Only show button on selected tab.");
// move a tab to another group and check the closebuttons attribute
TabView._initFrame(function() {
TabView.moveTabTo(newTabs[newTabs.length - 1], null);
ok(gBrowser.visibleTabs[0].getBoundingClientRect().width > gBrowser.tabContainer.mTabClipWidth,
"Tab width is bigger than tab clip width");
is(gBrowser.tabContainer.getAttribute("closebuttons"), "", "Show button on all tabs.")
// clean up and finish
newTabs.forEach(function(tab) {
gBrowser.removeTab(tab);
});
finish();
});
});
}

Просмотреть файл

@ -1,81 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
let cw;
let assertNumberOfGroupItems = function (num) {
let groupItems = cw.GroupItems.groupItems;
is(groupItems.length, num, "number of groupItems is " + num);
};
let dragTabOutOfGroup = function (groupItem) {
let tabItem = groupItem.getChild(0);
let target = tabItem.container;
EventUtils.synthesizeMouseAtCenter(target, {type: "mousedown"}, cw);
EventUtils.synthesizeMouse(target, 400, 100, {type: "mousemove"}, cw);
EventUtils.synthesizeMouseAtCenter(target, {type: "mouseup"}, cw);
};
let testCreateGroup = function (callback) {
let content = cw.document.getElementById("content");
// drag to create a new group
EventUtils.synthesizeMouse(content, 400, 50, {type: "mousedown"}, cw);
EventUtils.synthesizeMouse(content, 500, 250, {type: "mousemove"}, cw);
EventUtils.synthesizeMouse(content, 500, 250, {type: "mouseup"}, cw);
assertNumberOfGroupItems(2);
// enter a title for the new group
EventUtils.synthesizeKey("t", {}, cw);
EventUtils.synthesizeKey("VK_RETURN", {}, cw);
let groupItem = cw.GroupItems.groupItems[1];
is(groupItem.getTitle(), "t", "new groupItem's title is correct");
closeGroupItem(groupItem, callback);
};
let testDragOutOfGroup = function (callback) {
assertNumberOfGroupItems(1);
let groupItem = cw.GroupItems.groupItems[0];
dragTabOutOfGroup(groupItem);
assertNumberOfGroupItems(2);
// enter a title for the new group
EventUtils.synthesizeKey("t", {}, cw);
EventUtils.synthesizeKey("VK_RETURN", {}, cw);
groupItem = cw.GroupItems.groupItems[1];
is(groupItem.getTitle(), "t", "new groupItem's title is correct");
closeGroupItem(groupItem, callback);
};
let onLoad = function (win) {
registerCleanupFunction(() => win.close());
for (let i = 0; i < 2; i++)
win.gBrowser.addTab();
};
let onShow = function (win) {
cw = win.TabView.getContentWindow();
assertNumberOfGroupItems(1);
let groupItem = cw.GroupItems.groupItems[0];
groupItem.setSize(200, 600, true);
waitForFocus(function () {
testCreateGroup(function () {
testDragOutOfGroup(finish);
});
}, cw);
};
waitForExplicitFinish();
newWindowWithTabView(onShow, onLoad);
}

Просмотреть файл

@ -1,43 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var tabOne;
var tabTwo;
function test() {
waitForExplicitFinish();
tabOne = gBrowser.addTab("http://mochi.test:8888/");
tabTwo = gBrowser.addTab("http://mochi.test:8888/browser/browser/components/tabview/test/dummy_page.html");
afterAllTabsLoaded(function () {
// make sure the tab one is selected because undoCloseTab() would remove
// the selected tab if it's a blank tab.
gBrowser.selectedTab = tabOne;
showTabView(onTabViewWindowLoaded);
});
}
function onTabViewWindowLoaded() {
let contentWindow = TabView.getContentWindow();
let groupItems = contentWindow.GroupItems.groupItems;
is(groupItems.length, 1, "There is only one group");
is(groupItems[0].getChildren().length, 3, "The group has three tab items");
BrowserTestUtils.removeTab(tabTwo).then(() => {
ok(TabView.isVisible(), "Tab View is still visible after removing a tab");
is(groupItems[0].getChildren().length, 2, "The group has two tab items");
restoreTab(function (tabTwo) {
ok(TabView.isVisible(), "Tab View is still visible after restoring a tab");
is(groupItems[0].getChildren().length, 3, "The group still has three tab items");
// clean up and finish
hideTabView(function () {
gBrowser.removeTab(tabOne);
gBrowser.removeTab(tabTwo);
finish();
});
});
});
}

Просмотреть файл

@ -1,41 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
let pinnedTab = gBrowser.addTab();
gBrowser.pinTab(pinnedTab);
registerCleanupFunction(function() {
gBrowser.unpinTab(pinnedTab);
// Don't remove the initial tab.
gBrowser.moveTabTo(gBrowser.tabs[1], 0);
while (gBrowser.tabs[1])
gBrowser.removeTab(gBrowser.tabs[1]);
hideTabView();
});
showTabView(function() {
let cw = TabView.getContentWindow();
let groupItemOne = cw.GroupItems.groupItems[0];
let groupItemTwo = createGroupItemWithBlankTabs(window, 250, 250, 40, 1);
is(cw.GroupItems.groupItems.length, 2, "Two group items");
hideTabView(function() {
gBrowser.selectedTab = pinnedTab;
is(cw.GroupItems.getActiveGroupItem(), groupItemTwo, "Group two is active");
is(gBrowser.selectedTab, pinnedTab, "Selected tab is the pinned tab");
goToNextGroup();
is(cw.GroupItems.getActiveGroupItem(), groupItemOne, "Group one is active");
is(gBrowser.selectedTab, pinnedTab, "Selected tab is the pinned tab");
finish();
});
});
}

Просмотреть файл

@ -1,30 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
Components.utils.import("resource://gre/modules/Promise.jsm", this);
function test() {
waitForExplicitFinish();
newWindowWithTabView(onTabViewWindowLoaded);
}
function onTabViewWindowLoaded(win) {
let contentWindow = win.TabView.getContentWindow();
is(contentWindow.GroupItems.groupItems.length, 1,
"There is one group item on startup");
is(win.gBrowser.tabs.length, 1, "There is one tab on startup");
let groupItem = contentWindow.GroupItems.groupItems[0];
hideGroupItem(groupItem, function () {
hideTabView(() => {
is(contentWindow.GroupItems.groupItems.length, 1,
"There is still one group item");
isnot(groupItem, contentWindow.GroupItems.groupItems[0],
"The initial group item is not the same as the final group item");
is(win.gBrowser.tabs.length, 1, "There is only one tab");
ok(!win.TabView.isVisible(), "Tab View is hidden");
promiseWindowClosed(win).then(finish);
}, win);
});
}

Просмотреть файл

@ -1,36 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
let origTab = gBrowser.visibleTabs[0];
let newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
let relatedTab = gBrowser.addTab("about:blank", { ownerTab: newTab });
// init the frame, move the owner tab to a new group and close the related
// tab.
TabView._initFrame(function() {
let newTabGroupItemId = newTab._tabViewTabItem.parent.id;
is(relatedTab.owner, newTab, "The related tab's owner is the right tab");
// move current tab to a new group
TabView.moveTabTo(newTab, null);
// close the related tab
gBrowser.removeTab(relatedTab);
is(gBrowser.visibleTabs.length, 1, "The number of visible tabs is 1");
is(gBrowser.visibleTabs[0], origTab,
"The original tab is the only visible tab");
isnot(newTab._tabViewTabItem.parent.id, newTabGroupItemId,
"The moved tab item has a new group id");
// clean up
gBrowser.removeTab(newTab);
finish();
});
}

Просмотреть файл

@ -1,54 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
let cw;
let createGroupItem = function () {
let bounds = new cw.Rect(20, 20, 200, 200);
let groupItem = new cw.GroupItem([], {bounds: bounds, immediately: true});
cw.UI.setActive(groupItem);
gBrowser.loadOneTab('about:blank', {inBackground: true});
return groupItem;
}
let finishTest = function () {
ok(!TabView.isVisible(), 'cleanup: tabview is hidden');
is(gBrowser.tabs.length, 1, 'cleanup: there is one tab, only');
is(cw.GroupItems.groupItems.length, 1, 'cleanup: there is one group, only');
finish();
}
let testAddChildFromAnotherGroup = function () {
let sourceGroup = cw.GroupItems.groupItems[0];
let targetGroup = createGroupItem();
afterAllTabsLoaded(function () {
// check setup
is(sourceGroup.getChildren().length, 1, 'setup: source group has one child');
is(targetGroup.getChildren().length, 1, 'setup: target group has one child');
let tabItem = sourceGroup.getChild(0);
targetGroup.add(tabItem);
// check state after adding tabItem to targetGroup
is(tabItem.parent, targetGroup, 'tabItem changed groups');
is(cw.GroupItems.groupItems.length, 1, 'source group was closed automatically');
is(targetGroup.getChildren().length, 2, 'target group has now two children');
// cleanup and finish
targetGroup.getChild(0).close();
hideTabView(finishTest);
});
}
waitForExplicitFinish();
showTabView(function () {
cw = TabView.getContentWindow();
testAddChildFromAnotherGroup();
});
}

Просмотреть файл

@ -1,242 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
requestLongerTimeout(4);
let cw;
let win;
let groupItem;
let next = function () {
let test = tests.shift();
if (test) {
test();
return;
}
win.close();
finish();
}
let closeTabItemManually = function (tabItem) {
EventUtils.synthesizeMouseAtCenter(tabItem.container, {button: 1}, cw);
}
let prepareTest = function (testName) {
let originalBounds = groupItem.getChild(0).getBounds();
let tabItem = groupItem.getChild(1);
let bounds = tabItem.getBounds();
closeTabItemManually(tabItem);
ok(originalBounds.equals(groupItem.getChild(0).getBounds()), testName + ': tabs did not change their size');
ok(bounds.equals(groupItem.getChild(1).getBounds()), testName + ': third tab is now on second tab\'s previous position');
return originalBounds;
}
let cleanUpTest = function (testName, originalBounds, callback) {
// Use setTimeout here because the groupItem.arrange() call uses
// animation to re-arrange the tabItems.
win.setTimeout(function () {
ok(!originalBounds.equals(groupItem.getChild(0).getBounds()), testName + ': tabs changed their size');
// cleanup
cw.UI.setActive(groupItem);
win.gBrowser.loadOneTab('about:blank', {inBackground: true});
afterAllTabsLoaded(callback, win);
}, 500);
}
let tests = [];
// focus group title's input field to cause item arrange
let testFocusTitle = function () {
let originalBounds = prepareTest('testFocusTitle');
let target = groupItem.$titleShield[0];
EventUtils.synthesizeMouseAtCenter(target, {}, cw);
cleanUpTest('testFocusTitle', originalBounds, next);
}
// hide tabview to cause item arrange
let testHideTabView = function () {
let originalBounds = prepareTest('testHideTabView');
hideTabView(function () {
cleanUpTest('testHideTabView', originalBounds, function () {
showTabView(next, win);
});
}, win);
}
// (undo) close a group to cause item arrange
let testCloseGroupUndo = function () {
let originalBounds = prepareTest('testCloseGroupUndo');
hideGroupItem(groupItem, function () {
unhideGroupItem(groupItem, function () {
cleanUpTest('testCloseGroupUndo', originalBounds, next);
});
});
}
// leave the group's container with the mouse to cause item arrange
let testMouseOut = function () {
let originalBounds = prepareTest('testMouseOut');
let doc = cw.document.documentElement;
let bounds = groupItem.getBounds();
EventUtils.synthesizeMouse(doc, bounds.right - 5, bounds.bottom - 5, {type: 'mousemove'}, cw);
ok(originalBounds.equals(groupItem.getChild(0).getBounds()), 'testMouseOut: tabs did not change their size');
EventUtils.synthesizeMouse(doc, bounds.right + 1, bounds.bottom + 1, {type: 'mousemove'}, cw);
cleanUpTest('testMouseOut', originalBounds, next);
}
// sort item (drag it around) in its group to cause item arrange
let testSortInGroup = function () {
let originalBounds = prepareTest('testSortInGroup');
let target = groupItem.getChild(0).container;
// simulate drag/drop sorting
EventUtils.synthesizeMouse(target, 20, 20, {type: 'mousedown'}, cw);
EventUtils.synthesizeMouse(target, 40, 20, {type: 'mousemove'}, cw);
EventUtils.synthesizeMouse(target, 20, 20, {type: 'mouseup'}, cw);
cleanUpTest('testSortInGroup', originalBounds, next);
}
// arrange items when the containing group is resized
let testResizeGroup = function () {
let originalBounds = prepareTest('testResizeGroup');
let oldBounds = groupItem.getBounds();
let resizer = groupItem.$resizer[0];
// simulate drag/drop resizing
EventUtils.synthesizeMouse(resizer, 5, 5, {type: 'mousedown'}, cw);
EventUtils.synthesizeMouse(resizer, 40, 20, {type: 'mousemove'}, cw);
EventUtils.synthesizeMouse(resizer, 20, 20, {type: 'mouseup'}, cw);
// reset group size
groupItem.setBounds(oldBounds);
groupItem.setUserSize();
cleanUpTest('testResizeGroup', originalBounds, next);
}
// make sure we don't freeze item size when removing an item from a stack
let testRemoveWhileStacked = function () {
let oldBounds = groupItem.getBounds();
groupItem.setSize(250, 250, true);
groupItem.setUserSize();
ok(!groupItem.isStacked(), 'testRemoveWhileStacked: group is not stacked');
let originalBounds;
let tabItem = groupItem.getChild(0);
// add new tabs to let the group stack
while (!groupItem.isStacked()) {
originalBounds = tabItem.getBounds();
win.gBrowser.addTab();
}
afterAllTabsLoaded(function () {
tabItem.close();
ok(!groupItem.isStacked(), 'testRemoveWhileStacked: group is not stacked');
let bounds = groupItem.getChild(0).getBounds();
ok(originalBounds.equals(bounds), 'testRemoveWhileStacked: tabs did not change their size');
// reset group size
groupItem.setBounds(oldBounds);
groupItem.setUserSize();
next();
}, win);
}
// 1) make sure item size is frozen when removing an item in expanded mode
// 2) make sure item size stays frozen while moving the mouse in the expanded
// layer
let testExpandedMode = function () {
let oldBounds = groupItem.getBounds();
groupItem.setSize(100, 100, true);
groupItem.setUserSize();
ok(groupItem.isStacked(), 'testExpandedMode: group is stacked');
groupItem.addSubscriber('expanded', function onGroupExpanded() {
groupItem.removeSubscriber('expanded', onGroupExpanded);
onExpanded();
});
groupItem.addSubscriber('collapsed', function onGroupCollapsed() {
groupItem.removeSubscriber('collapsed', onGroupCollapsed);
onCollapsed();
});
let onExpanded = function () {
let originalBounds = groupItem.getChild(0).getBounds();
let tabItem = groupItem.getChild(1);
let bounds = tabItem.getBounds();
while (groupItem.getChildren().length > 2)
closeTabItemManually(groupItem.getChild(1));
ok(originalBounds.equals(groupItem.getChild(0).getBounds()), 'testExpandedMode: tabs did not change their size');
// move the mouse over the expanded layer
let trayBounds = groupItem.expanded.bounds;
let target = groupItem.expanded.$tray[0];
EventUtils.synthesizeMouse(target, trayBounds.right - 5, trayBounds.bottom -5, {type: 'mousemove'}, cw);
ok(originalBounds.equals(groupItem.getChild(0).getBounds()), 'testExpandedMode: tabs did not change their size');
groupItem.collapse();
}
let onCollapsed = function () {
// reset group size
groupItem.setBounds(oldBounds);
groupItem.setUserSize();
next();
}
groupItem.expand();
}
tests.push(testFocusTitle);
tests.push(testHideTabView);
tests.push(testCloseGroupUndo);
tests.push(testMouseOut);
tests.push(testSortInGroup);
tests.push(testResizeGroup);
tests.push(testRemoveWhileStacked);
tests.push(testExpandedMode);
waitForExplicitFinish();
newWindowWithTabView(function (tvwin) {
win = tvwin;
registerCleanupFunction(function () {
if (!win.closed)
win.close();
});
cw = win.TabView.getContentWindow();
groupItem = cw.GroupItems.groupItems[0];
groupItem.setSize(400, 200, true);
groupItem.setUserSize();
for (let i=0; i<3; i++)
win.gBrowser.loadOneTab('about:blank', {inBackground: true});
afterAllTabsLoaded(next, win);
});
}

Просмотреть файл

@ -1,96 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
newWindowWithTabView(onTabViewWindowLoaded);
}
function onTabViewWindowLoaded(win) {
win.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
ok(win.TabView.isVisible(), "Tab View is visible");
let contentWindow = win.document.getElementById("tab-view").contentWindow;
let [originalTab] = win.gBrowser.visibleTabs;
let currentGroup = contentWindow.GroupItems.getActiveGroupItem();
// Create a group and make it active
let box = new contentWindow.Rect(100, 100, 370, 370);
let group = new contentWindow.GroupItem([], { bounds: box });
ok(group.isEmpty(), "This group is empty");
contentWindow.UI.setActive(group);
is(contentWindow.GroupItems.getActiveGroupItem(), group, "new group is active");
// Create a bunch of tabs in the group
let bg = {inBackground: true};
let datatext = win.gBrowser.loadOneTab("data:text/plain,bug610242", bg);
let datahtml = win.gBrowser.loadOneTab("data:text/html,<h1>hi!</h1>", bg);
let mozilla = win.gBrowser.loadOneTab("about:mozilla", bg);
let synclog = win.gBrowser.loadOneTab("about:sync-log", bg);
let html = win.gBrowser.loadOneTab("http://example.com", bg);
let png = win.gBrowser.loadOneTab("http://mochi.test:8888/browser/browser/base/content/test/general/moz.png", bg);
let svg = win.gBrowser.loadOneTab("http://mochi.test:8888/browser/browser/base/content/test/general/title_test.svg", bg);
ok(!group.shouldStack(group._children.length), "Group should not stack.");
// PREPARE FINISH:
group.addSubscriber("close", function onClose() {
group.removeSubscriber("close", onClose);
ok(group.isEmpty(), "The group is empty again");
contentWindow.UI.setActive(currentGroup);
isnot(contentWindow.GroupItems.getActiveGroupItem(), null, "There is an active group");
is(win.gBrowser.tabs.length, 1, "There is only one tab left");
is(win.gBrowser.visibleTabs.length, 1, "There is also only one visible tab");
whenTabViewIsHidden(function() {
win.close();
ok(win.closed, "new window is closed");
finish();
}, win);
win.gBrowser.selectedTab = originalTab;
win.TabView.hide();
});
function check(tab, label, visible) {
let display = contentWindow.getComputedStyle(tab._tabViewTabItem.$fav[0], null).getPropertyValue("display");
if (visible) {
is(display, "block", label + " has favicon");
} else {
is(display, "none", label + " has no favicon");
}
}
afterAllTabsLoaded(function() {
let children = group.getChildren();
let len = children.length;
let iconUpdateCounter = 0;
children.forEach(function(tabItem) {
tabItem.addSubscriber("iconUpdated", function onIconUpdated() {
tabItem.removeSubscriber("iconUpdated", onIconUpdated);
if (++iconUpdateCounter == len) {
check(datatext, "datatext", false);
check(datahtml, "datahtml", false);
check(mozilla, "about:mozilla", false);
check(synclog, "about:sync-log", true);
check(html, "html", true);
check(png, "png", false);
check(svg, "svg", true);
// Get rid of the group and its children
// The group close will trigger a finish().
closeGroupItem(group);
}
});
});
afterAllTabItemsUpdated(function () {}, win);
}, win);
}

Просмотреть файл

@ -1,46 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that groups behave properly when closing all tabs but app tabs.
function test() {
let cw, win, groupItem;
let onLoad = function (tvwin) {
win = tvwin;
registerCleanupFunction(() => win.close());
win.gBrowser.pinTab(win.gBrowser.tabs[0]);
win.gBrowser.loadOneTab("about:blank", {inBackground: true});
};
let onShow = function () {
cw = win.TabView.getContentWindow();
is(cw.GroupItems.groupItems.length, 1, "There's only one group");
groupItem = createEmptyGroupItem(cw, 200, 200, 20);
cw.UI.setActive(groupItem);
whenTabViewIsHidden(onHide, win);
cw.UI.goToTab(win.gBrowser.tabs[0]);
};
let onHide = function () {
let tab = win.gBrowser.loadOneTab("about:blank", {inBackground: true});
is(groupItem.getChildren().length, 1, "One tab is in the new group");
executeSoon(function () {
is(win.gBrowser.visibleTabs.length, 2, "There are two tabs displayed");
win.gBrowser.removeTab(tab);
is(groupItem.getChildren().length, 0, "No tabs are in the new group");
is(win.gBrowser.visibleTabs.length, 1, "There is one tab displayed");
is(cw.GroupItems.groupItems.length, 2, "There are two groups still");
finish();
});
};
waitForExplicitFinish();
newWindowWithTabView(onShow, onLoad);
}

Просмотреть файл

@ -1,290 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
Components.utils.import("resource://gre/modules/Promise.jsm", this);
function test() {
let cw;
let win;
let currentTest;
let getGroupItem = function (index) {
return cw.GroupItems.groupItems[index];
}
let createGroupItem = function (numTabs) {
let bounds = new cw.Rect(20, 20, 200, 200);
let groupItem = new cw.GroupItem([], {bounds: bounds, immediately: true});
cw.UI.setActive(groupItem);
for (let i=0; i<numTabs || 0; i++)
win.gBrowser.loadOneTab('about:blank', {inBackground: true});
return groupItem;
}
let tests = [];
let next = function () {
let test = tests.shift();
if (test) {
// check that the previous test left things as expected
if (currentTest) {
currentTest += ' (post-check)';
assertTabViewIsHidden();
assertNumberOfGroupItems(1);
assertNumberOfTabs(1);
}
currentTest = test.name;
showTabView(test.func, win);
} else
promiseWindowClosed(win).then(finish);
}
let assertTabViewIsHidden = function () {
ok(!win.TabView.isVisible(), currentTest + ': tabview is hidden');
}
let assertNumberOfGroupItems = function (num) {
is(cw.GroupItems.groupItems.length, num, currentTest + ': number of groupItems is equal to ' + num);
}
let assertNumberOfTabs = function (num) {
is(win.gBrowser.tabs.length, num, currentTest + ': number of tabs is equal to ' + num);
}
let assertGroupItemRemoved = function (groupItem) {
is(cw.GroupItems.groupItems.indexOf(groupItem), -1, currentTest + ': groupItem was removed');
}
let assertGroupItemExists = function (groupItem) {
isnot(cw.GroupItems.groupItems.indexOf(groupItem), -1, currentTest + ': groupItem still exists');
}
// setup: 1 non-empty group
// action: close the group
// expected: new group with blank tab is created and zoomed into
let testSingleGroup1 = function () {
let groupItem = getGroupItem(0);
closeGroupItem(groupItem, function () {
assertNumberOfGroupItems(1);
assertGroupItemRemoved(groupItem);
whenTabViewIsHidden(next, win);
});
}
// setup: 1 non-empty group
// action: hide the group, exit panorama
// expected: new group with blank tab is created and zoomed into
let testSingleGroup2 = function () {
let groupItem = getGroupItem(0);
hideGroupItem(groupItem, function () {
hideTabView(function () {
assertNumberOfGroupItems(1);
assertGroupItemRemoved(groupItem);
next();
}, win);
});
}
// setup: 2 non-empty groups
// action: close one group
// expected: nothing should happen
let testNonEmptyGroup1 = function () {
let groupItem = getGroupItem(0);
let newGroupItem = createGroupItem(1);
assertNumberOfGroupItems(2);
closeGroupItem(groupItem, function () {
assertNumberOfGroupItems(1);
assertGroupItemExists(newGroupItem);
hideTabView(next, win);
});
}
// setup: 2 non-empty groups
// action: hide one group, exit panorama
// expected: nothing should happen
let testNonEmptyGroup2 = function () {
let groupItem = getGroupItem(0);
let newGroupItem = createGroupItem(1);
assertNumberOfGroupItems(2);
hideGroupItem(groupItem, function () {
hideTabView(function () {
assertNumberOfGroupItems(1);
assertGroupItemRemoved(groupItem);
assertGroupItemExists(newGroupItem);
next();
}, win);
});
}
// setup: 1 pinned tab, 1 empty group
// action: exit panorama
// expected: nothing should happen
let testPinnedTab1 = function () {
win.gBrowser.pinTab(win.gBrowser.selectedTab);
let groupItem = getGroupItem(0);
hideTabView(function () {
assertNumberOfGroupItems(1);
assertGroupItemExists(groupItem);
win.gBrowser.unpinTab(win.gBrowser.selectedTab);
next();
}, win);
}
// setup: 1 pinned tab
// action: exit panorama
// expected: new blank group is created
let testPinnedTab2 = function () {
win.gBrowser.pinTab(win.gBrowser.selectedTab);
getGroupItem(0).close();
hideTabView(function () {
assertNumberOfTabs(1);
assertNumberOfGroupItems(1);
win.gBrowser.unpinTab(win.gBrowser.selectedTab);
next();
}, win);
}
// setup: 1 pinned tab, 1 empty group, 1 non-empty group
// action: close non-empty group
// expected: nothing should happen
let testPinnedTab3 = function () {
win.gBrowser.pinTab(win.gBrowser.selectedTab);
let groupItem = getGroupItem(0);
let newGroupItem = createGroupItem(1);
assertNumberOfGroupItems(2);
closeGroupItem(newGroupItem, function () {
assertNumberOfGroupItems(1);
assertGroupItemExists(groupItem);
win.gBrowser.unpinTab(win.gBrowser.selectedTab);
hideTabView(next, win);
});
}
// setup: 1 pinned tab, 1 empty group, 1 non-empty group
// action: hide non-empty group, exit panorama
// expected: nothing should happen
let testPinnedTab4 = function () {
win.gBrowser.pinTab(win.gBrowser.selectedTab);
let groupItem = getGroupItem(0);
let newGroupItem = createGroupItem(1);
assertNumberOfGroupItems(2);
hideGroupItem(newGroupItem, function () {
hideTabView(function () {
assertNumberOfGroupItems(1);
assertGroupItemExists(groupItem);
assertGroupItemRemoved(newGroupItem);
win.gBrowser.unpinTab(win.gBrowser.selectedTab);
next();
}, win);
});
}
// setup: 1 non-empty group, 1 empty group
// action: close non-empty group
// expected: empty group is re-used, new tab is created and zoomed into
let testEmptyGroup1 = function () {
let groupItem = getGroupItem(0);
let newGroupItem = createGroupItem(0);
assertNumberOfGroupItems(2);
closeGroupItem(groupItem, function () {
assertNumberOfGroupItems(1);
assertGroupItemExists(newGroupItem);
whenTabViewIsHidden(next, win);
});
}
// setup: 1 non-empty group, 1 empty group
// action: hide non-empty group, exit panorama
// expected: empty group is re-used, new tab is created and zoomed into
let testEmptyGroup2 = function () {
let groupItem = getGroupItem(0);
let newGroupItem = createGroupItem(0);
assertNumberOfGroupItems(2);
hideGroupItem(groupItem, function () {
hideTabView(function () {
assertNumberOfGroupItems(1);
assertGroupItemRemoved(groupItem);
assertGroupItemExists(newGroupItem);
next();
}, win);
});
}
// setup: 1 hidden group, 1 non-empty group
// action: close non-empty group
// expected: nothing should happen
let testHiddenGroup1 = function () {
let groupItem = getGroupItem(0);
let hiddenGroupItem = createGroupItem(1);
assertNumberOfGroupItems(2);
hideGroupItem(hiddenGroupItem, function () {
closeGroupItem(groupItem, function () {
assertNumberOfGroupItems(1);
assertGroupItemRemoved(groupItem);
assertGroupItemExists(hiddenGroupItem);
hideTabView(next, win);
});
});
}
// setup: 1 hidden group, 1 non-empty group
// action: hide non-empty group, exit panorama
// expected: new group with blank tab is created and zoomed into
let testHiddenGroup2 = function () {
let groupItem = getGroupItem(0);
let hiddenGroupItem = createGroupItem(1);
assertNumberOfGroupItems(2);
hideGroupItem(hiddenGroupItem, function () {
hideGroupItem(groupItem, function () {
hideTabView(function () {
assertNumberOfGroupItems(1);
assertGroupItemRemoved(groupItem);
assertGroupItemRemoved(hiddenGroupItem);
next();
}, win);
});
});
}
tests.push({name: 'testSingleGroup1', func: testSingleGroup1});
tests.push({name: 'testSingleGroup2', func: testSingleGroup2});
tests.push({name: 'testNonEmptyGroup1', func: testNonEmptyGroup1});
tests.push({name: 'testNonEmptyGroup2', func: testNonEmptyGroup2});
tests.push({name: 'testPinnedTab1', func: testPinnedTab1});
tests.push({name: 'testPinnedTab2', func: testPinnedTab2});
tests.push({name: 'testPinnedTab3', func: testPinnedTab3});
tests.push({name: 'testPinnedTab4', func: testPinnedTab4});
tests.push({name: 'testEmptyGroup1', func: testEmptyGroup1});
tests.push({name: 'testEmptyGroup2', func: testEmptyGroup2});
tests.push({name: 'testHiddenGroup1', func: testHiddenGroup1});
tests.push({name: 'testHiddenGroup2', func: testHiddenGroup2}),
waitForExplicitFinish();
newWindowWithTabView(window => {
win = window;
cw = win.TabView.getContentWindow();
next();
});
}

Просмотреть файл

@ -1,109 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
let cw;
let createGroupItem = function () {
return createGroupItemWithBlankTabs(window, 400, 200, 0, 5);
}
let assertCorrectItemOrder = function (items) {
for (let i=1; i<items.length; i++) {
if (items[i-1].tab._tPos > items[i].tab._tPos) {
ok(false, 'tabs were correctly reordered');
return;
}
}
ok(true, 'tabs were correctly reordered');
}
let testVariousTabOrders = function () {
let groupItem = createGroupItem();
let [tab1, tab2, tab3, tab4, tab5] = groupItem.getChildren();
// prepare tests
let tests = [];
tests.push([tab1, tab2, tab3, tab4, tab5]);
tests.push([tab5, tab4, tab3, tab2, tab1]);
tests.push([tab1, tab2, tab3, tab4]);
tests.push([tab4, tab3, tab2, tab1]);
tests.push([tab1, tab2, tab3]);
tests.push([tab1, tab2, tab3]);
tests.push([tab1, tab3, tab2]);
tests.push([tab2, tab1, tab3]);
tests.push([tab2, tab3, tab1]);
tests.push([tab3, tab1, tab2]);
tests.push([tab3, tab2, tab1]);
tests.push([tab1, tab2]);
tests.push([tab2, tab1]);
tests.push([tab1]);
// test reordering of empty groups - removes the last tab and causes
// the groupItem to close
tests.push([]);
while (tests.length) {
let test = tests.shift();
// prepare
let items = groupItem.getChildren();
while (test.length < items.length)
items[items.length-1].close();
let orig = cw.Utils.copy(items);
items.sort((a, b) => test.indexOf(a) - test.indexOf(b));
// order and check
groupItem.reorderTabsBasedOnTabItemOrder();
assertCorrectItemOrder(items);
// revert to original item order
items.sort((a, b) => orig.indexOf(a) - orig.indexOf(b));
groupItem.reorderTabsBasedOnTabItemOrder();
}
testMoveBetweenGroups();
}
let testMoveBetweenGroups = function () {
let groupItem = createGroupItem();
let groupItem2 = createGroupItem();
afterAllTabsLoaded(function () {
// move item from group1 to group2
let child = groupItem.getChild(2);
groupItem.remove(child);
groupItem2.add(child, {index: 3});
groupItem2.reorderTabsBasedOnTabItemOrder();
assertCorrectItemOrder(groupItem.getChildren());
assertCorrectItemOrder(groupItem2.getChildren());
// move item from group2 to group1
child = groupItem2.getChild(1);
groupItem2.remove(child);
groupItem.add(child, {index: 1});
groupItem.reorderTabsBasedOnTabItemOrder();
assertCorrectItemOrder(groupItem.getChildren());
assertCorrectItemOrder(groupItem2.getChildren());
// cleanup
closeGroupItem(groupItem, function () {
closeGroupItem(groupItem2, function () {
hideTabView(finish);
});
});
});
}
waitForExplicitFinish();
showTabView(function () {
cw = TabView.getContentWindow();
afterAllTabsLoaded(testVariousTabOrders);
});
}

Просмотреть файл

@ -1,20 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
let branch = Services.prefs.getBranch('browser.panorama.');
branch.setBoolPref('experienced_first_run', false);
newWindowWithTabView(function (win) {
is(win.gBrowser.visibleTabs.length, 1, 'There should be one visible tab, only');
win.TabView._initFrame(function () {
is(win.gBrowser.visibleTabs.length, 1, 'There should be one visible tab, only');
win.close();
finish();
});
});
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше