diff --git a/CLOBBER b/CLOBBER index b02b8fc90d36aaa3867d9afd66d4d684ce4d04f9..cc2cb7ee4f26d5c50e570b7a16a1919ae390e00a 100644 --- a/CLOBBER +++ b/CLOBBER @@ -18,4 +18,4 @@ # Modifying this file will now automatically clobber the buildbot machines \o/ # -Bug 928390 requires a clobber because of bug 939416. +Australis landing. diff --git a/accessible/tests/mochitest/events/test_focus_general.html b/accessible/tests/mochitest/events/test_focus_general.html index 55f71d5f7b55db95b297d8d5e4814d00accee3d8..e1a09c6149567e59491125bd4d997a22d0718b43 100644 --- a/accessible/tests/mochitest/events/test_focus_general.html +++ b/accessible/tests/mochitest/events/test_focus_general.html @@ -96,7 +96,7 @@ gQueue.push(new focusElmWhileSubdocIsFocused("link")); gQueue.push(new synthTab(editableDoc, new focusChecker(editableDoc))); - if (WIN) { + if (WIN || LINUX) { // Alt key is used to active menubar and focus menu item on Windows, // other platforms requires setting a ui.key.menuAccessKeyFocuses // preference. diff --git a/accessible/tests/mochitest/events/test_menu.xul b/accessible/tests/mochitest/events/test_menu.xul index a286964a1fbb901ab86514baf68ce9d5c25c2d24..bae36fb7123934d74d4cdf930101a42c2ac61653 100644 --- a/accessible/tests/mochitest/events/test_menu.xul +++ b/accessible/tests/mochitest/events/test_menu.xul @@ -156,7 +156,7 @@ // Alt key is used to active menubar and focus menu item on Windows, // other platforms requires setting a ui.key.menuAccessKeyFocuses // preference. - if (WIN) { + if (WIN || LINUX) { gQueue.push(new focusFileMenu()); gQueue.push(new focusEditMenu()); gQueue.push(new leaveMenubar()); diff --git a/addon-sdk/source/test/test-ui-button.js b/addon-sdk/source/test/test-ui-button.js index f481fae29062ba429d0713c696b27acfa09aa740..3f05eeb774497ed7c4af35cb7d350289818bf8de 100644 --- a/addon-sdk/source/test/test-ui-button.js +++ b/addon-sdk/source/test/test-ui-button.js @@ -11,7 +11,7 @@ module.metadata = { const { Cu } = require('chrome'); const { Loader } = require('sdk/test/loader'); -const data = require('./fixtures'); +const { data } = require('sdk/self'); const { open, focus, close } = require('sdk/window/helpers'); const { setTimeout } = require('sdk/timers'); const { getMostRecentBrowserWindow } = require('sdk/window/utils'); diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index bb29699a8f779c9168d238c3fc06b09e2e9aabd9..88dc128fb8129bce52f388a01376e450ed956671 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -444,11 +444,10 @@ pref("browser.tabs.loadDivertedInBackground", false); pref("browser.tabs.loadBookmarksInBackground", false); pref("browser.tabs.tabClipWidth", 140); pref("browser.tabs.animate", true); -pref("browser.tabs.onTop", true); -#ifdef XP_WIN -pref("browser.tabs.drawInTitlebar", true); -#else +#ifdef UNIX_BUT_NOT_MAC pref("browser.tabs.drawInTitlebar", false); +#else +pref("browser.tabs.drawInTitlebar", true); #endif // Where to show tab close buttons: @@ -1332,3 +1331,6 @@ pref("geo.wifi.uri", "https://www.googleapis.com/geolocation/v1/geolocate?key=%G // Necko IPC security checks only needed for app isolation for cookies/cache/etc: // currently irrelevant for desktop e10s pref("network.disable.ipc.security", true); + +// CustomizableUI debug logging. +pref("browser.uiCustomization.debug", false); diff --git a/browser/base/content/browser-addons.js b/browser/base/content/browser-addons.js index b638f31f9ea2b717446586576803613fcd35287a..fe40e408a2a738deb5dfce9b0b2aae86abf02303 100644 --- a/browser/base/content/browser-addons.js +++ b/browser/base/content/browser-addons.js @@ -178,50 +178,6 @@ const gXPInstallObserver = { } }; -/* - * When addons are installed/uninstalled, check and see if the number of items - * on the add-on bar changed: - * - If an add-on was installed, incrementing the count, show the bar. - * - If an add-on was uninstalled, and no more items are left, hide the bar. - */ -let AddonsMgrListener = { - get addonBar() document.getElementById("addon-bar"), - get statusBar() document.getElementById("status-bar"), - getAddonBarItemCount: function() { - // Take into account the contents of the status bar shim for the count. - var itemCount = this.statusBar.childNodes.length; - - var defaultOrNoninteractive = this.addonBar.getAttribute("defaultset") - .split(",") - .concat(["separator", "spacer", "spring"]); - for (let item of this.addonBar.currentSet.split(",")) { - if (defaultOrNoninteractive.indexOf(item) == -1) - itemCount++; - } - - return itemCount; - }, - onInstalling: function(aAddon) { - this.lastAddonBarCount = this.getAddonBarItemCount(); - }, - onInstalled: function(aAddon) { - if (this.getAddonBarItemCount() > this.lastAddonBarCount) - setToolbarVisibility(this.addonBar, true); - }, - onUninstalling: function(aAddon) { - this.lastAddonBarCount = this.getAddonBarItemCount(); - }, - onUninstalled: function(aAddon) { - if (this.getAddonBarItemCount() == 0) - setToolbarVisibility(this.addonBar, false); - }, - onEnabling: function(aAddon) this.onInstalling(), - onEnabled: function(aAddon) this.onInstalled(), - onDisabling: function(aAddon) this.onUninstalling(), - onDisabled: function(aAddon) this.onUninstalled(), -}; - - var LightWeightThemeWebInstaller = { handleEvent: function (event) { switch (event.type) { @@ -415,3 +371,60 @@ var LightWeightThemeWebInstaller = { node.baseURI); } } + +/* + * Listen for Lightweight Theme styling changes and update the browser's theme accordingly. + */ +let LightweightThemeListener = { + _modifiedStyles: [], + + init: function () { + XPCOMUtils.defineLazyGetter(this, "styleSheet", function() { + for (let i = document.styleSheets.length - 1; i >= 0; i--) { + let sheet = document.styleSheets[i]; + if (sheet.href == "chrome://browser/skin/browser-lightweightTheme.css") + return sheet; + } + }); + + Services.obs.addObserver(this, "lightweight-theme-styling-update", false); + if (document.documentElement.hasAttribute("lwtheme")) + this.updateStyleSheet(document.documentElement.style.backgroundImage); + }, + + uninit: function () { + Services.obs.removeObserver(this, "lightweight-theme-styling-update"); + }, + + /** + * Append the headerImage to the background-image property of all rulesets in + * browser-lightweightTheme.css. + * + * @param headerImage - a string containing a CSS image for the lightweight theme header. + */ + updateStyleSheet: function(headerImage) { + if (!this.styleSheet) + return; + for (let i = 0; i < this.styleSheet.cssRules.length; i++) { + let rule = this.styleSheet.cssRules[i]; + if (!rule.style.backgroundImage) + continue; + + if (!this._modifiedStyles[i]) + this._modifiedStyles[i] = { backgroundImage: rule.style.backgroundImage }; + + rule.style.backgroundImage = this._modifiedStyles[i].backgroundImage + ", " + headerImage; + } + }, + + // nsIObserver + observe: function (aSubject, aTopic, aData) { + if (aTopic != "lightweight-theme-styling-update" || !this.styleSheet) + return; + + let themeData = JSON.parse(aData); + if (!themeData) + return; + this.updateStyleSheet("url(" + themeData.headerURL + ")"); + }, +}; diff --git a/browser/base/content/browser-appmenu.inc b/browser/base/content/browser-appmenu.inc deleted file mode 100644 index 0cd58f2ecf49130ac60770fc6f3efb29855502e7..0000000000000000000000000000000000000000 --- a/browser/base/content/browser-appmenu.inc +++ /dev/null @@ -1,406 +0,0 @@ -# -*- Mode: HTML -*- -# 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/. - -<menupopup id="appmenu-popup" - onpopupshowing="if (event.target == this) { - updateEditUIVisibility(); -#ifdef MOZ_SERVICES_SYNC - gSyncUI.updateUI(); -#endif - return; - } - updateCharacterEncodingMenuState(); - if (event.target.parentNode.parentNode.parentNode.parentNode == this) - this._currentPopup = event.target;"> - <hbox> - <vbox id="appmenuPrimaryPane"> - <splitmenu id="appmenu_newTab" - label="&tabCmd.label;" - command="cmd_newNavigatorTab"> - <menupopup> - <menuitem id="appmenu_newTab_popup" - label="&tabCmd.label;" - command="cmd_newNavigatorTab" - key="key_newNavigatorTab"/> - <menuitem id="appmenu_newNavigator" - label="&newNavigatorCmd.label;" - command="cmd_newNavigator" - key="key_newNavigator"/> - <menuseparator/> - <menuitem id="appmenu_openFile" - label="&openFileCmd.label;" - command="Browser:OpenFile" - key="openFileKb"/> - </menupopup> - </splitmenu> - <menuitem id="appmenu_newPrivateWindow" - class="menuitem-iconic menuitem-iconic-tooltip" - label="&newPrivateWindow.label;" - command="Tools:PrivateBrowsing" - key="key_privatebrowsing"/> - <menuitem label="&goOfflineCmd.label;" - id="appmenu_offlineModeRecovery" - type="checkbox" - observes="workOfflineMenuitemState" - oncommand="BrowserOffline.toggleOfflineStatus();"/> - <menuseparator class="appmenu-menuseparator"/> - <hbox> - <menuitem id="appmenu-edit-label" - label="&appMenuEdit.label;" - disabled="true"/> - <toolbarbutton id="appmenu-cut" - class="appmenu-edit-button" - command="cmd_cut" - onclick="if (!this.disabled) hidePopup();" - tooltiptext="&cutButton.tooltip;"/> - <toolbarbutton id="appmenu-copy" - class="appmenu-edit-button" - command="cmd_copy" - onclick="if (!this.disabled) hidePopup();" - tooltiptext="©Button.tooltip;"/> - <toolbarbutton id="appmenu-paste" - class="appmenu-edit-button" - command="cmd_paste" - onclick="if (!this.disabled) hidePopup();" - tooltiptext="&pasteButton.tooltip;"/> - <spacer flex="1"/> - <menu id="appmenu-editmenu"> - <menupopup id="appmenu-editmenu-menupopup"> - <menuitem id="appmenu-editmenu-cut" - class="menuitem-iconic" - label="&cutCmd.label;" - key="key_cut" - command="cmd_cut"/> - <menuitem id="appmenu-editmenu-copy" - class="menuitem-iconic" - label="©Cmd.label;" - key="key_copy" - command="cmd_copy"/> - <menuitem id="appmenu-editmenu-paste" - class="menuitem-iconic" - label="&pasteCmd.label;" - key="key_paste" - command="cmd_paste"/> - <menuseparator/> - <menuitem id="appmenu-editmenu-undo" - label="&undoCmd.label;" - key="key_undo" - command="cmd_undo"/> - <menuitem id="appmenu-editmenu-redo" - label="&redoCmd.label;" - key="key_redo" - command="cmd_redo"/> - <menuseparator/> - <menuitem id="appmenu-editmenu-selectAll" - label="&selectAllCmd.label;" - key="key_selectAll" - command="cmd_selectAll"/> - <menuseparator/> - <menuitem id="appmenu-editmenu-delete" - label="&deleteCmd.label;" - key="key_delete" - command="cmd_delete"/> - </menupopup> - </menu> - </hbox> - <menuitem id="appmenu_find" - class="menuitem-tooltip" - label="&appMenuFind.label;" - command="cmd_find" - key="key_find"/> - <menuseparator class="appmenu-menuseparator"/> - <menuitem id="appmenu_savePage" - class="menuitem-tooltip" - label="&savePageCmd.label;" - command="Browser:SavePage" - key="key_savePage"/> - <menuitem id="appmenu_sendLink" - label="&emailPageCmd.label;" - command="Browser:SendLink"/> - <splitmenu id="appmenu_print" - iconic="true" - label="&printCmd.label;" - command="cmd_print"> - <menupopup> - <menuitem id="appmenu_print_popup" - class="menuitem-iconic" - label="&printCmd.label;" - command="cmd_print" - key="printKb"/> - <menuitem id="appmenu_printPreview" - label="&printPreviewCmd.label;" - command="cmd_printPreview"/> - <menuitem id="appmenu_printSetup" - label="&printSetupCmd.label;" - command="cmd_pageSetup"/> - </menupopup> - </splitmenu> - <menuseparator class="appmenu-menuseparator"/> - <splitmenu id="appmenu_webDeveloper" - command="Tools:DevToolbox" - label="&appMenuWebDeveloper.label;"> - <menupopup id="appmenu_webDeveloper_popup"> - <menuitem id="appmenu_devToolbox" - observes="devtoolsMenuBroadcaster_DevToolbox"/> - <menuseparator id="appmenu_devtools_separator"/> - <menuitem id="appmenu_devToolbar" - observes="devtoolsMenuBroadcaster_DevToolbar"/> - <menuitem id="appmenu_devAppMgr" - observes="devtoolsMenuBroadcaster_DevAppMgr"/> - <menuitem id="appmenu_chromeDebugger" - observes="devtoolsMenuBroadcaster_ChromeDebugger"/> - <menuitem id="appmenu_browserConsole" - observes="devtoolsMenuBroadcaster_BrowserConsole"/> - <menuitem id="appmenu_responsiveUI" - observes="devtoolsMenuBroadcaster_ResponsiveUI"/> - <menuitem id="appmenu_scratchpad" - observes="devtoolsMenuBroadcaster_Scratchpad"/> - <menuitem id="appmenu_pageSource" - observes="devtoolsMenuBroadcaster_PageSource"/> - <menuitem id="appmenu_errorConsole" - observes="devtoolsMenuBroadcaster_ErrorConsole"/> - <menuitem id="appmenu_devtools_connect" - observes="devtoolsMenuBroadcaster_connect"/> - <menuseparator id="appmenu_devToolsEndSeparator"/> - <menuitem id="appmenu_getMoreDevtools" - observes="devtoolsMenuBroadcaster_GetMoreTools"/> - <menuseparator/> -#define ID_PREFIX appmenu_developer_ -#define OMIT_ACCESSKEYS -#include browser-charsetmenu.inc -#undef ID_PREFIX -#undef OMIT_ACCESSKEYS - <menuitem label="&goOfflineCmd.label;" - type="checkbox" - observes="workOfflineMenuitemState" - oncommand="BrowserOffline.toggleOfflineStatus();"/> - </menupopup> - </splitmenu> - <menuseparator class="appmenu-menuseparator"/> -#define ID_PREFIX appmenu_ -#define OMIT_ACCESSKEYS -#include browser-charsetmenu.inc -#undef ID_PREFIX -#undef OMIT_ACCESSKEYS - <menuitem id="appmenu_fullScreen" - class="menuitem-tooltip" - label="&fullScreenCmd.label;" - type="checkbox" - observes="View:FullScreen" - key="key_fullScreen"/> -#ifdef MOZ_SERVICES_SYNC - <!-- only one of sync-setup or sync-syncnow will be showing at once --> - <menuitem id="sync-setup-appmenu" - label="&syncSetup.label;" - observes="sync-setup-state" - oncommand="gSyncUI.openSetup()"/> - <menuitem id="sync-syncnowitem-appmenu" - label="&syncSyncNowItem.label;" - observes="sync-syncnow-state" - oncommand="gSyncUI.doSync(event);"/> -#endif - <menuitem id="appmenu-quit" - class="menuitem-iconic" -#ifdef XP_WIN - label="&quitApplicationCmdWin.label;" -#else - label="&quitApplicationCmd.label;" -#endif - command="cmd_quitApplication"/> - </vbox> - <vbox id="appmenuSecondaryPane"> - <splitmenu id="appmenu_bookmarks" - iconic="true" - label="&bookmarksMenu.label;" - command="Browser:ShowAllBookmarks"> - <menupopup id="appmenu_bookmarksPopup" - placespopup="true" - context="placesContext" - openInTabs="children" - oncommand="BookmarksEventHandler.onCommand(event, this.parentNode._placesView);" - onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);" - onpopupshowing="BookmarkingUI.onPopupShowing(event); - if (!this.parentNode._placesView) - new PlacesMenu(event, 'place:folder=BOOKMARKS_MENU');" - tooltip="bhTooltip" - popupsinherittooltip="true"> - <menuitem id="appmenu_showAllBookmarks" - label="&showAllBookmarks2.label;" - command="Browser:ShowAllBookmarks" - context="" - key="manBookmarkKb"/> - <menuseparator/> - <menuitem id="appmenu_bookmarkThisPage" - class="menuitem-iconic" - label="&bookmarkThisPageCmd.label;" - command="Browser:AddBookmarkAs" - key="addBookmarkAsKb"/> - <menuitem id="appmenu_subscribeToPage" - class="menuitem-iconic" - label="&subscribeToPageMenuitem.label;" - oncommand="return FeedHandler.subscribeToFeed(null, event);" - onclick="checkForMiddleClick(this, event);" - observes="singleFeedMenuitemState"/> - <menu id="appmenu_subscribeToPageMenu" - class="menu-iconic" - label="&subscribeToPageMenupopup.label;" - observes="multipleFeedsMenuState"> - <menupopup id="appmenu_subscribeToPageMenupopup" - onpopupshowing="return FeedHandler.buildFeedList(event.target);" - oncommand="return FeedHandler.subscribeToFeed(null, event);" - onclick="checkForMiddleClick(this, event);"/> - </menu> - <menuseparator/> - <menu id="appmenu_bookmarksToolbar" - placesanonid="toolbar-autohide" - class="menu-iconic bookmark-item" - label="&personalbarCmd.label;" - container="true"> - <menupopup id="appmenu_bookmarksToolbarPopup" - placespopup="true" - context="placesContext" - onpopupshowing="if (!this.parentNode._placesView) - new PlacesMenu(event, 'place:folder=TOOLBAR');"/> - </menu> - <menuseparator/> - <!-- Bookmarks menu items --> - <menuseparator builder="end" - class="hide-if-empty-places-result"/> - <menuitem id="appmenu_unsortedBookmarks" - label="&appMenuUnsorted.label;" - oncommand="PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks');" - class="menuitem-iconic"/> - </menupopup> - </splitmenu> - <splitmenu id="appmenu_history" - iconic="true" - label="&historyMenu.label;" - command="Browser:ShowAllHistory"> - <menupopup id="appmenu_historyMenupopup" - placespopup="true" - oncommand="this.parentNode._placesView._onCommand(event);" - onclick="checkForMiddleClick(this, event);" - onpopupshowing="if (!this.parentNode._placesView) - new HistoryMenu(event);" - tooltip="bhTooltip" - popupsinherittooltip="true"> - <menuitem id="appmenu_showAllHistory" - label="&showAllHistoryCmd2.label;" - command="Browser:ShowAllHistory" - key="showAllHistoryKb"/> - <menuseparator/> - <menuitem id="appmenu_sanitizeHistory" - label="&clearRecentHistory.label;" - key="key_sanitize" - command="Tools:Sanitize"/> - <menuseparator class="hide-if-empty-places-result"/> -#ifdef MOZ_SERVICES_SYNC - <menuitem id="appmenu_sync-tabs" - class="syncTabsMenuItem" - label="&syncTabsMenu2.label;" - oncommand="BrowserOpenSyncTabs();" - disabled="true"/> -#endif - <menuitem id="appmenu_restoreLastSession" - label="&historyRestoreLastSession.label;" - command="Browser:RestoreLastSession"/> - <menu id="appmenu_recentlyClosedTabsMenu" - class="recentlyClosedTabsMenu" - label="&historyUndoMenu.label;" - disabled="true"> - <menupopup id="appmenu_recentlyClosedTabsMenupopup" - onpopupshowing="document.getElementById('appmenu_history')._placesView.populateUndoSubmenu();"/> - </menu> - <menu id="appmenu_recentlyClosedWindowsMenu" - class="recentlyClosedWindowsMenu" - label="&historyUndoWindowMenu.label;" - disabled="true"> - <menupopup id="appmenu_recentlyClosedWindowsMenupopup" - onpopupshowing="document.getElementById('appmenu_history')._placesView.populateUndoWindowSubmenu();"/> - </menu> - <menuseparator/> - </menupopup> - </splitmenu> - <menuitem id="appmenu_downloads" - class="menuitem-tooltip" - label="&downloads.label;" - command="Tools:Downloads" - key="key_openDownloads"/> - <spacer id="appmenuSecondaryPane-spacer"/> - <menuitem id="appmenu_addons" - class="menuitem-iconic menuitem-iconic-tooltip" - label="&addons.label;" - command="Tools:Addons" - key="key_openAddons"/> - <splitmenu id="appmenu_customize" -#ifdef XP_UNIX - label="&preferencesCmdUnix.label;" -#else - label="&preferencesCmd2.label;" -#endif - oncommand="openPreferences();"> - <menupopup id="appmenu_customizeMenu" - onpopupshowing="onViewToolbarsPopupShowing(event, document.getElementById('appmenu_toggleToolbarsSeparator'));"> - <menuitem id="appmenu_preferences" -#ifdef XP_UNIX - label="&preferencesCmdUnix.label;" -#else - label="&preferencesCmd2.label;" -#endif - oncommand="openPreferences();"/> - <menuseparator/> - <menuseparator id="appmenu_toggleToolbarsSeparator"/> - <menuitem id="appmenu_toggleTabsOnTop" - label="&viewTabsOnTop.label;" - type="checkbox" - command="cmd_ToggleTabsOnTop"/> - <menuitem id="appmenu_toolbarLayout" - label="&appMenuToolbarLayout.label;" - command="cmd_CustomizeToolbars"/> - </menupopup> - </splitmenu> - <splitmenu id="appmenu_help" - label="&helpMenu.label;" - oncommand="openHelpLink('firefox-help')"> - <menupopup id="appmenu_helpMenupopup"> - <menuitem id="appmenu_openHelp" - label="&helpMenu.label;" - oncommand="openHelpLink('firefox-help')" - onclick="checkForMiddleClick(this, event);"/> - <menuitem id="appmenu_gettingStarted" - label="&appMenuGettingStarted.label;" - oncommand="gBrowser.loadOneTab('https://www.mozilla.org/firefox/central/', {inBackground: false});" - onclick="checkForMiddleClick(this, event);"/> - <menuitem id="appmenu_keyboardShortcuts" - label="&helpKeyboardShortcuts.label;" - oncommand="openHelpLink('keyboard-shortcuts')" - onclick="checkForMiddleClick(this, event);"/> -#ifdef MOZ_SERVICES_HEALTHREPORT - <menuitem id="appmenu_healthReport" - label="&healthReport.label;" - oncommand="openHealthReport()" - onclick="checkForMiddleClick(this, event);"/> -#endif - <menuitem id="appmenu_troubleshootingInfo" - label="&helpTroubleshootingInfo.label;" - oncommand="openTroubleshootingPage()" - onclick="checkForMiddleClick(this,event);"/> - <menuitem id="appmenu_feedbackPage" - label="&helpFeedbackPage.label;" - oncommand="openFeedbackPage()" - onclick="checkForMiddleClick(this, event);"/> - <menuseparator/> - <menuitem id="appmenu_safeMode" - label="&appMenuSafeMode.label;" - oncommand="safeModeRestart();"/> - <menuseparator/> - <menuitem id="appmenu_about" - label="&aboutProduct.label;" - oncommand="openAboutDialog();"/> - </menupopup> - </splitmenu> - </vbox> - </hbox> -</menupopup> diff --git a/browser/base/content/browser-customization.js b/browser/base/content/browser-customization.js new file mode 100644 index 0000000000000000000000000000000000000000..369f6cbd22cf9b16cc1c2fb7d0b6c1372c1f4ed8 --- /dev/null +++ b/browser/base/content/browser-customization.js @@ -0,0 +1,97 @@ +# -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- +# 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/. + +/** + * Customization handler prepares this browser window for entering and exiting + * customization mode by handling customizationstarting and customizationending + * events. + */ +let CustomizationHandler = { + handleEvent: function(aEvent) { + switch(aEvent.type) { + case "customizationstarting": + this._customizationStarting(); + break; + case "customizationending": + this._customizationEnding(aEvent.detail); + break; + } + }, + + isCustomizing: function() { + return document.documentElement.hasAttribute("customizing") || + document.documentElement.hasAttribute("customize-exiting"); + }, + + _customizationStarting: function() { + // Disable the toolbar context menu items + let menubar = document.getElementById("main-menubar"); + for (let childNode of menubar.childNodes) + childNode.setAttribute("disabled", true); + + let cmd = document.getElementById("cmd_CustomizeToolbars"); + cmd.setAttribute("disabled", "true"); + + let splitter = document.getElementById("urlbar-search-splitter"); + if (splitter) { + splitter.parentNode.removeChild(splitter); + } + + CombinedStopReload.uninit(); + PlacesToolbarHelper.customizeStart(); + BookmarkingUI.customizeStart(); + DownloadsButton.customizeStart(); + }, + + _customizationEnding: function(aDetails) { + // Update global UI elements that may have been added or removed + if (aDetails.changed) { + gURLBar = document.getElementById("urlbar"); + + gProxyFavIcon = document.getElementById("page-proxy-favicon"); + gHomeButton.updateTooltip(); + gIdentityHandler._cacheElements(); + XULBrowserWindow.init(); + +#ifndef XP_MACOSX + updateEditUIVisibility(); +#endif + + // Hacky: update the PopupNotifications' object's reference to the iconBox, + // if it already exists, since it may have changed if the URL bar was + // added/removed. + if (!window.__lookupGetter__("PopupNotifications")) { + PopupNotifications.iconBox = + document.getElementById("notification-popup-box"); + } + + } + + PlacesToolbarHelper.customizeDone(); + BookmarkingUI.customizeDone(); + DownloadsButton.customizeDone(); + + // The url bar splitter state is dependent on whether stop/reload + // and the location bar are combined, so we need this ordering + CombinedStopReload.init(); + UpdateUrlbarSearchSplitterState(); + + // Update the urlbar + if (gURLBar) { + URLBarSetURI(); + XULBrowserWindow.asyncUpdateUI(); + BookmarkingUI.updateStarState(); + } + + // Re-enable parts of the UI we disabled during the dialog + let menubar = document.getElementById("main-menubar"); + for (let childNode of menubar.childNodes) + childNode.setAttribute("disabled", false); + let cmd = document.getElementById("cmd_CustomizeToolbars"); + cmd.removeAttribute("disabled"); + + gBrowser.selectedBrowser.focus(); + } +} diff --git a/browser/base/content/browser-feeds.js b/browser/base/content/browser-feeds.js index 7bba395408246a6c8f04db282b872853c518f1e8..2bdb33cd09eb19ea93e59a38f8381ade18864157 100644 --- a/browser/base/content/browser-feeds.js +++ b/browser/base/content/browser-feeds.js @@ -8,66 +8,53 @@ * and shows UI when they are discovered. */ var FeedHandler = { - /** - * The click handler for the Feed icon in the toolbar. Opens the - * subscription page if user is not given a choice of feeds. - * (Otherwise the list of available feeds will be presented to the - * user in a popup menu.) - */ - onFeedButtonClick: function(event) { - event.stopPropagation(); - - let feeds = gBrowser.selectedBrowser.feeds || []; - // If there are multiple feeds, the menu will open, so no need to do - // anything. If there are no feeds, nothing to do either. - if (feeds.length != 1) - return; - - if (event.eventPhase == Event.AT_TARGET && - (event.button == 0 || event.button == 1)) { - this.subscribeToFeed(feeds[0].href, event); - } - }, - - /** Called when the user clicks on the Subscribe to This Page... menu item. + /** Called when the user clicks on the Subscribe to This Page... menu item, + * or when the user clicks the feed button when the page contains multiple + * feeds. * Builds a menu of unique feeds associated with the page, and if there * is only one, shows the feed inline in the browser window. - * @param menuPopup - * The feed list menupopup to be populated. - * @returns true if the menu should be shown, false if there was only + * @param container + * The feed list container (menupopup or subview) to be populated. + * @param isSubview + * Whether we're creating a subview (true) or menu (false/undefined) + * @returns true if the menu/subview should be shown, false if there was only * one feed and the feed should be shown inline in the browser - * window (do not show the menupopup). + * window (do not show the menupopup/subview). */ - buildFeedList: function(menuPopup) { + buildFeedList: function(container, isSubview) { var feeds = gBrowser.selectedBrowser.feeds; - if (feeds == null) { + if (!isSubview && feeds == null) { // XXX hack -- menu opening depends on setting of an "open" // attribute, and the menu refuses to open if that attribute is // set (because it thinks it's already open). onpopupshowing gets // called after the attribute is unset, and it doesn't get unset // if we return false. so we unset it here; otherwise, the menu // refuses to work past this point. - menuPopup.parentNode.removeAttribute("open"); + container.parentNode.removeAttribute("open"); return false; } - while (menuPopup.firstChild) - menuPopup.removeChild(menuPopup.firstChild); + while (container.firstChild) + container.removeChild(container.firstChild); - if (feeds.length <= 1) + if (!feeds || feeds.length <= 1) return false; // Build the menu showing the available feed choices for viewing. + var itemNodeType = isSubview ? "toolbarbutton" : "menuitem"; for (let feedInfo of feeds) { - var menuItem = document.createElement("menuitem"); + var item = document.createElement(itemNodeType); var baseTitle = feedInfo.title || feedInfo.href; var labelStr = gNavigatorBundle.getFormattedString("feedShowFeedNew", [baseTitle]); - menuItem.setAttribute("class", "feed-menuitem"); - menuItem.setAttribute("label", labelStr); - menuItem.setAttribute("feed", feedInfo.href); - menuItem.setAttribute("tooltiptext", feedInfo.href); - menuItem.setAttribute("crop", "center"); - menuPopup.appendChild(menuItem); + item.setAttribute("class", "feed-" + itemNodeType); + item.setAttribute("label", labelStr); + item.setAttribute("feed", feedInfo.href); + item.setAttribute("tooltiptext", feedInfo.href); + item.setAttribute("crop", "center"); + if (isSubview) { + item.setAttribute("tabindex", "0"); + } + container.appendChild(item); } return true; }, @@ -76,7 +63,7 @@ var FeedHandler = { * Subscribe to a given feed. Called when * 1. Page has a single feed and user clicks feed icon in location bar * 2. Page has a single feed and user selects Subscribe menu item - * 3. Page has multiple feeds and user selects from feed icon popup + * 3. Page has multiple feeds and user selects from feed icon popup (or subview) * 4. Page has multiple feeds and user selects from Subscribe submenu * @param href * The feed to subscribe to. May be null, in which case the diff --git a/browser/base/content/browser-fullScreen.js b/browser/base/content/browser-fullScreen.js index a8ffa754ad028ace501330d35555f7bedd1356b2..4e416ef0437e516c1e268a042defe14754c86e8f 100644 --- a/browser/base/content/browser-fullScreen.js +++ b/browser/base/content/browser-fullScreen.js @@ -17,7 +17,7 @@ var FullScreen = { enterFS = !enterFS; // Toggle the View:FullScreen command, which controls elements like the - // fullscreen menuitem, menubars, and the appmenu. + // fullscreen menuitem, and menubars. let fullscreenCommand = document.getElementById("View:FullScreen"); if (enterFS) { fullscreenCommand.setAttribute("checked", enterFS); @@ -517,15 +517,6 @@ var FullScreen = { // XXX don't interfere with previously collapsed toolbars if (el.getAttribute("fullscreentoolbar") == "true") { if (!aShow) { - - var toolbarMode = el.getAttribute("mode"); - if (toolbarMode != "text") { - el.setAttribute("saved-mode", toolbarMode); - el.setAttribute("saved-iconsize", el.getAttribute("iconsize")); - el.setAttribute("mode", "icons"); - el.setAttribute("iconsize", "small"); - } - // Give the main nav bar and the tab bar the fullscreen context menu, // otherwise remove context menu to prevent breakage el.setAttribute("saved-context", el.getAttribute("context")); @@ -539,18 +530,10 @@ var FullScreen = { el.setAttribute("inFullscreen", true); } else { - var restoreAttr = function restoreAttr(attrName) { - var savedAttr = "saved-" + attrName; - if (el.hasAttribute(savedAttr)) { - el.setAttribute(attrName, el.getAttribute(savedAttr)); - el.removeAttribute(savedAttr); - } + if (el.hasAttribute("saved-context")) { + el.setAttribute("context", el.getAttribute("saved-context")); + el.removeAttribute("saved-context"); } - - restoreAttr("mode"); - restoreAttr("iconsize"); - restoreAttr("context"); - el.removeAttribute("inFullscreen"); } } else { @@ -571,11 +554,9 @@ var FullScreen = { document.documentElement.setAttribute("inFullscreen", true); } - // In tabs-on-top mode, move window controls to the tab bar, - // and in tabs-on-bottom mode, move them back to the navigation toolbar. var fullscreenctls = document.getElementById("window-controls"); var navbar = document.getElementById("nav-bar"); - var ctlsOnTabbar = window.toolbar.visible && (navbar.collapsed || TabsOnTop.enabled); + var ctlsOnTabbar = window.toolbar.visible; if (fullscreenctls.parentNode == navbar && ctlsOnTabbar) { fullscreenctls.removeAttribute("flex"); document.getElementById("TabsToolbar").appendChild(fullscreenctls); diff --git a/browser/base/content/browser-fullZoom.js b/browser/base/content/browser-fullZoom.js index d92dfcc625e1b27585c8c98c18e468095fc86e22..55f02c38b9e6adc659a2af86dd2a999f02ad86f5 100644 --- a/browser/base/content/browser-fullZoom.js +++ b/browser/base/content/browser-fullZoom.js @@ -397,6 +397,7 @@ var FullZoom = { * @param browser The zoom of this browser will be saved. Required. */ _applyZoomToPref: function FullZoom__applyZoomToPref(browser) { + Services.obs.notifyObservers(null, "browser-fullZoom:zoomChange", ""); if (!this.siteSpecific || gInPrintPreviewMode || browser.contentDocument.mozSyntheticDocument) @@ -417,6 +418,7 @@ var FullZoom = { * @param browser The zoom of this browser will be removed. Required. */ _removePref: function FullZoom__removePref(browser) { + Services.obs.notifyObservers(null, "browser-fullZoom:zoomReset", ""); if (browser.contentDocument.mozSyntheticDocument) return; let ctxt = this._loadContextFromWindow(browser.contentWindow); diff --git a/browser/base/content/browser-menubar.inc b/browser/base/content/browser-menubar.inc index 856f81b92f1b8891fc6f67350d48f058f8e71461..1db9222eb731047edbe04324771685cc36fb4b2e 100644 --- a/browser/base/content/browser-menubar.inc +++ b/browser/base/content/browser-menubar.inc @@ -185,11 +185,6 @@ accesskey="&viewToolbarsMenu.accesskey;"> <menupopup onpopupshowing="onViewToolbarsPopupShowing(event);"> <menuseparator/> - <menuitem id="menu_tabsOnTop" - command="cmd_ToggleTabsOnTop" - type="checkbox" - label="&viewTabsOnTop.label;" - accesskey="&viewTabsOnTop.accesskey;"/> <menuitem id="menu_customizeToolbars" label="&viewCustomizeToolbar.label;" accesskey="&viewCustomizeToolbar.accesskey;" diff --git a/browser/base/content/browser-places.js b/browser/base/content/browser-places.js index 61a9618fe968c4d160568b8c7bd74b1aecffdaa5..9ed823376b5b24b21cb071b8c99dc2a62dea9463 100644 --- a/browser/base/content/browser-places.js +++ b/browser/base/content/browser-places.js @@ -134,9 +134,6 @@ var StarUI = { document.loadOverlay( "chrome://browser/content/places/editBookmarkOverlay.xul", (function (aSubject, aTopic, aData) { - //XXX We just caused localstore.rdf to be re-applied (bug 640158) - retrieveToolbarIconsizesFromTheme(); - // Move the header (star, title, button) into the grid, // so that it aligns nicely with the other items (bug 484022). let header = this._element("editBookmarkPanelHeader"); @@ -745,9 +742,10 @@ var BookmarksEventHandler = { // Handles special drag and drop functionality for Places menus that are not // part of a Places view (e.g. the bookmarks menu in the menubar). var PlacesMenuDNDHandler = { - _springLoadDelay: 350, // milliseconds + _springLoadDelayMs: 350, + _closeDelayMs: 500, _loadTimer: null, - _closerTimer: null, + _closeTimer: null, /** * Called when the user enters the <menu> element during a drag. @@ -768,7 +766,7 @@ var PlacesMenuDNDHandler = { this._loadTimer = null; popup.setAttribute("autoopened", "true"); popup.showPopup(popup); - }, this._springLoadDelay, Ci.nsITimer.TYPE_ONE_SHOT); + }, this._springLoadDelayMs, Ci.nsITimer.TYPE_ONE_SHOT); event.preventDefault(); event.stopPropagation(); }, @@ -781,7 +779,8 @@ var PlacesMenuDNDHandler = { onDragLeave: function PMDH_onDragLeave(event) { // Handle menu-button separate targets. if (event.relatedTarget === event.currentTarget || - event.relatedTarget.parentNode === event.currentTarget) + (event.relatedTarget && + event.relatedTarget.parentNode === event.currentTarget)) return; // Closing menus in a Places popup is handled by the view itself. @@ -807,7 +806,7 @@ var PlacesMenuDNDHandler = { popup.removeAttribute("autoopened"); popup.hidePopup(); } - }, this._springLoadDelay, Ci.nsITimer.TYPE_ONE_SHOT); + }, this._closeDelayMs, Ci.nsITimer.TYPE_ONE_SHOT); }, /** @@ -875,30 +874,52 @@ let PlacesToolbarHelper = { if (!viewElt || viewElt._placesView) return; - // If the bookmarks toolbar item is hidden because the parent toolbar is - // collapsed or hidden (i.e. in a popup), spare the initialization. Also, - // there is no need to initialize the toolbar if customizing because - // init() will be called when the customization is done. - let toolbar = viewElt.parentNode.parentNode; - if (toolbar.collapsed || - getComputedStyle(toolbar, "").display == "none" || - this._isCustomizing) + // If the bookmarks toolbar item is: + // - not in a toolbar, or; + // - the toolbar is collapsed, or; + // - the toolbar is hidden some other way: + // don't initialize. Also, there is no need to initialize the toolbar if + // customizing, because that will happen when the customization is done. + let toolbar = this._getParentToolbar(viewElt); + if (!toolbar || toolbar.collapsed || this._isCustomizing || + getComputedStyle(toolbar, "").display == "none") return; new PlacesToolbar(this._place); }, customizeStart: function PTH_customizeStart() { - let viewElt = this._viewElt; - if (viewElt && viewElt._placesView) - viewElt._placesView.uninit(); - - this._isCustomizing = true; + try { + let viewElt = this._viewElt; + if (viewElt && viewElt._placesView) + viewElt._placesView.uninit(); + } finally { + this._isCustomizing = true; + } }, customizeDone: function PTH_customizeDone() { this._isCustomizing = false; this.init(); + }, + + onPlaceholderCommand: function () { + let widgetGroup = CustomizableUI.getWidget("personal-bookmarks"); + let widget = widgetGroup.forWindow(window); + if (widget.overflowed || + widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL) { + PlacesCommandHook.showPlacesOrganizer("BookmarksToolbar"); + } + }, + + _getParentToolbar: function(element) { + while (element) { + if (element.localName == "toolbar") { + return element; + } + element = element.parentNode; + } + return null; } }; @@ -906,31 +927,33 @@ let PlacesToolbarHelper = { //// BookmarkingUI /** - * Handles the bookmarks star button in the URL bar, as well as the bookmark - * menu button. + * Handles the bookmarks menu-button in the toolbar. */ let BookmarkingUI = { get button() { - if (!this._button) { - this._button = document.getElementById("bookmarks-menu-button"); + let widgetGroup = CustomizableUI.getWidget("bookmarks-menu-button"); + if (widgetGroup.areaType == CustomizableUI.TYPE_TOOLBAR) { + return widgetGroup.forWindow(window).node; } - return this._button; + return null; }, get star() { - if (!this._star) { - this._star = document.getElementById("star-button"); - } - return this._star; + let button = this.button; + return button && document.getAnonymousElementByAttribute(button, "anonid", + "button"); }, get anchor() { - if (this.star && isElementVisible(this.star)) { - // Anchor to the icon, so the panel looks more natural. - return this.star; - } - return null; + let widget = CustomizableUI.getWidget("bookmarks-menu-button") + .forWindow(window); + if (widget.overflowed) + return widget.anchor; + + let star = this.star; + return star && document.getAnonymousElementByAttribute(star, "class", + "toolbarbutton-icon"); }, STATUS_UPDATING: -1, @@ -939,9 +962,9 @@ let BookmarkingUI = { get status() { if (this._pendingStmt) return this.STATUS_UPDATING; - return this.star && - this.star.hasAttribute("starred") ? this.STATUS_STARRED - : this.STATUS_UNSTARRED; + let button = this.button; + return button && button.hasAttribute("starred") ? this.STATUS_STARRED + : this.STATUS_UNSTARRED; }, get _starredTooltip() @@ -974,6 +997,16 @@ let BookmarkingUI = { if (event.target != event.currentTarget) return; + let widget = CustomizableUI.getWidget("bookmarks-menu-button") + .forWindow(window); + if (widget.overflowed) { + // Don't open a popup in the overflow popup, rather just open the Library. + event.preventDefault(); + widget.node.removeAttribute("noautoclose"); + PlacesCommandHook.showPlacesOrganizer("BookmarksMenu"); + return; + } + if (!this._popupNeedsUpdate) return; this._popupNeedsUpdate = false; @@ -990,14 +1023,6 @@ let BookmarkingUI = { let personalToolbar = document.getElementById("PersonalToolbar"); viewToolbarMenuitem.setAttribute("checked", !personalToolbar.collapsed); } - - let toolbarMenuitem = getPlacesAnonymousElement("toolbar-autohide"); - if (toolbarMenuitem) { - // If bookmarks items are visible, hide Bookmarks Toolbar menu and the - // separator after it. - toolbarMenuitem.collapsed = toolbarMenuitem.nextSibling.collapsed = - isElementVisible(document.getElementById("personal-bookmarks")); - } }, /** @@ -1010,29 +1035,31 @@ let BookmarkingUI = { if (aState == "invalid") { this.star.setAttribute("disabled", "true"); - this.star.removeAttribute("starred"); + this.button.removeAttribute("starred"); + this.button.setAttribute("buttontooltiptext", ""); } else { this.star.removeAttribute("disabled"); } + this._updateToolbarStyle(); }, _updateToolbarStyle: function BUI__updateToolbarStyle() { - if (!this.button) { + let button = this.button; + if (!button) return; - } let personalToolbar = document.getElementById("PersonalToolbar"); - let onPersonalToolbar = this.button.parentNode == personalToolbar || - this.button.parentNode.parentNode == personalToolbar; + let onPersonalToolbar = button.parentNode == personalToolbar || + button.parentNode.parentNode == personalToolbar; if (onPersonalToolbar) { - this.button.classList.add("bookmark-item"); - this.button.classList.remove("toolbarbutton-1"); + button.classList.add("bookmark-item"); + button.classList.remove("toolbarbutton-1"); } else { - this.button.classList.remove("bookmark-item"); - this.button.classList.add("toolbarbutton-1"); + button.classList.remove("bookmark-item"); + button.classList.add("toolbarbutton-1"); } }, @@ -1040,9 +1067,9 @@ let BookmarkingUI = { // When an element with a placesView attached is removed and re-inserted, // XBL reapplies the binding causing any kind of issues and possible leaks, // so kill current view and let popupshowing generate a new one. - if (this.button && this.button._placesView) { - this.button._placesView.uninit(); - } + let button = this.button; + if (button && button._placesView) + button._placesView.uninit(); }, customizeStart: function BUI_customizeStart() { @@ -1054,7 +1081,6 @@ let BookmarkingUI = { }, customizeDone: function BUI_customizeDone() { - delete this._button; this.onToolbarVisibilityChange(); this._updateToolbarStyle(); }, @@ -1074,7 +1100,7 @@ let BookmarkingUI = { }, updateStarState: function BUI_updateStarState() { - if (!this.star || (this._uri && gBrowser.currentURI.equals(this._uri))) { + if (!this.button || (this._uri && gBrowser.currentURI.equals(this._uri))) { return; } @@ -1123,17 +1149,17 @@ let BookmarkingUI = { }, _updateStar: function BUI__updateStar() { - if (!this.star) { + let button = this.button; + if (!button) return; - } if (this._itemIds.length > 0) { - this.star.setAttribute("starred", "true"); - this.star.setAttribute("tooltiptext", this._starredTooltip); + button.setAttribute("starred", "true"); + button.setAttribute("buttontooltiptext", this._starredTooltip); } else { - this.star.removeAttribute("starred"); - this.star.setAttribute("tooltiptext", this._unstarredTooltip); + button.removeAttribute("starred"); + button.setAttribute("buttontooltiptext", this._unstarredTooltip); } }, @@ -1141,15 +1167,71 @@ let BookmarkingUI = { if (aEvent.target != aEvent.currentTarget) { return; } + + // Handle special case when the button is in the panel. + let widgetGroup = CustomizableUI.getWidget("bookmarks-menu-button"); + let widget = widgetGroup.forWindow(window); + if (widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL) { + let view = document.getElementById("PanelUI-bookmarks"); + view.addEventListener("ViewShowing", this.onPanelMenuViewShowing); + view.addEventListener("ViewHiding", this.onPanelMenuViewHiding); + widget.node.setAttribute("noautoclose", "true"); + PanelUI.showSubView("PanelUI-bookmarks", widget.node, + CustomizableUI.AREA_PANEL); + return; + } + else if (widget.overflowed) { + // Allow to close the panel if the page is already bookmarked, cause + // we are going to open the edit bookmark panel. + if (this._itemIds.length > 0) + widget.node.removeAttribute("noautoclose"); + else + widget.node.setAttribute("noautoclose", "true"); + } + // Ignore clicks on the star if we are updating its state. if (!this._pendingStmt) { PlacesCommandHook.bookmarkCurrentPage(this._itemIds.length > 0); } }, + onPanelMenuViewShowing: function BUI_onViewShowing(aEvent) { + // Update checked status of the toolbar toggle. + let viewToolbar = document.getElementById("panelMenu_viewBookmarksToolbar"); + let personalToolbar = document.getElementById("PersonalToolbar"); + if (personalToolbar.collapsed) + viewToolbar.removeAttribute("checked"); + else + viewToolbar.setAttribute("checked", "true"); + // Setup the Places view. + this._panelMenuView = new PlacesPanelMenuView("place:folder=BOOKMARKS_MENU", + "panelMenu_bookmarksMenu", + "panelMenu_bookmarksMenu"); + }, + + onPanelMenuViewHiding: function BUI_onViewHiding(aEvent) { + this._panelMenuView.uninit(); + delete this._panelMenuView; + }, + + onPanelMenuViewCommand: function BUI_onPanelMenuViewCommand(aEvent, aView) { + let target = aEvent.originalTarget; + if (!target._placesNode) + return; + if (PlacesUtils.nodeIsContainer(target._placesNode)) + PlacesCommandHook.showPlacesOrganizer([ "BookmarksMenu", target._placesNode.itemId ]); + else + PlacesUIUtils.openNodeWithEvent(target._placesNode, aEvent, aView); + PanelUI.hide(); + }, + // nsINavBookmarkObserver onItemAdded: function BUI_onItemAdded(aItemId, aParentId, aIndex, aItemType, aURI) { + if (!this.button) { + return; + } + if (aURI && aURI.equals(this._uri)) { // If a new bookmark has been added to the tracked uri, register it. if (this._itemIds.indexOf(aItemId) == -1) { @@ -1160,6 +1242,10 @@ let BookmarkingUI = { }, onItemRemoved: function BUI_onItemRemoved(aItemId) { + if (!this.button) { + return; + } + let index = this._itemIds.indexOf(aItemId); // If one of the tracked bookmarks has been removed, unregister it. if (index != -1) { @@ -1170,6 +1256,10 @@ let BookmarkingUI = { onItemChanged: function BUI_onItemChanged(aItemId, aProperty, aIsAnnotationProperty, aNewValue) { + if (!this.button) { + return; + } + if (aProperty == "uri") { let index = this._itemIds.indexOf(aItemId); // If the changed bookmark was tracked, check if it is now pointing to diff --git a/browser/base/content/browser-sets.inc b/browser/base/content/browser-sets.inc index 41af8c405d08ae55414cce910167a3ada60bc162..d969516d768ef2a069b4ff62e31640290ee956e6 100644 --- a/browser/base/content/browser-sets.inc +++ b/browser/base/content/browser-sets.inc @@ -32,7 +32,6 @@ <command id="cmd_printPreview" oncommand="PrintUtils.printPreview(PrintPreviewListener);"/> <command id="cmd_close" oncommand="BrowserCloseTabOrWindow()"/> <command id="cmd_closeWindow" oncommand="BrowserTryToCloseWindow()"/> - <command id="cmd_ToggleTabsOnTop" oncommand="TabsOnTop.toggle()"/> <command id="cmd_CustomizeToolbars" oncommand="BrowserCustomizeToolbar()"/> <command id="cmd_quitApplication" oncommand="goQuitApplication()"/> @@ -109,13 +108,13 @@ oncommand="OpenBrowserWindow({private: true});"/> <command id="History:UndoCloseTab" oncommand="undoCloseTab();"/> <command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/> - <command id="Browser:ToggleAddonBar" oncommand="toggleAddonBar();"/> <command id="Social:SharePage" oncommand="SocialShare.sharePage();" disabled="true"/> <command id="Social:ToggleSidebar" oncommand="Social.toggleSidebar();" hidden="true"/> <command id="Social:ToggleNotifications" oncommand="Social.toggleNotifications();" hidden="true"/> <command id="Social:FocusChat" oncommand="SocialChatBar.focus();" hidden="true" disabled="true"/> <command id="Social:Toggle" oncommand="Social.toggle();" hidden="true"/> <command id="Social:Addons" oncommand="BrowserOpenAddonsMgr('addons://list/service');"/> + <command id="MenuPanel:Toggle" oncommand="PanelUI.toggle(event);"/> </commandset> <commandset id="placesCommands"> @@ -412,6 +411,13 @@ #endif <key id="key_undoCloseWindow" command="History:UndoCloseWindow" key="&newNavigatorCmd.key;" modifiers="accel,shift"/> + <key id="key_menuButton" command="MenuPanel:Toggle" +#ifdef XP_MACOSX + key="&toggleMenuPanelMac.key;" modifiers="accel,shift"/> +#else + key="&toggleMenuPanel.key;" modifiers="accel"/> +#endif + #ifdef XP_GNOME #define NUM_SELECT_TAB_MODIFIER alt #else @@ -428,8 +434,6 @@ #expand <key id="key_selectTab8" oncommand="gBrowser.selectTabAtIndex(7, event);" key="8" modifiers="__NUM_SELECT_TAB_MODIFIER__"/> #expand <key id="key_selectLastTab" oncommand="gBrowser.selectTabAtIndex(-1, event);" key="9" modifiers="__NUM_SELECT_TAB_MODIFIER__"/> - <key id="key_toggleAddonBar" command="Browser:ToggleAddonBar" key="&toggleAddonBarCmd.key;" modifiers="accel"/> - </keyset> # Used by baseMenuOverlay diff --git a/browser/base/content/browser-social.js b/browser/base/content/browser-social.js index b8239bab6237b4e2fd7209cb7f4b00469a3c1e16..54626a3571435a4e7af72792065d75e54536bc59 100644 --- a/browser/base/content/browser-social.js +++ b/browser/base/content/browser-social.js @@ -795,9 +795,7 @@ SocialShare = { iframe.setAttribute("src", shareEndpoint); let navBar = document.getElementById("nav-bar"); - let anchor = navBar.getAttribute("mode") == "text" ? - document.getAnonymousElementByAttribute(this.shareButton, "class", "toolbarbutton-text") : - document.getAnonymousElementByAttribute(this.shareButton, "class", "toolbarbutton-icon"); + let anchor = document.getAnonymousElementByAttribute(this.shareButton, "class", "toolbarbutton-icon"); this.panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false); Social.setErrorListener(iframe, this.setErrorMessage.bind(this)); } @@ -1130,9 +1128,7 @@ SocialToolbar = { }); let navBar = document.getElementById("nav-bar"); - let anchor = navBar.getAttribute("mode") == "text" ? - document.getAnonymousElementByAttribute(aToolbarButton, "class", "toolbarbutton-text") : - document.getAnonymousElementByAttribute(aToolbarButton, "class", "toolbarbutton-badge-container"); + let anchor = document.getAnonymousElementByAttribute(aToolbarButton, "class", "toolbarbutton-badge-container"); // Bug 849216 - open the popup in a setTimeout so we avoid the auto-rollup // handling from preventing it being opened in some cases. setTimeout(function() { diff --git a/browser/base/content/browser-tabview.js b/browser/base/content/browser-tabview.js index e5c2f060d90182a5dbd629e263777b22289a7ad9..6769a1df67eac12b9b3ff06884ace96b12726abd 100644 --- a/browser/base/content/browser-tabview.js +++ b/browser/base/content/browser-tabview.js @@ -426,16 +426,13 @@ let TabView = { let toolbar = document.getElementById("TabsToolbar"); let currentSet = toolbar.currentSet.split(","); - let alltabsPos = currentSet.indexOf("alltabs-button"); if (-1 == alltabsPos) return; - currentSet[alltabsPos] += "," + buttonId; - currentSet = currentSet.join(","); - toolbar.currentSet = currentSet; - toolbar.setAttribute("currentset", currentSet); - document.persist(toolbar.id, "currentset"); + let allTabsBtn = document.getElementById("alltabs-button"); + let nextItem = allTabsBtn.nextSibling; + toolbar.insertItem(buttonId, nextItem); }, // ---------- diff --git a/browser/base/content/browser.css b/browser/base/content/browser.css index 616d0cdd8fdef3ff63c5c9b12e6752fe89a8dd15..f361d5889a43380cc5b808e5c55252e11ced4c2f 100644 --- a/browser/base/content/browser.css +++ b/browser/base/content/browser.css @@ -21,6 +21,63 @@ searchbar { -moz-binding: url("chrome://global/content/bindings/remote-browser.xml#remote-browser"); } +toolbar[customizable="true"] { + -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar"); +} + +%ifdef XP_MACOSX +#toolbar-menubar { + -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-menubar-stub"); +} + +toolbar[customizable="true"]:not([nowindowdrag="true"]) { + -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-drag"); +} +%endif + +#toolbar-menubar[autohide="true"] { + -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-menubar-autohide"); +} + +#addon-bar { + -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#addonbar-delegating"); + visibility: visible; + margin: 0; + height: 0 !important; + overflow: hidden; + padding: 0; + border: 0 none; +} + +#addonbar-closebutton { + visibility: visible; + height: 0 !important; +} + +#status-bar { + height: 0 !important; + -moz-binding: none; + padding: 0; + margin: 0; +} + +panelmultiview { + -moz-binding: url("chrome://browser/content/customizableui/panelUI.xml#panelmultiview"); +} + +panelview { + -moz-binding: url("chrome://browser/content/customizableui/panelUI.xml#panelview"); + -moz-box-orient: vertical; +} + +.panel-mainview { + transition: transform 150ms; +} + +panelview:not([mainview]):not([current]) { + display: none; +} + tabbrowser { -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser"); } @@ -47,21 +104,19 @@ tabbrowser { .tabbrowser-tab:not([pinned]) { -moz-box-flex: 100; - max-width: 250px; + max-width: 180px; min-width: 100px; width: 0; transition: min-width 200ms ease-out, - max-width 250ms ease-out, - opacity 50ms ease-out 20ms /* hide the tab for the first 20ms of the max-width transition */; + max-width 230ms ease-out; } .tabbrowser-tab:not([pinned]):not([fadein]) { max-width: 0.1px; min-width: 0.1px; - opacity: 0 !important; + visibility: hidden; transition: min-width 200ms ease-out, - max-width 250ms ease-out, - opacity 50ms ease-out 180ms /* hide the tab for the last 20ms of the max-width transition */; + max-width 230ms ease-out; } .tab-throbber:not([fadein]):not([pinned]), @@ -94,20 +149,13 @@ toolbar[printpreview="true"] { -moz-binding: url("chrome://global/content/printPreviewBindings.xml#printpreviewtoolbar"); } -#toolbar-menubar { - -moz-box-ordinal-group: 5; -} - -#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) { - -moz-box-ordinal-group: 50; -} - -#TabsToolbar { - -moz-box-ordinal-group: 100; +toolbar[overflowable] > .customization-target { + overflow: hidden; } -#TabsToolbar[tabsontop="true"] { - -moz-box-ordinal-group: 10; +toolbar:not([overflowing]) > .overflow-button, +toolbar[customizing] > .overflow-button { + display: none; } %ifdef CAN_DRAW_IN_TITLEBAR @@ -125,43 +173,78 @@ toolbar[printpreview="true"] { pointer-events: none; } -#main-window[tabsintitlebar] #appmenu-button-container, #main-window[tabsintitlebar] #titlebar-buttonbox { position: relative; } + +#titlebar-buttonbox { + -moz-appearance: -moz-window-button-box; +} + +%ifdef XP_MACOSX +#titlebar-fullscreen-button { + -moz-appearance: -moz-mac-fullscreen-button; +} %endif -.bookmarks-toolbar-customize, -#wrapper-personal-bookmarks > #personal-bookmarks > #PlacesToolbar > hbox > #PlacesToolbarItems { +%ifdef XP_WIN +#main-window[sizemode="maximized"] #titlebar-buttonbox { + -moz-appearance: -moz-window-button-box-maximized; +} +%endif + +%endif + +/* Rules to help integrate SDK widgets */ +toolbarpaletteitem > toolbaritem[sdkstylewidget="true"] > .toolbarbutton-text { + display: -moz-box; +} + +toolbarpaletteitem > toolbaritem[sdkstylewidget="true"] > iframe { display: none; } -#wrapper-personal-bookmarks[place="toolbar"] > #personal-bookmarks > #PlacesToolbar > .bookmarks-toolbar-customize { +#bookmarks-toolbar-placeholder, +toolbarpaletteitem > #personal-bookmarks > #PlacesToolbar, +#personal-bookmarks[cui-areatype="menu-panel"] > #PlacesToolbar, +#personal-bookmarks[cui-areatype="toolbar"].overflowedItem > #PlacesToolbar { + display: none; +} + +toolbarpaletteitem > #personal-bookmarks > #bookmarks-toolbar-placeholder, +#personal-bookmarks[cui-areatype="menu-panel"] > #bookmarks-toolbar-placeholder, +#personal-bookmarks[cui-areatype="toolbar"].overflowedItem > #bookmarks-toolbar-placeholder { display: -moz-box; } -#main-window[disablechrome] #navigator-toolbox[tabsontop="true"] > toolbar:not(#toolbar-menubar):not(#TabsToolbar) { - visibility: collapse; +#zoom-controls[cui-areatype="toolbar"]:not(.overflowedItem) > #zoom-reset-button > .toolbarbutton-text { + display: -moz-box; } -#wrapper-urlbar-container #urlbar-container > #urlbar > toolbarbutton, -#urlbar-container:not([combined]) > #urlbar > toolbarbutton, -#urlbar-container[combined] + #reload-button + #stop-button, -#urlbar-container[combined] + #reload-button, -toolbar:not([mode="icons"]) > #urlbar-container > #urlbar > toolbarbutton, -toolbar[mode="icons"] > #urlbar-container > #urlbar > #urlbar-reload-button:not([displaystop]) + #urlbar-stop-button, -toolbar[mode="icons"] > #urlbar-container > #urlbar > #urlbar-reload-button[displaystop], -toolbar[mode="icons"] > #reload-button:not([displaystop]) + #stop-button, -toolbar[mode="icons"] > #reload-button[displaystop] { +#wrapper-urlbar-container > #urlbar-container > #urlbar-wrapper > #urlbar > toolbarbutton, +#urlbar-reload-button:not([displaystop]) + #urlbar-stop-button, +#urlbar-reload-button[displaystop] { visibility: collapse; } -#feed-button > .toolbarbutton-menu-dropmarker { - display: none; +#PanelUI-feeds > .feed-toolbarbutton:-moz-locale-dir(rtl) { + direction: rtl; } -#feed-menu > .feed-menuitem:-moz-locale-dir(rtl) { - direction: rtl; +#panelMenu_bookmarksMenu { + overflow-x: hidden; + overflow-y: auto; +} +#panelMenu_bookmarksMenu > .bookmark-item { + max-width: none; +} + +#urlbar-container { + min-width: 50ch; +} + +#search-container { + min-width: 25ch; } #main-window:-moz-lwtheme { @@ -180,27 +263,6 @@ toolbar[mode="icons"] > #reload-button[displaystop] { background-position: bottom left; } -splitmenu { - -moz-binding: url("chrome://browser/content/urlbarBindings.xml#splitmenu"); -} - -.splitmenu-menuitem { - -moz-binding: url("chrome://global/content/bindings/menu.xml#menuitem"); - list-style-image: inherit; - -moz-image-region: inherit; -} - -.splitmenu-menuitem[iconic="true"] { - -moz-binding: url("chrome://global/content/bindings/menu.xml#menuitem-iconic"); -} - -.splitmenu-menu > .menu-text, -:-moz-any(.splitmenu-menu, .splitmenu-menuitem) > .menu-accel-container, -#appmenu-editmenu > .menu-text, -#appmenu-editmenu > .menu-accel-container { - display: none; -} - .menuitem-tooltip { -moz-binding: url("chrome://browser/content/urlbarBindings.xml#menuitem-tooltip"); } @@ -211,18 +273,6 @@ splitmenu { -moz-binding: url("chrome://browser/content/urlbarBindings.xml#menuitem-iconic-tooltip"); } -%ifdef MENUBAR_CAN_AUTOHIDE -%ifndef CAN_DRAW_IN_TITLEBAR -#appmenu-toolbar-button > .toolbarbutton-text { - display: -moz-box; -} -%endif - -#appmenu_offlineModeRecovery:not([checked=true]) { - display: none; -} -%endif - /* Hide menu elements intended for keyboard access support */ #main-menubar[openedwithkey=false] .show-only-for-keyboard { display: none; @@ -257,7 +307,7 @@ panel[noactions] > richlistbox > richlistitem[type~="action"] > .ac-url-box > .a display: none; } -#wrapper-urlbar-container > #urlbar-container > #urlbar { +#wrapper-urlbar-container > #urlbar-container > #urlbar-wrapper > #urlbar { -moz-user-input: disabled; cursor: grab; } @@ -270,9 +320,7 @@ panel[noactions] > richlistbox > richlistitem[type~="action"] > .ac-url-box > .a -moz-binding: url("chrome://browser/content/urlbarBindings.xml#urlbar-rich-result-popup"); } -#urlbar-container[combined] > #urlbar > #urlbar-icons > #go-button, -#urlbar[pageproxystate="invalid"] > #urlbar-icons > .urlbar-icon:not(#go-button), -#urlbar[pageproxystate="valid"] > #urlbar-icons > #go-button, +#urlbar[pageproxystate="invalid"] > #urlbar-icons > .urlbar-icon, #urlbar[pageproxystate="invalid"][focused="true"] > #urlbar-go-button ~ toolbarbutton, #urlbar[pageproxystate="valid"] > #urlbar-go-button, #urlbar:not([focused="true"]) > #urlbar-go-button { @@ -316,18 +364,20 @@ toolbarbutton.bookmark-item { max-width: 13em; } -%ifdef MENUBAR_CAN_AUTOHIDE -#toolbar-menubar:not([autohide="true"]) ~ toolbar > #bookmarks-menu-button, -#toolbar-menubar:not([autohide="true"]) > #bookmarks-menu-button { - display: none; -} -%endif - #editBMPanel_tagsSelector { /* override default listbox width from xul.css */ width: auto; } +/* The star doesn't make sense as text */ +toolbar[mode="text"] #bookmarks-menu-button > .toolbarbutton-menubutton-button > .toolbarbutton-icon { + display: -moz-box !important; +} +toolbar[mode="text"] #bookmarks-menu-button > .toolbarbutton-menubutton-button > .toolbarbutton-text, +toolbar[mode="full"] #bookmarks-menu-button.bookmark-item > .toolbarbutton-menubutton-button > .toolbarbutton-text { + display: none; +} + menupopup[emptyplacesresult="true"] > .hide-if-empty-places-result { display: none; } @@ -352,7 +402,6 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m } #navigator-toolbox , -#status-bar , #mainPopupSet { min-width: 1px; } @@ -451,14 +500,6 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m min-width: 1px; } -#nav-bar[mode="text"] > #window-controls > toolbarbutton > .toolbarbutton-icon { - display: -moz-box; -} - -#nav-bar[mode="text"] > #window-controls > toolbarbutton > .toolbarbutton-text { - display: none; -} - /* ::::: Ctrl-Tab Panel ::::: */ .ctrlTab-preview > html|img, @@ -523,17 +564,6 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m -moz-binding: url("chrome://browser/content/urlbarBindings.xml#plugin-popupnotification-center-item"); } -/* override hidden="true" for the status bar compatibility shim - in case it was persisted for the real status bar */ -#status-bar { - display: -moz-box; -} - -/* Remove the resizer from the statusbar compatibility shim */ -#status-bar[hideresizer] > .statusbar-resizerpanel { - display: none; -} - browser[tabmodalPromptShowing] { -moz-user-focus: none !important; } @@ -776,6 +806,17 @@ chatbox:-moz-full-screen-ancestor > .chat-titlebar { -moz-margin-start: 2em; } +/* Give this menupopup an arrow panel styling */ +#BMB_bookmarksPopup { + -moz-appearance: none; + -moz-binding: url("chrome://browser/content/places/menu.xml#places-popup-arrow"); + background: transparent; + border: none; + transition: opacity 300ms; + /* The popup inherits -moz-image-region from the button, must reset it */ + -moz-image-region: auto; +} + /* UI Tour */ @keyframes uitour-wobble { diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index e1a10b7158185929e34b764a8b1757ce27f52d4a..fac713990e3916a5d91f651a74f1db25a2faf55c 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -85,6 +85,12 @@ this.__defineSetter__("PluralForm", function (val) { XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch", "resource://gre/modules/TelemetryStopwatch.jsm"); +XPCOMUtils.defineLazyGetter(this, "gCustomizeMode", function() { + let scope = {}; + Cu.import("resource:///modules/CustomizeMode.jsm", scope); + return new scope.CustomizeMode(window); +}); + #ifdef MOZ_SERVICES_SYNC XPCOMUtils.defineLazyModuleGetter(this, "Weave", "resource://services-sync/main.js"); @@ -153,6 +159,7 @@ let gInitialPages = [ ]; #include browser-addons.js +#include browser-customization.js #include browser-feeds.js #include browser-fullScreen.js #include browser-fullZoom.js @@ -315,29 +322,22 @@ function SetClickAndHoldHandlers() { aElm.addEventListener("click", clickHandler, true); } - // Bug 414797: Clone unified-back-forward-button's context menu into both the - // back and the forward buttons. - var unifiedButton = document.getElementById("unified-back-forward-button"); - if (unifiedButton && !unifiedButton._clickHandlersAttached) { - unifiedButton._clickHandlersAttached = true; - - let popup = document.getElementById("backForwardMenu").cloneNode(true); - popup.removeAttribute("id"); - // Prevent the context attribute on unified-back-forward-button from being - // inherited. - popup.setAttribute("context", ""); - - let backButton = document.getElementById("back-button"); - backButton.setAttribute("type", "menu"); - backButton.appendChild(popup); - _addClickAndHoldListenersOnElement(backButton); - - let forwardButton = document.getElementById("forward-button"); - popup = popup.cloneNode(true); - forwardButton.setAttribute("type", "menu"); - forwardButton.appendChild(popup); - _addClickAndHoldListenersOnElement(forwardButton); - } + // Bug 414797: Clone the back/forward buttons' context menu into both buttons. + let popup = document.getElementById("backForwardMenu").cloneNode(true); + popup.removeAttribute("id"); + // Prevent the back/forward buttons' context attributes from being inherited. + popup.setAttribute("context", ""); + + let backButton = document.getElementById("back-button"); + backButton.setAttribute("type", "menu"); + backButton.appendChild(popup); + _addClickAndHoldListenersOnElement(backButton); + + let forwardButton = document.getElementById("forward-button"); + popup = popup.cloneNode(true); + forwardButton.setAttribute("type", "menu"); + forwardButton.appendChild(popup); + _addClickAndHoldListenersOnElement(forwardButton); } const gSessionHistoryObserver = { @@ -737,6 +737,8 @@ const gFormSubmitObserver = { }; var gBrowserInit = { + delayedStartupFinished: false, + onLoad: function() { gMultiProcessBrowser = gPrefService.getBoolPref("browser.tabs.remote"); @@ -889,9 +891,6 @@ var gBrowserInit = { document.documentElement.setAttribute("height", defaultHeight); } - if (!gShowPageResizers) - document.getElementById("status-bar").setAttribute("hideresizer", "true"); - if (!window.toolbar.visible) { // adjust browser UI for popups if (gURLBar) { @@ -901,16 +900,10 @@ var gBrowserInit = { goSetCommandEnabled("cmd_newNavigatorTab", false); } -#ifdef MENUBAR_CAN_AUTOHIDE - updateAppButtonDisplay(); -#endif - // Misc. inits. CombinedStopReload.init(); - TabsOnTop.init(); gPrivateBrowsingUI.init(); TabsInTitlebar.init(); - retrieveToolbarIconsizesFromTheme(); // Wait until chrome is painted before executing code not critical to making the window visible this._boundDelayedStartup = this._delayedStartup.bind(this, mustLoadSidebar); @@ -1012,7 +1005,13 @@ var gBrowserInit = { IndexedDBPromptHelper.init(); gFormSubmitObserver.init(); SocialUI.init(); - AddonManager.addAddonListener(AddonsMgrListener); + + // Initialize the full zoom setting. + // We do this before the session restore service gets initialized so we can + // apply full zoom settings to tabs restored by the session restore service. + FullZoom.init(); + PanelUI.init(); + LightweightThemeListener.init(); WebrtcIndicator.init(); // Ensure login manager is up and running. @@ -1063,11 +1062,6 @@ var gBrowserInit = { if (!getBoolPref("ui.click_hold_context_menus", false)) SetClickAndHoldHandlers(); - // Initialize the full zoom setting. - // We do this before the session restore service gets initialized so we can - // apply full zoom settings to tabs restored by the session restore service. - FullZoom.init(); - // Bug 666804 - NetworkPrioritizer support for e10s if (!gMultiProcessBrowser) { let NP = {}; @@ -1138,44 +1132,15 @@ var gBrowserInit = { gBrowserThumbnails.init(); - setUrlAndSearchBarWidthForConditionalForwardButton(); - window.addEventListener("resize", function resizeHandler(event) { - if (event.target == window) - setUrlAndSearchBarWidthForConditionalForwardButton(); - }); - -#ifdef MENUBAR_CAN_AUTOHIDE - // If the user (or the locale) hasn't enabled the top-level "Character - // Encoding" menu via the "browser.menu.showCharacterEncoding" preference, - // hide it. - if ("true" != gPrefService.getComplexValue("browser.menu.showCharacterEncoding", - Ci.nsIPrefLocalizedString).data) - document.getElementById("appmenu_charsetMenu").hidden = true; -#endif - // Add Devtools menuitems and listeners gDevToolsBrowser.registerBrowserWindow(window); - let appMenuButton = document.getElementById("appmenu-button"); - let appMenuPopup = document.getElementById("appmenu-popup"); - if (appMenuButton && appMenuPopup) { - let appMenuOpening = null; - appMenuButton.addEventListener("mousedown", function(event) { - if (event.button == 0) - appMenuOpening = new Date(); - }, false); - appMenuPopup.addEventListener("popupshown", function(event) { - if (event.target != appMenuPopup || !appMenuOpening) - return; - let duration = new Date() - appMenuOpening; - appMenuOpening = null; - Services.telemetry.getHistogramById("FX_APP_MENU_OPEN_MS").add(duration); - }, false); - } - window.addEventListener("mousemove", MousePosTracker, false); window.addEventListener("dragover", MousePosTracker, false); + gNavToolbox.addEventListener("customizationstarting", CustomizationHandler); + gNavToolbox.addEventListener("customizationending", CustomizationHandler); + // End startup crash tracking after a delay to catch crashes while restoring // tabs and to postpone saving the pref to disk. try { @@ -1209,6 +1174,7 @@ var gBrowserInit = { setTimeout(function () { BrowserChromeTest.markAsReady(); }, 0); }); + this.delayedStartupFinished = true; Services.obs.notifyObservers(window, "browser-delayed-startup-finished", ""); TelemetryTimestamps.add("delayedStartupFinished"); @@ -1274,8 +1240,6 @@ var gBrowserInit = { BookmarkingUI.uninit(); - TabsOnTop.uninit(); - TabsInTitlebar.uninit(); var enumerator = Services.wm.getEnumerator(null); @@ -1326,8 +1290,9 @@ var gBrowserInit = { BrowserOffline.uninit(); OfflineApps.uninit(); IndexedDBPromptHelper.uninit(); - AddonManager.removeAddonListener(AddonsMgrListener); SocialUI.uninit(); + LightweightThemeListener.uninit(); + PanelUI.uninit(); } // Final window teardown, do this last. @@ -1352,7 +1317,7 @@ var gBrowserInit = { 'viewToolbarsMenu', 'viewSidebarMenuMenu', 'Browser:Reload', 'viewFullZoomMenu', 'pageStyleMenu', 'charsetMenu', 'View:PageSource', 'View:FullScreen', 'viewHistorySidebar', 'Browser:AddBookmarkAs', 'Browser:BookmarkAllTabs', - 'View:PageInfo', 'Browser:ToggleTabView', 'Browser:ToggleAddonBar']; + 'View:PageInfo', 'Browser:ToggleTabView']; var element; for (let disabledItem of disabledItems) { @@ -2151,13 +2116,17 @@ function UpdateUrlbarSearchSplitterState() var splitter = document.getElementById("urlbar-search-splitter"); var urlbar = document.getElementById("urlbar-container"); var searchbar = document.getElementById("search-container"); - var stop = document.getElementById("stop-button"); + + // If the splitter is already in the right place, we don't need to do anything: + if (splitter && + ((splitter.nextSibling == searchbar && splitter.previousSibling == urlbar) || + (splitter.nextSibling == urlbar && splitter.previousSibling == searchbar))) { + return; + } var ibefore = null; if (urlbar && searchbar) { - if (urlbar.nextSibling == searchbar || - urlbar.getAttribute("combined") && - stop && stop.nextSibling == searchbar) + if (urlbar.nextSibling == searchbar) ibefore = searchbar; else if (searchbar.nextSibling == urlbar) ibefore = urlbar; @@ -2170,6 +2139,7 @@ function UpdateUrlbarSearchSplitterState() splitter.setAttribute("resizebefore", "flex"); splitter.setAttribute("resizeafter", "flex"); splitter.setAttribute("skipintoolbarset", "true"); + splitter.setAttribute("overflows", "false"); splitter.className = "chromeclass-toolbar-additional"; } urlbar.parentNode.insertBefore(splitter, ibefore); @@ -2177,24 +2147,6 @@ function UpdateUrlbarSearchSplitterState() splitter.parentNode.removeChild(splitter); } -function setUrlAndSearchBarWidthForConditionalForwardButton() { - // Workaround for bug 694084: Showing/hiding the conditional forward button resizes - // the search bar when the url/search bar splitter hasn't been used. - var urlbarContainer = document.getElementById("urlbar-container"); - var searchbarContainer = document.getElementById("search-container"); - if (!urlbarContainer || - !searchbarContainer || - urlbarContainer.hasAttribute("width") || - searchbarContainer.hasAttribute("width") || - urlbarContainer.parentNode != searchbarContainer.parentNode) - return; - urlbarContainer.style.width = searchbarContainer.style.width = ""; - var urlbarWidth = urlbarContainer.clientWidth; - var searchbarWidth = searchbarContainer.clientWidth; - urlbarContainer.style.width = urlbarWidth + "px"; - searchbarContainer.style.width = searchbarWidth + "px"; -} - function UpdatePageProxyState() { if (gURLBar && gURLBar.value != gLastValidURLStr) @@ -2594,9 +2546,7 @@ var PrintPreviewListener = { if (this._chromeState.sidebarOpen) toggleSidebar(this._sidebarCommand); -#ifdef MENUBAR_CAN_AUTOHIDE - updateAppButtonDisplay(); -#endif + TabsInTitlebar.allowedBy("print-preview", !gInPrintPreviewMode); }, _hideChrome: function () { this._chromeState = {}; @@ -2610,9 +2560,6 @@ var PrintPreviewListener = { notificationBox.notificationsHidden = true; document.getElementById("sidebar").setAttribute("src", "about:blank"); - var addonBar = document.getElementById("addon-bar"); - this._chromeState.addonBarOpen = !addonBar.collapsed; - addonBar.collapsed = true; gBrowser.updateWindowResizers(); this._chromeState.findOpen = gFindBarInitialized && !gFindBar.hidden; @@ -2634,11 +2581,6 @@ var PrintPreviewListener = { if (this._chromeState.notificationsOpen) gBrowser.getNotificationBox().notificationsHidden = false; - if (this._chromeState.addonBarOpen) { - document.getElementById("addon-bar").collapsed = false; - gBrowser.updateWindowResizers(); - } - if (this._chromeState.findOpen) gFindBar.open(); @@ -2715,35 +2657,6 @@ function openHomeDialog(aURL) } } -var bookmarksButtonObserver = { - onDrop: function (aEvent) - { - let name = { }; - let url = browserDragAndDrop.drop(aEvent, name); - try { - PlacesUIUtils.showBookmarkDialog({ action: "add" - , type: "bookmark" - , uri: makeURI(url) - , title: name - , hiddenRows: [ "description" - , "location" - , "loadInSidebar" - , "keyword" ] - }, window); - } catch(ex) { } - }, - - onDragOver: function (aEvent) - { - browserDragAndDrop.dragOver(aEvent); - aEvent.dropEffect = "link"; - }, - - onDragExit: function (aEvent) - { - } -} - var newTabButtonObserver = { onDragOver: function (aEvent) { @@ -3286,153 +3199,18 @@ function OpenBrowserWindow(options) return win; } -var gCustomizeSheet = false; +//XXXunf Are these still useful to keep around? function BrowserCustomizeToolbar() { - // Disable the toolbar context menu items - var menubar = document.getElementById("main-menubar"); - for (let childNode of menubar.childNodes) - childNode.setAttribute("disabled", true); - - var cmd = document.getElementById("cmd_CustomizeToolbars"); - cmd.setAttribute("disabled", "true"); - - var splitter = document.getElementById("urlbar-search-splitter"); - if (splitter) - splitter.parentNode.removeChild(splitter); - - CombinedStopReload.uninit(); - - PlacesToolbarHelper.customizeStart(); - BookmarkingUI.customizeStart(); - DownloadsButton.customizeStart(); - - TabsInTitlebar.allowedBy("customizing-toolbars", false); - - var customizeURL = "chrome://global/content/customizeToolbar.xul"; - gCustomizeSheet = getBoolPref("toolbar.customization.usesheet", false); - - if (gCustomizeSheet) { - let sheetFrame = document.createElement("iframe"); - let panel = document.getElementById("customizeToolbarSheetPopup"); - sheetFrame.id = "customizeToolbarSheetIFrame"; - sheetFrame.toolbox = gNavToolbox; - sheetFrame.panel = panel; - sheetFrame.setAttribute("style", panel.getAttribute("sheetstyle")); - panel.appendChild(sheetFrame); - - // Open the panel, but make it invisible until the iframe has loaded so - // that the user doesn't see a white flash. - panel.style.visibility = "hidden"; - gNavToolbox.addEventListener("beforecustomization", function onBeforeCustomization() { - gNavToolbox.removeEventListener("beforecustomization", onBeforeCustomization, false); - panel.style.removeProperty("visibility"); - }, false); - - sheetFrame.setAttribute("src", customizeURL); - - panel.openPopup(gNavToolbox, "after_start", 0, 0); - } else { - window.openDialog(customizeURL, - "CustomizeToolbar", - "chrome,titlebar,toolbar,location,resizable,dependent", - gNavToolbox); - } + gCustomizeMode.enter(); } function BrowserToolboxCustomizeDone(aToolboxChanged) { - if (gCustomizeSheet) { - document.getElementById("customizeToolbarSheetPopup").hidePopup(); - let iframe = document.getElementById("customizeToolbarSheetIFrame"); - iframe.parentNode.removeChild(iframe); - } - - // Update global UI elements that may have been added or removed - if (aToolboxChanged) { - gURLBar = document.getElementById("urlbar"); - - gProxyFavIcon = document.getElementById("page-proxy-favicon"); - gHomeButton.updateTooltip(); - gIdentityHandler._cacheElements(); - window.XULBrowserWindow.init(); - -#ifndef XP_MACOSX - updateEditUIVisibility(); -#endif - - // Hacky: update the PopupNotifications' object's reference to the iconBox, - // if it already exists, since it may have changed if the URL bar was - // added/removed. - if (!window.__lookupGetter__("PopupNotifications")) - PopupNotifications.iconBox = document.getElementById("notification-popup-box"); - } - - PlacesToolbarHelper.customizeDone(); - BookmarkingUI.customizeDone(); - DownloadsButton.customizeDone(); - - // The url bar splitter state is dependent on whether stop/reload - // and the location bar are combined, so we need this ordering - CombinedStopReload.init(); - UpdateUrlbarSearchSplitterState(); - setUrlAndSearchBarWidthForConditionalForwardButton(); - - // Update the urlbar - if (gURLBar) { - URLBarSetURI(); - XULBrowserWindow.asyncUpdateUI(); - BookmarkingUI.updateStarState(); - SocialUI.updateState(); - } - - TabsInTitlebar.allowedBy("customizing-toolbars", true); - - // Re-enable parts of the UI we disabled during the dialog - var menubar = document.getElementById("main-menubar"); - for (let childNode of menubar.childNodes) - childNode.setAttribute("disabled", false); - var cmd = document.getElementById("cmd_CustomizeToolbars"); - cmd.removeAttribute("disabled"); - - // make sure to re-enable click-and-hold - if (!getBoolPref("ui.click_hold_context_menus", false)) - SetClickAndHoldHandlers(); - - gBrowser.selectedBrowser.focus(); + gCustomizeMode.exit(aToolboxChanged); } function BrowserToolboxCustomizeChange(aType) { - switch (aType) { - case "iconsize": - case "mode": - retrieveToolbarIconsizesFromTheme(); - break; - default: - gHomeButton.updatePersonalToolbarStyle(); - BookmarkingUI.customizeChange(); - } -} - -/** - * Allows themes to override the "iconsize" attribute on toolbars. - */ -function retrieveToolbarIconsizesFromTheme() { - function retrieveToolbarIconsize(aToolbar) { - if (aToolbar.localName != "toolbar") - return; - - // The theme indicates that it wants to override the "iconsize" attribute - // by specifying a special value for the "counter-reset" property on the - // toolbar. A custom property cannot be used because getComputedStyle can - // only return the values of standard CSS properties. - let counterReset = getComputedStyle(aToolbar).counterReset; - if (counterReset == "smallicons 0") - aToolbar.setAttribute("iconsize", "small"); - else if (counterReset == "largeicons 0") - aToolbar.setAttribute("iconsize", "large"); - } - - Array.forEach(gNavToolbox.childNodes, retrieveToolbarIconsize); - gNavToolbox.externalToolbars.forEach(retrieveToolbarIconsize); + gHomeButton.updatePersonalToolbarStyle(); + BookmarksMenuButton.customizeChange(); } /** @@ -3461,9 +3239,6 @@ function updateEditUIVisibility() let editMenuPopupState = document.getElementById("menu_EditPopup").state; let contextMenuPopupState = document.getElementById("contentAreaContextMenu").state; let placesContextMenuPopupState = document.getElementById("placesContext").state; -#ifdef MENUBAR_CAN_AUTOHIDE - let appMenuPopupState = document.getElementById("appmenu-popup").state; -#endif // The UI is visible if the Edit menu is opening or open, if the context menu // is open, or if the toolbar has been customized to include the Cut, Copy, @@ -3474,13 +3249,7 @@ function updateEditUIVisibility() contextMenuPopupState == "open" || placesContextMenuPopupState == "showing" || placesContextMenuPopupState == "open" || -#ifdef MENUBAR_CAN_AUTOHIDE - appMenuPopupState == "showing" || - appMenuPopupState == "open" || -#endif - document.getElementById("cut-button") || - document.getElementById("copy-button") || - document.getElementById("paste-button") ? true : false; + document.getElementById("edit-controls") ? true : false; // If UI is visible, update the edit commands' enabled state to reflect // whether or not they are actually enabled for the current focus/selection. @@ -3510,9 +3279,6 @@ function updateEditUIVisibility() function updateCharacterEncodingMenuState() { let charsetMenu = document.getElementById("charsetMenu"); - let appCharsetMenu = document.getElementById("appmenu_charsetMenu"); - let appDevCharsetMenu = - document.getElementById("appmenu_developer_charsetMenu"); // gBrowser is null on Mac when the menubar shows in the context of // non-browser windows. The above elements may be null depending on // what parts of the menubar are present. E.g. no app menu on Mac. @@ -3522,22 +3288,10 @@ function updateCharacterEncodingMenuState() if (charsetMenu) { charsetMenu.removeAttribute("disabled"); } - if (appCharsetMenu) { - appCharsetMenu.removeAttribute("disabled"); - } - if (appDevCharsetMenu) { - appDevCharsetMenu.removeAttribute("disabled"); - } } else { if (charsetMenu) { charsetMenu.setAttribute("disabled", "true"); } - if (appCharsetMenu) { - appCharsetMenu.setAttribute("disabled", "true"); - } - if (appDevCharsetMenu) { - appDevCharsetMenu.setAttribute("disabled", "true"); - } } } @@ -3569,8 +3323,8 @@ var XULBrowserWindow = { startTime: 0, statusText: "", isBusy: false, - inContentWhitelist: ["about:addons", "about:downloads", "about:permissions", - "about:sync-progress", "about:preferences"], + // Left here for add-on compatibility, see bug 752434 + inContentWhitelist: [], QueryInterface: function (aIID) { if (aIID.equals(Ci.nsIWebProgressListener) || @@ -3599,8 +3353,6 @@ var XULBrowserWindow = { }, init: function () { - this.throbberElement = document.getElementById("navigator-throbber"); - // Initialize the security button's state and tooltip text. var securityUI = gBrowser.securityUI; this.onSecurityChange(null, null, securityUI.state); @@ -3724,10 +3476,6 @@ var XULBrowserWindow = { if (!(aStateFlags & nsIWebProgressListener.STATE_RESTORING)) { this._busyUI = true; - // Turn the throbber on. - if (this.throbberElement) - this.throbberElement.setAttribute("busy", "true"); - // XXX: This needs to be based on window activity... this.stopCommand.removeAttribute("disabled"); CombinedStopReload.switchToStop(); @@ -3772,10 +3520,6 @@ var XULBrowserWindow = { if (this._busyUI) { this._busyUI = false; - // Turn the throbber off. - if (this.throbberElement) - this.throbberElement.removeAttribute("busy"); - this.stopCommand.setAttribute("disabled", "true"); CombinedStopReload.switchToReload(aRequest instanceof Ci.nsIRequest); } @@ -3842,16 +3586,6 @@ var XULBrowserWindow = { SocialUI.updateState(); } - // Show or hide browser chrome based on the whitelist - if (this.hideChromeForLocation(location)) { - document.documentElement.setAttribute("disablechrome", "true"); - } else { - if (SessionStore.getTabValue(gBrowser.selectedTab, "appOrigin")) - document.documentElement.setAttribute("disablechrome", "true"); - else - document.documentElement.removeAttribute("disablechrome"); - } - // Utility functions for disabling find var shouldDisableFind = function shouldDisableFind(aDocument) { let docElt = aDocument.documentElement; @@ -3892,6 +3626,17 @@ var XULBrowserWindow = { } } else disableFindCommands(false); + + // Try not to instantiate gCustomizeMode as much as possible, + // so don't use CustomizeMode.jsm to check for URI or customizing. + let customizingURI = "about:customizing"; + if (location == customizingURI && + !CustomizationHandler.isCustomizing()) { + gCustomizeMode.enter(); + } else if (location != customizingURI && + CustomizationHandler.isCustomizing()) { + gCustomizeMode.exit(); + } } UpdateBackForwardCommands(gBrowser.webNavigation); @@ -3909,12 +3654,8 @@ var XULBrowserWindow = { FeedHandler.updateFeeds(); }, - hideChromeForLocation: function(aLocation) { - aLocation = aLocation.toLowerCase(); - return this.inContentWhitelist.some(function(aSpec) { - return aSpec == aLocation; - }); - }, + // Left here for add-on compatibility, see bug 752434 + hideChromeForLocation: function() {}, onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) { this.status = aMessage; @@ -4052,21 +3793,8 @@ var CombinedStopReload = { if (this._initialized) return; - var urlbar = document.getElementById("urlbar-container"); - var reload = document.getElementById("reload-button"); - var stop = document.getElementById("stop-button"); - - if (urlbar) { - if (urlbar.parentNode.getAttribute("mode") != "icons" || - !reload || urlbar.nextSibling != reload || - !stop || reload.nextSibling != stop) - urlbar.removeAttribute("combined"); - else { - urlbar.setAttribute("combined", "true"); - reload = document.getElementById("urlbar-reload-button"); - stop = document.getElementById("urlbar-stop-button"); - } - } + let reload = document.getElementById("urlbar-reload-button"); + let stop = document.getElementById("urlbar-stop-button"); if (!stop || !reload || reload.nextSibling != stop) return; @@ -4398,7 +4126,6 @@ function onViewToolbarsPopupShowing(aEvent, aInsertPoint) { var firstMenuItem = aInsertPoint || popup.firstChild; let toolbarNodes = Array.slice(gNavToolbox.childNodes); - toolbarNodes.push(document.getElementById("addon-bar")); for (let toolbar of toolbarNodes) { let toolbarName = toolbar.getAttribute("toolbarname"); @@ -4411,8 +4138,7 @@ function onViewToolbarsPopupShowing(aEvent, aInsertPoint) { menuItem.setAttribute("type", "checkbox"); menuItem.setAttribute("label", toolbarName); menuItem.setAttribute("checked", toolbar.getAttribute(hidingAttribute) != "true"); - if (popup.id != "appmenu_customizeMenu") - menuItem.setAttribute("accesskey", toolbar.getAttribute("accesskey")); + menuItem.setAttribute("accesskey", toolbar.getAttribute("accesskey")); if (popup.id != "toolbar-context-menu") menuItem.setAttribute("key", toolbar.getAttribute("key")); @@ -4436,65 +4162,18 @@ function setToolbarVisibility(toolbar, isVisible) { toolbar.setAttribute(hidingAttribute, !isVisible); document.persist(toolbar.id, hidingAttribute); + let eventParams = { + detail: { + visible: isVisible + }, + bubbles: true + }; + let event = new CustomEvent("toolbarvisibilitychange", eventParams); + toolbar.dispatchEvent(event); PlacesToolbarHelper.init(); BookmarkingUI.onToolbarVisibilityChange(); gBrowser.updateWindowResizers(); - -#ifdef MENUBAR_CAN_AUTOHIDE - updateAppButtonDisplay(); -#endif -} - -var TabsOnTop = { - init: function TabsOnTop_init() { - Services.prefs.addObserver(this._prefName, this, false); - - // Only show the toggle UI if the user disabled tabs on top. - if (Services.prefs.getBoolPref(this._prefName)) { - for (let item of document.querySelectorAll("menuitem[command=cmd_ToggleTabsOnTop]")) - item.parentNode.removeChild(item); - } - }, - - uninit: function TabsOnTop_uninit() { - Services.prefs.removeObserver(this._prefName, this); - }, - - toggle: function () { - this.enabled = !Services.prefs.getBoolPref(this._prefName); - }, - - syncUI: function () { - let userEnabled = Services.prefs.getBoolPref(this._prefName); - let enabled = userEnabled && gBrowser.tabContainer.visible; - - document.getElementById("cmd_ToggleTabsOnTop") - .setAttribute("checked", userEnabled); - - document.documentElement.setAttribute("tabsontop", enabled); - document.getElementById("navigator-toolbox").setAttribute("tabsontop", enabled); - document.getElementById("TabsToolbar").setAttribute("tabsontop", enabled); - document.getElementById("nav-bar").setAttribute("tabsontop", enabled); - gBrowser.tabContainer.setAttribute("tabsontop", enabled); - TabsInTitlebar.allowedBy("tabs-on-top", enabled); - }, - - get enabled () { - return gNavToolbox.getAttribute("tabsontop") == "true"; - }, - - set enabled (val) { - Services.prefs.setBoolPref(this._prefName, !!val); - return val; - }, - - observe: function (subject, topic, data) { - if (topic == "nsPref:changed") - this.syncUI(); - }, - - _prefName: "browser.tabs.onTop" } var TabsInTitlebar = { @@ -4503,9 +4182,31 @@ var TabsInTitlebar = { this._readPref(); Services.prefs.addObserver(this._prefName, this, false); - // Don't trust the initial value of the sizemode attribute; wait for - // the resize event (handled in tabbrowser.xml). - this.allowedBy("sizemode", false); + // We need to update the appearance of the titlebar when the menu changes + // from the active to the inactive state. We can't, however, rely on + // DOMMenuBarInactive, because the menu fires this event and then removes + // the inactive attribute after an event-loop spin. + // + // Because updating the appearance involves sampling the heights and margins + // of various elements, it's important that the layout be more or less + // settled before updating the titlebar. So instead of listening to + // DOMMenuBarActive and DOMMenuBarInactive, we use a MutationObserver to + // watch the "invalid" attribute directly. + let menu = document.getElementById("toolbar-menubar"); + this._menuObserver = new MutationObserver(this._onMenuMutate); + this._menuObserver.observe(menu, {attributes: true}); + + gNavToolbox.addEventListener("customization-transitionend", this); + + this.onAreaReset = function(aArea) { + if (aArea == CustomizableUI.AREA_TABSTRIP || aArea == CustomizableUI.AREA_MENUBAR) + this._update(true); + }; + this.onWidgetAdded = this.onWidgetRemoved = function(aWidgetId, aArea) { + if (aArea == CustomizableUI.AREA_TABSTRIP || aArea == CustomizableUI.AREA_MENUBAR) + this._update(true); + }; + CustomizableUI.addListener(this); this._initialized = true; #endif @@ -4516,17 +4217,23 @@ var TabsInTitlebar = { if (allow) { if (condition in this._disallowed) { delete this._disallowed[condition]; - this._update(); + this._update(true); } } else { if (!(condition in this._disallowed)) { this._disallowed[condition] = null; - this._update(); + this._update(true); } } #endif }, + updateAppearance: function updateAppearance(aForce) { +#ifdef CAN_DRAW_IN_TITLEBAR + this._update(aForce); +#endif + }, + get enabled() { return document.documentElement.getAttribute("tabsintitlebar") == "true"; }, @@ -4537,62 +4244,200 @@ var TabsInTitlebar = { this._readPref(); }, + handleEvent: function(ev) { + if (ev.type == "customization-transitionend") { + this._update(true); + } + }, + + _onMenuMutate: function (aMutations) { + for (let mutation of aMutations) { + if (mutation.attributeName == "inactive" || + mutation.attributeName == "autohide") { + TabsInTitlebar._update(true); + return; + } + } + }, + _initialized: false, _disallowed: {}, _prefName: "browser.tabs.drawInTitlebar", + _lastSizeMode: null, _readPref: function () { this.allowedBy("pref", Services.prefs.getBoolPref(this._prefName)); }, - _update: function () { + _update: function (aForce=false) { function $(id) document.getElementById(id); function rect(ele) ele.getBoundingClientRect(); + function verticalMargins(cstyle) parseFloat(cstyle.marginBottom) + parseFloat(cstyle.marginTop); if (!this._initialized || window.fullScreen) return; let allowed = true; + + if (!aForce) { + // _update is called on resize events, because the window is not ready + // after sizemode events. However, we only care about the event when the + // sizemode is different from the last time we updated the appearance of + // the tabs in the titlebar. + let sizemode = document.documentElement.getAttribute("sizemode"); + if (this._lastSizeMode == sizemode) { + return; + } + this._lastSizeMode = sizemode; + } + for (let something in this._disallowed) { allowed = false; break; } - if (allowed == this.enabled) - return; - let titlebar = $("titlebar"); + let titlebarContent = $("titlebar-content"); + let menubar = $("toolbar-menubar"); if (allowed) { - let tabsToolbar = $("TabsToolbar"); + // We set the tabsintitlebar attribute first so that our CSS for + // tabsintitlebar manifests before we do our measurements. + document.documentElement.setAttribute("tabsintitlebar", "true"); + updateTitlebarDisplay(); + + // Try to avoid reflows in this code by calculating dimensions first and + // then later set the properties affecting layout together in a batch. -#ifdef MENUBAR_CAN_AUTOHIDE - let appmenuButtonBox = $("appmenu-button-container"); - this._sizePlaceholder("appmenu-button", rect(appmenuButtonBox).width); + // Buttons first: + let captionButtonsBoxWidth = rect($("titlebar-buttonbox")).width; +#ifdef XP_MACOSX + let fullscreenButtonWidth = rect($("titlebar-fullscreen-button")).width; + // No need to look up the menubar stuff on OS X: + let menuHeight = 0; + let fullMenuHeight = 0; + // Instead, look up the titlebar padding: + let titlebarPadding = parseInt(window.getComputedStyle(titlebar).paddingTop, 10); +#else + // Otherwise, get the height and margins separately for the menubar + let menuHeight = rect(menubar).height; + let menuStyles = window.getComputedStyle(menubar); + let fullMenuHeight = verticalMargins(menuStyles) + menuHeight; #endif - let captionButtonsBox = $("titlebar-buttonbox"); - this._sizePlaceholder("caption-buttons", rect(captionButtonsBox).width); + // Get the full height of the tabs toolbar: + let tabsToolbar = $("TabsToolbar"); + let tabsStyles = window.getComputedStyle(tabsToolbar); + let fullTabsHeight = rect(tabsToolbar).height + verticalMargins(tabsStyles); + + // If the navbar overlaps the tabbar using negative margins, we need to take those into + // account so we don't overlap it + let navbarMarginTop = parseFloat(window.getComputedStyle($("nav-bar")).marginTop); + navbarMarginTop = Math.min(navbarMarginTop, 0); + + // And get the height of what's in the titlebar: + let titlebarContentHeight = rect(titlebarContent).height; + + // Padding surrounds the tab-view-deck when we are in customization mode, + // so take that into account: + let areCustomizing = document.documentElement.hasAttribute("customizing") || + document.documentElement.hasAttribute("customize-exiting"); + let customizePadding = 0; + if (areCustomizing) { + let deckStyle = window.getComputedStyle($("tab-view-deck")); + customizePadding = parseFloat(deckStyle.paddingTop); + } - let tabsToolbarRect = rect(tabsToolbar); - let titlebarTop = rect($("titlebar-content")).top; - titlebar.style.marginBottom = - Math.min(tabsToolbarRect.top - titlebarTop, - tabsToolbarRect.height) + "px"; + // Begin setting CSS properties which will cause a reflow + + // If the menubar is around (menuHeight is non-zero), try to adjust + // its full height (i.e. including margins) to match the titlebar, + // by changing the menubar's bottom padding + if (menuHeight) { + // Calculate the difference between the titlebar's height and that of the menubar + let menuTitlebarDelta = titlebarContentHeight - fullMenuHeight; + let paddingBottom; + // The titlebar is bigger: + if (menuTitlebarDelta > 0) { + fullMenuHeight += menuTitlebarDelta; + // If there is already padding on the menubar, we need to add that + // to the difference so the total padding is correct: + if ((paddingBottom = menuStyles.paddingBottom)) { + menuTitlebarDelta += parseFloat(paddingBottom); + } + menubar.style.paddingBottom = menuTitlebarDelta + "px"; + // The menubar is bigger, but has bottom padding we can remove: + } else if (menuTitlebarDelta < 0 && (paddingBottom = menuStyles.paddingBottom)) { + let existingPadding = parseFloat(paddingBottom); + // menuTitlebarDelta is negative; work out what's left, but don't set negative padding: + let desiredPadding = Math.max(0, existingPadding + menuTitlebarDelta); + menubar.style.paddingBottom = desiredPadding + "px"; + // We've changed the menu height now: + fullMenuHeight += desiredPadding - existingPadding; + } + } - document.documentElement.setAttribute("tabsintitlebar", "true"); + // Next, we calculate how much we need to stretch the titlebar down to + // go all the way to the bottom of the tab strip, if necessary. + let tabAndMenuHeight = fullTabsHeight + fullMenuHeight; + // Oh, and don't forget customization mode: + if (areCustomizing) { + tabAndMenuHeight += customizePadding; + } + + if (tabAndMenuHeight > titlebarContentHeight) { + // We need to increase the titlebar content's outer height (ie including margins) + // to match the tab and menu height: + let extraMargin = tabAndMenuHeight - titlebarContentHeight; + // We need to reduce the height by the amount of navbar overlap + // (this value is 0 or negative): + extraMargin += navbarMarginTop; + // On non-OSX, we can just use bottom margin: +#ifndef XP_MACOSX + titlebarContent.style.marginBottom = extraMargin + "px"; +#else + // Otherwise, center the content. This means taking the titlebar's + // padding into account: + let halfMargin = (extraMargin - titlebarPadding) / 2; + titlebarContent.style.marginTop = halfMargin + "px"; + titlebarContent.style.marginBottom = (titlebarPadding + halfMargin) + "px"; +#endif + titlebarContentHeight += extraMargin; + } - if (!this._draghandle) { + // Then we bring up the titlebar by the same amount, but we add any negative margin: + titlebar.style.marginBottom = "-" + titlebarContentHeight + "px"; + + + // Finally, size the placeholders: +#ifdef XP_MACOSX + this._sizePlaceholder("fullscreen-button", fullscreenButtonWidth); +#endif + this._sizePlaceholder("caption-buttons", captionButtonsBoxWidth); + + if (!this._draghandles) { + this._draghandles = {}; let tmp = {}; Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp); - this._draghandle = new tmp.WindowDraggingElement(tabsToolbar); - this._draghandle.mouseDownCheck = function () { + + let mouseDownCheck = function () { return !this._dragBindingAlive && TabsInTitlebar.enabled; }; + + this._draghandles.tabsToolbar = new tmp.WindowDraggingElement(tabsToolbar); + this._draghandles.tabsToolbar.mouseDownCheck = mouseDownCheck; + + this._draghandles.navToolbox = new tmp.WindowDraggingElement(gNavToolbox); + this._draghandles.navToolbox.mouseDownCheck = mouseDownCheck; } } else { document.documentElement.removeAttribute("tabsintitlebar"); + updateTitlebarDisplay(); + // Reset the margins and padding that might have been modified: + titlebarContent.style.marginBottom = ""; titlebar.style.marginBottom = ""; + menubar.style.paddingBottom = ""; } }, @@ -4606,30 +4451,24 @@ var TabsInTitlebar = { #ifdef CAN_DRAW_IN_TITLEBAR this._initialized = false; Services.prefs.removeObserver(this._prefName, this); + this._menuObserver.disconnect(); + CustomizableUI.removeListener(this); #endif } }; -#ifdef MENUBAR_CAN_AUTOHIDE -function updateAppButtonDisplay() { - var displayAppButton = - !gInPrintPreviewMode && - window.menubar.visible && - document.getElementById("toolbar-menubar").getAttribute("autohide") == "true"; - #ifdef CAN_DRAW_IN_TITLEBAR - document.getElementById("titlebar").hidden = !displayAppButton; +function updateTitlebarDisplay() { + document.getElementById("titlebar").hidden = !TabsInTitlebar.enabled; - if (displayAppButton) + if (TabsInTitlebar.enabled) +#ifdef XP_WIN document.documentElement.setAttribute("chromemargin", "0,2,2,2"); - else - document.documentElement.removeAttribute("chromemargin"); - - TabsInTitlebar.allowedBy("drawing-in-titlebar", displayAppButton); #else - document.getElementById("appmenu-toolbar-button").hidden = - !displayAppButton; + document.documentElement.setAttribute("chromemargin", "0,-1,-1,-1"); #endif + else + document.documentElement.removeAttribute("chromemargin"); } #endif @@ -6911,12 +6750,6 @@ let gPrivateBrowsingUI = { document.getElementById("Tools:Sanitize").setAttribute("disabled", "true"); if (window.location.href == getBrowserURL()) { -#ifdef XP_MACOSX - if (!PrivateBrowsingUtils.permanentPrivateBrowsing) { - document.documentElement.setAttribute("drawintitlebar", true); - } -#endif - // Adjust the window's title let docElement = document.documentElement; if (!PrivateBrowsingUtils.permanentPrivateBrowsing) { @@ -6933,7 +6766,6 @@ let gPrivateBrowsingUI = { // Adjust the New Window menu entries [ { normal: "menu_newNavigator", private: "menu_newPrivateWindow" }, - { normal: "appmenu_newNavigator", private: "appmenu_newPrivateWindow" }, ].forEach(function(menu) { let newWindow = document.getElementById(menu.normal); let newPrivateWindow = document.getElementById(menu.private); @@ -7178,11 +7010,6 @@ function duplicateTabIn(aTab, where, delta) { } } -function toggleAddonBar() { - let addonBar = document.getElementById("addon-bar"); - setToolbarVisibility(addonBar, addonBar.collapsed); -} - var Scratchpad = { openScratchpad: function SP_openScratchpad() { return this.ScratchpadManager.openScratchpad(); diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul index 1158166737d0b15b97d94368cb7f040d54251ee1..3303293bae8607e992e51f9fe0ec0af334e6a617 100644 --- a/browser/base/content/browser.xul +++ b/browser/base/content/browser.xul @@ -9,7 +9,9 @@ <?xml-stylesheet href="chrome://browser/content/browser.css" type="text/css"?> <?xml-stylesheet href="chrome://browser/content/places/places.css" type="text/css"?> <?xml-stylesheet href="chrome://browser/skin/devtools/common.css" type="text/css"?> +<?xml-stylesheet href="chrome://browser/skin/customizableui/panelUIOverlay.css" type="text/css"?> <?xml-stylesheet href="chrome://browser/skin/" type="text/css"?> +<?xml-stylesheet href="chrome://browser/skin/browser-lightweightTheme.css" type="text/css"?> <?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?> <?xul-overlay href="chrome://browser/content/baseMenuOverlay.xul"?> @@ -38,6 +40,14 @@ titlemodifier="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@" titlemodifier_normal="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@" titlemodifier_privatebrowsing="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@ &mainWindow.titlePrivateBrowsingSuffix;" +#endif +#ifdef CAN_DRAW_IN_TITLEBAR +#ifdef XP_WIN + chromemargin="0,2,2,2" +#else + chromemargin="0,-1,-1,-1" +#endif + tabsintitlebar="true" #endif titlemenuseparator="&mainWindow.titlemodifiermenuseparator;" lightweightthemes="true" @@ -46,6 +56,7 @@ macanimationtype="document" screenX="4" screenY="4" fullscreenbutton="true" + sizemode="normal" persist="screenX screenY width height sizemode"> # All JS files which are not content (only) dependent that browser.xul @@ -257,10 +268,6 @@ <menupopup id="toolbar-context-menu" onpopupshowing="onViewToolbarsPopupShowing(event);"> <menuseparator/> - <menuitem command="cmd_ToggleTabsOnTop" - type="checkbox" - label="&viewTabsOnTop.label;" - accesskey="&viewTabsOnTop.accesskey;"/> <menuitem command="cmd_CustomizeToolbars" label="&viewCustomizeToolbar.label;" accesskey="&viewCustomizeToolbar.accesskey;"/> @@ -381,10 +388,6 @@ <!-- Bookmarks and history tooltip --> <tooltip id="bhTooltip"/> - <panel id="customizeToolbarSheetPopup" - noautohide="true" - sheetstyle="&dialog.dimensions;"/> - <tooltip id="tabbrowser-tab-tooltip" onpopupshowing="gBrowser.createTooltip(event);"/> <tooltip id="back-button-tooltip"> @@ -407,6 +410,8 @@ #include popup-notifications.inc +#include ../../components/customizableui/content/panelUI.inc.xul + <hbox id="downloads-animation-container" mousethrough="always"> <vbox id="downloads-notification-anchor"> <vbox id="downloads-indicator-notification"/> @@ -417,24 +422,21 @@ #ifdef CAN_DRAW_IN_TITLEBAR <vbox id="titlebar"> <hbox id="titlebar-content"> -#ifdef MENUBAR_CAN_AUTOHIDE - <hbox id="appmenu-button-container"> - <button id="appmenu-button" - type="menu" - label="&brandShortName;" - style="-moz-user-focus: ignore;"> -#include browser-appmenu.inc - </button> - </hbox> -#endif <spacer id="titlebar-spacer" flex="1"/> - <hbox id="titlebar-buttonbox-container" align="start"> + <hbox id="titlebar-buttonbox-container" align="start" +#ifdef XP_MACOSX + ordinal="0" +#endif + > <hbox id="titlebar-buttonbox"> <toolbarbutton class="titlebar-button" id="titlebar-min" oncommand="window.minimize();"/> <toolbarbutton class="titlebar-button" id="titlebar-max" oncommand="onTitlebarMaxClick();"/> <toolbarbutton class="titlebar-button" id="titlebar-close" command="cmd_closeWindow"/> </hbox> </hbox> +#ifdef XP_MACOSX + <hbox id="titlebar-fullscreen-button" ordinal="1000"/> +#endif </hbox> </vbox> #endif @@ -442,329 +444,451 @@ <deck flex="1" id="tab-view-deck"> <vbox flex="1" id="browser-panel"> - <toolbox id="navigator-toolbox" - defaultmode="icons" mode="icons" - iconsize="large"> + <toolbox id="navigator-toolbox"> <!-- Menu --> <toolbar type="menubar" id="toolbar-menubar" class="chromeclass-menubar" customizable="true" defaultset="menubar-items" - mode="icons" iconsize="small" defaulticonsize="small" - lockiconsize="true" + mode="icons" iconsize="small" #ifdef MENUBAR_CAN_AUTOHIDE toolbarname="&menubarCmd.label;" accesskey="&menubarCmd.accesskey;" +#ifdef XP_LINUX + autohide="true" +#endif #endif context="toolbar-context-menu"> - <toolbaritem id="menubar-items" align="center"> + <toolbaritem id="menubar-items" align="center" + cui-areatype="toolbar"> # The entire main menubar is placed into browser-menubar.inc, so that it can be shared by # hiddenWindow.xul. #include browser-menubar.inc </toolbaritem> #ifdef CAN_DRAW_IN_TITLEBAR - <hbox class="titlebar-placeholder" type="appmenu-button" ordinal="0"/> - <hbox class="titlebar-placeholder" type="caption-buttons" ordinal="1000"/> +#ifndef XP_MACOSX + <hbox class="titlebar-placeholder" type="caption-buttons" ordinal="1000" + id="titlebar-placeholder-on-menubar-for-caption-buttons" persist="width" + skipintoolbarset="true"/> +#endif #endif </toolbar> - <toolbar id="nav-bar" class="toolbar-primary chromeclass-toolbar" - toolbarname="&navbarCmd.label;" accesskey="&navbarCmd.accesskey;" - fullscreentoolbar="true" mode="icons" customizable="true" - iconsize="large" - defaultset="unified-back-forward-button,urlbar-container,reload-button,stop-button,search-container,webrtc-status-button,bookmarks-menu-button,downloads-button,home-button,window-controls" - context="toolbar-context-menu"> - - <toolbaritem id="unified-back-forward-button" class="chromeclass-toolbar-additional" - context="backForwardMenu" removable="true" - forwarddisabled="true" - title="&backForwardItem.title;"> - <toolbarbutton id="back-button" class="toolbarbutton-1" - label="&backCmd.label;" - command="Browser:BackOrBackDuplicate" - onclick="checkForMiddleClick(this, event);" - tooltip="back-button-tooltip"/> - <toolbarbutton id="forward-button" class="toolbarbutton-1" - label="&forwardCmd.label;" - command="Browser:ForwardOrForwardDuplicate" - onclick="checkForMiddleClick(this, event);" - tooltip="forward-button-tooltip"/> - <dummyobservertarget hidden="true" - onbroadcast="if (this.getAttribute('disabled') == 'true') - this.parentNode.setAttribute('forwarddisabled', 'true'); - else - this.parentNode.removeAttribute('forwarddisabled');"> - <observes element="Browser:ForwardOrForwardDuplicate" attribute="disabled"/> - </dummyobservertarget> - </toolbaritem> + <toolbar id="TabsToolbar" + class="toolbar-primary" + fullscreentoolbar="true" + customizable="true" + mode="icons" + iconsize="small" + aria-label="&tabsToolbar.label;" + context="toolbar-context-menu" + defaultset="tabbrowser-tabs,new-tab-button,alltabs-button,tabs-closebutton" + collapsed="true"> - <toolbaritem id="urlbar-container" align="center" flex="400" persist="width" combined="true" - title="&locationItem.title;" class="chromeclass-location" removable="true"> - <textbox id="urlbar" flex="1" - placeholder="&urlbar.placeholder2;" - type="autocomplete" - autocompletesearch="urlinline history" - autocompletesearchparam="enable-actions" - autocompletepopup="PopupAutoCompleteRichResult" - completeselectedindex="true" - tabscrolling="true" - showcommentcolumn="true" - showimagecolumn="true" - enablehistory="true" - maxrows="6" - newlines="stripsurroundingwhitespace" - oninput="gBrowser.userTypedValue = this.value;" - ontextentered="this.handleCommand(param);" - ontextreverted="return this.handleRevert();" - pageproxystate="invalid" - onfocus="document.getElementById('identity-box').style.MozUserFocus= 'normal'" - onblur="setTimeout(function() document.getElementById('identity-box').style.MozUserFocus = '', 0);"> - <box id="notification-popup-box" hidden="true" align="center"> - <image id="default-notification-icon" class="notification-anchor-icon" role="button"/> - <image id="identity-notification-icon" class="notification-anchor-icon" role="button"/> - <image id="geo-notification-icon" class="notification-anchor-icon" role="button"/> - <image id="addons-notification-icon" class="notification-anchor-icon" role="button"/> - <image id="indexedDB-notification-icon" class="notification-anchor-icon" role="button"/> - <image id="password-notification-icon" class="notification-anchor-icon" role="button"/> - <image id="webapps-notification-icon" class="notification-anchor-icon" role="button"/> - <image id="plugins-notification-icon" class="notification-anchor-icon" role="button"/> - <image id="web-notifications-notification-icon" class="notification-anchor-icon" role="button"/> - <image id="plugin-install-notification-icon" class="notification-anchor-icon" role="button"/> - <image id="mixed-content-blocked-notification-icon" class="notification-anchor-icon" role="button"/> - <image id="webRTC-shareDevices-notification-icon" class="notification-anchor-icon" role="button"/> - <image id="webRTC-sharingDevices-notification-icon" class="notification-anchor-icon" role="button"/> - <image id="pointerLock-notification-icon" class="notification-anchor-icon" role="button"/> - <image id="servicesInstall-notification-icon" class="notification-anchor-icon" role="button"/> - </box> - <!-- Use onclick instead of normal popup= syntax since the popup - code fires onmousedown, and hence eats our favicon drag events. - We only add the identity-box button to the tab order when the location bar - has focus, otherwise pressing F6 focuses it instead of the location bar --> - <box id="identity-box" role="button" - align="center" - onclick="gIdentityHandler.handleIdentityButtonEvent(event);" - onkeypress="gIdentityHandler.handleIdentityButtonEvent(event);" - ondragstart="gIdentityHandler.onDragStart(event);"> - <image id="page-proxy-favicon" - onclick="PageProxyClickHandler(event);" - pageproxystate="invalid"/> - <hbox id="identity-icon-labels"> - <label id="identity-icon-label" class="plain" flex="1"/> - <label id="identity-icon-country-label" class="plain"/> - </hbox> - </box> - <box id="urlbar-display-box" align="center"> - <label id="urlbar-display" value="&urlbar.switchToTab.label;"/> - </box> - <hbox id="urlbar-icons"> - <image id="page-report-button" - class="urlbar-icon" - hidden="true" - tooltiptext="&pageReportIcon.tooltip;" - onclick="gPopupBlockerObserver.onReportButtonClick(event);"/> - <image id="star-button" - class="urlbar-icon" - onclick="if (event.button === 0) BookmarkingUI.onCommand(event);"/> - <image id="go-button" - class="urlbar-icon" - tooltiptext="&goEndCap.tooltip;" - onclick="gURLBar.handleCommand(event);"/> - </hbox> - <toolbarbutton id="urlbar-go-button" - class="chromeclass-toolbar-additional" - onclick="gURLBar.handleCommand(event);" - tooltiptext="&goEndCap.tooltip;"/> - <toolbarbutton id="urlbar-reload-button" - class="chromeclass-toolbar-additional" - command="Browser:ReloadOrDuplicate" - onclick="checkForMiddleClick(this, event);" - tooltiptext="&reloadButton.tooltip;"/> - <toolbarbutton id="urlbar-stop-button" - class="chromeclass-toolbar-additional" - command="Browser:Stop" - tooltiptext="&stopButton.tooltip;"/> - </textbox> - </toolbaritem> + <tabs id="tabbrowser-tabs" + class="tabbrowser-tabs" + tabbrowser="content" + flex="1" + setfocus="false" + tooltip="tabbrowser-tab-tooltip" + cui-areatype="toolbar" + stopwatchid="FX_TAB_CLICK_MS"> + <tab class="tabbrowser-tab" selected="true" fadein="true"/> + </tabs> - <toolbarbutton id="reload-button" class="toolbarbutton-1 chromeclass-toolbar-additional" - label="&reloadCmd.label;" removable="true" - command="Browser:ReloadOrDuplicate" + <toolbarbutton id="new-tab-button" + class="toolbarbutton-1 chromeclass-toolbar-additional" + label="&tabCmd.label;" + command="cmd_newNavigatorTab" onclick="checkForMiddleClick(this, event);" - tooltiptext="&reloadButton.tooltip;"/> - - <toolbarbutton id="stop-button" class="toolbarbutton-1 chromeclass-toolbar-additional" - label="&stopCmd.label;" removable="true" - command="Browser:Stop" - tooltiptext="&stopButton.tooltip;"/> - - <toolbaritem id="search-container" title="&searchItem.title;" - align="center" class="chromeclass-toolbar-additional" - flex="100" persist="width" removable="true"> - <searchbar id="searchbar" flex="1"/> - </toolbaritem> + tooltiptext="&newTabButton.tooltip;" + ondrop="newTabButtonObserver.onDrop(event)" + ondragover="newTabButtonObserver.onDragOver(event)" + ondragenter="newTabButtonObserver.onDragOver(event)" + ondragexit="newTabButtonObserver.onDragExit(event)" + cui-areatype="toolbar" + removable="true"/> - <toolbarbutton id="webrtc-status-button" - class="toolbarbutton-1 chromeclass-toolbar-additional" + <toolbarbutton id="alltabs-button" + class="toolbarbutton-1 chromeclass-toolbar-additional tabs-alltabs-button" type="menu" - hidden="true" - orient="horizontal" - label="&webrtcIndicatorButton.label;" - tooltiptext="&webrtcIndicatorButton.tooltip;"> - <menupopup onpopupshowing="WebrtcIndicator.fillPopup(this);" - onpopuphiding="WebrtcIndicator.clearPopup(this);" - oncommand="WebrtcIndicator.menuCommand(event.target);"/> + label="&listAllTabs.label;" + tooltiptext="&listAllTabs.label;" + 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" + cui-areatype="toolbar" + observes="tabviewGroupsNumber"/> + <menuseparator id="alltabs-popup-separator"/> + </menupopup> </toolbarbutton> - <toolbarbutton id="bookmarks-menu-button" - class="toolbarbutton-1 chromeclass-toolbar-additional" - persist="class" - removable="true" - type="menu" - label="&bookmarksMenuButton.label;" - tooltiptext="&bookmarksMenuButton.tooltip;" - ondragenter="PlacesMenuDNDHandler.onDragEnter(event);" - ondragover="PlacesMenuDNDHandler.onDragOver(event);" - ondragleave="PlacesMenuDNDHandler.onDragLeave(event);" - ondrop="PlacesMenuDNDHandler.onDrop(event);"> - <menupopup id="BMB_bookmarksPopup" - placespopup="true" - context="placesContext" - openInTabs="children" - oncommand="BookmarksEventHandler.onCommand(event, this.parentNode._placesView);" - onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);" - onpopupshowing="BookmarkingUI.onPopupShowing(event); - if (!this.parentNode._placesView) - new PlacesMenu(event, 'place:folder=BOOKMARKS_MENU');" - tooltip="bhTooltip" popupsinherittooltip="true"> - <menuitem id="BMB_viewBookmarksToolbar" - placesanonid="view-toolbar" - toolbarId="PersonalToolbar" - type="checkbox" - oncommand="onViewToolbarCommand(event)" - label="&viewBookmarksToolbar.label;"/> - <menuseparator/> - <menuitem id="BMB_bookmarksShowAll" - label="&showAllBookmarks2.label;" - command="Browser:ShowAllBookmarks" - key="manBookmarkKb"/> - <menuseparator/> - <menuitem id="BMB_bookmarkThisPage" + <toolbarbutton id="tabs-closebutton" + class="close-button tabs-closebutton close-icon" + command="cmd_close" + label="&closeTab.label;" + cui-areatype="toolbar" + tooltiptext="&closeTab.label;"/> + +#ifdef CAN_DRAW_IN_TITLEBAR + <hbox class="titlebar-placeholder" type="caption-buttons" + id="titlebar-placeholder-on-TabsToolbar-for-captions-buttons" persist="width" #ifndef XP_MACOSX - class="menuitem-iconic" + ordinal="1000" #endif - label="&bookmarkThisPageCmd.label;" - command="Browser:AddBookmarkAs" - key="addBookmarkAsKb"/> - <menuitem id="BMB_subscribeToPageMenuitem" + skipintoolbarset="true"/> + +#ifdef XP_MACOSX + <hbox class="titlebar-placeholder" type="fullscreen-button" + id="titlebar-placeholder-on-TabsToolbar-for-fullscreen-button" persist="width" + skipintoolbarset="true"/> +#endif +#endif + </toolbar> + + <!-- + CAVEAT EMPTOR + Should you need to add items to the toolbar here, make sure to also add them + to the default placements of buttons in CustomizableUI.jsm, so the + customization code doesn't get confused. + --> + <toolbar id="nav-bar" class="toolbar-primary chromeclass-toolbar" + aria-label="&navbarCmd.label;" + fullscreentoolbar="true" mode="icons" customizable="true" + iconsize="small" + defaultset="urlbar-container,search-container,webrtc-status-button,bookmarks-menu-button,downloads-button,home-button,social-share-button,social-toolbar-item" + customizationtarget="nav-bar-customization-target" + overflowable="true" + overflowbutton="nav-bar-overflow-button" + overflowtarget="widget-overflow-list" + context="toolbar-context-menu"> + + <hbox id="nav-bar-customization-target" class="customization-target" flex="1"> + <toolbaritem id="urlbar-container" flex="400" persist="width" + forwarddisabled="true" title="&locationItem.title;" removable="false" + cui-areatype="toolbar" + class="chromeclass-location" overflows="false"> + <toolbarbutton id="back-button" class="toolbarbutton-1 chromeclass-toolbar-additional" + label="&backCmd.label;" + command="Browser:BackOrBackDuplicate" + onclick="checkForMiddleClick(this, event);" + tooltip="back-button-tooltip" + context="backForwardMenu"/> + <toolbarbutton id="forward-button" class="toolbarbutton-1 chromeclass-toolbar-additional" + label="&forwardCmd.label;" + command="Browser:ForwardOrForwardDuplicate" + onclick="checkForMiddleClick(this, event);" + tooltip="forward-button-tooltip" + context="backForwardMenu"/> + <dummyobservertarget hidden="true" + onbroadcast="if (this.getAttribute('disabled') == 'true') + this.parentNode.setAttribute('forwarddisabled', 'true'); + else + this.parentNode.removeAttribute('forwarddisabled');"> + <observes element="Browser:ForwardOrForwardDuplicate" attribute="disabled"/> + </dummyobservertarget> + <hbox id="urlbar-wrapper" flex="1" align="center"> + <textbox id="urlbar" flex="1" + placeholder="&urlbar.placeholder2;" + type="autocomplete" + autocompletesearch="urlinline history" + autocompletesearchparam="enable-actions" + autocompletepopup="PopupAutoCompleteRichResult" + completeselectedindex="true" + tabscrolling="true" + showcommentcolumn="true" + showimagecolumn="true" + enablehistory="true" + maxrows="6" + newlines="stripsurroundingwhitespace" + oninput="gBrowser.userTypedValue = this.value;" + ontextentered="this.handleCommand(param);" + ontextreverted="return this.handleRevert();" + pageproxystate="invalid" + onfocus="document.getElementById('identity-box').style.MozUserFocus= 'normal'" + onblur="setTimeout(function() document.getElementById('identity-box').style.MozUserFocus = '', 0);"> + <box id="notification-popup-box" hidden="true" align="center"> + <image id="default-notification-icon" class="notification-anchor-icon" role="button"/> + <image id="identity-notification-icon" class="notification-anchor-icon" role="button"/> + <image id="geo-notification-icon" class="notification-anchor-icon" role="button"/> + <image id="addons-notification-icon" class="notification-anchor-icon" role="button"/> + <image id="indexedDB-notification-icon" class="notification-anchor-icon" role="button"/> + <image id="password-notification-icon" class="notification-anchor-icon" role="button"/> + <image id="webapps-notification-icon" class="notification-anchor-icon" role="button"/> + <image id="plugins-notification-icon" class="notification-anchor-icon" role="button"/> + <image id="web-notifications-notification-icon" class="notification-anchor-icon" role="button"/> + <image id="plugin-install-notification-icon" class="notification-anchor-icon" role="button"/> + <image id="mixed-content-blocked-notification-icon" class="notification-anchor-icon" role="button"/> + <image id="webRTC-shareDevices-notification-icon" class="notification-anchor-icon" role="button"/> + <image id="webRTC-sharingDevices-notification-icon" class="notification-anchor-icon" role="button"/> + <image id="pointerLock-notification-icon" class="notification-anchor-icon" role="button"/> + <image id="servicesInstall-notification-icon" class="notification-anchor-icon" role="button"/> + </box> + <!-- Use onclick instead of normal popup= syntax since the popup + code fires onmousedown, and hence eats our favicon drag events. + We only add the identity-box button to the tab order when the location bar + has focus, otherwise pressing F6 focuses it instead of the location bar --> + <box id="identity-box" role="button" + align="center" + onclick="gIdentityHandler.handleIdentityButtonEvent(event);" + onkeypress="gIdentityHandler.handleIdentityButtonEvent(event);" + ondragstart="gIdentityHandler.onDragStart(event);"> + <image id="page-proxy-favicon" + onclick="PageProxyClickHandler(event);" + pageproxystate="invalid"/> + <hbox id="identity-icon-labels"> + <label id="identity-icon-label" class="plain" flex="1"/> + <label id="identity-icon-country-label" class="plain"/> + </hbox> + </box> + <box id="urlbar-display-box" align="center"> + <label id="urlbar-display" value="&urlbar.switchToTab.label;"/> + </box> + <hbox id="urlbar-icons"> + <image id="page-report-button" + class="urlbar-icon" + hidden="true" + tooltiptext="&pageReportIcon.tooltip;" + onclick="gPopupBlockerObserver.onReportButtonClick(event);"/> + <image id="star-button" + class="urlbar-icon" + onclick="if (event.button === 0) BookmarkingUI.onCommand(event);"/> + </hbox> + <toolbarbutton id="urlbar-go-button" + class="chromeclass-toolbar-additional" + onclick="gURLBar.handleCommand(event);" + tooltiptext="&goEndCap.tooltip;"/> + <toolbarbutton id="urlbar-reload-button" + class="chromeclass-toolbar-additional" + command="Browser:ReloadOrDuplicate" + onclick="checkForMiddleClick(this, event);" + tooltiptext="&reloadButton.tooltip;"/> + <toolbarbutton id="urlbar-stop-button" + class="chromeclass-toolbar-additional" + command="Browser:Stop" + tooltiptext="&stopButton.tooltip;"/> + </textbox> + </hbox> + </toolbaritem> + + <toolbaritem id="search-container" title="&searchItem.title;" + align="center" class="chromeclass-toolbar-additional panel-wide-item" + cui-areatype="toolbar" + flex="100" persist="width" removable="true"> + <searchbar id="searchbar" flex="1"/> + </toolbaritem> + + <toolbarbutton id="webrtc-status-button" + class="toolbarbutton-1 chromeclass-toolbar-additional" + type="menu" + hidden="true" + orient="horizontal" + label="&webrtcIndicatorButton.label;" + tooltiptext="&webrtcIndicatorButton.tooltip;" + cui-areatype="toolbar" + overflows="false"> + <menupopup onpopupshowing="WebrtcIndicator.fillPopup(this);" + onpopuphiding="WebrtcIndicator.clearPopup(this);" + oncommand="WebrtcIndicator.menuCommand(event.target);"/> + </toolbarbutton> + + <toolbarbutton id="bookmarks-menu-button" + class="toolbarbutton-1 chromeclass-toolbar-additional" + persist="class" + removable="true" + type="menu-button" + label="&bookmarksMenuButton.label;" + tooltiptext="&bookmarksMenuButton.tooltip;" + ondragenter="PlacesMenuDNDHandler.onDragEnter(event);" + ondragover="PlacesMenuDNDHandler.onDragOver(event);" + ondragleave="PlacesMenuDNDHandler.onDragLeave(event);" + ondrop="PlacesMenuDNDHandler.onDrop(event);" + cui-areatype="toolbar" + oncommand="BookmarkingUI.onCommand(event);"> + <menupopup id="BMB_bookmarksPopup" + placespopup="true" + context="placesContext" + openInTabs="children" + anonanchorclass="toolbarbutton-menubutton-dropmarker" + oncommand="BookmarksEventHandler.onCommand(event, this.parentNode._placesView);" + onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);" + onpopupshowing="BookmarkingUI.onPopupShowing(event); + if (!this.parentNode._placesView) + new PlacesMenu(event, 'place:folder=BOOKMARKS_MENU');" + tooltip="bhTooltip" popupsinherittooltip="true"> + <menuitem id="BMB_bookmarksShowAll" + label="&showAllBookmarks2.label;" + command="Browser:ShowAllBookmarks" + key="manBookmarkKb"/> + <menuitem id="BMB_viewBookmarksSidebar" + label="&viewBookmarksSidebar2.label;" + type="checkbox" + oncommand="toggleSidebar('viewBookmarksSidebar');"> + <observes element="viewBookmarksSidebar" attribute="checked"/> + </menuitem> + <menuseparator/> + <menuitem id="BMB_subscribeToPageMenuitem" #ifndef XP_MACOSX - class="menuitem-iconic" + class="menuitem-iconic" #endif - label="&subscribeToPageMenuitem.label;" - oncommand="return FeedHandler.subscribeToFeed(null, event);" - onclick="checkForMiddleClick(this, event);" - observes="singleFeedMenuitemState"/> - <menu id="BMB_subscribeToPageMenupopup" + label="&subscribeToPageMenuitem.label;" + oncommand="return FeedHandler.subscribeToFeed(null, event);" + onclick="checkForMiddleClick(this, event);" + observes="singleFeedMenuitemState"/> + <menu id="BMB_subscribeToPageMenupopup" #ifndef XP_MACOSX - class="menu-iconic" + class="menu-iconic" #endif - label="&subscribeToPageMenupopup.label;" - observes="multipleFeedsMenuState"> - <menupopup id="BMB_subscribeToPageSubmenuMenupopup" - onpopupshowing="return FeedHandler.buildFeedList(event.target);" - oncommand="return FeedHandler.subscribeToFeed(null, event);" - onclick="checkForMiddleClick(this, event);"/> - </menu> - <menuseparator/> - <menu id="BMB_bookmarksToolbar" - placesanonid="toolbar-autohide" - class="menu-iconic bookmark-item" - label="&personalbarCmd.label;" - container="true"> - <menupopup id="BMB_bookmarksToolbarPopup" - placespopup="true" - context="placesContext" - onpopupshowing="if (!this.parentNode._placesView) - new PlacesMenu(event, 'place:folder=TOOLBAR');"/> - </menu> - <menuseparator/> - <!-- Bookmarks menu items --> - <menuseparator builder="end" - class="hide-if-empty-places-result"/> - <menuitem id="BMB_unsortedBookmarks" - label="&bookmarksMenuButton.unsorted.label;" - oncommand="PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks');" - class="menuitem-iconic"/> - </menupopup> - </toolbarbutton> + label="&subscribeToPageMenupopup.label;" + observes="multipleFeedsMenuState"> + <menupopup id="BMB_subscribeToPageSubmenuMenupopup" + onpopupshowing="return FeedHandler.buildFeedList(event.target);" + oncommand="return FeedHandler.subscribeToFeed(null, event);" + onclick="checkForMiddleClick(this, event);"/> + </menu> + <menuseparator/> + <menu id="BMB_bookmarksToolbar" + class="menu-iconic bookmark-item" + label="&personalbarCmd.label;" + container="true"> + <menupopup id="BMB_bookmarksToolbarPopup" + placespopup="true" + context="placesContext" + onpopupshowing="if (!this.parentNode._placesView) + new PlacesMenu(event, 'place:folder=TOOLBAR');"> + <menuitem id="BMB_viewBookmarksToolbar" + placesanonid="view-toolbar" + toolbarId="PersonalToolbar" + type="checkbox" + oncommand="onViewToolbarCommand(event)" + label="&viewBookmarksToolbar.label;"/> + <menuseparator/> + <!-- Bookmarks toolbar items --> + </menupopup> + </menu> + <menu id="BMB_unsortedBookmarks" + class="menu-iconic bookmark-item" + label="&bookmarksMenuButton.unsorted.label;" + container="true"> + <menupopup id="BMB_unsortedBookmarksPopup" + placespopup="true" + context="placesContext" + onpopupshowing="if (!this.parentNode._placesView) + new PlacesMenu(event, 'place:folder=UNFILED_BOOKMARKS');"/> + </menu> + <menuseparator/> + <!-- Bookmarks menu items --> + </menupopup> + </toolbarbutton> - <toolbarbutton id="home-button" class="toolbarbutton-1 chromeclass-toolbar-additional" - persist="class" removable="true" - label="&homeButton.label;" - ondragover="homeButtonObserver.onDragOver(event)" - ondragenter="homeButtonObserver.onDragOver(event)" - ondrop="homeButtonObserver.onDrop(event)" - ondragexit="homeButtonObserver.onDragExit(event)" - onclick="BrowserGoHome(event);" - aboutHomeOverrideTooltip="&abouthome.pageTitle;"/> - - <toolbarbutton id="social-share-button" - class="toolbarbutton-1 chromeclass-toolbar-additional" + <!-- This is a placeholder for the Downloads Indicator. It is visible + during the customization of the toolbar, in the palette, and before + the Downloads Indicator overlay is loaded. --> + <toolbarbutton id="downloads-button" class="toolbarbutton-1 chromeclass-toolbar-additional" + oncommand="DownloadsIndicatorView.onCommand(event);" + ondrop="DownloadsIndicatorView.onDrop(event);" + ondragover="DownloadsIndicatorView.onDragOver(event);" + ondragenter="DownloadsIndicatorView.onDragOver(event);" + label="&downloads.label;" + removable="true" + cui-areatype="toolbar" + tooltiptext="&downloads.tooltip;"/> + + <toolbarbutton id="home-button" class="toolbarbutton-1 chromeclass-toolbar-additional" + persist="class" removable="true" + label="&homeButton.label;" + ondragover="homeButtonObserver.onDragOver(event)" + ondragenter="homeButtonObserver.onDragOver(event)" + ondrop="homeButtonObserver.onDrop(event)" + ondragexit="homeButtonObserver.onDragExit(event)" + onclick="BrowserGoHome(event);" + cui-areatype="toolbar" + aboutHomeOverrideTooltip="&abouthome.pageTitle;"/> + + + <toolbarbutton id="social-share-button" + class="toolbarbutton-1 chromeclass-toolbar-additional" + hidden="true" + overflows="false" + label="&sharePageCmd.label;" + tooltiptext="&sharePageCmd.label;" + cui-areatype="toolbar" + command="Social:SharePage"/> + + <toolbaritem id="social-toolbar-item" + class="chromeclass-toolbar-additional toolbaritem-with-separator" + removable="false" + title="&socialToolbar.title;" hidden="true" - label="&sharePageCmd.label;" - tooltiptext="&sharePageCmd.label;" - command="Social:SharePage"/> - - <toolbaritem id="social-toolbar-item" - class="chromeclass-toolbar-additional" - removable="false" - title="&socialToolbar.title;" - hidden="true" - skipintoolbarset="true" - observes="socialActiveBroadcaster"> + overflows="false" + cui-areatype="toolbar" + observes="socialActiveBroadcaster"> <toolbarbutton id="social-notification-icon" class="default-notification-icon toolbarbutton-1 notification-anchor-icon" oncommand="PopupNotifications._reshowNotifications(this, document.getElementById('social-sidebar-browser'));"/> - <toolbarbutton id="social-provider-button" - class="toolbarbutton-1" - type="menu"> - <menupopup id="social-statusarea-popup"> - <menuitem class="social-statusarea-user menuitem-iconic" pack="start" align="center" - observes="socialBroadcaster_userDetails" - oncommand="SocialUI.showProfile(); document.getElementById('social-statusarea-popup').hidePopup();"> - <image class="social-statusarea-user-portrait" - observes="socialBroadcaster_userDetails"/> - <vbox> - <label class="social-statusarea-loggedInStatus" + <toolbarbutton id="social-provider-button" + class="toolbarbutton-1" + type="menu"> + <menupopup id="social-statusarea-popup"> + <menuitem class="social-statusarea-user menuitem-iconic" pack="start" align="center" + observes="socialBroadcaster_userDetails" + oncommand="SocialUI.showProfile(); document.getElementById('social-statusarea-popup').hidePopup();"> + <image class="social-statusarea-user-portrait" observes="socialBroadcaster_userDetails"/> - </vbox> - </menuitem> + <vbox> + <label class="social-statusarea-loggedInStatus" + observes="socialBroadcaster_userDetails"/> + </vbox> + </menuitem> #ifndef XP_WIN - <menuseparator class="social-statusarea-separator"/> + <menuseparator class="social-statusarea-separator"/> #endif - <menuitem class="social-toggle-sidebar-menuitem" - type="checkbox" - autocheck="false" - command="Social:ToggleSidebar" - label="&social.toggleSidebar.label;" - accesskey="&social.toggleSidebar.accesskey;"/> - <menuitem class="social-toggle-notifications-menuitem" - type="checkbox" - autocheck="false" - command="Social:ToggleNotifications" - label="&social.toggleNotifications.label;" - accesskey="&social.toggleNotifications.accesskey;"/> - <menuitem class="social-toggle-menuitem" command="Social:Toggle"/> - <menuseparator/> - <menuseparator class="social-provider-menu" hidden="true"/> - <menuitem class="social-addons-menuitem" command="Social:Addons" - label="&social.addons.label;"/> - <menuitem label="&social.learnMore.label;" - accesskey="&social.learnMore.accesskey;" - oncommand="SocialUI.showLearnMore();"/> - </menupopup> - </toolbarbutton> + <menuitem class="social-toggle-sidebar-menuitem" + type="checkbox" + autocheck="false" + command="Social:ToggleSidebar" + label="&social.toggleSidebar.label;" + accesskey="&social.toggleSidebar.accesskey;"/> + <menuitem class="social-toggle-notifications-menuitem" + type="checkbox" + autocheck="false" + command="Social:ToggleNotifications" + label="&social.toggleNotifications.label;" + accesskey="&social.toggleNotifications.accesskey;"/> + <menuitem class="social-toggle-menuitem" command="Social:Toggle"/> + <menuseparator/> + <menuseparator class="social-provider-menu" hidden="true"/> + <menuitem class="social-addons-menuitem" command="Social:Addons" + label="&social.addons.label;"/> + <menuitem label="&social.learnMore.label;" + accesskey="&social.learnMore.accesskey;" + oncommand="SocialUI.showLearnMore();"/> + </menupopup> + </toolbarbutton> + </toolbaritem> + </hbox> + + <toolbarbutton id="nav-bar-overflow-button" + class="toolbarbutton-1 chromeclass-toolbar-additional overflow-button" + skipintoolbarset="true" + tooltiptext="&navbarOverflow.label;"/> + + <toolbaritem id="PanelUI-button" + class="chromeclass-toolbar-additional" + removable="false" + title="&appmenu.title;"> + <toolbarbutton id="PanelUI-menu-button" + class="toolbarbutton-1" + label="&brandShortName;" + tooltiptext="&appmenu.title;"/> </toolbaritem> - <hbox id="window-controls" hidden="true" pack="end"> + <hbox id="window-controls" hidden="true" pack="end" skipintoolbarset="true" + ordinal="1000"> <toolbarbutton id="minimize-button" tooltiptext="&fullScreenMinimize.tooltip;" oncommand="window.minimize();"/> @@ -782,16 +906,23 @@ <toolbarset id="customToolbars" context="toolbar-context-menu"/> <toolbar id="PersonalToolbar" - mode="icons" iconsize="small" defaulticonsize="small" - lockiconsize="true" + mode="icons" iconsize="small" class="chromeclass-directories" context="toolbar-context-menu" defaultset="personal-bookmarks" toolbarname="&personalbarCmd.label;" accesskey="&personalbarCmd.accesskey;" collapsed="true" customizable="true"> - <toolbaritem flex="1" id="personal-bookmarks" title="&bookmarksItem.title;" + <toolbaritem id="personal-bookmarks" + flex="1" + title="&bookmarksToolbarItem.label;" + cui-areatype="toolbar" removable="true"> + <toolbarbutton id="bookmarks-toolbar-placeholder" + type="wrap" + mousethrough="never" + label="&bookmarksToolbarItem.label;" + oncommand="PlacesToolbarHelper.onPlaceholderCommand();"/> <hbox flex="1" id="PlacesToolbar" context="placesContext" @@ -799,9 +930,6 @@ oncommand="BookmarksEventHandler.onCommand(event, this._placesView);" tooltip="bhTooltip" popupsinherittooltip="true"> - <toolbarbutton class="bookmark-item bookmarks-toolbar-customize" - mousethrough="never" - label="&bookmarksToolbarItem.label;"/> <hbox flex="1"> <hbox align="center"> <image id="PlacesToolbarDropIndicator" @@ -829,88 +957,10 @@ </toolbaritem> </toolbar> -#ifdef MENUBAR_CAN_AUTOHIDE -#ifndef CAN_DRAW_IN_TITLEBAR -#define APPMENU_ON_TABBAR -#endif -#endif - - - <toolbar id="TabsToolbar" - class="toolbar-primary" - fullscreentoolbar="true" - customizable="true" - mode="icons" lockmode="true" - iconsize="small" defaulticonsize="small" lockiconsize="true" - aria-label="&tabsToolbar.label;" - context="toolbar-context-menu" -#ifdef APPMENU_ON_TABBAR - defaultset="appmenu-toolbar-button,tabbrowser-tabs,new-tab-button,alltabs-button,tabs-closebutton" -#else - defaultset="tabbrowser-tabs,new-tab-button,alltabs-button,tabs-closebutton" -#endif - collapsed="true"> - -#ifdef APPMENU_ON_TABBAR - <toolbarbutton id="appmenu-toolbar-button" - class="chromeclass-toolbar-additional" - type="menu" - label="&brandShortName;" - tooltiptext="&appMenuButton.tooltip;"> -#include browser-appmenu.inc - </toolbarbutton> -#endif - - <tabs id="tabbrowser-tabs" - class="tabbrowser-tabs" - tabbrowser="content" - flex="1" - setfocus="false" - tooltip="tabbrowser-tab-tooltip" - stopwatchid="FX_TAB_CLICK_MS"> - <tab class="tabbrowser-tab" selected="true" fadein="true"/> - </tabs> - - <toolbarbutton id="new-tab-button" - class="toolbarbutton-1 chromeclass-toolbar-additional" - label="&tabCmd.label;" - command="cmd_newNavigatorTab" - onclick="checkForMiddleClick(this, event);" - tooltiptext="&newTabButton.tooltip;" - ondrop="newTabButtonObserver.onDrop(event)" - ondragover="newTabButtonObserver.onDragOver(event)" - ondragenter="newTabButtonObserver.onDragOver(event)" - ondragexit="newTabButtonObserver.onDragExit(event)" - removable="true"/> - - <toolbarbutton id="alltabs-button" - class="toolbarbutton-1 chromeclass-toolbar-additional tabs-alltabs-button" - type="menu" - label="&listAllTabs.label;" - tooltiptext="&listAllTabs.label;" - removable="true"> - <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"/> - <menuseparator id="alltabs-popup-separator"/> - </menupopup> - </toolbarbutton> - - <toolbarbutton id="tabs-closebutton" - class="close-button tabs-closebutton" - command="cmd_close" - label="&closeTab.label;" - tooltiptext="&closeTab.label;"/> - -#ifdef CAN_DRAW_IN_TITLEBAR - <hbox class="titlebar-placeholder" type="appmenu-button" ordinal="0"/> - <hbox class="titlebar-placeholder" type="caption-buttons" ordinal="1000"/> -#endif + <!-- This is a shim which will go away ASAP. See bug 749804 for details --> + <toolbar id="addon-bar" toolbar-delegate="nav-bar"> + <hbox id="addonbar-closebutton"/> + <statusbar id="status-bar"/> </toolbar> <toolbarpalette id="BrowserToolbarPalette"> @@ -919,31 +969,13 @@ # or removing default items with the toolbarbutton-1 class. <toolbarbutton id="print-button" class="toolbarbutton-1 chromeclass-toolbar-additional" - label="&printButton.label;" command="cmd_print" - tooltiptext="&printButton.tooltip;"/> - - <!-- This is a placeholder for the Downloads Indicator. It is visible - during the customization of the toolbar, in the palette, and before - the Downloads Indicator overlay is loaded. --> - <toolbarbutton id="downloads-button" class="toolbarbutton-1 chromeclass-toolbar-additional" - oncommand="DownloadsIndicatorView.onCommand(event);" - ondrop="DownloadsIndicatorView.onDrop(event);" - ondragover="DownloadsIndicatorView.onDragOver(event);" - ondragenter="DownloadsIndicatorView.onDragOver(event);" - label="&downloads.label;" - tooltiptext="&downloads.tooltip;"/> - - <toolbarbutton id="history-button" class="toolbarbutton-1 chromeclass-toolbar-additional" - observes="viewHistorySidebar" label="&historyButton.label;" - tooltiptext="&historyButton.tooltip;"/> - - <toolbarbutton id="bookmarks-button" class="toolbarbutton-1 chromeclass-toolbar-additional" - observes="viewBookmarksSidebar" - tooltiptext="&bookmarksButton.tooltip;" - ondrop="bookmarksButtonObserver.onDrop(event)" - ondragover="bookmarksButtonObserver.onDragOver(event)" - ondragenter="bookmarksButtonObserver.onDragOver(event)" - ondragexit="bookmarksButtonObserver.onDragExit(event)"/> +#ifdef XP_MACOSX + command="cmd_print" +#else + command="cmd_printPreview" +#endif + label="&printButton.label;" tooltiptext="&printButton.tooltip;"/> + <toolbarbutton id="new-window-button" class="toolbarbutton-1 chromeclass-toolbar-additional" label="&newNavigatorCmd.label;" @@ -960,47 +992,6 @@ label="&fullScreenCmd.label;" tooltiptext="&fullScreenButton.tooltip;"/> - <toolbaritem id="zoom-controls" class="chromeclass-toolbar-additional" - title="&zoomControls.label;"> - <toolbarbutton id="zoom-out-button" class="toolbarbutton-1" - label="&fullZoomReduceCmd.label;" - command="cmd_fullZoomReduce" - tooltiptext="&zoomOutButton.tooltip;"/> - <toolbarbutton id="zoom-in-button" class="toolbarbutton-1" - label="&fullZoomEnlargeCmd.label;" - command="cmd_fullZoomEnlarge" - tooltiptext="&zoomInButton.tooltip;"/> - </toolbaritem> - - <toolbarbutton id="feed-button" - type="menu" - class="toolbarbutton-1 chromeclass-toolbar-additional" - disabled="true" - label="&feedButton.label;" - tooltiptext="&feedButton.tooltip;" - onclick="return FeedHandler.onFeedButtonClick(event);"> - <menupopup position="after_end" - id="feed-menu" - onpopupshowing="return FeedHandler.buildFeedList(this);" - oncommand="return FeedHandler.subscribeToFeed(null, event);" - onclick="checkForMiddleClick(this, event);"/> - </toolbarbutton> - - <toolbarbutton id="cut-button" class="toolbarbutton-1 chromeclass-toolbar-additional" - label="&cutCmd.label;" - command="cmd_cut" - tooltiptext="&cutButton.tooltip;"/> - - <toolbarbutton id="copy-button" class="toolbarbutton-1 chromeclass-toolbar-additional" - label="©Cmd.label;" - command="cmd_copy" - tooltiptext="©Button.tooltip;"/> - - <toolbarbutton id="paste-button" class="toolbarbutton-1 chromeclass-toolbar-additional" - label="&pasteCmd.label;" - command="cmd_paste" - tooltiptext="&pasteButton.tooltip;"/> - #ifdef MOZ_SERVICES_SYNC <toolbarbutton id="sync-button" class="toolbarbutton-1 chromeclass-toolbar-additional" @@ -1008,11 +999,6 @@ oncommand="gSyncUI.handleToolbarButton()"/> #endif - <toolbaritem id="navigator-throbber" title="&throbberItem.title;" align="center" pack="center" - mousethrough="always"> - <image/> - </toolbaritem> - <toolbarbutton id="tabview-button" class="toolbarbutton-1 chromeclass-toolbar-additional" label="&tabGroupsButton.label;" command="Browser:ToggleTabView" @@ -1023,46 +1009,50 @@ <hbox id="fullscr-toggler" collapsed="true"/> - <hbox flex="1" id="browser"> - <vbox id="browser-border-start" hidden="true" layer="true"/> - <vbox id="sidebar-box" hidden="true" class="chromeclass-extrachrome"> - <sidebarheader id="sidebar-header" align="center"> - <label id="sidebar-title" persist="value" flex="1" crop="end" control="sidebar"/> - <image id="sidebar-throbber"/> - <toolbarbutton class="tabs-closebutton" tooltiptext="&sidebarCloseButton.tooltip;" oncommand="toggleSidebar();"/> - </sidebarheader> - <browser id="sidebar" flex="1" autoscroll="false" disablehistory="true" - style="min-width: 14em; width: 18em; max-width: 36em;"/> - </vbox> - - <splitter id="sidebar-splitter" class="chromeclass-extrachrome sidebar-splitter" hidden="true"/> - <vbox id="appcontent" flex="1"> - <tabbrowser id="content" - flex="1" contenttooltip="aHTMLTooltip" - tabcontainer="tabbrowser-tabs" - contentcontextmenu="contentAreaContextMenu" - autocompletepopup="PopupAutoComplete" - selectpopup="ContentSelectDropdown"/> - <chatbar id="pinnedchats" layer="true" mousethrough="always" hidden="true"/> - </vbox> - <splitter id="social-sidebar-splitter" - class="chromeclass-extrachrome sidebar-splitter" - observes="socialSidebarBroadcaster"/> - <vbox id="social-sidebar-box" - class="chromeclass-extrachrome" - observes="socialSidebarBroadcaster" - persist="width"> - <browser id="social-sidebar-browser" - type="content" - context="contentAreaContextMenu" - disableglobalhistory="true" - tooltip="aHTMLTooltip" + <deck id="content-deck" flex="1"> + <hbox flex="1" id="browser"> + <vbox id="browser-border-start" hidden="true" layer="true"/> + <vbox id="sidebar-box" hidden="true" class="chromeclass-extrachrome"> + <sidebarheader id="sidebar-header" align="center"> + <label id="sidebar-title" persist="value" flex="1" crop="end" control="sidebar"/> + <image id="sidebar-throbber"/> + <toolbarbutton class="tabs-closebutton close-icon" tooltiptext="&sidebarCloseButton.tooltip;" oncommand="toggleSidebar();"/> + </sidebarheader> + <browser id="sidebar" flex="1" autoscroll="false" disablehistory="true" + style="min-width: 14em; width: 18em; max-width: 36em;"/> + </vbox> + + <splitter id="sidebar-splitter" class="chromeclass-extrachrome sidebar-splitter" hidden="true"/> + <vbox id="appcontent" flex="1"> + <tabbrowser id="content" + flex="1" contenttooltip="aHTMLTooltip" + tabcontainer="tabbrowser-tabs" + contentcontextmenu="contentAreaContextMenu" + autocompletepopup="PopupAutoComplete" + selectpopup="ContentSelectDropdown" + onclick="contentAreaClick(event, false);"/> + <chatbar id="pinnedchats" layer="true" mousethrough="always" hidden="true"/> + </vbox> + <splitter id="social-sidebar-splitter" + class="chromeclass-extrachrome sidebar-splitter" + observes="socialSidebarBroadcaster"/> + <vbox id="social-sidebar-box" + class="chromeclass-extrachrome" + observes="socialSidebarBroadcaster" + persist="width"> + <browser id="social-sidebar-browser" + type="content" + context="contentAreaContextMenu" + disableglobalhistory="true" + tooltip="aHTMLTooltip" popupnotificationanchor="social-notification-icon" - flex="1" - style="min-width: 14em; width: 18em; max-width: 36em;"/> - </vbox> - <vbox id="browser-border-end" hidden="true" layer="true"/> - </hbox> + flex="1" + style="min-width: 14em; width: 18em; max-width: 36em;"/> + </vbox> + <vbox id="browser-border-end" hidden="true" layer="true"/> + </hbox> +#include ../../components/customizableui/content/customizeMode.inc.xul + </deck> <hbox id="full-screen-warning-container" hidden="true" fadeout="true"> <hbox style="width: 100%;" pack="center"> <!-- Inner hbox needed due to bug 579776. --> @@ -1119,56 +1109,28 @@ tooltiptext="&devToolbarCloseButton.tooltiptext;"/> #endif </toolbar> - - <toolbar id="addon-bar" - toolbarname="&addonBarCmd.label;" accesskey="&addonBarCmd.accesskey;" - collapsed="true" - class="toolbar-primary chromeclass-toolbar" - context="toolbar-context-menu" toolboxid="navigator-toolbox" - mode="icons" iconsize="small" defaulticonsize="small" - lockiconsize="true" - defaultset="addonbar-closebutton,spring,status-bar" - customizable="true" - key="key_toggleAddonBar"> - <toolbarbutton id="addonbar-closebutton" - tooltiptext="&addonBarCloseButton.tooltip;" - oncommand="setToolbarVisibility(this.parentNode, false);"/> - <statusbar id="status-bar" ordinal="1000"/> - </toolbar> </vbox> -#ifndef XP_UNIX <svg:svg height="0"> +#include tab-shape.inc.svg + +#ifndef XP_UNIX <svg:clipPath id="windows-keyhole-forward-clip-path" clipPathUnits="objectBoundingBox"> <svg:path d="M 0,0 C 0.16,0.11 0.28,0.29 0.28,0.5 0.28,0.71 0.16,0.89 0,1 L 1,1 1,0 0,0 z"/> </svg:clipPath> <svg:clipPath id="windows-urlbar-back-button-clip-path" clipPathUnits="userSpaceOnUse"> - <svg:path d="M 0,0 0,7.8 C 2.5,11 4,14 4,18 4,22 2.5,25 0,28 l 0,22 10000,0 0,-50 L 0,0 z"/> + <svg:path d="m 0,-5 l 0,7.8 c 2.5,3.2 4,6.2 4,10.2 c 0,4 -1.5,7 -4,10 l 0,22l10000,0 l 0,-50 l -10000,0 z"/> </svg:clipPath> - </svg:svg> #endif #ifdef XP_MACOSX - <svg:svg height="0"> <svg:clipPath id="osx-keyhole-forward-clip-path" clipPathUnits="objectBoundingBox"> <svg:path d="M 0,0 C 0.15,0.12 0.25,0.3 0.25,0.5 0.25,0.7 0.15,0.88 0,1 L 1,1 1,0 0,0 z"/> </svg:clipPath> <svg:clipPath id="osx-urlbar-back-button-clip-path" clipPathUnits="userSpaceOnUse"> - <svg:path d="m 0,-5 0,4.03 C 3.6,1.8 6,6.1 6,11 6,16 3.6,20 0,23 l 0,27 10000,0 0,-55 L 0,-5 z"/> - </svg:clipPath> - <svg:clipPath id="osx-tab-ontop-left-curve-clip-path" clipPathUnits="userSpaceOnUse"> - <svg:path d="M 9,0 C 7.3,0 6,1.3 6,3 l 0,14 c 0,3 -2.2,5 -5,5 l -1,0 0,1 12,0 0,-1 0,-19 0,-3 -3,0 z"/> - </svg:clipPath> - <svg:clipPath id="osx-tab-ontop-right-curve-clip-path" clipPathUnits="userSpaceOnUse"> - <svg:path d="m 0,0 0,3 0,19 0,1 12,0 0,-1 -1,0 C 8.2,22 6,20 6,17 L 6,3 C 6,1.3 4.7,0 3,0 L 0,0 z"/> - </svg:clipPath> - <svg:clipPath id="osx-tab-onbottom-left-curve-clip-path" clipPathUnits="userSpaceOnUse"> - <svg:path d="m 0,0 0,1 1,0 c 2.8,0 5,2.2 5,5 l 0,14 c 0,2 1.3,3 3,3 l 3,0 0,-3 L 12,1 12,0 0,0 z"/> + <svg:path d="m -3,-10 l -0.1,7.7 c 6.6,1.8 8.8,7.6 8.8,12.5 c 0,5 -1.9,11.5 -8.25,13.25 l 0.05,25.75 l 10000,0 l 0,-55 l -10000,-4.2 z"/> </svg:clipPath> - <svg:clipPath id="osx-tab-onbottom-right-curve-clip-path" clipPathUnits="userSpaceOnUse"> - <svg:path d="m 0,0 0,1 0,19 0,3 3,0 c 1.7,0 3,-1 3,-3 L 6,6 C 6,3.2 8.2,1 11,1 L 12,1 12,0 0,0 z"/> - </svg:clipPath> - </svg:svg> #endif + </svg:svg> </vbox> # <iframe id="tab-view"> is dynamically appended as the 2nd child of #tab-view-deck. diff --git a/browser/base/content/global-scripts.inc b/browser/base/content/global-scripts.inc index b4de574ae922eab322043d586562b16c6b1c9d90..22b61aeae84d84b71fddc6be2b57e735dd5559da 100755 --- a/browser/base/content/global-scripts.inc +++ b/browser/base/content/global-scripts.inc @@ -9,5 +9,6 @@ <script type="application/javascript" src="chrome://browser/content/browser.js"/> <script type="application/javascript" src="chrome://browser/content/downloads/downloads.js"/> <script type="application/javascript" src="chrome://browser/content/downloads/indicator.js"/> +<script type="application/javascript" src="chrome://browser/content/customizableui/panelUI.js"/> <script type="application/javascript" src="chrome://global/content/inlineSpellCheckUI.js"/> <script type="application/javascript" src="chrome://global/content/viewSourceUtils.js"/> diff --git a/browser/base/content/newtab/newTab.xul b/browser/base/content/newtab/newTab.xul index bab2c28e79cbad621a6ab7193b51aeb496843e8c..6fc202f296eff827dc4d4bdd798d4e874f51ea50 100644 --- a/browser/base/content/newtab/newTab.xul +++ b/browser/base/content/newtab/newTab.xul @@ -31,6 +31,7 @@ label="&newtab.undo.restoreButton;" class="newtab-undo-button" /> <xul:toolbarbutton id="newtab-undo-close-button" tabindex="-1" + class="close-icon" tooltiptext="&newtab.undo.closeTooltip;" /> </div> </div> diff --git a/browser/base/content/sync/notification.xml b/browser/base/content/sync/notification.xml index 94e83f14181748c995e603f127b31c4c669819b2..7a2b773821cf482f477cd11d2b65ea6dcbc92bf7 100644 --- a/browser/base/content/sync/notification.xml +++ b/browser/base/content/sync/notification.xml @@ -83,7 +83,7 @@ <content> <xul:hbox class="notification-inner outset" flex="1" xbl:inherits="type"> <xul:toolbarbutton ondblclick="event.stopPropagation();" - class="messageCloseButton tabbable" + class="messageCloseButton close-icon tabbable" xbl:inherits="hidden=hideclose" tooltiptext="&closeNotification.tooltip;" oncommand="document.getBindingParent(this).close()"/> diff --git a/browser/base/content/tab-shape.inc.svg b/browser/base/content/tab-shape.inc.svg new file mode 100644 index 0000000000000000000000000000000000000000..f97889389e21f98087c4f7c17e4aa494bf6282d6 --- /dev/null +++ b/browser/base/content/tab-shape.inc.svg @@ -0,0 +1,11 @@ +<!-- 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/. --> + +<svg:clipPath id="tab-curve-clip-path-start" clipPathUnits="objectBoundingBox"> + <svg:path d="m 1,0.0625 0.05,0 0,0.938 -1,0 0,-0.028 C 0.32082458,0.95840561 0.4353096,0.81970962 0.48499998,0.5625 0.51819998,0.3905 0.535,0.0659 1,0.0625 z"/> +</svg:clipPath> + +<svg:clipPath id="tab-curve-clip-path-end" clipPathUnits="objectBoundingBox"> + <svg:path d="m 0,0.0625 -0.05,0 0,0.938 1,0 0,-0.028 C 0.67917542,0.95840561 0.56569036,0.81970962 0.51599998,0.5625 0.48279998,0.3905 0.465,0.0659 0,0.0625 z"/> +</svg:clipPath> diff --git a/browser/base/content/tabbrowser.css b/browser/base/content/tabbrowser.css index 2dd6a05297c86438453509be8ed1693ffac289fe..e47e3d6e428786a6b5148e8ef6c0c25c6dde89a0 100644 --- a/browser/base/content/tabbrowser.css +++ b/browser/base/content/tabbrowser.css @@ -41,6 +41,7 @@ tabpanels { z-index: 2; } +.tab-icon-image:not([src]):not([pinned]), .tab-throbber:not([busy]), .tab-throbber[busy] + .tab-icon-image { display: none; diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index 999509c21e8012b708473ac0e4b4423770cbb63f..98735de61cbe3d00a4fd50eee2383c9197600485 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -207,8 +207,7 @@ if (!window.gShowPageResizers) return; - var show = document.getElementById("addon-bar").collapsed && - window.windowState == window.STATE_NORMAL; + var show = window.windowState == window.STATE_NORMAL; for (let i = 0; i < this.browsers.length; i++) { this.browsers[i].showWindowResizer = show; } @@ -999,7 +998,7 @@ this.mCurrentTab = this.tabContainer.selectedItem; this.showTab(this.mCurrentTab); - var backForwardContainer = document.getElementById("unified-back-forward-button"); + var backForwardContainer = document.getElementById("urlbar-container"); if (backForwardContainer) { backForwardContainer.setAttribute("switchingtabs", "true"); window.addEventListener("MozAfterPaint", function removeSwitchingtabsAttr() { @@ -1500,8 +1499,7 @@ if (remote) b.setAttribute("remote", "true"); - if (window.gShowPageResizers && document.getElementById("addon-bar").collapsed && - window.windowState == window.STATE_NORMAL) { + if (window.gShowPageResizers && window.windowState == window.STATE_NORMAL) { b.setAttribute("showresizer", "true"); } @@ -1927,6 +1925,11 @@ aTab.closing = true; this._removingTabs.push(aTab); this._visibleTabs = null; // invalidate cache + + // Invalidate hovered tab state tracking for this closing tab. + if (this.tabContainer._hoveredTab == aTab) + aTab._mouseleave(); + if (newTab) this.addTab(BROWSER_NEW_TAB_URL, {skipAnimation: true}); else @@ -3245,6 +3248,28 @@ return !tab.pinned && !tab.hidden; ]]></body> </method> + <field name="_tabMarginLeft">null</field> + <field name="_tabMarginRight">null</field> + <method name="_adjustElementStartAndEnd"> + <parameter name="aTab"/> + <parameter name="tabStart"/> + <parameter name="tabEnd"/> + <body><![CDATA[ + if (this._tabMarginLeft === null || this._tabMarginRight === null) { + let tabMiddle = document.getAnonymousElementByAttribute(aTab, "class", "tab-background-middle"); + let tabMiddleStyle = window.getComputedStyle(tabMiddle, null); + this._tabMarginLeft = parseFloat(tabMiddleStyle.marginLeft); + this._tabMarginRight = parseFloat(tabMiddleStyle.marginRight); + } + if (this._tabMarginLeft < 0) { + tabStart = tabStart + this._tabMarginLeft; + } + if (this._tabMarginRight < 0) { + tabEnd = tabEnd - this._tabMarginRight; + } + return [tabStart, tabEnd]; + ]]></body> + </method> </implementation> <handlers> @@ -3266,8 +3291,11 @@ <handler event="overflow"><![CDATA[ if (event.detail == 0) return; // Ignore vertical events - var tabs = document.getBindingParent(this); + var numberOfTabs = tabs.tabbrowser.visibleTabs.length; + if (numberOfTabs == 1) + return; + tabs.setAttribute("overflow", "true"); tabs._positionPinnedTabs(); tabs._handleTabSelect(false); @@ -3364,6 +3392,15 @@ <field name="_afterSelectedTab">null</field> <field name="_beforeHoveredTab">null</field> <field name="_afterHoveredTab">null</field> + <field name="_hoveredTab">null</field> + + <property name="_isCustomizing" readonly="true"> + <getter> + let root = document.documentElement; + return root.getAttribute("customizing") == "true" || + root.getAttribute("customize-exiting") == "true"; + </getter> + </property> <method name="_setPositionalAttributes"> <body><![CDATA[ @@ -3394,6 +3431,12 @@ this._lastTab.removeAttribute("last-visible-tab"); this._lastTab = visibleTabs[lastVisible]; this._lastTab.setAttribute("last-visible-tab", "true"); + + let hoveredTab = this._hoveredTab; + if (hoveredTab) { + hoveredTab._mouseleave(); + hoveredTab._mouseenter(); + } ]]></body> </method> @@ -3472,10 +3515,6 @@ document.getElementById("menu_close").setAttribute("label", this.tabbrowser.mStringBundle.getString(visible ? "tabs.closeTab" : "tabs.close")); - goSetCommandEnabled("cmd_ToggleTabsOnTop", visible); - - TabsOnTop.syncUI(); - TabsInTitlebar.allowedBy("tabs-visible", visible); ]]></body> </method> @@ -3827,16 +3866,16 @@ if (aEvent.target != window) break; - let sizemode = document.documentElement.getAttribute("sizemode"); - TabsInTitlebar.allowedBy("sizemode", - sizemode == "maximized" || sizemode == "fullscreen"); + TabsInTitlebar.updateAppearance(); - var width = this.mTabstrip.boxObject.width; - if (width != this.mTabstripWidth) { - this.adjustTabstrip(); - this._fillTrailingGap(); - this._handleTabSelect(); - this.mTabstripWidth = width; + if (this.tabbrowser.visibleTabs.length > 1) { + var width = this.mTabstrip.boxObject.width; + if (width != this.mTabstripWidth) { + this.adjustTabstrip(); + this._fillTrailingGap(); + this._handleTabSelect(); + this.mTabstripWidth = width; + } } this.tabbrowser.updateWindowResizers(); @@ -4130,8 +4169,7 @@ // When the tabbar has an unified appearance with the titlebar // and menubar, a double-click in it should have the same behavior // as double-clicking the titlebar - if (TabsInTitlebar.enabled || - (TabsOnTop.enabled && this.parentNode._dragBindingAlive)) + if (TabsInTitlebar.enabled || this.parentNode._dragBindingAlive) return; #endif @@ -4254,7 +4292,7 @@ <handler event="dragstart"><![CDATA[ var tab = this._getDragTargetTab(event); - if (!tab) + if (!tab || this._isCustomizing) return; let dt = event.dataTransfer; @@ -4498,7 +4536,7 @@ var dt = event.dataTransfer; var draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0); - if (dt.mozUserCancelled || dt.dropEffect != "none") { + if (dt.mozUserCancelled || dt.dropEffect != "none" || this._isCustomizing) { delete draggedTab._dragData; return; } @@ -4630,7 +4668,7 @@ role="presentation"/> <xul:toolbarbutton anonid="close-button" xbl:inherits="fadein,pinned,selected" - class="tab-close-button"/> + class="tab-close-button close-icon"/> </xul:hbox> </xul:stack> </content> @@ -4651,6 +4689,54 @@ <field name="mCorrespondingMenuitem">null</field> <field name="closing">false</field> <field name="lastAccessed">0</field> + + <method name="_mouseenter"> + <body><![CDATA[ + if (this.closing) + return; + + let tabContainer = this.parentNode; + let visibleTabs = tabContainer.tabbrowser.visibleTabs; + let tabIndex = visibleTabs.indexOf(this); + if (tabIndex == 0) { + tabContainer._beforeHoveredTab = null; + } else { + let candidate = visibleTabs[tabIndex - 1]; + if (!candidate.selected) { + tabContainer._beforeHoveredTab = candidate; + candidate.setAttribute("beforehovered", "true"); + } + } + + if (tabIndex == visibleTabs.length - 1) { + tabContainer._afterHoveredTab = null; + } else { + let candidate = visibleTabs[tabIndex + 1]; + if (!candidate.selected) { + tabContainer._afterHoveredTab = candidate; + candidate.setAttribute("afterhovered", "true"); + } + } + + tabContainer._hoveredTab = this; + ]]></body> + </method> + + <method name="_mouseleave"> + <body><![CDATA[ + let tabContainer = this.parentNode; + if (tabContainer._beforeHoveredTab) { + tabContainer._beforeHoveredTab.removeAttribute("beforehovered"); + tabContainer._beforeHoveredTab = null; + } + if (tabContainer._afterHoveredTab) { + tabContainer._afterHoveredTab.removeAttribute("afterhovered"); + tabContainer._afterHoveredTab = null; + } + + tabContainer._hoveredTab = null; + ]]></body> + </method> </implementation> <handlers> @@ -4659,47 +4745,14 @@ if (anonid == "close-button") this.mOverCloseButton = true; - let tab = event.target; - if (tab.closing) - return; - - let tabContainer = this.parentNode; - let visibleTabs = tabContainer.tabbrowser.visibleTabs; - let tabIndex = visibleTabs.indexOf(tab); - if (tabIndex == 0) { - tabContainer._beforeHoveredTab = null; - } else { - let candidate = visibleTabs[tabIndex - 1]; - if (!candidate.selected) { - tabContainer._beforeHoveredTab = candidate; - candidate.setAttribute("beforehovered", "true"); - } - } - - if (tabIndex == visibleTabs.length - 1) { - tabContainer._afterHoveredTab = null; - } else { - let candidate = visibleTabs[tabIndex + 1]; - if (!candidate.selected) { - tabContainer._afterHoveredTab = candidate; - candidate.setAttribute("afterhovered", "true"); - } - } + this._mouseenter(); ]]></handler> <handler event="mouseout"><![CDATA[ let anonid = event.originalTarget.getAttribute("anonid"); if (anonid == "close-button") this.mOverCloseButton = false; - let tabContainer = this.parentNode; - if (tabContainer._beforeHoveredTab) { - tabContainer._beforeHoveredTab.removeAttribute("beforehovered"); - tabContainer._beforeHoveredTab = null; - } - if (tabContainer._afterHoveredTab) { - tabContainer._afterHoveredTab.removeAttribute("afterhovered"); - tabContainer._afterHoveredTab = null; - } + this._mouseleave(); ]]></handler> <handler event="dragstart" phase="capturing"> this.style.MozUserFocus = ''; diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index 31b315a464427b4b7304d717b1badd95a2c93b04..232ccb7ea8ed96a7570df149b2065984bbc059f8 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -17,7 +17,6 @@ support-files = bug792517.html bug792517.sjs bug839103.css - disablechrome.html discovery.html domplate_test.js download_page.html @@ -105,9 +104,6 @@ run-if = crashreporter [browser_aboutHome.js] [browser_aboutSyncProgress.js] [browser_addKeywordSearch.js] -[browser_addon_bar_aomlistener.js] -[browser_addon_bar_close_button.js] -[browser_addon_bar_shortcut.js] [browser_alltabslistener.js] [browser_blob-channelname.js] [browser_bookmark_titles.js] @@ -188,10 +184,7 @@ run-if = toolkit == "cocoa" [browser_bug595507.js] [browser_bug596687.js] [browser_bug597218.js] -[browser_bug598923.js] -[browser_bug599325.js] [browser_bug609700.js] -[browser_bug616836.js] [browser_bug623155.js] [browser_bug623893.js] [browser_bug624734.js] @@ -238,11 +231,9 @@ run-if = toolkit == "cocoa" [browser_contentAreaClick.js] [browser_contextSearchTabPosition.js] [browser_ctrlTab.js] -[browser_customize.js] [browser_customize_popupNotification.js] [browser_datareporting_notification.js] run-if = datareporting -[browser_disablechrome.js] [browser_discovery.js] [browser_duplicateIDs.js] [browser_drag.js] @@ -304,6 +295,9 @@ skip-if = true # disabled until the tree view is added [browser_tab_dragdrop.js] [browser_tab_dragdrop2.js] [browser_tab_dragdrop2_frame1.xul] +[browser_tabbar_big_widgets.js] +skip-if = os == "linux" # No tabs in titlebar on linux + [browser_tabfocus.js] [browser_tabopen_reflows.js] [browser_tabs_isActive.js] @@ -325,6 +319,7 @@ skip-if = true # disabled until the tree view is added [browser_visibleTabs_bookmarkAllTabs.js] [browser_visibleTabs_contextMenu.js] [browser_visibleTabs_tabPreview.js] +[browser_windowopen_reflows.js] [browser_wyciwyg_urlbarCopying.js] [browser_zbug569342.js] [browser_registerProtocolHandler_notification.js] diff --git a/browser/base/content/test/general/browser_addon_bar.js b/browser/base/content/test/general/browser_addon_bar.js deleted file mode 100644 index 3607eb1220cb323c1a883e6a3e4d736c04ad2de6..0000000000000000000000000000000000000000 --- a/browser/base/content/test/general/browser_addon_bar.js +++ /dev/null @@ -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/. */ - -function test() { - waitForExplicitFinish(); - - let addonbar = document.getElementById("addon-bar"); - ok(addonbar.collapsed, "addon bar is collapsed by default"); - - let topMenu, toolbarMenu; - - function onTopMenuShown(event) { - ok(1, "top menu popupshown listener called"); - event.currentTarget.removeEventListener("popupshown", arguments.callee, false); - // open the customize or toolbars menu - toolbarMenu = document.getElementById("appmenu_customizeMenu") || - document.getElementById("viewToolbarsMenu").firstElementChild; - toolbarMenu.addEventListener("popupshown", onToolbarMenuShown, false); - toolbarMenu.addEventListener("popuphidden", onToolbarMenuHidden, false); - toolbarMenu.openPopup(); - } - - function onTopMenuHidden(event) { - ok(1, "top menu popuphidden listener called"); - event.currentTarget.removeEventListener("popuphidden", arguments.callee, false); - finish(); - } - - function onToolbarMenuShown(event) { - ok(1, "sub menu popupshown listener called"); - event.currentTarget.removeEventListener("popupshown", arguments.callee, false); - - // test the menu item's default state - let menuitem = document.getElementById("toggle_addon-bar"); - ok(menuitem, "found the menu item"); - is(menuitem.getAttribute("checked"), "false", "menuitem is not checked by default"); - - // click on the menu item - // TODO: there's got to be a way to check+command in one shot - menuitem.setAttribute("checked", "true"); - menuitem.click(); - - // now the addon bar should be visible and the menu checked - is(addonbar.getAttribute("collapsed"), "false", "addon bar is visible after executing the command"); - is(menuitem.getAttribute("checked"), "true", "menuitem is checked after executing the command"); - - toolbarMenu.hidePopup(); - } - - function onToolbarMenuHidden(event) { - ok(1, "toolbar menu popuphidden listener called"); - event.currentTarget.removeEventListener("popuphidden", arguments.callee, false); - topMenu.hidePopup(); - } - - // open the appmenu or view menu - topMenu = document.getElementById("appmenu-popup") || - document.getElementById("menu_viewPopup"); - topMenu.addEventListener("popupshown", onTopMenuShown, false); - topMenu.addEventListener("popuphidden", onTopMenuHidden, false); - topMenu.openPopup(); -} diff --git a/browser/base/content/test/general/browser_addon_bar_aomlistener.js b/browser/base/content/test/general/browser_addon_bar_aomlistener.js deleted file mode 100644 index 75a539e0727492da7d378cbe614139a9547be103..0000000000000000000000000000000000000000 --- a/browser/base/content/test/general/browser_addon_bar_aomlistener.js +++ /dev/null @@ -1,67 +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/. */ - -function test() { - - let addonbar = document.getElementById("addon-bar"); - ok(addonbar.collapsed, "addon bar is collapsed by default"); - - function addItem(id) { - let button = document.createElement("toolbarbutton"); - button.id = id; - let palette = document.getElementById("navigator-toolbox").palette; - palette.appendChild(button); - addonbar.insertItem(id, null, null, false); - } - - // call onInstalling - AddonsMgrListener.onInstalling(); - - // add item to the bar - let id = "testbutton"; - addItem(id); - - // call onInstalled - AddonsMgrListener.onInstalled(); - - // confirm bar is visible - ok(!addonbar.collapsed, "addon bar is not collapsed after toggle"); - - // call onUninstalling - AddonsMgrListener.onUninstalling(); - - // remove item from the bar - addonbar.currentSet = addonbar.currentSet.replace("," + id, ""); - - // call onUninstalled - AddonsMgrListener.onUninstalled(); - - // confirm bar is not visible - ok(addonbar.collapsed, "addon bar is collapsed after toggle"); - - // call onEnabling - AddonsMgrListener.onEnabling(); - - // add item to the bar - let id = "testbutton"; - addItem(id); - - // call onEnabled - AddonsMgrListener.onEnabled(); - - // confirm bar is visible - ok(!addonbar.collapsed, "addon bar is not collapsed after toggle"); - - // call onDisabling - AddonsMgrListener.onDisabling(); - - // remove item from the bar - addonbar.currentSet = addonbar.currentSet.replace("," + id, ""); - - // call onDisabled - AddonsMgrListener.onDisabled(); - - // confirm bar is not visible - ok(addonbar.collapsed, "addon bar is collapsed after toggle"); -} diff --git a/browser/base/content/test/general/browser_addon_bar_close_button.js b/browser/base/content/test/general/browser_addon_bar_close_button.js deleted file mode 100644 index 7d3afb333ba5469fbd8f6469b5991c94ad15bdb0..0000000000000000000000000000000000000000 --- a/browser/base/content/test/general/browser_addon_bar_close_button.js +++ /dev/null @@ -1,19 +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/. */ - -function test() { - let addonbar = document.getElementById("addon-bar"); - ok(addonbar.collapsed, "addon bar is collapsed by default"); - - // make add-on bar visible - setToolbarVisibility(addonbar, true); - ok(!addonbar.collapsed, "addon bar is not collapsed after toggle"); - - // click the close button - let closeButton = document.getElementById("addonbar-closebutton"); - EventUtils.synthesizeMouseAtCenter(closeButton, {}); - - // confirm addon bar is closed - ok(addonbar.collapsed, "addon bar is collapsed after clicking close button"); -} diff --git a/browser/base/content/test/general/browser_addon_bar_shortcut.js b/browser/base/content/test/general/browser_addon_bar_shortcut.js deleted file mode 100644 index 847f967214c59f1245639f090afed6b64149568a..0000000000000000000000000000000000000000 --- a/browser/base/content/test/general/browser_addon_bar_shortcut.js +++ /dev/null @@ -1,18 +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/. */ - -function test() { - let addonbar = document.getElementById("addon-bar"); - ok(addonbar.collapsed, "addon bar is collapsed by default"); - - // show the add-on bar - EventUtils.synthesizeKey("/", { accelKey: true }, window); - ok(!addonbar.collapsed, "addon bar is not collapsed after toggle"); - - // hide the add-on bar - EventUtils.synthesizeKey("/", { accelKey: true }, window); - - // confirm addon bar is closed - ok(addonbar.collapsed, "addon bar is collapsed after toggle"); -} diff --git a/browser/base/content/test/general/browser_bug462289.js b/browser/base/content/test/general/browser_bug462289.js index fcde120ffc645d678d54e94e587bfbd62d0435df..eee46c01e117744c93548d2852ad78e5f7b8c32a 100644 --- a/browser/base/content/test/general/browser_bug462289.js +++ b/browser/base/content/test/general/browser_bug462289.js @@ -34,16 +34,9 @@ function step3() is(gBrowser.selectedTab, tab1, "2nd click on selected tab1 keeps tab selected"); isnot(document.activeElement, tab1, "2nd click on selected tab1 does not activate tab"); - if (gNavToolbox.getAttribute("tabsontop") == "true") { - ok(true, "[tabsontop=true] focusing URLBar then sending 1 Shift+Tab."); - gURLBar.focus(); - EventUtils.synthesizeKey("VK_TAB", {shiftKey: true}); - } else { - ok(true, "[tabsontop=false] focusing SearchBar then sending Tab(s) until out of nav-bar."); - document.getElementById("searchbar").focus(); - while (focus_in_navbar()) - EventUtils.synthesizeKey("VK_TAB", { }); - } + ok(true, "focusing URLBar then sending 1 Shift+Tab."); + gURLBar.focus(); + EventUtils.synthesizeKey("VK_TAB", {shiftKey: true}); is(gBrowser.selectedTab, tab1, "tab key to selected tab1 keeps tab selected"); is(document.activeElement, tab1, "tab key to selected tab1 activates tab"); diff --git a/browser/base/content/test/general/browser_bug598923.js b/browser/base/content/test/general/browser_bug598923.js deleted file mode 100644 index 35e9c09f0d23355b02c29faa3889d2e09f35e07e..0000000000000000000000000000000000000000 --- a/browser/base/content/test/general/browser_bug598923.js +++ /dev/null @@ -1,33 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - */ - -// Test: -// * if add-on is installed to the add-on bar, the bar is made visible. -// * if add-on is uninstalled from the add-on bar, and no more add-ons there, -// the bar is hidden. - -function test() { - let aml = AddonsMgrListener; - ok(aml, "AddonsMgrListener exists"); - // check is hidden - is(aml.addonBar.collapsed, true, "add-on bar is hidden initially"); - // aob gets the count - AddonsMgrListener.onInstalling(); - // add an item - let element = document.createElement("toolbaritem"); - element.id = "bug598923-addon-item"; - aml.addonBar.appendChild(element); - // aob checks the count, makes visible - AddonsMgrListener.onInstalled(); - // check is visible - is(aml.addonBar.collapsed, false, "add-on bar has been made visible"); - // aob gets the count - AddonsMgrListener.onUninstalling(); - // remove an item - aml.addonBar.removeChild(element); - // aob checks the count, makes hidden - AddonsMgrListener.onUninstalled(); - // check is hidden - is(aml.addonBar.collapsed, true, "add-on bar is hidden again"); -} diff --git a/browser/base/content/test/general/browser_bug599325.js b/browser/base/content/test/general/browser_bug599325.js deleted file mode 100644 index d721fc6632c79ee81cb84d37590c95d18e7c810c..0000000000000000000000000000000000000000 --- a/browser/base/content/test/general/browser_bug599325.js +++ /dev/null @@ -1,21 +0,0 @@ -function test() { - waitForExplicitFinish(); - - let addonBar = document.getElementById("addon-bar"); - ok(addonBar, "got addon bar"); - ok(!isElementVisible(addonBar), "addon bar initially hidden"); - - openToolbarCustomizationUI(function () { - ok(isElementVisible(addonBar), - "add-on bar is visible during toolbar customization"); - - closeToolbarCustomizationUI(onClose); - }); - - function onClose() { - ok(!isElementVisible(addonBar), - "addon bar is hidden after toolbar customization"); - - finish(); - } -} diff --git a/browser/base/content/test/general/browser_bug616836.js b/browser/base/content/test/general/browser_bug616836.js deleted file mode 100644 index efaaa837ab0fdb5ed953b27109e7b4c4d9b81070..0000000000000000000000000000000000000000 --- a/browser/base/content/test/general/browser_bug616836.js +++ /dev/null @@ -1,4 +0,0 @@ -function test() { - is(document.querySelectorAll("#appmenu-popup [accesskey]").length, 0, - "there should be no items with access keys in the app menu popup"); -} diff --git a/browser/base/content/test/general/browser_bug624734.js b/browser/base/content/test/general/browser_bug624734.js index 7d5caeea5e952bfcb84b816ec29998a5fe60ba85..7c5e5e31bd783b0253dce0a0b9f3601f755032f1 100644 --- a/browser/base/content/test/general/browser_bug624734.js +++ b/browser/base/content/test/general/browser_bug624734.js @@ -4,6 +4,15 @@ // Bug 624734 - Star UI has no tooltip until bookmarked page is visited +function finishTest() { + is(BookmarkingUI.button.getAttribute("buttontooltiptext"), + BookmarkingUI._unstarredTooltip, + "Star icon should have the unstarred tooltip text"); + + gBrowser.removeCurrentTab(); + finish(); +} + function test() { waitForExplicitFinish(); @@ -11,12 +20,11 @@ function test() { tab.linkedBrowser.addEventListener("load", (function(event) { tab.linkedBrowser.removeEventListener("load", arguments.callee, true); - is(BookmarkingUI.star.getAttribute("tooltiptext"), - BookmarkingUI._unstarredTooltip, - "Star icon should have the unstarred tooltip text"); - - gBrowser.removeCurrentTab(); - finish(); + if (BookmarkingUI.status == BookmarkingUI.STATUS_UPDATING) { + waitForCondition(function() BookmarkingUI.status != BookmarkingUI.STATUS_UPDATING, finishTest, "BookmarkingUI was updating for too long"); + } else { + finishTest(); + } }), true); tab.linkedBrowser.loadURI("http://example.com/browser/browser/base/content/test/general/dummy_page.html"); diff --git a/browser/base/content/test/general/browser_customize.js b/browser/base/content/test/general/browser_customize.js deleted file mode 100644 index 8cff36686ede7bbfabcadfb6804d2e3358cd7bd5..0000000000000000000000000000000000000000 --- a/browser/base/content/test/general/browser_customize.js +++ /dev/null @@ -1,24 +0,0 @@ -function test() { - waitForExplicitFinish(); - - openToolbarCustomizationUI(customizationWindowLoaded); -} - -function customizationWindowLoaded(win) { - let x = win.screenX; - let iconModeList = win.document.getElementById("modelist"); - - iconModeList.addEventListener("popupshown", function popupshown() { - iconModeList.removeEventListener("popupshown", popupshown, false); - - executeSoon(function () { - is(win.screenX, x, - "toolbar customization window shouldn't move when the iconmode menulist is opened"); - iconModeList.open = false; - - closeToolbarCustomizationUI(finish); - }); - }, false); - - iconModeList.open = true; -} diff --git a/browser/base/content/test/general/browser_disablechrome.js b/browser/base/content/test/general/browser_disablechrome.js deleted file mode 100644 index e00cf16575975b10898e287e20772dba1cd68a44..0000000000000000000000000000000000000000 --- a/browser/base/content/test/general/browser_disablechrome.js +++ /dev/null @@ -1,216 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - */ - -// Tests that the disablechrome attribute gets propogated to the main UI - -const HTTPSRC = "http://example.com/browser/browser/base/content/test/general/"; - -function is_element_hidden(aElement) { - var style = window.getComputedStyle(document.getElementById("nav-bar"), ""); - if (style.visibility != "visible" || style.display == "none") - return true; - - if (aElement.ownerDocument != aElement.parentNode) - return is_element_hidden(aElement.parentNode); - - return false; -} - -function is_chrome_hidden() { - is(document.documentElement.getAttribute("disablechrome"), "true", "Attribute should be set"); - if (TabsOnTop.enabled) - ok(is_element_hidden(document.getElementById("nav-bar")), "Toolbar should be hidden"); - else - ok(!is_element_hidden(document.getElementById("nav-bar")), "Toolbar should not be hidden"); -} - -function is_chrome_visible() { - isnot(document.getElementById("main-window").getAttribute("disablechrome"), "true", "Attribute should not be set"); - ok(!is_element_hidden(document.getElementById("nav-bar")), "Toolbar should not be hidden"); -} - -function load_page(aURL, aCanHide, aCallback) { - gNewBrowser.addEventListener("pageshow", function() { - // Filter out about:blank loads - if (gNewBrowser.currentURI.spec != aURL) - return; - - gNewBrowser.removeEventListener("pageshow", arguments.callee, false); - - if (aCanHide) - is_chrome_hidden(); - else - is_chrome_visible(); - - if (aURL == "about:addons") { - function check_after_init() { - if (aCanHide) - is_chrome_hidden(); - else - is_chrome_visible(); - - aCallback(); - } - - if (gNewBrowser.contentWindow.gIsInitializing) { - gNewBrowser.contentDocument.addEventListener("Initialized", function() { - gNewBrowser.contentDocument.removeEventListener("Initialized", arguments.callee, false); - - check_after_init(); - }, false); - } - else { - check_after_init(); - } - } - else { - executeSoon(aCallback); - } - }, false); - gNewBrowser.loadURI(aURL); -} - -var gOldTab; -var gNewTab; -var gNewBrowser; - -function test() { - // Opening the add-ons manager and waiting for it to load the discovery pane - // takes more time in windows debug builds - requestLongerTimeout(2); - - var gOldTabsOnTop = TabsOnTop.enabled; - registerCleanupFunction(function() { - TabsOnTop.enabled = gOldTabsOnTop; - }); - - waitForExplicitFinish(); - - gOldTab = gBrowser.selectedTab; - gNewTab = gBrowser.selectedTab = gBrowser.addTab("about:blank"); - gNewBrowser = gBrowser.selectedBrowser; - - info("Tabs on top"); - TabsOnTop.enabled = true; - - run_http_test_1(); -} - -function end_test() { - gBrowser.removeTab(gNewTab); - finish(); -} - -function test_url(aURL, aCanHide, aNextTest) { - is_chrome_visible(); - info("Page load"); - load_page(aURL, aCanHide, function() { - info("Switch away"); - gBrowser.selectedTab = gOldTab; - is_chrome_visible(); - - info("Switch back"); - gBrowser.selectedTab = gNewTab; - if (aCanHide) - is_chrome_hidden(); - else - is_chrome_visible(); - - gBrowser.removeTab(gNewTab); - gNewTab = gBrowser.selectedTab = gBrowser.addTab("about:blank"); - gNewBrowser = gBrowser.selectedBrowser; - - gBrowser.selectedTab = gOldTab; - - info("Background load"); - load_page(aURL, false, function() { - info("Switch back"); - gBrowser.selectedTab = gNewTab; - if (aCanHide) - is_chrome_hidden(); - else - is_chrome_visible(); - - load_page("about:blank", false, aNextTest); - }); - }); -} - -// Should never hide the chrome -function run_http_test_1() { - info("HTTP tests"); - test_url(HTTPSRC + "disablechrome.html", false, run_chrome_about_test); -} - -// Should hide the chrome -function run_chrome_about_test() { - info("Chrome about: tests"); - test_url("about:addons", true, function() { - info("Tabs on bottom"); - TabsOnTop.enabled = false; - run_http_test_2(); - }); -} - -// Should never hide the chrome -function run_http_test_2() { - info("HTTP tests"); - test_url(HTTPSRC + "disablechrome.html", false, run_chrome_about_test_2); -} - -// Should not hide the chrome -function run_chrome_about_test_2() { - info("Chrome about: tests"); - test_url("about:addons", true, run_http_test3); -} - -function run_http_test3() { - info("HTTP tests"); - test_url(HTTPSRC + "disablechrome.html", false, run_chrome_about_test_3); -} - -// Should not hide the chrome -function run_chrome_about_test_3() { - info("Chrome about: tests"); - test_url("about:Addons", true, function(){ - info("Tabs on top"); - TabsOnTop.enabled = true; - run_http_test4(); - }); -} - -function run_http_test4() { - info("HTTP tests"); - test_url(HTTPSRC + "disablechrome.html", false, run_chrome_about_test_4); -} - -function run_chrome_about_test_4() { - info("Chrome about: tests"); - test_url("about:Addons", true, run_http_test5); - } - -function run_http_test5() { - info("HTTP tests"); - test_url(HTTPSRC + "disablechrome.html", false, run_chrome_about_test_5); -} - -// Should hide the chrome -function run_chrome_about_test_5() { - info("Chrome about: tests"); - test_url("about:preferences", true, function(){ - info("Tabs on bottom"); - TabsOnTop.enabled = false; - run_http_test6(); - }); -} - -function run_http_test6() { - info("HTTP tests"); - test_url(HTTPSRC + "disablechrome.html", false, run_chrome_about_test_6); -} - -function run_chrome_about_test_6() { - info("Chrome about: tests"); - test_url("about:preferences", true, end_test); -} \ No newline at end of file diff --git a/browser/base/content/test/general/browser_overflowScroll.js b/browser/base/content/test/general/browser_overflowScroll.js index 8c0eac70949d048498069697b98e1170d12cf5f0..bc82ab4193f803133b06466fe56788dc028e2126 100644 --- a/browser/base/content/test/general/browser_overflowScroll.js +++ b/browser/base/content/test/general/browser_overflowScroll.js @@ -7,8 +7,8 @@ function rect(ele) ele.getBoundingClientRect(); function width(ele) rect(ele).width; function left(ele) rect(ele).left; function right(ele) rect(ele).right; -function isLeft(ele, msg) is(left(ele), left(scrollbox), msg); -function isRight(ele, msg) is(right(ele), right(scrollbox), msg); +function isLeft(ele, msg) is(left(ele) + tabstrip._tabMarginLeft, left(scrollbox), msg); +function isRight(ele, msg) is(right(ele) - tabstrip._tabMarginRight, right(scrollbox), msg); function elementFromPoint(x) tabstrip._elementFromPoint(x); function nextLeftElement() elementFromPoint(left(scrollbox) - 1); function nextRightElement() elementFromPoint(right(scrollbox) + 1); @@ -62,7 +62,11 @@ function runOverflowTests(aEvent) { EventUtils.synthesizeMouse(upButton, 1, 1, {}); isLeft(element, "Scrolled one tab to the left with a single click"); - element = elementFromPoint(left(scrollbox) - width(scrollbox)); + let elementPoint = left(scrollbox) - width(scrollbox); + element = elementFromPoint(elementPoint); + if (elementPoint == right(element)) { + element = element.nextSibling; + } EventUtils.synthesizeMouse(upButton, 1, 1, {clickCount: 2}); isLeft(element, "Scrolled one page of tabs with a double click"); diff --git a/browser/base/content/test/general/browser_tabbar_big_widgets.js b/browser/base/content/test/general/browser_tabbar_big_widgets.js new file mode 100644 index 0000000000000000000000000000000000000000..7a4c4513845dc88bff8ff020f88c6ee7887b8312 --- /dev/null +++ b/browser/base/content/test/general/browser_tabbar_big_widgets.js @@ -0,0 +1,29 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +const kButtonId = "test-tabbar-size-with-large-buttons"; + +function test() { + registerCleanupFunction(cleanup); + let titlebar = document.getElementById("titlebar"); + let originalHeight = titlebar.getBoundingClientRect().height; + let button = document.createElement("toolbarbutton"); + button.id = kButtonId; + button.setAttribute("style", "min-height: 100px"); + gNavToolbox.palette.appendChild(button); + CustomizableUI.addWidgetToArea(kButtonId, CustomizableUI.AREA_TABSTRIP); + let currentHeight = titlebar.getBoundingClientRect().height; + ok(currentHeight > originalHeight, "Titlebar should have grown"); + CustomizableUI.removeWidgetFromArea(kButtonId); + currentHeight = titlebar.getBoundingClientRect().height; + is(currentHeight, originalHeight, "Titlebar should have gone back to its original size."); +} + +function cleanup() { + let btn = document.getElementById(kButtonId); + if (btn) { + btn.remove(); + } +} + diff --git a/browser/base/content/test/general/browser_windowopen_reflows.js b/browser/base/content/test/general/browser_windowopen_reflows.js new file mode 100644 index 0000000000000000000000000000000000000000..8df4e2e8fb597567d9ec1565c59c657df50103b0 --- /dev/null +++ b/browser/base/content/test/general/browser_windowopen_reflows.js @@ -0,0 +1,115 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const EXPECTED_REFLOWS = [ + // handleEvent flushes layout to get the tabstrip width after a resize. + "handleEvent@chrome://browser/content/tabbrowser.xml|", + + // Loading a tab causes a reflow. + "loadTabs@chrome://browser/content/tabbrowser.xml|" + + "loadOneOrMoreURIs@chrome://browser/content/browser.js|" + + "gBrowserInit._delayedStartup@chrome://browser/content/browser.js|", + + // Selecting the address bar causes a reflow. + "select@chrome://global/content/bindings/textbox.xml|" + + "focusAndSelectUrlBar@chrome://browser/content/browser.js|" + + "gBrowserInit._delayedStartup@chrome://browser/content/browser.js|", + + // Focusing the content area causes a reflow. + "gBrowserInit._delayedStartup@chrome://browser/content/browser.js|", + + // Sometimes sessionstore collects data during this test, which causes a sync reflow + // (https://bugzilla.mozilla.org/show_bug.cgi?id=892154 will fix this) + "ssi_getWindowDimension@resource:///modules/sessionstore/SessionStore.jsm", +]; + +if (Services.appinfo.OS == "Darwin") { + // TabsInTitlebar._update causes a reflow on OS X trying to do calculations + // since layout info is already dirty. This doesn't seem to happen before + // MozAfterPaint on other platforms. + EXPECTED_REFLOWS.push("rect@chrome://browser/content/browser.js|" + + "TabsInTitlebar._update@chrome://browser/content/browser.js|" + + "updateAppearance@chrome://browser/content/browser.js|" + + "handleEvent@chrome://browser/content/tabbrowser.xml|"); + + // _onOverflow causes a reflow getting widths. + EXPECTED_REFLOWS.push("OverflowableToolbar.prototype._onOverflow@resource:///modules/CustomizableUI.jsm|" + + "OverflowableToolbar.prototype.init@resource:///modules/CustomizableUI.jsm|" + + "OverflowableToolbar.prototype.observe@resource:///modules/CustomizableUI.jsm|" + + "gBrowserInit._delayedStartup@chrome://browser/content/browser.js|"); + // Same as above since in packaged builds there are no function names and the resource URI includes "app" + EXPECTED_REFLOWS.push("@resource://app/modules/CustomizableUI.jsm|" + + "@resource://app/modules/CustomizableUI.jsm|" + + "@resource://app/modules/CustomizableUI.jsm|" + + "gBrowserInit._delayedStartup@chrome://browser/content/browser.js|"); +} + +/* + * This test ensures that there are no unexpected + * uninterruptible reflows when opening new windows. + */ +function test() { + waitForExplicitFinish(); + + // Add a reflow observer and open a new window + let win = OpenBrowserWindow(); + let docShell = win.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShell); + docShell.addWeakReflowObserver(observer); + + // Wait until the mozafterpaint event occurs. + waitForMozAfterPaint(win, function paintListener() { + // Remove reflow observer and clean up. + docShell.removeWeakReflowObserver(observer); + win.close(); + + finish(); + }); +} + +let observer = { + reflow: function (start, end) { + // Gather information about the current code path. + let stack = new Error().stack; + let path = stack.split("\n").slice(1).map(line => { + return line.replace(/:\d+$/, ""); + }).join("|"); + let pathWithLineNumbers = (new Error().stack).split("\n").slice(1).join("|"); + + // Stack trace is empty. Reflow was triggered by native code. + if (path === "") { + return; + } + + // Check if this is an expected reflow. + for (let expectedStack of EXPECTED_REFLOWS) { + if (path.startsWith(expectedStack) || + // Accept an empty function name for gBrowserInit._delayedStartup or TabsInTitlebar._update to workaround bug 906578. + path.startsWith(expectedStack.replace(/(^|\|)(gBrowserInit\._delayedStartup|TabsInTitlebar\._update)@/, "$1@"))) { + ok(true, "expected uninterruptible reflow '" + expectedStack + "'"); + return; + } + } + + ok(false, "unexpected uninterruptible reflow '" + pathWithLineNumbers + "'"); + }, + + reflowInterruptible: function (start, end) { + // We're not interested in interruptible reflows. + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver, + Ci.nsISupportsWeakReference]) +}; + +function waitForMozAfterPaint(win, callback) { + win.addEventListener("MozAfterPaint", function onEnd(event) { + if (event.target != win) + return; + win.removeEventListener("MozAfterPaint", onEnd); + executeSoon(callback); + }); +} diff --git a/browser/base/content/test/general/disablechrome.html b/browser/base/content/test/general/disablechrome.html deleted file mode 100644 index 7879e1ce9fd77d4d90054013725af5137e8ef31a..0000000000000000000000000000000000000000 --- a/browser/base/content/test/general/disablechrome.html +++ /dev/null @@ -1,4 +0,0 @@ -<html> -<body> -</body> -</html> diff --git a/browser/base/content/test/general/head.js b/browser/base/content/test/general/head.js index 1d33893e8ede3f3d2ac7cd14d05e43af1cb0ae4b..3f3702ec3827aa141569aa823f17348806b37287 100644 --- a/browser/base/content/test/general/head.js +++ b/browser/base/content/test/general/head.js @@ -37,49 +37,27 @@ function updateTabContextMenu(tab) { menu.hidePopup(); } -function findToolbarCustomizationWindow(aBrowserWin) { - if (!aBrowserWin) - aBrowserWin = window; - - let iframe = aBrowserWin.document.getElementById("customizeToolbarSheetIFrame"); - let win = iframe && iframe.contentWindow; - if (win) - return win; - - win = findChromeWindowByURI("chrome://global/content/customizeToolbar.xul"); - if (win && win.opener == aBrowserWin) - return win; - - throw Error("Failed to find the customization window"); -} - function openToolbarCustomizationUI(aCallback, aBrowserWin) { if (!aBrowserWin) aBrowserWin = window; - aBrowserWin.document.getElementById("cmd_CustomizeToolbars").doCommand(); - - aBrowserWin.gNavToolbox.addEventListener("beforecustomization", function UI_loaded() { - aBrowserWin.gNavToolbox.removeEventListener("beforecustomization", UI_loaded); + aBrowserWin.gCustomizeMode.enter(); - let win = findToolbarCustomizationWindow(aBrowserWin); - waitForFocus(function () { - aCallback(win); - }, win); + aBrowserWin.gNavToolbox.addEventListener("customizationready", function UI_loaded() { + aBrowserWin.gNavToolbox.removeEventListener("customizationready", UI_loaded); + executeSoon(function() { + aCallback(aBrowserWin) + }); }); } function closeToolbarCustomizationUI(aCallback, aBrowserWin) { - let win = findToolbarCustomizationWindow(aBrowserWin); - - win.addEventListener("unload", function unloaded() { - win.removeEventListener("unload", unloaded); + aBrowserWin.gNavToolbox.addEventListener("aftercustomization", function unloaded() { + aBrowserWin.gNavToolbox.removeEventListener("aftercustomization", unloaded); executeSoon(aCallback); }); - let button = win.document.getElementById("donebutton"); - button.focus(); - button.doCommand(); + aBrowserWin.gCustomizeMode.exit(); } function waitForCondition(condition, nextTest, errorMsg) { diff --git a/browser/base/content/urlbarBindings.xml b/browser/base/content/urlbarBindings.xml index f4a593fe05832abeeee9bcad09a864db2ac498a9..c19e499984c98f59130697dd3d6a66923de868c6 100644 --- a/browser/base/content/urlbarBindings.xml +++ b/browser/base/content/urlbarBindings.xml @@ -937,7 +937,7 @@ <xul:menupopup anonid="menupopup" xbl:inherits="oncommand=menucommand"> <children/> - <xul:menuitem class="menuitem-iconic popup-notification-closeitem" + <xul:menuitem class="menuitem-iconic popup-notification-closeitem close-icon" label="&closeNotificationItem.label;" xbl:inherits="oncommand=closeitemcommand"/> </xul:menupopup> @@ -946,7 +946,7 @@ </xul:vbox> <xul:vbox pack="start"> <xul:toolbarbutton anonid="closebutton" - class="messageCloseButton popup-notification-closebutton tabbable" + class="messageCloseButton close-icon popup-notification-closebutton tabbable" xbl:inherits="oncommand=closebuttoncommand" tooltiptext="&closeNotification.tooltip;"/> </xul:vbox> @@ -1169,7 +1169,7 @@ <xul:menupopup anonid="menupopup" xbl:inherits="oncommand=menucommand"> <children/> - <xul:menuitem class="menuitem-iconic popup-notification-closeitem" + <xul:menuitem class="menuitem-iconic popup-notification-closeitem close-icon" label="&closeNotificationItem.label;" xbl:inherits="oncommand=closeitemcommand"/> </xul:menupopup> @@ -1178,7 +1178,7 @@ </xul:vbox> <xul:vbox pack="start"> <xul:toolbarbutton anonid="closebutton" - class="messageCloseButton popup-notification-closebutton tabbable" + class="messageCloseButton close-icon popup-notification-closebutton tabbable" xbl:inherits="oncommand=closebuttoncommand" tooltiptext="&closeNotification.tooltip;"/> </xul:vbox> @@ -1508,7 +1508,7 @@ <xul:label class="text-link click-to-play-plugins-notification-link" anonid="click-to-play-plugins-notification-link" /> </xul:description> <xul:toolbarbutton anonid="closebutton" - class="messageCloseButton popup-notification-closebutton tabbable" + class="messageCloseButton popup-notification-closebutton tabbable close-icon" xbl:inherits="oncommand=closebuttoncommand" tooltiptext="&closeNotification.tooltip;"/> </xul:hbox> @@ -2027,7 +2027,7 @@ onclick="document.getBindingParent(this).onLinkClick();"/> </xul:description> </xul:hbox> - <xul:toolbarbutton class="panel-promo-closebutton" + <xul:toolbarbutton class="panel-promo-closebutton close-icon" oncommand="document.getBindingParent(this).onCloseButtonCommand();" tooltiptext="&closeNotification.tooltip;"/> </xul:hbox> diff --git a/browser/base/jar.mn b/browser/base/jar.mn index 3113094fcb844882197054d78820f9121137f0eb..f6c615674d35639e41b3d761f69acf463df6ecec 100644 --- a/browser/base/jar.mn +++ b/browser/base/jar.mn @@ -13,8 +13,7 @@ browser.jar: #endif % overlay chrome://global/content/viewSource.xul chrome://browser/content/viewSourceOverlay.xul % overlay chrome://global/content/viewPartialSource.xul chrome://browser/content/viewSourceOverlay.xul -% style chrome://global/content/customizeToolbar.xul chrome://browser/content/browser.css -% style chrome://global/content/customizeToolbar.xul chrome://browser/skin/ + * content/browser/aboutDialog.xul (content/aboutDialog.xul) * content/browser/aboutDialog.js (content/aboutDialog.js) content/browser/aboutDialog.css (content/aboutDialog.css) diff --git a/browser/components/about/AboutRedirector.cpp b/browser/components/about/AboutRedirector.cpp index c1de734b7f451159cd1ebd080733de355e6ff716..15d813804dc267a4bff5f06b0f6bfcec7361d548 100644 --- a/browser/components/about/AboutRedirector.cpp +++ b/browser/components/about/AboutRedirector.cpp @@ -92,6 +92,8 @@ static RedirEntry kRedirMap[] = { #endif { "app-manager", "chrome://browser/content/devtools/app-manager/index.xul", nsIAboutModule::ALLOW_SCRIPT }, + { "customizing", "chrome://browser/content/customizableui/aboutCustomizing.xhtml", + nsIAboutModule::ALLOW_SCRIPT }, }; static const int kRedirTotal = NS_ARRAY_LENGTH(kRedirMap); diff --git a/browser/components/build/nsModule.cpp b/browser/components/build/nsModule.cpp index c0b927396281578efe7212688cdf303afc10d2d6..3ae8c28898ef2cca6d5652aad7a52509af0b16c7 100644 --- a/browser/components/build/nsModule.cpp +++ b/browser/components/build/nsModule.cpp @@ -110,6 +110,7 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = { { NS_ABOUT_MODULE_CONTRACTID_PREFIX "healthreport", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, #endif { NS_ABOUT_MODULE_CONTRACTID_PREFIX "app-manager", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, + { NS_ABOUT_MODULE_CONTRACTID_PREFIX "customizing", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, #if defined(XP_WIN) { NS_IEHISTORYENUMERATOR_CONTRACTID, &kNS_WINIEHISTORYENUMERATOR_CID }, #elif defined(XP_MACOSX) diff --git a/browser/components/customizableui/content/aboutCustomizing.xhtml b/browser/components/customizableui/content/aboutCustomizing.xhtml new file mode 100644 index 0000000000000000000000000000000000000000..9a55f5b5ff6f30c45ecbba062e23a6a209c32838 --- /dev/null +++ b/browser/components/customizableui/content/aboutCustomizing.xhtml @@ -0,0 +1,23 @@ +<?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 % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> + %brandDTD; + <!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd"> + %browserDTD; +]> + +<html xmlns="http://www.w3.org/1999/xhtml" + disablefastfind="true"> + <head> + <title>&customizeMode.tabTitle;</title> + </head> + <body></body> +</html> diff --git a/browser/components/customizableui/content/customizeMode.inc.xul b/browser/components/customizableui/content/customizeMode.inc.xul new file mode 100644 index 0000000000000000000000000000000000000000..5f860153ac7ad09d360acb4d5baaea566f81906c --- /dev/null +++ b/browser/components/customizableui/content/customizeMode.inc.xul @@ -0,0 +1,28 @@ +<!-- 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/. --> + +<hbox id="customization-container" flex="1" hidden="true"> + <vbox flex="1" id="customization-palette-container"> + <label id="customization-header" value="&customizeMode.menuAndToolbars.header;"/> + <vbox id="customization-palette" flex="1"/> + <hbox pack="start"> + <button id="customization-reset-button" oncommand="gCustomizeMode.reset();" label="&customizeMode.restoreDefaults;" class="customizationmode-button"/> + </hbox> + </vbox> + <vbox id="customization-panel-container"> + <vbox id="customization-panelWrapper"> + <html:style html:type="text/html" scoped="scoped"> + @import url(chrome://global/skin/popup.css); + </html:style> + <box class="panel-arrowbox"> + <box flex="1"/> + <image class="panel-arrow" side="top"/> + </box> + <box class="panel-arrowcontent" side="top" flex="1"> + <hbox id="customization-panelHolder"/> + <box class="panel-inner-arrowcontentfooter" hidden="true"/> + </box> + </vbox> + </vbox> +</hbox> diff --git a/browser/components/customizableui/content/jar.mn b/browser/components/customizableui/content/jar.mn new file mode 100644 index 0000000000000000000000000000000000000000..43f68f4c3dea12132e035027d52f25206e0eafaa --- /dev/null +++ b/browser/components/customizableui/content/jar.mn @@ -0,0 +1,11 @@ +# 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/customizableui/aboutCustomizing.xhtml + content/browser/customizableui/panelUI.css + content/browser/customizableui/panelUI.js + content/browser/customizableui/panelUI.xml + content/browser/customizableui/toolbar.xml + diff --git a/browser/components/customizableui/content/moz.build b/browser/components/customizableui/content/moz.build new file mode 100644 index 0000000000000000000000000000000000000000..895d11993cfbb162d47a99608e92843c5a06e999 --- /dev/null +++ b/browser/components/customizableui/content/moz.build @@ -0,0 +1,6 @@ +# -*- 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/. + diff --git a/browser/components/customizableui/content/panelUI.css b/browser/components/customizableui/content/panelUI.css new file mode 100644 index 0000000000000000000000000000000000000000..a3f46df3534ca03299ab3ed91fa1929ffd25f073 --- /dev/null +++ b/browser/components/customizableui/content/panelUI.css @@ -0,0 +1,31 @@ +/* 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/. */ + +.panel-viewstack[viewtype="main"] > .panel-clickcapturer { + pointer-events: none; +} + +.panel-mainview, +.panel-viewcontainer, +.panel-viewstack { + overflow: hidden; +} + +.panel-viewstack { + position: relative; +} + +.panel-subviews { + -moz-stack-sizing: ignore; + transform: translateX(0); + overflow-y: auto; +} + +.panel-subviews[panelopen] { + transition: transform 150ms; +} + +.panel-viewcontainer[panelopen]:-moz-any(:not([viewtype="main"]),[transitioning="true"]) { + transition: height 150ms; +} diff --git a/browser/components/customizableui/content/panelUI.inc.xul b/browser/components/customizableui/content/panelUI.inc.xul new file mode 100644 index 0000000000000000000000000000000000000000..212779084f7f9450c21eec9d9c48e5e39ded1e7a --- /dev/null +++ b/browser/components/customizableui/content/panelUI.inc.xul @@ -0,0 +1,153 @@ +<!-- 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/. --> + +<panel id="PanelUI-popup" + role="group" + type="arrow" + level="top" + hidden="true" + noautofocus="true"> + <panelmultiview id="PanelUI-multiView" mainViewId="PanelUI-mainView"> + <panelview id="PanelUI-mainView" contextmenu="customizationPanelContextMenu"> + <vbox id="PanelUI-contents-scroller"> + <vbox id="PanelUI-contents"/> + </vbox> + + <footer id="PanelUI-footer"> + <!-- The parentNode is used so that the footer is presented as the anchor + instead of just the button being the anchor. --> + <toolbarbutton id="PanelUI-help" label="&helpMenu.label;" tabindex="0" + oncommand="PanelUI.showHelpView(this.parentNode);"/> + <toolbarbutton id="PanelUI-customize" label="&appMenuCustomize.label;" tabindex="0" + oncommand="gCustomizeMode.toggle();"/> + <toolbarbutton id="PanelUI-quit" tabindex="0" +#ifdef XP_WIN + label="&quitApplicationCmdWin.label;" +#else + label="&quitApplicationCmd.label;" +#endif + command="cmd_quitApplication"/> + </footer> + </panelview> + + <panelview id="PanelUI-history" flex="1"> + <label value="&appMenuHistory.label;"/> + <toolbarbutton id="appMenuClearRecentHistory" tabindex="0" + label="&appMenuHistory.clearRecent.label;" + command="Tools:Sanitize"/> + <toolbarbutton id="appMenuRestoreLastSession" tabindex="0" + label="&appMenuHistory.restoreSession.label;" + command="Browser:RestoreLastSession"/> + <menuseparator id="PanelUI-recentlyClosedTabs-separator"/> + <vbox id="PanelUI-recentlyClosedTabs"/> + <menuseparator id="PanelUI-recentlyClosedWindows-separator"/> + <vbox id="PanelUI-recentlyClosedWindows"/> + <menuseparator id="PanelUI-historyItems-separator"/> + <vbox id="PanelUI-historyItems"/> + <label value="&appMenuHistory.showAll.label;" + id="PanelUI-historyMore" + class="text-link" + onclick="PlacesCommandHook.showPlacesOrganizer('History'); CustomizableUI.hidePanelForNode(this);"/> + </panelview> + + <panelview id="PanelUI-bookmarks" flex="1"> + <toolbarbutton id="panelMenuBookmarkThisPage" + label="&bookmarkThisPageCmd.label;" + command="Browser:AddBookmarkAs" + onclick="PanelUI.hide();"/> + <toolbarseparator/> + <toolbarbutton id="panelMenu_showAllBookmarks" + label="&showAllBookmarks2.label;" + command="Browser:ShowAllBookmarks" + onclick="PanelUI.hide();"/> + <toolbarbutton id="panelMenu_viewBookmarksSidebar" + label="&viewBookmarksSidebar2.label;" + oncommand="toggleSidebar('viewBookmarksSidebar'); PanelUI.hide();"> + <observes element="viewBookmarksSidebar" attribute="checked"/> + </toolbarbutton> + <toolbarbutton id="panelMenu_viewBookmarksToolbar" + label="&viewBookmarksToolbar.label;" + type="checkbox" + toolbarId="PersonalToolbar" + oncommand="onViewToolbarCommand(event); PanelUI.hide();"/> + <toolbarseparator/> + <toolbarbutton id="panelMenu_bookmarksToolbar" + label="&personalbarCmd.label;" + oncommand="PlacesCommandHook.showPlacesOrganizer('BookmarksToolbar'); PanelUI.hide();"/> + <toolbarbutton id="panelMenu_unsortedBookmarks" + label="&unsortedBookmarksCmd.label;" + oncommand="PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks'); PanelUI.hide();"/> + <toolbarseparator/> + <toolbaritem id="panelMenu_bookmarksMenu" + flex="1" + orient="vertical" + smoothscroll="false" + onclick="if (event.button == 1) BookmarkingUI.onPanelMenuViewCommand(event, this._placesView);" + oncommand="BookmarkingUI.onPanelMenuViewCommand(event, this._placesView);" + flatList="true" + tooltip="bhTooltip"> + <!-- bookmarks menu items --> + </toolbaritem> + + </panelview> + + <panelview id="PanelUI-feeds" flex="1" oncommand="FeedHandler.subscribeToFeed(null, event);"></panelview> + + <panelview id="PanelUI-helpView" flex="1"> + <label value="&helpMenu.label;"/> + <vbox id="PanelUI-helpItems"/> + </panelview> + + <panelview id="PanelUI-developer" flex="1"> + <label value="&webDeveloperMenu.label;"/> + <vbox id="PanelUI-developerItems"/> + </panelview> + + <panelview id="PanelUI-characterEncodingView" flex="1"> + <label value="&charsetMenu.label;"/> + <toolbarbutton label="&charsetCustomize.label;" + oncommand="PanelUI.onCharsetCustomizeCommand();"/> + + <vbox id="PanelUI-characterEncodingView-customlist" + class="PanelUI-characterEncodingView-list"/> + <vbox> + <label value="&charsetMenuAutodet.label;"/> + <vbox id="PanelUI-characterEncodingView-autodetect" + class="PanelUI-characterEncodingView-list"/> + </vbox> + </panelview> + + </panelmultiview> + <popupset id="customizationContextMenus"> + <menupopup id="customizationContextMenu"> + <menuitem oncommand="gCustomizeMode.addToToolbar(document.popupNode)" + accesskey="&customizeMenu.addToToolbar.accesskey;" + label="&customizeMenu.addToToolbar.label;"/> + <menuitem oncommand="gCustomizeMode.removeFromPanel(document.popupNode)" + accesskey="&customizeMenu.removeFromMenu.accesskey;" + label="&customizeMenu.removeFromMenu.label;"/> + <menuseparator/> + <menuitem command="cmd_CustomizeToolbars" + accesskey="&viewCustomizeToolbar.accesskey;" + label="&viewCustomizeToolbar.label;"/> + </menupopup> + + <menupopup id="customizationPanelContextMenu"> + <menuitem command="cmd_CustomizeToolbars" + accesskey="&customizeMenu.addMoreItems.accesskey;" + label="&customizeMenu.addMoreItems.label;"/> + </menupopup> + </popupset> +</panel> + +<panel id="widget-overflow" + role="group" + type="arrow" + level="top" + hidden="true" + consumeoutsideclicks="true"> + <vbox id="widget-overflow-scroller"> + <vbox id="widget-overflow-list"/> + </vbox> +</panel> diff --git a/browser/components/customizableui/content/panelUI.js b/browser/components/customizableui/content/panelUI.js new file mode 100644 index 0000000000000000000000000000000000000000..2071414eb3eadf7fb7ec45a0350db24680b5cd7b --- /dev/null +++ b/browser/components/customizableui/content/panelUI.js @@ -0,0 +1,400 @@ +/* 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/. */ + +XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI", + "resource:///modules/CustomizableUI.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "ScrollbarSampler", + "resource:///modules/ScrollbarSampler.jsm"); +/** + * Maintains the state and dispatches events for the main menu panel. + */ + +const PanelUI = { + /** Panel events that we listen for. **/ + get kEvents() ["popupshowing", "popupshown", "popuphiding", "popuphidden"], + /** + * Used for lazily getting and memoizing elements from the document. Lazy + * getters are set in init, and memoizing happens after the first retrieval. + */ + get kElements() { + return { + contents: "PanelUI-contents", + mainView: "PanelUI-mainView", + multiView: "PanelUI-multiView", + helpView: "PanelUI-helpView", + menuButton: "PanelUI-menu-button", + panel: "PanelUI-popup", + scroller: "PanelUI-contents-scroller" + }; + }, + + init: function() { + for (let [k, v] of Iterator(this.kElements)) { + // Need to do fresh let-bindings per iteration + let getKey = k; + let id = v; + this.__defineGetter__(getKey, function() { + delete this[getKey]; + return this[getKey] = document.getElementById(id); + }); + } + + this.menuButton.addEventListener("mousedown", this); + this.menuButton.addEventListener("keypress", this); + }, + + _eventListenersAdded: false, + _ensureEventListenersAdded: function() { + if (this._eventListenersAdded) + return; + this._addEventListeners(); + }, + + _addEventListeners: function() { + for (let event of this.kEvents) { + this.panel.addEventListener(event, this); + } + + this.helpView.addEventListener("ViewShowing", this._onHelpViewShow, false); + this.helpView.addEventListener("ViewHiding", this._onHelpViewHide, false); + this._eventListenersAdded = true; + }, + + uninit: function() { + if (!this._eventListenersAdded) { + return; + } + + for (let event of this.kEvents) { + this.panel.removeEventListener(event, this); + } + this.helpView.removeEventListener("ViewShowing", this._onHelpViewShow); + this.helpView.removeEventListener("ViewHiding", this._onHelpViewHide); + this.menuButton.removeEventListener("mousedown", this); + this.menuButton.removeEventListener("keypress", this); + }, + + /** + * Customize mode extracts the mainView and puts it somewhere else while the + * user customizes. Upon completion, this function can be called to put the + * panel back to where it belongs in normal browsing mode. + * + * @param aMainView + * The mainView node to put back into place. + */ + setMainView: function(aMainView) { + this._ensureEventListenersAdded(); + this.multiView.setMainView(aMainView); + }, + + /** + * Opens the menu panel if it's closed, or closes it if it's + * open. + * + * @param aEvent the event that triggers the toggle. + */ + toggle: function(aEvent) { + // Don't show the panel if the window is in customization mode, + // since this button doubles as an exit path for the user in this case. + if (document.documentElement.hasAttribute("customizing")) { + return; + } + this._ensureEventListenersAdded(); + if (this.panel.state == "open") { + this.hide(); + } else if (this.panel.state == "closed") { + this.show(aEvent); + } + }, + + /** + * Opens the menu panel. If the event target has a child with the + * toolbarbutton-icon attribute, the panel will be anchored on that child. + * Otherwise, the panel is anchored on the event target itself. + * + * @param aEvent the event (if any) that triggers showing the menu. + */ + show: function(aEvent) { + if (this.panel.state == "open" || this.panel.state == "showing" || + document.documentElement.hasAttribute("customizing")) { + return; + } + + this.ensureReady().then(() => { + this.panel.hidden = false; + let editControlPlacement = CustomizableUI.getPlacementOfWidget("edit-controls"); + if (editControlPlacement && editControlPlacement.area == CustomizableUI.AREA_PANEL) { + updateEditUIVisibility(); + } + + let anchor; + if (!aEvent || + aEvent.type == "command") { + anchor = this.menuButton; + } else { + anchor = aEvent.target; + } + let iconAnchor = + document.getAnonymousElementByAttribute(anchor, "class", + "toolbarbutton-icon"); + + // Only focus the panel if it's opened using the keyboard, so that + // cut/copy/paste buttons will work for mouse users. + let keyboardOpened = aEvent && aEvent.sourceEvent && + aEvent.sourceEvent.target.localName == "key"; + this.panel.setAttribute("noautofocus", !keyboardOpened); + this.panel.openPopup(iconAnchor || anchor, "bottomcenter topright"); + }); + }, + + /** + * If the menu panel is being shown, hide it. + */ + hide: function() { + if (document.documentElement.hasAttribute("customizing")) { + return; + } + + this.panel.hidePopup(); + }, + + handleEvent: function(aEvent) { + switch (aEvent.type) { + case "popupshowing": + // Fall through + case "popupshown": + // Fall through + case "popuphiding": + // Fall through + case "popuphidden": + this._updatePanelButton(aEvent.target); + break; + case "mousedown": + if (aEvent.button == 0) + this.toggle(aEvent); + break; + case "keypress": + this.toggle(aEvent); + break; + } + }, + + /** + * Registering the menu panel is done lazily for performance reasons. This + * method is exposed so that CustomizationMode can force panel-readyness in the + * event that customization mode is started before the panel has been opened + * by the user. + * + * @param aCustomizing (optional) set to true if this was called while entering + * customization mode. If that's the case, we trust that customization + * mode will handle calling beginBatchUpdate and endBatchUpdate. + * + * @return a Promise that resolves once the panel is ready to roll. + */ + ensureReady: function(aCustomizing=false) { + if (this._readyPromise) { + return this._readyPromise; + } + this._readyPromise = Task.spawn(function() { + if (!this._scrollWidth) { + // In order to properly center the contents of the panel, while ensuring + // that we have enough space on either side to show a scrollbar, we have to + // do a bit of hackery. In particular, we calculate a new width for the + // scroller, based on the system scrollbar width. + this._scrollWidth = + (yield ScrollbarSampler.getSystemScrollbarWidth()) + "px"; + let cstyle = window.getComputedStyle(this.scroller); + let widthStr = cstyle.width; + // Get the calculated padding on the left and right sides of + // the scroller too. We'll use that in our final calculation so + // that if a scrollbar appears, we don't have the contents right + // up against the edge of the scroller. + let paddingLeft = cstyle.paddingLeft; + let paddingRight = cstyle.paddingRight; + let calcStr = [widthStr, this._scrollWidth, + paddingLeft, paddingRight].join(" + "); + this.scroller.style.width = "calc(" + calcStr + ")"; + } + + if (aCustomizing) { + CustomizableUI.registerMenuPanel(this.contents); + } else { + this.beginBatchUpdate(); + CustomizableUI.registerMenuPanel(this.contents); + this.endBatchUpdate(); + } + }.bind(this)).then(null, Cu.reportError); + + return this._readyPromise; + }, + + /** + * Switch the panel to the main view if it's not already + * in that view. + */ + showMainView: function() { + this._ensureEventListenersAdded(); + this.multiView.showMainView(); + }, + + /** + * Switch the panel to the help view if it's not already + * in that view. + */ + showHelpView: function(aAnchor) { + this._ensureEventListenersAdded(); + this.multiView.showSubView("PanelUI-helpView", aAnchor); + }, + + /** + * Shows a subview in the panel with a given ID. + * + * @param aViewId the ID of the subview to show. + * @param aAnchor the element that spawned the subview. + * @param aPlacementArea the CustomizableUI area that aAnchor is in. + */ + showSubView: function(aViewId, aAnchor, aPlacementArea) { + this._ensureEventListenersAdded(); + let viewNode = document.getElementById(aViewId); + if (!viewNode) { + Cu.reportError("Could not show panel subview with id: " + aViewId); + return; + } + + if (!aAnchor) { + Cu.reportError("Expected an anchor when opening subview with id: " + aViewId); + return; + } + + if (aPlacementArea == CustomizableUI.AREA_PANEL) { + this.multiView.showSubView(aViewId, aAnchor); + } else if (!aAnchor.open) { + aAnchor.open = true; + // Emit the ViewShowing event so that the widget definition has a chance + // to lazily populate the subview with things. + let evt = document.createEvent("CustomEvent"); + evt.initCustomEvent("ViewShowing", true, true, viewNode); + viewNode.dispatchEvent(evt); + if (evt.defaultPrevented) { + return; + } + + let tempPanel = document.createElement("panel"); + tempPanel.setAttribute("type", "arrow"); + tempPanel.setAttribute("id", "customizationui-widget-panel"); + tempPanel.setAttribute("level", "top"); + document.getElementById(CustomizableUI.AREA_NAVBAR).appendChild(tempPanel); + + let multiView = document.createElement("panelmultiview"); + tempPanel.appendChild(multiView); + multiView.setMainView(viewNode); + CustomizableUI.addPanelCloseListeners(tempPanel); + + let panelRemover = function() { + tempPanel.removeEventListener("popuphidden", panelRemover); + CustomizableUI.removePanelCloseListeners(tempPanel); + let evt = new CustomEvent("ViewHiding", {detail: viewNode}); + viewNode.dispatchEvent(evt); + aAnchor.open = false; + + this.multiView.appendChild(viewNode); + tempPanel.parentElement.removeChild(tempPanel); + }.bind(this); + tempPanel.addEventListener("popuphidden", panelRemover); + + let iconAnchor = + document.getAnonymousElementByAttribute(aAnchor, "class", + "toolbarbutton-icon"); + + tempPanel.openPopup(iconAnchor || aAnchor, "bottomcenter topright"); + } + }, + + /** + * This function can be used as a command event listener for subviews + * so that the panel knows if and when to close itself. + */ + onCommandHandler: function(aEvent) { + if (!aEvent.originalTarget.hasAttribute("noautoclose")) { + PanelUI.hide(); + } + }, + + /** + * Open a dialog window that allow the user to customize listed character sets. + */ + onCharsetCustomizeCommand: function() { + this.hide(); + window.openDialog("chrome://global/content/customizeCharset.xul", + "PrefWindow", + "chrome,modal=yes,resizable=yes", + "browser"); + }, + + /** + * Signal that we're about to make a lot of changes to the contents of the + * panels all at once. For performance, we ignore the mutations. + */ + beginBatchUpdate: function() { + this._ensureEventListenersAdded(); + this.multiView.ignoreMutations = true; + }, + + /** + * Signal that we're done making bulk changes to the panel. We now pay + * attention to mutations. This automatically synchronizes the multiview + * container with whichever view is displayed if the panel is open. + */ + endBatchUpdate: function(aReason) { + this._ensureEventListenersAdded(); + this.multiView.ignoreMutations = false; + }, + + /** + * Sets the anchor node into the open or closed state, depending + * on the state of the panel. + */ + _updatePanelButton: function() { + this.menuButton.open = this.panel.state == "open" || + this.panel.state == "showing"; + }, + + _onHelpViewShow: function(aEvent) { + // Call global menu setup function + buildHelpMenu(); + + let helpMenu = document.getElementById("menu_HelpPopup"); + let items = this.getElementsByTagName("vbox")[0]; + let attrs = ["oncommand", "onclick", "label", "key", "disabled"]; + let NSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + + // Remove all buttons from the view + while (items.firstChild) { + items.removeChild(items.firstChild); + } + + // Add the current set of menuitems of the Help menu to this view + let menuItems = Array.prototype.slice.call(helpMenu.getElementsByTagName("menuitem")); + let fragment = document.createDocumentFragment(); + for (let node of menuItems) { + if (node.hidden) + continue; + let button = document.createElementNS(NSXUL, "toolbarbutton"); + // Copy specific attributes from a menuitem of the Help menu + for (let attrName of attrs) { + if (!node.hasAttribute(attrName)) + continue; + button.setAttribute(attrName, node.getAttribute(attrName)); + } + fragment.appendChild(button); + } + items.appendChild(fragment); + + this.addEventListener("command", PanelUI.onCommandHandler); + }, + + _onHelpViewHide: function(aEvent) { + this.removeEventListener("command", PanelUI.onCommandHandler); + } +}; diff --git a/browser/components/customizableui/content/panelUI.xml b/browser/components/customizableui/content/panelUI.xml new file mode 100644 index 0000000000000000000000000000000000000000..3e1de7a2ad0d1ce2b4f3321a513b2398cc27b157 --- /dev/null +++ b/browser/components/customizableui/content/panelUI.xml @@ -0,0 +1,342 @@ +<?xml version="1.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/. --> + +<bindings id="browserPanelUIBindings" + xmlns="http://www.mozilla.org/xbl" + xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + xmlns:xbl="http://www.mozilla.org/xbl"> + + <binding id="panelmultiview"> + <resources> + <stylesheet src="chrome://browser/content/customizableui/panelUI.css"/> + </resources> + <content> + <xul:box anonid="viewContainer" class="panel-viewcontainer" xbl:inherits="panelopen,viewtype,transitioning"> + <xul:stack anonid="viewStack" xbl:inherits="viewtype" viewtype="main" class="panel-viewstack"> + <xul:vbox anonid="mainViewContainer" class="panel-mainview"/> + + <!-- Used to capture click events over the PanelUI-mainView if we're in + subview mode. That way, any click on the PanelUI-mainView causes us + to revert to the mainView mode, whereupon PanelUI-click-capture then + allows click events to go through it. --> + <xul:vbox anonid="clickCapturer" class="panel-clickcapturer"/> + + <!-- We manually set display: none (via a CSS attribute selector) on the + subviews that are not being displayed. We're using this over a deck + because a deck assumes the size of its largest child, regardless of + whether or not it is shown. That's not good for our case, since we + want to allow each subview to be uniquely sized. --> + <xul:vbox anonid="subViews" class="panel-subviews" xbl:inherits="panelopen"> + <children includes="panelview"/> + </xul:vbox> + </xul:stack> + </xul:box> + </content> + <implementation implements="nsIDOMEventListener"> + <field name="_clickCapturer" readonly="true"> + document.getAnonymousElementByAttribute(this, "anonid", "clickCapturer"); + </field> + <field name="_viewContainer" readonly="true"> + document.getAnonymousElementByAttribute(this, "anonid", "viewContainer"); + </field> + <field name="_mainViewContainer" readonly="true"> + document.getAnonymousElementByAttribute(this, "anonid", "mainViewContainer"); + </field> + <field name="_subViews" readonly="true"> + document.getAnonymousElementByAttribute(this, "anonid", "subViews"); + </field> + <field name="_viewStack" readonly="true"> + document.getAnonymousElementByAttribute(this, "anonid", "viewStack"); + </field> + <field name="_panel" readonly="true"> + this.parentNode; + </field> + + <field name="_currentSubView">null</field> + <field name="_anchorElement">null</field> + <field name="_mainViewHeight">0</field> + <field name="_subViewObserver">null</field> + <field name="__transitioning">false</field> + <field name="_ignoreMutations">false</field> + + <property name="showingSubView" readonly="true" + onget="return this._viewStack.getAttribute('viewtype') == 'subview'"/> + <property name="_mainViewId" onget="return this.getAttribute('mainViewId');" onset="this.setAttribute('mainViewId', val); return val;"/> + <property name="_mainView" readonly="true" + onget="return this._mainViewId ? document.getElementById(this._mainViewId) : null;"/> + + <property name="ignoreMutations"> + <getter> + return this._ignoreMutations; + </getter> + <setter><![CDATA[ + this._ignoreMutations = val; + if (!val && this._panel.state == "open") { + if (this.showingSubView) { + this._syncContainerWithSubView(); + } else { + this._syncContainerWithMainView(); + } + } + ]]></setter> + </property> + + <property name="_transitioning"> + <getter> + return this.__transitioning; + </getter> + <setter><![CDATA[ + this.__transitioning = val; + if (val) { + this.setAttribute("transitioning", "true"); + } else { + this.removeAttribute("transitioning"); + } + ]]></setter> + </property> + <constructor><![CDATA[ + this._clickCapturer.addEventListener("click", this); + this._panel.addEventListener("popupshowing", this); + this._panel.addEventListener("popupshown", this); + this._panel.addEventListener("popuphidden", this); + this._subViews.addEventListener("overflow", this); + this._mainViewContainer.addEventListener("overflow", this); + + // Get a MutationObserver ready to react to subview size changes. We + // only attach this MutationObserver when a subview is being displayed. + this._subViewObserver = + new MutationObserver(this._syncContainerWithSubView.bind(this)); + this._mainViewObserver = + new MutationObserver(this._syncContainerWithMainView.bind(this)); + + this._mainViewContainer.setAttribute("panelid", + this._panel.id); + + if (this._mainView) { + this.setMainView(this._mainView); + } + this.setAttribute("viewtype", "main"); + ]]></constructor> + + <destructor><![CDATA[ + if (this._mainView) { + this._mainView.removeAttribute("mainview"); + } + this._mainViewObserver.disconnect(); + this._subViewObserver.disconnect(); + this._panel.removeEventListener("popupshowing", this); + this._panel.removeEventListener("popupshown", this); + this._panel.removeEventListener("popuphidden", this); + this._subViews.removeEventListener("overflow", this); + this._mainViewContainer.removeEventListener("overflow", this); + this._clickCapturer.removeEventListener("click", this); + ]]></destructor> + + <method name="setMainView"> + <parameter name="aNewMainView"/> + <body><![CDATA[ + if (this._mainView) { + this._mainViewObserver.disconnect(); + this._subViews.appendChild(this._mainView); + this._mainView.removeAttribute("mainview"); + } + this._mainViewId = aNewMainView.id; + aNewMainView.setAttribute("mainview", "true"); + this._mainViewContainer.appendChild(aNewMainView); + ]]></body> + </method> + + <method name="showMainView"> + <body><![CDATA[ + if (this.showingSubView) { + let viewNode = this._currentSubView; + let evt = document.createEvent("CustomEvent"); + evt.initCustomEvent("ViewHiding", true, true, viewNode); + viewNode.dispatchEvent(evt); + + viewNode.removeAttribute("current"); + this._currentSubView = null; + + this._subViewObserver.disconnect(); + + this._transitioning = true; + + this._viewContainer.addEventListener("transitionend", function trans() { + this._viewContainer.removeEventListener("transitionend", trans); + this._transitioning = false; + }.bind(this)); + this._viewContainer.style.height = this._mainViewHeight + "px"; + + this.setAttribute("viewtype", "main"); + } + + this._mainViewObserver.observe(this._mainView, { + attributes: true, + characterData: true, + childList: true, + subtree: true + }); + + this._shiftMainView(); + ]]></body> + </method> + + <method name="showSubView"> + <parameter name="aViewId"/> + <parameter name="aAnchor"/> + <body><![CDATA[ + let viewNode = this.querySelector("#" + aViewId); + viewNode.setAttribute("current", true); + // Emit the ViewShowing event so that the widget definition has a chance + // to lazily populate the subview with things. + let evt = document.createEvent("CustomEvent"); + evt.initCustomEvent("ViewShowing", true, true, viewNode); + viewNode.dispatchEvent(evt); + if (evt.defaultPrevented) { + return; + } + + this._currentSubView = viewNode; + + // Now we have to transition to transition the panel. There are a few parts + // to this: + // + // 1) The main view content gets shifted so that the center of the anchor + // node is at the left-most edge of the panel. + // 2) The subview deck slides in so that it takes up almost all of the + // panel. + // 3) If the subview is taller then the main panel contents, then the panel + // must grow to meet that new height. Otherwise, it must shrink. + // + // All three of these actions make use of CSS transformations, so they + // should all occur simultaneously. + this.setAttribute("viewtype", "subview"); + this._shiftMainView(aAnchor); + + this._mainViewHeight = this._viewStack.clientHeight; + + this._transitioning = true; + this._viewContainer.addEventListener("transitionend", function trans() { + this._viewContainer.removeEventListener("transitionend", trans); + this._transitioning = false; + }.bind(this)); + this._viewContainer.style.height = this._subViews.scrollHeight + "px"; + + this._subViewObserver.observe(viewNode, { + attributes: true, + characterData: true, + childList: true, + subtree: true + }); + ]]></body> + </method> + + <method name="_shiftMainView"> + <parameter name="aAnchor"/> + <body><![CDATA[ + if (aAnchor) { + // We need to find the edge of the anchor, relative to the main panel. + // Then we need to add half the width of the anchor. This is the target + // that we need to transition to. + let anchorRect = aAnchor.getBoundingClientRect(); + let mainViewRect = this._mainViewContainer.getBoundingClientRect(); + let center = aAnchor.clientWidth / 2; + let direction = aAnchor.ownerDocument.defaultView.getComputedStyle(aAnchor, null).direction; + let edge, target; + if (direction == "ltr") { + edge = anchorRect.left - mainViewRect.left; + target = "-" + (edge + center); + } else { + edge = mainViewRect.right - anchorRect.right; + target = edge + center; + } + this._mainViewContainer.style.transform = "translateX(" + target + "px)"; + aAnchor.classList.add("panel-multiview-anchor"); + } else { + this._mainViewContainer.style.transform = ""; + if (this.anchorElement) + this.anchorElement.classList.remove("panel-multiview-anchor"); + } + this.anchorElement = aAnchor; + ]]></body> + </method> + + <method name="handleEvent"> + <parameter name="aEvent"/> + <body><![CDATA[ + switch(aEvent.type) { + case "click": + if (aEvent.originalTarget == this._clickCapturer) { + this.showMainView(); + } + break; + case "overflow": + // Resize the right view on the next tick. + if (this.showingSubView) { + setTimeout(this._syncContainerWithSubView.bind(this), 0); + } else if (!this.transitioning) { + setTimeout(this._syncContainerWithMainView.bind(this), 0); + } + break; + case "popupshowing": + this.setAttribute("panelopen", "true"); + this._syncContainerWithMainView(); + break; + case "popupshown": + this._setMaxHeight(); + break; + case "popuphidden": + this.removeAttribute("panelopen"); + this._mainView.style.height = ""; + this.showMainView(); + break; + } + ]]></body> + </method> + + <method name="_setMaxHeight"> + <body><![CDATA[ + // Ignore the mutation that'll fire when we set the height of + // the main view. + this.ignoreMutations = true; + this._mainView.style.height = + this.getBoundingClientRect().height + "px"; + this.ignoreMutations = false; + ]]></body> + </method> + <method name="_syncContainerWithSubView"> + <body><![CDATA[ + if (!this.ignoreMutations && this.showingSubView) { + this._viewContainer.style.height = + this._subViews.scrollHeight + "px"; + } + ]]></body> + </method> + <method name="_syncContainerWithMainView"> + <body><![CDATA[ + if (!this.ignoreMutations && !this.showingSubView && !this._transitioning) { + this._viewContainer.style.height = + this._mainView.scrollHeight + "px"; + } + ]]></body> + </method> + + </implementation> + </binding> + + <binding id="panelview"> + <implementation> + <property name="panelMultiView" readonly="true"> + <getter><![CDATA[ + if (this.parentNode.localName != "panelmultiview") { + return document.getBindingParent(this.parentNode); + } + + return this.parentNode; + ]]></getter> + </property> + </implementation> + </binding> +</bindings> diff --git a/browser/components/customizableui/content/toolbar.xml b/browser/components/customizableui/content/toolbar.xml new file mode 100644 index 0000000000000000000000000000000000000000..4176c8f431c9c7cea4b0f14ca055555be2165339 --- /dev/null +++ b/browser/components/customizableui/content/toolbar.xml @@ -0,0 +1,556 @@ +<?xml version="1.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/. --> + +<bindings id="browserToolbarBindings" + xmlns="http://www.mozilla.org/xbl" + xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + xmlns:xbl="http://www.mozilla.org/xbl"> + + <binding id="toolbar"> + <resources> + <stylesheet src="chrome://global/skin/toolbar.css"/> + </resources> + <implementation implements="nsIAccessibleProvider"> + <field name="overflowedDuringConstruction">null</field> + + <property name="accessibleType" readonly="true"> + <getter> + return Components.interfaces.nsIAccessibleProvider.XULToolbar; + </getter> + </property> + + <constructor><![CDATA[ + let scope = {}; + Cu.import("resource:///modules/CustomizableUI.jsm", scope); + // Add an early overflow event listener that will mark if the + // toolbar overflowed during construction. + if (scope.CustomizableUI.isAreaOverflowable(this.id)) { + this.addEventListener("overflow", this); + this.addEventListener("underflow", this); + } + + if (document.readyState == "complete") { + this._init(); + } else { + // Need to wait until XUL overlays are loaded. See bug 554279. + let self = this; + document.addEventListener("readystatechange", function onReadyStateChange() { + if (document.readyState != "complete") + return; + document.removeEventListener("readystatechange", onReadyStateChange, false); + self._init(); + }, false); + } + ]]></constructor> + + <method name="_init"> + <body><![CDATA[ + let scope = {}; + Cu.import("resource:///modules/CustomizableUI.jsm", scope); + let CustomizableUI = scope.CustomizableUI; + + // Searching for the toolbox palette in the toolbar binding because + // toolbars are constructed first. + let toolbox = this.toolbox; + if (toolbox && !toolbox.palette) { + for (let node of toolbox.children) { + if (node.localName == "toolbarpalette") { + // Hold on to the palette but remove it from the document. + toolbox.palette = node; + toolbox.removeChild(node); + break; + } + } + } + + // pass the current set of children for comparison with placements: + let children = [node.id for (node of this.childNodes) + if (node.getAttribute("skipintoolbarset") != "true" && node.id)]; + CustomizableUI.registerToolbarNode(this, children); + ]]></body> + </method> + + <method name="handleEvent"> + <parameter name="aEvent"/> + <body><![CDATA[ + if (aEvent.type == "overflow" && aEvent.detail > 0) { + if (this.overflowable && this.overflowable.initialized) { + this.overflowable.onOverflow(aEvent); + } else { + this.overflowedDuringConstruction = aEvent; + } + } else if (aEvent.type == "underflow" && aEvent.detail > 0) { + this.overflowedDuringConstruction = null; + } + ]]></body> + </method> + + <method name="insertItem"> + <parameter name="aId"/> + <parameter name="aBeforeElt"/> + <parameter name="aWrapper"/> + <body><![CDATA[ + if (aWrapper) { + Cu.reportError("Can't insert " + aId + ": using insertItem " + + "no longer supports wrapper elements."); + return null; + } + + // Hack, the customizable UI code makes this be the last position + let pos = null; + if (aBeforeElt) { + let beforeInfo = CustomizableUI.getPlacementOfWidget(aBeforeElt.id); + if (beforeInfo.area != this.id) { + Cu.reportError("Can't insert " + aId + " before " + + aBeforeElt.id + " which isn't in this area (" + + this.id + ")."); + return null; + } + pos = beforeInfo.position; + } + + CustomizableUI.addWidgetToArea(aId, this.id, pos); + return this.ownerDocument.getElementById(aId); + ]]></body> + </method> + + <property name="toolbarName" + onget="return this.getAttribute('toolbarname');" + onset="this.setAttribute('toolbarname', val); return val;"/> + + <property name="customizationTarget" readonly="true"> + <getter><![CDATA[ + if (this._customizationTarget) + return this._customizationTarget; + + let id = this.getAttribute("customizationtarget"); + if (id) + this._customizationTarget = document.getElementById(id); + + if (this._customizationTarget) + this._customizationTarget.insertItem = this.insertItem.bind(this); + else + this._customizationTarget = this; + + return this._customizationTarget; + ]]></getter> + </property> + + <property name="toolbox" readonly="true"> + <getter><![CDATA[ + if (this._toolbox) + return this._toolbox; + + let toolboxId = this.getAttribute("toolboxid"); + if (toolboxId) { + let toolbox = document.getElementById(toolboxId); + if (toolbox) { + if (toolbox.externalToolbars.indexOf(this) == -1) + toolbox.externalToolbars.push(this); + + this._toolbox = toolbox; + } + } + + if (!this._toolbox && this.parentNode && + this.parentNode.localName == "toolbox") { + this._toolbox = this.parentNode; + } + + return this._toolbox; + ]]></getter> + </property> + + <property name="currentSet"> + <getter><![CDATA[ + let currentWidgets = new Set(); + for (let node of this.customizationTarget.children) { + let realNode = node.localName == "toolbarpaletteitem" ? node.firstChild : node; + if (realNode.getAttribute("skipintoolbarset") != "true") { + currentWidgets.add(realNode.id); + } + } + if (this.getAttribute("overflowing") == "true") { + let overflowTarget = this.getAttribute("overflowtarget"); + let overflowList = this.ownerDocument.getElementById(overflowTarget); + for (let node of overflowList.children) { + let realNode = node.localName == "toolbarpaletteitem" ? node.firstChild : node; + if (realNode.getAttribute("skipintoolbarset") != "true") { + currentWidgets.add(realNode.id); + } + } + } + let orderedPlacements = CustomizableUI.getWidgetIdsInArea(this.id); + return orderedPlacements.filter((x) => currentWidgets.has(x)).join(','); + ]]></getter> + <setter><![CDATA[ + // Get list of new and old ids: + let newVal = (val || '').split(',').filter(x => x); + let oldIds = CustomizableUI.getWidgetIdsInArea(this.id); + + // Get a list of items only in the new list + let newIds = [id for (id of newVal) if (oldIds.indexOf(id) == -1)]; + CustomizableUI.beginBatchUpdate(); + for (let newId of newIds) { + oldIds = CustomizableUI.getWidgetIdsInArea(this.id); + let nextId = newId; + let pos; + do { + // Get the next item + nextId = newVal[newVal.indexOf(nextId) + 1]; + // Figure out where it is in the old list + pos = oldIds.indexOf(nextId); + // If it's not in the old list, repeat: + } while (pos == -1 && nextId); + if (pos == -1) { + pos = null; // We didn't find anything, insert at the end + } + CustomizableUI.addWidgetToArea(newId, this.id, pos); + } + + let currentIds = this.currentSet.split(','); + let removedIds = [id for (id of currentIds) if (newIds.indexOf(id) == -1 && newVal.indexOf(id) == -1)]; + for (let removedId of removedIds) { + CustomizableUI.removeWidgetFromArea(removedId); + } + CustomizableUI.endBatchUpdate(); + ]]></setter> + </property> + + + </implementation> + </binding> + + <binding id="toolbar-menubar-stub"> + <implementation> + <property name="toolbox" readonly="true"> + <getter><![CDATA[ + if (this._toolbox) + return this._toolbox; + + if (this.parentNode && this.parentNode.localName == "toolbox") { + this._toolbox = this.parentNode; + } + + return this._toolbox; + ]]></getter> + </property> + <property name="currentSet" readonly="true"> + <getter><![CDATA[ + return this.getAttribute("defaultset"); + ]]></getter> + </property> + <method name="insertItem"> + <body><![CDATA[ + return null; + ]]></body> + </method> + </implementation> + </binding> + + <!-- The toolbar-menubar-autohide and toolbar-drag bindings are almost + verbatim copies of their toolkit counterparts - they just inherit from + the customizableui's toolbar binding instead of toolkit's. We're currently + OK with the maintainance burden of having two copies of a binding, since + the long term goal is to move the customization framework into toolkit. --> + + <binding id="toolbar-menubar-autohide" + extends="chrome://browser/content/customizableui/toolbar.xml#toolbar"> + <implementation> + <constructor> + this._setInactive(); + </constructor> + <destructor> + this._setActive(); + </destructor> + + <field name="_inactiveTimeout">null</field> + + <field name="_contextMenuListener"><![CDATA[({ + toolbar: this, + contextMenu: null, + + get active () !!this.contextMenu, + + init: function (event) { + let node = event.target; + while (node != this.toolbar) { + if (node.localName == "menupopup") + return; + node = node.parentNode; + } + + let contextMenuId = this.toolbar.getAttribute("context"); + if (!contextMenuId) + return; + + this.contextMenu = document.getElementById(contextMenuId); + if (!this.contextMenu) + return; + + this.contextMenu.addEventListener("popupshown", this, false); + this.contextMenu.addEventListener("popuphiding", this, false); + this.toolbar.addEventListener("mousemove", this, false); + }, + handleEvent: function (event) { + switch (event.type) { + case "popupshown": + this.toolbar.removeEventListener("mousemove", this, false); + break; + case "popuphiding": + case "mousemove": + this.toolbar._setInactiveAsync(); + this.toolbar.removeEventListener("mousemove", this, false); + this.contextMenu.removeEventListener("popuphiding", this, false); + this.contextMenu.removeEventListener("popupshown", this, false); + this.contextMenu = null; + break; + } + } + })]]></field> + + <method name="_setInactive"> + <body><![CDATA[ + this.setAttribute("inactive", "true"); + ]]></body> + </method> + + <method name="_setInactiveAsync"> + <body><![CDATA[ + this._inactiveTimeout = setTimeout(function (self) { + if (self.getAttribute("autohide") == "true") { + self._inactiveTimeout = null; + self._setInactive(); + } + }, 0, this); + ]]></body> + </method> + + <method name="_setActive"> + <body><![CDATA[ + if (this._inactiveTimeout) { + clearTimeout(this._inactiveTimeout); + this._inactiveTimeout = null; + } + this.removeAttribute("inactive"); + ]]></body> + </method> + </implementation> + + <handlers> + <handler event="DOMMenuBarActive" action="this._setActive();"/> + <handler event="popupshowing" action="this._setActive();"/> + <handler event="mousedown" button="2" action="this._contextMenuListener.init(event);"/> + <handler event="DOMMenuBarInactive"><![CDATA[ + if (!this._contextMenuListener.active) + this._setInactiveAsync(); + ]]></handler> + </handlers> + </binding> + + <binding id="toolbar-drag" + extends="chrome://browser/content/customizableui/toolbar.xml#toolbar"> + <implementation> + <field name="_dragBindingAlive">true</field> + <constructor><![CDATA[ + if (!this._draggableStarted) { + this._draggableStarted = true; + try { + let tmp = {}; + Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp); + let draggableThis = new tmp.WindowDraggingElement(this); + draggableThis.mouseDownCheck = function(e) { + return this._dragBindingAlive; + }; + } catch (e) {} + } + ]]></constructor> + </implementation> + </binding> + + +<!-- This is a peculiar binding. It is here to deal with overlayed/inserted add-on content, + and immediately direct such content elsewhere. --> + <binding id="addonbar-delegating"> + <implementation> + <constructor><![CDATA[ + // Reading these immediately so nobody messes with them anymore: + this._delegatingToolbar = this.getAttribute("toolbar-delegate"); + // Leaving those in here to unbreak some code: + if (document.readyState == "complete") { + this._init(); + } else { + // Need to wait until XUL overlays are loaded. See bug 554279. + let self = this; + document.addEventListener("readystatechange", function onReadyStateChange() { + if (document.readyState != "complete") + return; + document.removeEventListener("readystatechange", onReadyStateChange, false); + self._init(); + }, false); + } + ]]></constructor> + + <method name="_init"> + <body><![CDATA[ + // Searching for the toolbox palette in the toolbar binding because + // toolbars are constructed first. + let toolbox = this.toolbox; + if (toolbox && !toolbox.palette) { + for (let node of toolbox.children) { + if (node.localName == "toolbarpalette") { + // Hold on to the palette but remove it from the document. + toolbox.palette = node; + toolbox.removeChild(node); + } + } + } + + // pass the current set of children for comparison with placements: + let children = [node.id for (node of this.childNodes) + if (node.getAttribute("skipintoolbarset") != "true" && node.id)]; + CustomizableUI.registerToolbarNode(this, children); + this.evictNodes(); + // We can't easily use |this| or strong bindings for the observer fn here + // because that creates leaky circular references when the node goes away, + // and XBL destructors are unreliable. + let mutationObserver = new MutationObserver(function(mutations) { + if (!mutations.length) { + return; + } + let toolbar = mutations[0].target; + // Can't use our own attribute because we might not have one if we're set to + // collapsed + let areCustomizing = toolbar.ownerDocument.documentElement.getAttribute("customizing"); + if (!toolbar._isModifying && !areCustomizing) { + toolbar.evictNodes(); + } + }); + mutationObserver.observe(this, {childList: true}); + ]]></body> + </method> + <method name="evictNodes"> + <body><![CDATA[ + this._isModifying = true; + let i = this.childNodes.length; + while (i--) { + let node = this.childNodes[i]; + if (this.childNodes[i].id) { + this.evictNode(this.childNodes[i]); + } else { + node.remove(); + } + } + this._isModifying = false; + ]]></body> + </method> + <method name="evictNode"> + <parameter name="aNode"/> + <body> + <![CDATA[ + if (this._whiteListed.has(aNode.id) || CustomizableUI.isSpecialWidget(aNode.id)) { + return; + } + const kItemMaxWidth = 100; + let oldParent = aNode.parentNode; + + try { + aNode.setAttribute("removable", "true"); + + let nodeWidth = aNode.getBoundingClientRect().width; + if (nodeWidth == 0 || nodeWidth > kItemMaxWidth) { + throw new Error(aNode.id + " is too big (" + nodeWidth + + "px wide), moving to the palette"); + } + CustomizableUI.addWidgetToArea(aNode.id, this._delegatingToolbar); + } catch (ex) { + Cu.reportError(ex); + // This will throw if the node is too big, or can't be moved there for + // some reason. Try to remove it anyway: + try { + CustomizableUI.removeWidgetFromArea(aNode.id); + } catch (ex) { + Cu.reportError(ex); + aNode.remove(); + } + } + + // Surprise: addWidgetToArea(palette) will get you nothing if the palette + // is not constructed yet. Fix: + if (aNode.parentNode == oldParent) { + let palette = this.toolbox.palette; + if (palette && oldParent != palette) { + palette.appendChild(aNode); + } + } + ]]></body> + </method> + <method name="insertItem"> + <parameter name="aId"/> + <parameter name="aBeforeElt"/> + <parameter name="aWrapper"/> + <body><![CDATA[ + if (aWrapper) { + Cu.reportError("Can't insert " + aId + ": using insertItem " + + "no longer supports wrapper elements."); + return null; + } + + let widget = CustomizableUI.getWidget(aId); + widget = widget && widget.forWindow(window); + let node = widget && widget.node; + if (!node) { + return null; + } + + this._isModifying = true; + // Temporarily add it here so it can have a width, then ditch it: + this.appendChild(node); + this.evictNode(node); + this._isModifying = false; + // We will now have moved stuff around; kick off an aftercustomization event + // so add-ons know we've just moved their stuff: + if (window.gCustomizeMode) { + window.gCustomizeMode.dispatchToolboxEvent("aftercustomization"); + } + return node; + ]]></body> + </method> + <property name="customizationTarget" readonly="true"> + <getter><![CDATA[ + return this; + ]]></getter> + </property> + <property name="currentSet"> + <getter><![CDATA[ + return [node.id for (node of this.children)].join(','); + ]]></getter> + <setter><![CDATA[ + let v = val.split(','); + let newButtons = v.filter(x => x && (!this._whiteListed.has(x) && + !CustomizableUI.isSpecialWidget(x) && + !this._currentSetMigrated.has(x))); + for (x of newButtons) { + this._currentSetMigrated.add(x); + this.insertItem(x); + } + ]]></setter> + </property> + <property name="toolbox" readonly="true"> + <getter><![CDATA[ + if (!this._toolbox && this.parentNode && + this.parentNode.localName == "toolbox") { + this._toolbox = this.parentNode; + } + + return this._toolbox; + ]]></getter> + </property> + <field name="_whiteListed" readonly="true">new Set(["addonbar-closebutton", "status-bar"])</field> + <field name="_isModifying">false</field> + <field name="_currentSetMigrated">new Set()</field> + </implementation> + </binding> +</bindings> diff --git a/browser/components/customizableui/moz.build b/browser/components/customizableui/moz.build new file mode 100644 index 0000000000000000000000000000000000000000..2ee6d89f028abbd17ce1440d82af15c6c90deaca --- /dev/null +++ b/browser/components/customizableui/moz.build @@ -0,0 +1,12 @@ +# -*- 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/. + +PARALLEL_DIRS += [ + 'content', + 'src', +] + +BROWSER_CHROME_MANIFESTS += ['test/browser.ini'] diff --git a/browser/components/customizableui/src/CustomizableUI.jsm b/browser/components/customizableui/src/CustomizableUI.jsm new file mode 100644 index 0000000000000000000000000000000000000000..c2cc976fd544758357264450e8b2ae4933c906a5 --- /dev/null +++ b/browser/components/customizableui/src/CustomizableUI.jsm @@ -0,0 +1,2611 @@ +/* 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"; + +this.EXPORTED_SYMBOLS = ["CustomizableUI"]; + +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "PanelWideWidgetTracker", + "resource:///modules/PanelWideWidgetTracker.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "CustomizableWidgets", + "resource:///modules/CustomizableWidgets.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask", + "resource://gre/modules/DeferredTask.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", + "resource://gre/modules/PrivateBrowsingUtils.jsm"); +XPCOMUtils.defineLazyGetter(this, "gWidgetsBundle", function() { + const kUrl = "chrome://browser/locale/customizableui/customizableWidgets.properties"; + return Services.strings.createBundle(kUrl); +}); +XPCOMUtils.defineLazyModuleGetter(this, "ShortcutUtils", + "resource://gre/modules/ShortcutUtils.jsm"); +XPCOMUtils.defineLazyServiceGetter(this, "gELS", + "@mozilla.org/eventlistenerservice;1", "nsIEventListenerService"); + +const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + +const kSpecialWidgetPfx = "customizableui-special-"; + +const kCustomizationContextMenu = "customizationContextMenu"; + + +const kPrefCustomizationState = "browser.uiCustomization.state"; +const kPrefCustomizationAutoAdd = "browser.uiCustomization.autoAdd"; +const kPrefCustomizationDebug = "browser.uiCustomization.debug"; + +/** + * The keys are the handlers that are fired when the event type (the value) + * is fired on the subview. A widget that provides a subview has the option + * of providing onViewShowing and onViewHiding event handlers. + */ +const kSubviewEvents = [ + "ViewShowing", + "ViewHiding" +]; + +/** + * gPalette is a map of every widget that CustomizableUI.jsm knows about, keyed + * on their IDs. + */ +let gPalette = new Map(); + +/** + * gAreas maps area IDs to Sets of properties about those areas. An area is a + * place where a widget can be put. + */ +let gAreas = new Map(); + +/** + * gPlacements maps area IDs to Arrays of widget IDs, indicating that the widgets + * are placed within that area (either directly in the area node, or in the + * customizationTarget of the node). + */ +let gPlacements = new Map(); + +/** + * gFuturePlacements represent placements that will happen for areas that have + * not yet loaded (due to lazy-loading). This can occur when add-ons register + * widgets. + */ +let gFuturePlacements = new Map(); + +//XXXunf Temporary. Need a nice way to abstract functions to build widgets +// of these types. +let gSupportedWidgetTypes = new Set(["button", "view", "custom"]); + +/** + * gPanelsForWindow is a list of known panels in a window which we may need to close + * should command events fire which target them. + */ +let gPanelsForWindow = new WeakMap(); + +/** + * gSeenWidgets remembers which widgets the user has seen for the first time + * before. This way, if a new widget is created, and the user has not seen it + * before, it can be put in its default location. Otherwise, it remains in the + * palette. + */ +let gSeenWidgets = new Set(); + +/** + * gDirtyAreaCache is a set of area IDs for areas where items have been added, + * moved or removed at least once. This set is persisted, and is used to + * optimize building of toolbars in the default case where no toolbars should + * be "dirty". + */ +let gDirtyAreaCache = new Set(); + +let gSavedState = null; +let gRestoring = false; +let gDirty = false; +let gInBatchStack = 0; +let gResetting = false; + +/** + * gBuildAreas maps area IDs to actual area nodes within browser windows. + */ +let gBuildAreas = new Map(); + +/** + * gBuildWindows is a map of windows that have registered build areas, mapped + * to a Set of known toolboxes in that window. + */ +let gBuildWindows = new Map(); + +let gNewElementCount = 0; +let gGroupWrapperCache = new Map(); +let gSingleWrapperCache = new WeakMap(); +let gListeners = new Set(); + +let gModuleName = "[CustomizableUI]"; +#include logging.js + +let CustomizableUIInternal = { + initialize: function() { + LOG("Initializing"); + + this.addListener(this); + this._defineBuiltInWidgets(); + this.loadSavedState(); + + let panelPlacements = [ + "edit-controls", + "zoom-controls", + "new-window-button", + "privatebrowsing-button", + "save-page-button", + "print-button", + "history-panelmenu", + "fullscreen-button", + "find-button", + "preferences-button", + "add-ons-button", + ]; + let showCharacterEncoding = Services.prefs.getComplexValue( + "browser.menu.showCharacterEncoding", + Ci.nsIPrefLocalizedString + ).data; + if (showCharacterEncoding == "true") { + panelPlacements.push("characterencoding-button"); + } + + this.registerArea(CustomizableUI.AREA_PANEL, { + anchor: "PanelUI-menu-button", + type: CustomizableUI.TYPE_MENU_PANEL, + defaultPlacements: panelPlacements + }); + PanelWideWidgetTracker.init(); + + this.registerArea(CustomizableUI.AREA_NAVBAR, { + legacy: true, + type: CustomizableUI.TYPE_TOOLBAR, + overflowable: true, + defaultPlacements: [ + "urlbar-container", + "search-container", + "webrtc-status-button", + "bookmarks-menu-button", + "downloads-button", + "home-button", + "social-share-button", + "social-toolbar-item", + ] + }); +#ifndef XP_MACOSX + this.registerArea(CustomizableUI.AREA_MENUBAR, { + legacy: true, + type: CustomizableUI.TYPE_TOOLBAR, + defaultPlacements: [ + "menubar-items", + ] + }); +#endif + this.registerArea(CustomizableUI.AREA_TABSTRIP, { + legacy: true, + type: CustomizableUI.TYPE_TOOLBAR, + defaultPlacements: [ + "tabbrowser-tabs", + "new-tab-button", + "alltabs-button", + "tabs-closebutton", + ] + }); + this.registerArea(CustomizableUI.AREA_BOOKMARKS, { + legacy: true, + type: CustomizableUI.TYPE_TOOLBAR, + defaultPlacements: [ + "personal-bookmarks", + ] + }); + + this.registerArea(CustomizableUI.AREA_ADDONBAR, { + type: CustomizableUI.TYPE_TOOLBAR, + legacy: true, + defaultPlacements: ["addonbar-closebutton", "status-bar"] + }); + }, + + _defineBuiltInWidgets: function() { + //XXXunf Need to figure out how to auto-add new builtin widgets in new + // app versions to already customized areas. + for (let widgetDefinition of CustomizableWidgets) { + this.createBuiltinWidget(widgetDefinition); + } + }, + + wrapWidget: function(aWidgetId) { + if (gGroupWrapperCache.has(aWidgetId)) { + return gGroupWrapperCache.get(aWidgetId); + } + + let provider = this.getWidgetProvider(aWidgetId); + if (!provider) { + return null; + } + + if (provider == CustomizableUI.PROVIDER_API) { + let widget = gPalette.get(aWidgetId); + if (!widget.wrapper) { + widget.wrapper = new WidgetGroupWrapper(widget); + gGroupWrapperCache.set(aWidgetId, widget.wrapper); + } + return widget.wrapper; + } + + // PROVIDER_SPECIAL gets treated the same as PROVIDER_XUL. + let wrapper = new XULWidgetGroupWrapper(aWidgetId); + gGroupWrapperCache.set(aWidgetId, wrapper); + return wrapper; + }, + + registerArea: function(aName, aProperties) { + if (typeof aName != "string" || !/^[a-z0-9-_]{1,}$/i.test(aName)) { + throw new Error("Invalid area name"); + } + if (gAreas.has(aName)) { + throw new Error("Area already registered"); + } + + let props = new Map(); + for (let key in aProperties) { + //XXXgijs for special items, we need to make sure they have an appropriate ID + // so we aren't perpetually in a non-default state: + if (key == "defaultPlacements" && Array.isArray(aProperties[key])) { + props.set(key, aProperties[key].map(x => this.isSpecialWidget(x) ? this.ensureSpecialWidgetId(x) : x )); + } else { + props.set(key, aProperties[key]); + } + } + gAreas.set(aName, props); + + if (props.get("legacy")) { + // Guarantee this area exists in gFuturePlacements, to avoid checking it in + // various places elsewhere. + gFuturePlacements.set(aName, new Set()); + } else { + this.restoreStateForArea(aName); + } + }, + + unregisterArea: function(aName) { + if (typeof aName != "string" || !/^[a-z0-9-_]{1,}$/i.test(aName)) { + throw new Error("Invalid area name"); + } + if (!gAreas.has(aName)) { + throw new Error("Area not registered"); + } + + // Move all the widgets out + this.beginBatchUpdate(); + let placements = gPlacements.get(aName); + placements.forEach(this.removeWidgetFromArea, this); + + // Delete all remaining traces. + gAreas.delete(aName); + gPlacements.delete(aName); + gFuturePlacements.delete(aName); + gBuildAreas.delete(aName); + this.endBatchUpdate(true); + }, + + registerToolbarNode: function(aToolbar, aExistingChildren) { + let area = aToolbar.id; + if (gBuildAreas.has(area) && gBuildAreas.get(area).has(aToolbar)) { + return; + } + this.beginBatchUpdate(); + let document = aToolbar.ownerDocument; + let areaProperties = gAreas.get(area); + + if (!areaProperties) { + throw new Error("Unknown customization area: " + area); + } + + let placements = gPlacements.get(area); + if (!placements && areaProperties.has("legacy")) { + let legacyState = aToolbar.getAttribute("currentset"); + if (legacyState) { + legacyState = legacyState.split(",").filter(s => s); + } + + // Manually restore the state here, so the legacy state can be converted. + this.restoreStateForArea(area, legacyState); + placements = gPlacements.get(area); + } + + // Check that the current children and the current placements match. If + // not, mark it as dirty: + if (aExistingChildren.length != placements.length || + aExistingChildren.every((id, i) => id == placements[i])) { + gDirtyAreaCache.add(area); + } + + if (areaProperties.has("overflowable")) { + aToolbar.overflowable = new OverflowableToolbar(aToolbar); + } + + this.registerBuildArea(area, aToolbar); + + // We only build the toolbar if it's been marked as "dirty". Dirty means + // one of the following things: + // 1) Items have been added, moved or removed from this toolbar before. + // 2) The number of children of the toolbar does not match the length of + // the placements array for that area. + // + // This notion of being "dirty" is stored in a cache which is persisted + // in the saved state. + if (gDirtyAreaCache.has(area)) { + this.buildArea(area, placements, aToolbar); + } + aToolbar.setAttribute("currentset", placements.join(",")); + this.endBatchUpdate(); + }, + + buildArea: function(aArea, aPlacements, aAreaNode) { + let document = aAreaNode.ownerDocument; + let window = document.defaultView; + let inPrivateWindow = PrivateBrowsingUtils.isWindowPrivate(window); + let container = aAreaNode.customizationTarget; + + if (!container) { + throw new Error("Expected area " + aArea + + " to have a customizationTarget attribute."); + } + + this.beginBatchUpdate(); + + let currentNode = container.firstChild; + let placementsToRemove = new Set(); + for (let id of aPlacements) { + while (currentNode && currentNode.getAttribute("skipintoolbarset") == "true") { + currentNode = currentNode.nextSibling; + } + + if (currentNode && currentNode.id == id) { + currentNode = currentNode.nextSibling; + continue; + } + + let [provider, node] = this.getWidgetNode(id, window); + if (!node) { + LOG("Unknown widget: " + id); + continue; + } + + // If the placements have items in them which are (now) no longer removable, + // we shouldn't be moving them: + if (node.parentNode != container && !this.isWidgetRemovable(node)) { + placementsToRemove.add(id); + continue; + } + + if (inPrivateWindow && provider == CustomizableUI.PROVIDER_API) { + let widget = gPalette.get(id); + if (!widget.showInPrivateBrowsing && inPrivateWindow) { + continue; + } + } + + this.ensureButtonContextMenu(node, aArea == CustomizableUI.AREA_PANEL); + if (node.localName == "toolbarbutton" && aArea == CustomizableUI.AREA_PANEL) { + node.setAttribute("tabindex", "0"); + if (!node.hasAttribute("type")) { + node.setAttribute("type", "wrap"); + } + } + + this.insertWidgetBefore(node, currentNode, container, aArea); + if (gResetting) { + this.notifyListeners("onWidgetReset", id, aArea); + } + } + + if (currentNode) { + let palette = aAreaNode.toolbox ? aAreaNode.toolbox.palette : null; + let limit = currentNode.previousSibling; + let node = container.lastChild; + while (node && node != limit) { + let previousSibling = node.previousSibling; + // Nodes opt-in to removability. If they're removable, and we haven't + // seen them in the placements array, then we toss them into the palette + // if one exists. If no palette exists, we just remove the node. If the + // node is not removable, we leave it where it is. However, we can only + // safely touch elements that have an ID - both because we depend on + // IDs, and because such elements are not intended to be widgets + // (eg, titlebar-placeholder elements). + if (node.id && node.getAttribute("skipintoolbarset") != "true") { + if (this.isWidgetRemovable(node)) { + if (palette && !this.isSpecialWidget(node.id)) { + palette.appendChild(node); + this.removeLocationAttributes(node); + } else { + container.removeChild(node); + } + } else { + this.setLocationAttributes(currentNode, aArea); + node.setAttribute("removable", false); + LOG("Adding non-removable widget to placements of " + aArea + ": " + + node.id); + gPlacements.get(aArea).push(node.id); + gDirty = true; + } + } + node = previousSibling; + } + } + + // If there are placements in here which aren't removable from their original area, + // we remove them from this area's placement array. They will (have) be(en) added + // to their original area's placements array in the block above this one. + if (placementsToRemove.size) { + let placementAry = gPlacements.get(aArea); + for (let id of placementsToRemove) { + let index = placementAry.indexOf(id); + placementAry.splice(index, 1); + } + } + + if (gResetting) { + this.notifyListeners("onAreaReset", aArea); + } + + this.endBatchUpdate(); + }, + + addPanelCloseListeners: function(aPanel) { + gELS.addSystemEventListener(aPanel, "click", this, false); + gELS.addSystemEventListener(aPanel, "keypress", this, false); + let win = aPanel.ownerDocument.defaultView; + if (!gPanelsForWindow.has(win)) { + gPanelsForWindow.set(win, new Set()); + } + gPanelsForWindow.get(win).add(this._getPanelForNode(aPanel)); + }, + + removePanelCloseListeners: function(aPanel) { + gELS.removeSystemEventListener(aPanel, "click", this, false); + gELS.removeSystemEventListener(aPanel, "keypress", this, false); + let win = aPanel.ownerDocument.defaultView; + let panels = gPanelsForWindow.get(win); + if (panels) { + panels.delete(this._getPanelForNode(aPanel)); + } + }, + + ensureButtonContextMenu: function(aNode, aShouldHaveCustomizationMenu) { + let currentContextMenu = aNode.getAttribute("context") || + aNode.getAttribute("contextmenu"); + if (aShouldHaveCustomizationMenu) { + if (!currentContextMenu) + aNode.setAttribute("context", kCustomizationContextMenu); + } else { + if (currentContextMenu == kCustomizationContextMenu) + aNode.removeAttribute("context"); + } + }, + + getWidgetProvider: function(aWidgetId) { + if (this.isSpecialWidget(aWidgetId)) { + return CustomizableUI.PROVIDER_SPECIAL; + } + if (gPalette.has(aWidgetId)) { + return CustomizableUI.PROVIDER_API; + } + // If this was an API widget that was destroyed, return null: + if (gSeenWidgets.has(aWidgetId)) { + return null; + } + + // We fall back to the XUL provider, but we don't know for sure (at this + // point) whether it exists there either. So the API is technically lying. + // Ideally, it would be able to return an error value (or throw an + // exception) if it really didn't exist. Our code calling this function + // handles that fine, but this is a public API. + return CustomizableUI.PROVIDER_XUL; + }, + + getWidgetNode: function(aWidgetId, aWindow) { + let document = aWindow.document; + + if (this.isSpecialWidget(aWidgetId)) { + let widgetNode = document.getElementById(aWidgetId) || + this.createSpecialWidget(aWidgetId, document); + return [ CustomizableUI.PROVIDER_SPECIAL, widgetNode]; + } + + let widget = gPalette.get(aWidgetId); + if (widget) { + // If we have an instance of this widget already, just use that. + if (widget.instances.has(document)) { + LOG("An instance of widget " + aWidgetId + " already exists in this " + + "document. Reusing."); + return [ CustomizableUI.PROVIDER_API, + widget.instances.get(document) ]; + } + + return [ CustomizableUI.PROVIDER_API, + this.buildWidget(document, widget) ]; + } + + LOG("Searching for " + aWidgetId + " in toolbox."); + let node = this.findWidgetInWindow(aWidgetId, aWindow); + if (node) { + return [ CustomizableUI.PROVIDER_XUL, node ]; + } + + LOG("No node for " + aWidgetId + " found."); + return []; + }, + + registerMenuPanel: function(aPanel) { + if (gBuildAreas.has(CustomizableUI.AREA_PANEL) && + gBuildAreas.get(CustomizableUI.AREA_PANEL).has(aPanel)) { + return; + } + + let document = aPanel.ownerDocument; + + for (let btn of aPanel.querySelectorAll("toolbarbutton")) { + btn.setAttribute("tabindex", "0"); + this.ensureButtonContextMenu(btn, true); + if (!btn.hasAttribute("type")) { + btn.setAttribute("type", "wrap"); + } + } + + aPanel.toolbox = document.getElementById("navigator-toolbox"); + aPanel.customizationTarget = aPanel; + + this.addPanelCloseListeners(aPanel); + + let placements = gPlacements.get(CustomizableUI.AREA_PANEL); + this.buildArea(CustomizableUI.AREA_PANEL, placements, aPanel); + this.registerBuildArea(CustomizableUI.AREA_PANEL, aPanel); + }, + + onWidgetAdded: function(aWidgetId, aArea, aPosition) { + this.insertNode(aWidgetId, aArea, aPosition, true); + }, + + onWidgetRemoved: function(aWidgetId, aArea) { + let areaNodes = gBuildAreas.get(aArea); + if (!areaNodes) { + return; + } + + let area = gAreas.get(aArea); + let showInPrivateBrowsing = gPalette.has(aWidgetId) + ? gPalette.get(aWidgetId).showInPrivateBrowsing + : true; + + for (let areaNode of areaNodes) { + let window = areaNode.ownerDocument.defaultView; + if (!showInPrivateBrowsing && + PrivateBrowsingUtils.isWindowPrivate(window)) { + continue; + } + + let container = areaNode.customizationTarget; + let widgetNode = container.ownerDocument.getElementById(aWidgetId); + if (!widgetNode) { + ERROR("Widget not found, unable to remove"); + continue; + } + + this.notifyListeners("onWidgetBeforeDOMChange", widgetNode, null, container, true); + + // We remove location attributes here to make sure they're gone too when a + // widget is removed from a toolbar to the palette. See bug 930950. + this.removeLocationAttributes(widgetNode); + if (gPalette.has(aWidgetId) || this.isSpecialWidget(aWidgetId)) { + container.removeChild(widgetNode); + } else { + widgetNode.removeAttribute("tabindex"); + if (widgetNode.getAttribute("type") == "wrap") { + widgetNode.removeAttribute("type"); + } + areaNode.toolbox.palette.appendChild(widgetNode); + } + this.notifyListeners("onWidgetAfterDOMChange", widgetNode, null, container, true); + + if (area.get("type") == CustomizableUI.TYPE_TOOLBAR) { + areaNode.setAttribute("currentset", areaNode.currentSet); + } + + let windowCache = gSingleWrapperCache.get(window); + if (windowCache) { + windowCache.delete(aWidgetId); + } + } + }, + + onWidgetMoved: function(aWidgetId, aArea, aOldPosition, aNewPosition) { + this.insertNode(aWidgetId, aArea, aNewPosition); + }, + + registerBuildArea: function(aArea, aNode) { + // We ensure that the window is registered to have its customization data + // cleaned up when unloading. + let window = aNode.ownerDocument.defaultView; + if (window.closed) { + return; + } + this.registerBuildWindow(window); + + // Also register this build area's toolbox. + if (aNode.toolbox) { + gBuildWindows.get(window).add(aNode.toolbox); + } + + if (!gBuildAreas.has(aArea)) { + gBuildAreas.set(aArea, new Set()); + } + + gBuildAreas.get(aArea).add(aNode); + }, + + registerBuildWindow: function(aWindow) { + if (!gBuildWindows.has(aWindow)) { + gBuildWindows.set(aWindow, new Set()); + + aWindow.addEventListener("unload", this); + aWindow.addEventListener("command", this, true); + } + }, + + unregisterBuildWindow: function(aWindow) { + aWindow.removeEventListener("unload", this); + aWindow.removeEventListener("command", this, true); + gPanelsForWindow.delete(aWindow); + gBuildWindows.delete(aWindow); + gSingleWrapperCache.delete(aWindow); + let document = aWindow.document; + + for (let [areaId, areaNodes] of gBuildAreas) { + let areaProperties = gAreas.get(areaId); + for (let node of areaNodes) { + if (node.ownerDocument == document) { + if (areaProperties.has("overflowable")) { + node.overflowable.uninit(); + node.overflowable = null; + } + areaNodes.delete(node); + } + } + } + + for (let [,widget] of gPalette) { + widget.instances.delete(document); + this.notifyListeners("onWidgetInstanceRemoved", widget.id, document); + } + }, + + setLocationAttributes: function(aNode, aArea) { + let props = gAreas.get(aArea); + if (!props) { + throw new Error("Expected area " + aArea + " to have a properties Map " + + "associated with it."); + } + + aNode.setAttribute("cui-areatype", props.get("type") || ""); + let anchor = props.get("anchor"); + if (anchor) { + aNode.setAttribute("cui-anchorid", anchor); + } + }, + + removeLocationAttributes: function(aNode) { + aNode.removeAttribute("cui-areatype"); + aNode.removeAttribute("cui-anchorid"); + }, + + insertNode: function(aWidgetId, aArea, aPosition, isNew) { + let areaNodes = gBuildAreas.get(aArea); + if (!areaNodes) { + return; + } + + let placements = gPlacements.get(aArea); + if (!placements) { + ERROR("Could not find any placements for " + aArea + + " when moving a widget."); + return; + } + + let nextNodeId = placements[aPosition + 1]; + // Go through each of the nodes associated with this area and move the + // widget to the requested location. + for (let areaNode of areaNodes) { + this.insertNodeInWindow(aWidgetId, areaNode, nextNodeId, isNew); + } + }, + + insertNodeInWindow: function(aWidgetId, aAreaNode, aNextNodeId, isNew) { + let window = aAreaNode.ownerDocument.defaultView; + let showInPrivateBrowsing = gPalette.has(aWidgetId) + ? gPalette.get(aWidgetId).showInPrivateBrowsing + : true; + + if (!showInPrivateBrowsing && PrivateBrowsingUtils.isWindowPrivate(window)) { + return; + } + + let [, widgetNode] = this.getWidgetNode(aWidgetId, window); + if (!widgetNode) { + ERROR("Widget '" + aWidgetId + "' not found, unable to move"); + return; + } + + let areaId = aAreaNode.id; + if (isNew) { + this.ensureButtonContextMenu(widgetNode, areaId == CustomizableUI.AREA_PANEL); + if (widgetNode.localName == "toolbarbutton" && areaId == CustomizableUI.AREA_PANEL) { + widgetNode.setAttribute("tabindex", "0"); + if (!widgetNode.hasAttribute("type")) { + widgetNode.setAttribute("type", "wrap"); + } + } + } + + let container = aAreaNode.customizationTarget; + let [insertionContainer, nextNode] = this.findInsertionPoints(widgetNode, aNextNodeId, aAreaNode); + this.insertWidgetBefore(widgetNode, nextNode, insertionContainer, areaId); + + if (gAreas.get(areaId).get("type") == CustomizableUI.TYPE_TOOLBAR) { + aAreaNode.setAttribute("currentset", aAreaNode.currentSet); + } + }, + + findInsertionPoints: function(aNode, aNextNodeId, aAreaNode) { + let props = gAreas.get(aAreaNode.id); + if (props.get("type") == CustomizableUI.TYPE_TOOLBAR && props.get("overflowable") && + aAreaNode.getAttribute("overflowing") == "true") { + return aAreaNode.overflowable.getOverflowedInsertionPoints(aNode, aNextNodeId); + } + let nextNode = null; + if (aNextNodeId) { + nextNode = aAreaNode.customizationTarget.querySelector(idToSelector(aNextNodeId)); + } + return [aAreaNode.customizationTarget, nextNode]; + }, + + insertWidgetBefore: function(aNode, aNextNode, aContainer, aArea) { + this.notifyListeners("onWidgetBeforeDOMChange", aNode, aNextNode, aContainer); + this.setLocationAttributes(aNode, aArea); + aContainer.insertBefore(aNode, aNextNode); + this.notifyListeners("onWidgetAfterDOMChange", aNode, aNextNode, aContainer); + }, + + handleEvent: function(aEvent) { + switch (aEvent.type) { + case "command": + if (!this._originalEventInPanel(aEvent)) { + break; + } + aEvent = aEvent.sourceEvent; + // Fall through + case "click": + case "keypress": + this.maybeAutoHidePanel(aEvent); + break; + case "unload": + this.unregisterBuildWindow(aEvent.currentTarget); + break; + } + }, + + _originalEventInPanel: function(aEvent) { + let e = aEvent.sourceEvent; + if (!e) { + return false; + } + let node = this._getPanelForNode(e.target); + if (!node) { + return false; + } + let win = e.view; + let panels = gPanelsForWindow.get(win); + return !!panels && panels.has(node); + }, + + isSpecialWidget: function(aId) { + return (aId.startsWith(kSpecialWidgetPfx) || + aId.startsWith("separator") || + aId.startsWith("spring") || + aId.startsWith("spacer")); + }, + + ensureSpecialWidgetId: function(aId) { + let nodeType = aId.match(/spring|spacer|separator/)[0]; + // If the ID we were passed isn't a generated one, generate one now: + if (nodeType == aId) { + // Ids are differentiated through a unique count suffix. + return kSpecialWidgetPfx + aId + (++gNewElementCount); + } + return aId; + }, + + createSpecialWidget: function(aId, aDocument) { + let nodeName = "toolbar" + aId.match(/spring|spacer|separator/)[0]; + let node = aDocument.createElementNS(kNSXUL, nodeName); + node.id = this.ensureSpecialWidgetId(aId); + if (nodeName == "toolbarspring") { + node.flex = 1; + } + return node; + }, + + /* Find a XUL-provided widget in a window. Don't try to use this + * for an API-provided widget or a special widget. + */ + findWidgetInWindow: function(aId, aWindow) { + if (!gBuildWindows.has(aWindow)) { + throw new Error("Build window not registered"); + } + + if (!aId) { + ERROR("findWidgetInWindow was passed an empty string."); + return null; + } + + let document = aWindow.document; + + // look for a node with the same id, as the node may be + // in a different toolbar. + let node = document.getElementById(aId); + if (node) { + let parent = node.parentNode; + while (parent && !(parent.customizationTarget || + parent.localName == "toolbarpaletteitem")) { + parent = parent.parentNode; + } + + if (parent && ((parent.customizationTarget == node.parentNode && + gBuildWindows.get(aWindow).has(parent.toolbox)) || + parent.localName == "toolbarpaletteitem")) { + // Normalize the removable attribute. For backwards compat, if + // the widget is not defined in a toolbox palette then absence + // of the "removable" attribute means it is not removable. + if (!node.hasAttribute("removable")) { + parent = parent.localName == "toolbarpaletteitem" ? parent.parentNode : parent; + // If we first see this in customization mode, it may be in the + // customization palette instead of the toolbox palette. + node.setAttribute("removable", !parent.customizationTarget); + } + + return node; + } + } + + let toolboxes = gBuildWindows.get(aWindow); + for (let toolbox of toolboxes) { + if (toolbox.palette) { + // Attempt to locate a node with a matching ID within + // the palette. + let node = toolbox.palette.querySelector(idToSelector(aId)); + if (node) { + // Normalize the removable attribute. For backwards compat, this + // is optional if the widget is defined in the toolbox palette, + // and defaults to *true*, unlike if it was defined elsewhere. + if (!node.hasAttribute("removable")) { + node.setAttribute("removable", true); + } + return node; + } + } + } + return null; + }, + + buildWidget: function(aDocument, aWidget) { + if (typeof aWidget == "string") { + aWidget = gPalette.get(aWidget); + } + if (!aWidget) { + throw new Error("buildWidget was passed a non-widget to build."); + } + + LOG("Building " + aWidget.id + " of type " + aWidget.type); + + let node; + if (aWidget.type == "custom") { + if (aWidget.onBuild) { + try { + node = aWidget.onBuild(aDocument); + } catch (ex) { + ERROR("Custom widget with id " + aWidget.id + " threw an error: " + ex.message); + } + } + if (!node || !(node instanceof aDocument.defaultView.XULElement)) + ERROR("Custom widget with id " + aWidget.id + " does not return a valid node"); + } + else { + node = aDocument.createElementNS(kNSXUL, "toolbarbutton"); + + node.setAttribute("id", aWidget.id); + node.setAttribute("widget-id", aWidget.id); + node.setAttribute("widget-type", aWidget.type); + if (aWidget.disabled) { + node.setAttribute("disabled", true); + } + node.setAttribute("removable", aWidget.removable); + node.setAttribute("overflows", aWidget.overflows); + node.setAttribute("label", this.getLocalizedProperty(aWidget, "label")); + let additionalTooltipArguments = []; + if (aWidget.shortcutId) { + let keyEl = aDocument.getElementById(aWidget.shortcutId); + if (keyEl) { + additionalTooltipArguments.push(ShortcutUtils.prettifyShortcut(keyEl)); + } else { + ERROR("Key element with id '" + aWidget.shortcutId + "' for widget '" + aWidget.id + + "' not found!"); + } + } + let tooltip = this.getLocalizedProperty(aWidget, "tooltiptext", additionalTooltipArguments); + node.setAttribute("tooltiptext", tooltip); + node.setAttribute("class", "toolbarbutton-1 chromeclass-toolbar-additional"); + + let commandHandler = this.handleWidgetCommand.bind(this, aWidget, node); + node.addEventListener("command", commandHandler, false); + let clickHandler = this.handleWidgetClick.bind(this, aWidget, node); + node.addEventListener("click", clickHandler, false); + + // If the widget has a view, and has view showing / hiding listeners, + // hook those up to this widget. + if (aWidget.type == "view" && + (aWidget.onViewShowing || aWidget.onViewHiding)) { + LOG("Widget " + aWidget.id + " has a view with showing and hiding events. Auto-registering event handlers."); + let viewNode = aDocument.getElementById(aWidget.viewId); + + if (viewNode) { + // PanelUI relies on the .PanelUI-subView class to be able to show only + // one sub-view at a time. + viewNode.classList.add("PanelUI-subView"); + + for (let eventName of kSubviewEvents) { + let handler = "on" + eventName; + if (typeof aWidget[handler] == "function") { + viewNode.addEventListener(eventName, aWidget[handler], false); + } + } + + LOG("Widget " + aWidget.id + " showing and hiding event handlers set."); + } else { + ERROR("Could not find the view node with id: " + aWidget.viewId + + ", for widget: " + aWidget.id + "."); + } + } + + if (aWidget.onCreated) { + aWidget.onCreated(node); + } + } + + aWidget.instances.set(aDocument, node); + return node; + }, + + getLocalizedProperty: function(aWidget, aProp, aFormatArgs, aDef) { + if (typeof aWidget == "string") { + aWidget = gPalette.get(aWidget); + } + if (!aWidget) { + throw new Error("getLocalizedProperty was passed a non-widget to work with."); + } + let def, name; + // Let widgets pass their own string identifiers or strings, so that + // we can use strings which aren't the default (in case string ids change) + // and so that non-builtin-widgets can also provide labels, tooltips, etc. + if (aWidget[aProp]) { + name = aWidget[aProp]; + // By using this as the default, if a widget provides a full string rather + // than a string ID for localization, we will fall back to that string + // and return that. + def = aDef || name; + } else { + name = aWidget.id + "." + aProp; + def = aDef || ""; + } + try { + if (Array.isArray(aFormatArgs) && aFormatArgs.length) { + return gWidgetsBundle.formatStringFromName(name, aFormatArgs, + aFormatArgs.length) || def; + } + return gWidgetsBundle.GetStringFromName(name) || def; + } catch(ex) { + if (!def) { + ERROR("Could not localize property '" + name + "'."); + } + } + return def; + }, + + handleWidgetCommand: function(aWidget, aNode, aEvent) { + LOG("handleWidgetCommand"); + + if (aWidget.type == "button") { + this.maybeAutoHidePanel(aEvent); + + if (aWidget.onCommand) { + try { + aWidget.onCommand.call(null, aEvent); + } catch (e) { + ERROR(e); + } + } else { + //XXXunf Need to think this through more, and formalize. + Services.obs.notifyObservers(aNode, + "customizedui-widget-command", + aWidget.id); + } + } else if (aWidget.type == "view") { + let ownerWindow = aNode.ownerDocument.defaultView; + ownerWindow.PanelUI.showSubView(aWidget.viewId, aNode, + this.getPlacementOfWidget(aNode.id).area); + } + }, + + handleWidgetClick: function(aWidget, aNode, aEvent) { + LOG("handleWidgetClick"); + if (aWidget.type == "button") { + this.maybeAutoHidePanel(aEvent); + } + + if (aWidget.onClick) { + try { + aWidget.onClick.call(null, aEvent); + } catch(e) { + Cu.reportError(e); + } + } else { + //XXXunf Need to think this through more, and formalize. + Services.obs.notifyObservers(aNode, "customizedui-widget-click", aWidget.id); + } + }, + + _getPanelForNode: function(aNode) { + let panel = aNode; + while (panel && panel.localName != "panel") + panel = panel.parentNode; + return panel; + }, + + /* + * If people put things in the panel which need more than single-click interaction, + * we don't want to close it. Right now we check for text inputs and menu buttons. + * Anything else we should take care of? + */ + _isOnInteractiveElement: function(aEvent) { + let target = aEvent.originalTarget; + let panel = aEvent.currentTarget; + let inInput = false; + let inMenu = false; + while (!inInput && !inMenu && target != aEvent.currentTarget) { + inInput = target.localName == "input"; + inMenu = target.type == "menu"; + target = target.parentNode; + } + return inMenu || inInput; + }, + + hidePanelForNode: function(aNode) { + let panel = this._getPanelForNode(aNode); + if (panel) { + panel.hidePopup(); + } + }, + + maybeAutoHidePanel: function(aEvent) { + if (aEvent.type == "keypress") { + if (aEvent.keyCode != aEvent.DOM_VK_ENTER && + aEvent.keyCode != aEvent.DOM_VK_RETURN) { + return; + } + // If the user hit enter/return, we don't check preventDefault - it makes sense + // that this was prevented, but we probably still want to close the panel. + // If consumers don't want this to happen, they should specify noautoclose. + + } else if (aEvent.type != "command") { // mouse events: + if (aEvent.defaultPrevented || aEvent.button != 0) { + return; + } + let isInteractive = this._isOnInteractiveElement(aEvent); + LOG("maybeAutoHidePanel: interactive ? " + isInteractive); + if (isInteractive) { + return; + } + } + + if (aEvent.target.getAttribute("noautoclose") == "true" || + aEvent.target.getAttribute("widget-type") == "view") { + return; + } + + // If we get here, we can actually hide the popup: + this.hidePanelForNode(aEvent.target); + }, + + getUnusedWidgets: function(aWindowPalette) { + // We use a Set because there can be overlap between the widgets in + // gPalette and the items in the palette, especially after the first + // customization, since programmatically generated widgets will remain + // in the toolbox palette. + let widgets = new Set(); + + // It's possible that some widgets have been defined programmatically and + // have not been overlayed into the palette. We can find those inside + // gPalette. + for (let [id, widget] of gPalette) { + if (!widget.currentArea) { + widgets.add(id); + } + } + + LOG("Iterating the actual nodes of the window palette"); + for (let node of aWindowPalette.children) { + LOG("In palette children: " + node.id); + if (node.id && !this.getPlacementOfWidget(node.id)) { + widgets.add(node.id); + } + } + + return [...widgets]; + }, + + getPlacementOfWidget: function(aWidgetId, aOnlyRegistered) { + if (aOnlyRegistered && !this.widgetExists(aWidgetId)) { + return null; + } + + for (let [area, placements] of gPlacements) { + let index = placements.indexOf(aWidgetId); + if (index != -1) { + return { area: area, position: index }; + } + } + + return null; + }, + + widgetExists: function(aWidgetId) { + if (gPalette.has(aWidgetId) || this.isSpecialWidget(aWidgetId)) { + return true; + } + + // Destroyed API widgets are in gSeenWidgets, but not in gPalette: + if (gSeenWidgets.has(aWidgetId)) { + return false; + } + + // We're assuming XUL widgets always exist, as it's much harder to check, + // and checking would be much more error prone. + return true; + }, + + addWidgetToArea: function(aWidgetId, aArea, aPosition, aInitialAdd) { + if (!gAreas.has(aArea)) { + throw new Error("Unknown customization area: " + aArea); + } + + // If this is a lazy area that hasn't been restored yet, we can't yet modify + // it - would would at least like to add to it. So we keep track of it in + // gFuturePlacements, and use that to add it when restoring the area. We + // throw away aPosition though, as that can only be bogus if the area hasn't + // yet been restorted (caller can't possibly know where its putting the + // widget in relation to other widgets). + if (this.isAreaLazy(aArea)) { + gFuturePlacements.get(aArea).add(aWidgetId); + return; + } + + if (this.isSpecialWidget(aWidgetId)) { + aWidgetId = this.ensureSpecialWidgetId(aWidgetId); + } + + let oldPlacement = this.getPlacementOfWidget(aWidgetId); + if (oldPlacement && oldPlacement.area == aArea) { + this.moveWidgetWithinArea(aWidgetId, aPosition); + return; + } + + // Do nothing if the widget is not allowed to move to the target area. + if (!this.canWidgetMoveToArea(aWidgetId, aArea)) { + return; + } + + if (oldPlacement) { + this.removeWidgetFromArea(aWidgetId); + } + + if (!gPlacements.has(aArea)) { + gPlacements.set(aArea, [aWidgetId]); + aPosition = 0; + } else { + let placements = gPlacements.get(aArea); + if (typeof aPosition != "number") { + aPosition = placements.length; + } + if (aPosition < 0) { + aPosition = 0; + } + placements.splice(aPosition, 0, aWidgetId); + } + + let widget = gPalette.get(aWidgetId); + if (widget) { + widget.currentArea = aArea; + widget.currentPosition = aPosition; + } + + // We initially set placements with addWidgetToArea, so in that case + // we don't consider the area "dirtied". + if (!aInitialAdd) { + gDirtyAreaCache.add(aArea); + } + + gDirty = true; + this.saveState(); + + this.notifyListeners("onWidgetAdded", aWidgetId, aArea, aPosition); + }, + + removeWidgetFromArea: function(aWidgetId) { + let oldPlacement = this.getPlacementOfWidget(aWidgetId); + if (!oldPlacement) { + return; + } + + if (!this.isWidgetRemovable(aWidgetId)) { + return; + } + + let placements = gPlacements.get(oldPlacement.area); + let position = placements.indexOf(aWidgetId); + if (position != -1) { + placements.splice(position, 1); + } + + let widget = gPalette.get(aWidgetId); + if (widget) { + widget.currentArea = null; + widget.currentPosition = null; + } + + gDirty = true; + this.saveState(); + gDirtyAreaCache.add(oldPlacement.area); + + this.notifyListeners("onWidgetRemoved", aWidgetId, oldPlacement.area); + }, + + moveWidgetWithinArea: function(aWidgetId, aPosition) { + let oldPlacement = this.getPlacementOfWidget(aWidgetId); + if (!oldPlacement) { + return; + } + + let placements = gPlacements.get(oldPlacement.area); + if (typeof aPosition != "number") { + aPosition = placements.length; + } else if (aPosition < 0) { + aPosition = 0; + } else if (aPosition > placements.length) { + aPosition = placements.length; + } + + if (aPosition == oldPlacement.position) { + return; + } + + placements.splice(oldPlacement.position, 1); + // If we just removed the item from *before* where it is now added, + // we need to compensate the position offset for that: + if (oldPlacement.position < aPosition) { + aPosition--; + } + placements.splice(aPosition, 0, aWidgetId); + + let widget = gPalette.get(aWidgetId); + if (widget) { + widget.currentPosition = aPosition; + } + + gDirty = true; + gDirtyAreaCache.add(oldPlacement.area); + + this.saveState(); + + this.notifyListeners("onWidgetMoved", aWidgetId, oldPlacement.area, + oldPlacement.position, aPosition); + }, + + // Note that this does not populate gPlacements, which is done lazily so that + // the legacy state can be migrated, which is only available once a browser + // window is openned. + // The panel area is an exception here, since it has no legacy state and is + // built lazily - and therefore wouldn't otherwise result in restoring its + // state immediately when a browser window opens, which is important for + // other consumers of this API. + loadSavedState: function() { + let state = null; + try { + state = Services.prefs.getCharPref(kPrefCustomizationState); + } catch (e) { + LOG("No saved state found"); + // This will fail if nothing has been customized, so silently fall back to + // the defaults. + } + + if (!state) { + return; + } + try { + gSavedState = JSON.parse(state); + } catch(e) { + LOG("Error loading saved UI customization state, falling back to defaults."); + } + + if (!("placements" in gSavedState)) { + gSavedState.placements = {}; + } + + gSeenWidgets = new Set(gSavedState.seen || []); + gDirtyAreaCache = new Set(gSavedState.dirtyAreaCache || []); + gNewElementCount = gSavedState.newElementCount || 0; + }, + + restoreStateForArea: function(aArea, aLegacyState) { + if (gPlacements.has(aArea)) { + // Already restored. + return; + } + + this.beginBatchUpdate(); + gRestoring = true; + + let restored = false; + gPlacements.set(aArea, []); + + if (gSavedState && aArea in gSavedState.placements) { + LOG("Restoring " + aArea + " from saved state"); + let placements = gSavedState.placements[aArea]; + for (let id of placements) + this.addWidgetToArea(id, aArea); + gDirty = false; + restored = true; + } + + if (!restored && aLegacyState) { + LOG("Restoring " + aArea + " from legacy state"); + for (let id of aLegacyState) + this.addWidgetToArea(id, aArea); + // Don't override dirty state, to ensure legacy state is saved here and + // therefore only used once. + restored = true; + } + + if (!restored) { + LOG("Restoring " + aArea + " from default state"); + let defaults = gAreas.get(aArea).get("defaultPlacements"); + if (defaults) { + for (let id of defaults) + this.addWidgetToArea(id, aArea, null, true); + } + gDirty = false; + } + + // Finally, add widgets to the area that were added before the it was able + // to be restored. This can occur when add-ons register widgets for a + // lazily-restored area before it's been restored. + if (gFuturePlacements.has(aArea)) { + for (let id of gFuturePlacements.get(aArea)) + this.addWidgetToArea(id, aArea); + } + + LOG("Placements for " + aArea + ":\n\t" + gPlacements.get(aArea).join("\n\t")); + + gRestoring = false; + this.endBatchUpdate(); + }, + + saveState: function() { + if (gInBatchStack || !gDirty) { + return; + } + let state = { placements: gPlacements, + seen: gSeenWidgets, + dirtyAreaCache: gDirtyAreaCache, + newElementCount: gNewElementCount }; + + LOG("Saving state."); + let serialized = JSON.stringify(state, this.serializerHelper); + LOG("State saved as: " + serialized); + Services.prefs.setCharPref(kPrefCustomizationState, serialized); + gDirty = false; + }, + + serializerHelper: function(aKey, aValue) { + if (typeof aValue == "object" && aValue.constructor.name == "Map") { + let result = {}; + for (let [mapKey, mapValue] of aValue) + result[mapKey] = mapValue; + return result; + } + + if (typeof aValue == "object" && aValue.constructor.name == "Set") { + return [...aValue]; + } + + return aValue; + }, + + beginBatchUpdate: function() { + gInBatchStack++; + }, + + endBatchUpdate: function(aForceDirty) { + gInBatchStack--; + if (aForceDirty === true) { + gDirty = true; + } + if (gInBatchStack == 0) { + this.saveState(); + } else if (gInBatchStack < 0) { + throw new Error("The batch editing stack should never reach a negative number."); + } + }, + + addListener: function(aListener) { + gListeners.add(aListener); + }, + + removeListener: function(aListener) { + if (aListener == this) { + return; + } + + gListeners.delete(aListener); + }, + + notifyListeners: function(aEvent, ...aArgs) { + if (gRestoring) { + return; + } + + for (let listener of gListeners) { + try { + if (typeof listener[aEvent] == "function") { + listener[aEvent].apply(listener, aArgs); + } + } catch (e) { + ERROR(e + " -- " + e.fileName + ":" + e.lineNumber); + } + } + }, + + createWidget: function(aProperties) { + let widget = this.normalizeWidget(aProperties, CustomizableUI.SOURCE_EXTERNAL); + //XXXunf This should probably throw. + if (!widget) { + return; + } + + gPalette.set(widget.id, widget); + this.notifyListeners("onWidgetCreated", widget.id); + + if (widget.defaultArea) { + let area = gAreas.get(widget.defaultArea); + //XXXgijs this won't have any effect for legacy items. Sort of OK because + // consumers can modify currentset? Maybe? + if (area.has("defaultPlacements")) { + area.get("defaultPlacements").push(widget.id); + } else { + area.set("defaultPlacements", [widget.id]); + } + } + + // Look through previously saved state to see if we're restoring a widget. + let seenAreas = new Set(); + for (let [area, placements] of gPlacements) { + seenAreas.add(area); + let index = gPlacements.get(area).indexOf(widget.id); + if (index != -1) { + widget.currentArea = area; + widget.currentPosition = index; + break; + } + } + + // Also look at saved state data directly in areas that haven't yet been + // restored. Can't rely on this for restored areas, as they may have + // changed. + if (!widget.currentArea && gSavedState) { + for (let area of Object.keys(gSavedState.placements)) { + if (seenAreas.has(area)) { + continue; + } + + let index = gSavedState.placements[area].indexOf(widget.id); + if (index != -1) { + widget.currentArea = area; + widget.currentPosition = index; + break; + } + } + } + + // If we're restoring the widget to it's old placement, fire off the + // onWidgetAdded event - our own handler will take care of adding it to + // any build areas. + if (widget.currentArea) { + this.notifyListeners("onWidgetAdded", widget.id, widget.currentArea, + widget.currentPosition); + } else { + let autoAdd = true; + try { + autoAdd = Services.prefs.getBoolPref(kPrefCustomizationAutoAdd); + } catch (e) {} + + // If the widget doesn't have an existing placement, and it hasn't been + // seen before, then add it to its default area so it can be used. + if (autoAdd && !widget.currentArea && !gSeenWidgets.has(widget.id)) { + this.beginBatchUpdate(); + gSeenWidgets.add(widget.id); + + if (widget.defaultArea) { + if (this.isAreaLazy(widget.defaultArea)) { + gFuturePlacements.get(widget.defaultArea).add(widget.id); + } else { + this.addWidgetToArea(widget.id, widget.defaultArea); + } + } + + this.endBatchUpdate(true); + } + } + + this.notifyListeners("onWidgetAfterCreation", widget.id, widget.currentArea); + return widget.id; + }, + + createBuiltinWidget: function(aData) { + // This should only ever be called on startup, before any windows are + // opened - so we know there's no build areas to handle. Also, builtin + // widgets are expected to be (mostly) static, so shouldn't affect the + // current placement settings. + let widget = this.normalizeWidget(aData, CustomizableUI.SOURCE_BUILTIN); + if (!widget) { + ERROR("Error creating builtin widget: " + aData.id); + return; + } + + LOG("Creating built-in widget with id: " + widget.id); + gPalette.set(widget.id, widget); + }, + + // Returns true if the area will eventually lazily restore (but hasn't yet). + isAreaLazy: function(aArea) { + if (gPlacements.has(aArea)) { + return false; + } + return gAreas.get(aArea).has("legacy"); + }, + + //XXXunf Log some warnings here, when the data provided isn't up to scratch. + normalizeWidget: function(aData, aSource) { + let widget = { + implementation: aData, + source: aSource || "addon", + instances: new Map(), + currentArea: null, + removable: false, + overflows: true, + defaultArea: null, + shortcutId: null, + tooltiptext: null, + showInPrivateBrowsing: true, + }; + + if (typeof aData.id != "string" || !/^[a-z0-9-_]{1,}$/i.test(aData.id)) { + ERROR("Given an illegal id in normalizeWidget: " + aData.id); + return null; + } + + delete widget.implementation.currentArea; + widget.implementation.__defineGetter__("currentArea", function() widget.currentArea); + + const kReqStringProps = ["id"]; + for (let prop of kReqStringProps) { + if (typeof aData[prop] != "string") { + ERROR("Missing required property '" + prop + "' in normalizeWidget: " + + aData.id); + return null; + } + widget[prop] = aData[prop]; + } + + const kOptStringProps = ["label", "tooltiptext", "shortcutId"]; + for (let prop of kOptStringProps) { + if (typeof aData[prop] == "string") { + widget[prop] = aData[prop]; + } + } + + const kOptBoolProps = ["removable", "showInPrivateBrowsing", "overflows"]; + for (let prop of kOptBoolProps) { + if (typeof aData[prop] == "boolean") { + widget[prop] = aData[prop]; + } + } + + if (aData.defaultArea && gAreas.has(aData.defaultArea)) { + widget.defaultArea = aData.defaultArea; + } + + if ("type" in aData && gSupportedWidgetTypes.has(aData.type)) { + widget.type = aData.type; + } else { + widget.type = "button"; + } + + widget.disabled = aData.disabled === true; + + this.wrapWidgetEventHandler("onClick", widget); + this.wrapWidgetEventHandler("onCreated", widget); + + if (widget.type == "button") { + widget.onCommand = typeof aData.onCommand == "function" ? + aData.onCommand : + null; + } else if (widget.type == "view") { + if (typeof aData.viewId != "string") { + ERROR("Expected a string for widget " + widget.id + " viewId, but got " + + aData.viewId); + return null; + } + widget.viewId = aData.viewId; + + this.wrapWidgetEventHandler("onViewShowing", widget); + this.wrapWidgetEventHandler("onViewHiding", widget); + } else if (widget.type == "custom") { + this.wrapWidgetEventHandler("onBuild", widget); + } + + if (gPalette.has(widget.id)) { + return null; + } + + return widget; + }, + + wrapWidgetEventHandler: function(aEventName, aWidget) { + if (typeof aWidget.implementation[aEventName] != "function") { + aWidget[aEventName] = null; + return; + } + aWidget[aEventName] = function(...aArgs) { + // Wrap inside a try...catch to properly log errors, until bug 862627 is + // fixed, which in turn might help bug 503244. + try { + // Don't copy the function to the normalized widget object, instead + // keep it on the original object provided to the API so that + // additional methods can be implemented and used by the event + // handlers. + return aWidget.implementation[aEventName].apply(aWidget.implementation, + aArgs); + } catch (e) { + Cu.reportError(e); + } + }; + }, + + destroyWidget: function(aWidgetId) { + let widget = gPalette.get(aWidgetId); + if (!widget) { + return; + } + + // Remove it from the default placements of an area if it was added there: + if (widget.defaultArea) { + let area = gAreas.get(widget.defaultArea); + if (area) { + let defaultPlacements = area.get("defaultPlacements"); + // We can assume this is present because if a widget has a defaultArea, + // we automatically create a defaultPlacements array for that area. + let widgetIndex = defaultPlacements.indexOf(aWidgetId); + if (widgetIndex != -1) { + defaultPlacements.splice(widgetIndex, 1); + } + } + } + + // This will not remove the widget from gPlacements - we want to keep the + // setting so the widget gets put back in it's old position if/when it + // returns. + + let area = widget.currentArea; + let buildAreaNodes = area && gBuildAreas.get(area); + if (buildAreaNodes) { + for (let buildNode of buildAreaNodes) { + let widgetNode = buildNode.ownerDocument.getElementById(aWidgetId); + let windowCache = gSingleWrapperCache.get(buildNode.ownerDocument.defaultView); + if (windowCache) { + windowCache.delete(aWidgetId); + } + if (widgetNode) { + widgetNode.parentNode.removeChild(widgetNode); + } + if (widget.type == "view") { + let viewNode = buildNode.ownerDocument.getElementById(widget.viewId); + if (viewNode) { + for (let eventName of kSubviewEvents) { + let handler = "on" + eventName; + if (typeof widget[handler] == "function") { + viewNode.removeEventListener(eventName, widget[handler], false); + } + } + } + } + } + } + + gPalette.delete(aWidgetId); + gGroupWrapperCache.delete(aWidgetId); + + this.notifyListeners("onWidgetDestroyed", aWidgetId); + }, + + getCustomizeTargetForArea: function(aArea, aWindow) { + let buildAreaNodes = gBuildAreas.get(aArea); + if (!buildAreaNodes) { + return null; + } + + for (let node of buildAreaNodes) { + if (node.ownerDocument.defaultView === aWindow) { + return node.customizationTarget ? node.customizationTarget : node; + } + } + + return null; + }, + + reset: function() { + gResetting = true; + Services.prefs.clearUserPref(kPrefCustomizationState); + LOG("State reset"); + + // Reset placements to make restoring default placements possible. + gPlacements = new Map(); + gDirtyAreaCache = new Set(); + // Clear the saved state to ensure that defaults will be used. + gSavedState = null; + // Restore the state for each area to its defaults + for (let [areaId,] of gAreas) { + this.restoreStateForArea(areaId); + } + + // Rebuild each registered area (across windows) to reflect the state that + // was reset above. + for (let [areaId, areaNodes] of gBuildAreas) { + let placements = gPlacements.get(areaId); + for (let areaNode of areaNodes) { + this.buildArea(areaId, placements, areaNode); + } + } + gResetting = false; + }, + + /** + * @param {String|Node} aWidget - widget ID or a widget node (preferred for performance). + * @return {Boolean} whether the widget is removable + */ + isWidgetRemovable: function(aWidget) { + let widgetId; + let widgetNode; + if (typeof aWidget == "string") { + widgetId = aWidget; + } else { + widgetId = aWidget.id; + widgetNode = aWidget; + } + let provider = this.getWidgetProvider(widgetId); + + if (provider == CustomizableUI.PROVIDER_API) { + return gPalette.get(widgetId).removable; + } + + if (provider == CustomizableUI.PROVIDER_XUL) { + if (gBuildWindows.size == 0) { + // We don't have any build windows to look at, so just assume for now + // that its removable. + return true; + } + + if (!widgetNode) { + // Pick any of the build windows to look at. + let [window,] = [...gBuildWindows][0]; + [, widgetNode] = this.getWidgetNode(widgetId, window); + } + // If we don't have a node, we assume it's removable. This can happen because + // getWidgetProvider returns PROVIDER_XUL by default, but this will also happen + // for API-provided widgets which have been destroyed. + if (!widgetNode) { + return true; + } + return widgetNode.getAttribute("removable") == "true"; + } + + // Otherwise this is either a special widget, which is always removable, or + // an API widget which has already been removed from gPalette. Returning true + // here allows us to then remove its ID from any placements where it might + // still occur. + return true; + }, + + canWidgetMoveToArea: function(aWidgetId, aArea) { + let placement = this.getPlacementOfWidget(aWidgetId); + if (placement && placement.area != aArea && + !this.isWidgetRemovable(aWidgetId)) { + return false; + } + return true; + }, + + ensureWidgetPlacedInWindow: function(aWidgetId, aWindow) { + let placement = this.getPlacementOfWidget(aWidgetId); + if (!placement) { + return false; + } + let areaNodes = gBuildAreas.get(placement.area); + if (!areaNodes) { + return false; + } + let container = [...areaNodes].filter((n) => n.ownerDocument.defaultView == aWindow); + if (!container.length) { + return false; + } + let existingNode = container[0].querySelector(idToSelector(aWidgetId)); + if (existingNode) { + return true; + } + + let placementAry = gPlacements.get(placement.area); + let nextNodeId = placementAry[placement.position + 1]; + this.insertNodeInWindow(aWidgetId, container[0], nextNodeId, true); + return true; + }, + + get inDefaultState() { + for (let [areaId, props] of gAreas) { + let defaultPlacements = props.get("defaultPlacements"); + // Areas without default placements (like legacy ones?) get skipped + if (!defaultPlacements) { + continue; + } + + let currentPlacements = gPlacements.get(areaId); + // We're excluding all of the placement IDs for items that do not exist, + // because we don't want to consider them when determining if we're + // in the default state. This way, if an add-on introduces a widget + // and is then uninstalled, the leftover placement doesn't cause us to + // automatically assume that the buttons are not in the default state. + let buildAreaNodes = gBuildAreas.get(areaId); + if (buildAreaNodes && buildAreaNodes.size) { + let container = [...buildAreaNodes][0]; + // Toolbars have a currentSet property which also deals correctly with overflown + // widgets (if any) - use that instead: + if (props.get("type") == CustomizableUI.TYPE_TOOLBAR) { + currentPlacements = container.currentSet.split(','); + } else { + // Clone the array so we don't modify the actual placements... + currentPlacements = [...currentPlacements]; + // Loop backwards through the placements so we can easily remove items: + let itemIndex = currentPlacements.length; + while (itemIndex--) { + if (!container.querySelector(idToSelector(currentPlacements[itemIndex]))) { + currentPlacements.splice(itemIndex, 1); + } + } + } + } + LOG("Checking default state for " + areaId + ":\n" + currentPlacements.join(",") + + "\nvs.\n" + defaultPlacements.join(",")); + + if (currentPlacements.length != defaultPlacements.length) { + return false; + } + + for (let i = 0; i < currentPlacements.length; ++i) { + if (currentPlacements[i] != defaultPlacements[i]) { + LOG("Found " + currentPlacements[i] + " in " + areaId + " where " + + defaultPlacements[i] + " was expected!"); + return false; + } + } + } + + return true; + } +}; +Object.freeze(CustomizableUIInternal); + +this.CustomizableUI = { + get AREA_PANEL() "PanelUI-contents", + get AREA_NAVBAR() "nav-bar", + get AREA_MENUBAR() "toolbar-menubar", + get AREA_TABSTRIP() "TabsToolbar", + get AREA_BOOKMARKS() "PersonalToolbar", + get AREA_ADDONBAR() "addon-bar", + + get PROVIDER_XUL() "xul", + get PROVIDER_API() "api", + get PROVIDER_SPECIAL() "special", + + get SOURCE_BUILTIN() "builtin", + get SOURCE_EXTERNAL() "external", + + get TYPE_BUTTON() "button", + get TYPE_MENU_PANEL() "menu-panel", + get TYPE_TOOLBAR() "toolbar", + + addListener: function(aListener) { + CustomizableUIInternal.addListener(aListener); + }, + removeListener: function(aListener) { + CustomizableUIInternal.removeListener(aListener); + }, + registerArea: function(aName, aProperties) { + CustomizableUIInternal.registerArea(aName, aProperties); + }, + registerToolbarNode: function(aToolbar, aExistingChildren) { + CustomizableUIInternal.registerToolbarNode(aToolbar, aExistingChildren); + }, + registerMenuPanel: function(aPanel) { + CustomizableUIInternal.registerMenuPanel(aPanel); + }, + unregisterArea: function(aName) { + CustomizableUIInternal.unregisterArea(aName); + }, + addWidgetToArea: function(aWidgetId, aArea, aPosition) { + CustomizableUIInternal.addWidgetToArea(aWidgetId, aArea, aPosition); + }, + removeWidgetFromArea: function(aWidgetId) { + CustomizableUIInternal.removeWidgetFromArea(aWidgetId); + }, + moveWidgetWithinArea: function(aWidgetId, aPosition) { + CustomizableUIInternal.moveWidgetWithinArea(aWidgetId, aPosition); + }, + ensureWidgetPlacedInWindow: function(aWidgetId, aWindow) { + return CustomizableUIInternal.ensureWidgetPlacedInWindow(aWidgetId, aWindow); + }, + beginBatchUpdate: function() { + CustomizableUIInternal.beginBatchUpdate(); + }, + endBatchUpdate: function(aForceDirty) { + CustomizableUIInternal.endBatchUpdate(aForceDirty); + }, + createWidget: function(aProperties) { + return CustomizableUIInternal.wrapWidget( + CustomizableUIInternal.createWidget(aProperties) + ); + }, + destroyWidget: function(aWidgetId) { + CustomizableUIInternal.destroyWidget(aWidgetId); + }, + getWidget: function(aWidgetId) { + return CustomizableUIInternal.wrapWidget(aWidgetId); + }, + getUnusedWidgets: function(aWindowPalette) { + return CustomizableUIInternal.getUnusedWidgets(aWindowPalette).map( + CustomizableUIInternal.wrapWidget, + CustomizableUIInternal + ); + }, + getWidgetIdsInArea: function(aArea) { + if (!gAreas.has(aArea)) { + throw new Error("Unknown customization area: " + aArea); + } + if (!gPlacements.has(aArea)) { + throw new Error("Area not yet restored"); + } + + // We need to clone this, as we don't want to let consumers muck with placements + return [...gPlacements.get(aArea)]; + }, + getWidgetsInArea: function(aArea) { + return this.getWidgetIdsInArea(aArea).map( + CustomizableUIInternal.wrapWidget, + CustomizableUIInternal + ); + }, + get areas() { + return [area for ([area, props] of gAreas)]; + }, + getAreaType: function(aArea) { + let area = gAreas.get(aArea); + return area ? area.get("type") : null; + }, + getCustomizeTargetForArea: function(aArea, aWindow) { + return CustomizableUIInternal.getCustomizeTargetForArea(aArea, aWindow); + }, + reset: function() { + CustomizableUIInternal.reset(); + }, + getPlacementOfWidget: function(aWidgetId) { + return CustomizableUIInternal.getPlacementOfWidget(aWidgetId, true); + }, + isWidgetRemovable: function(aWidgetId) { + return CustomizableUIInternal.isWidgetRemovable(aWidgetId); + }, + canWidgetMoveToArea: function(aWidgetId, aArea) { + return CustomizableUIInternal.canWidgetMoveToArea(aWidgetId, aArea); + }, + get inDefaultState() { + return CustomizableUIInternal.inDefaultState; + }, + getLocalizedProperty: function(aWidget, aProp, aFormatArgs, aDef) { + return CustomizableUIInternal.getLocalizedProperty(aWidget, aProp, + aFormatArgs, aDef); + }, + hidePanelForNode: function(aNode) { + CustomizableUIInternal.hidePanelForNode(aNode); + }, + isSpecialWidget: function(aWidgetId) { + return CustomizableUIInternal.isSpecialWidget(aWidgetId); + }, + addPanelCloseListeners: function(aPanel) { + CustomizableUIInternal.addPanelCloseListeners(aPanel); + }, + removePanelCloseListeners: function(aPanel) { + CustomizableUIInternal.removePanelCloseListeners(aPanel); + }, + onWidgetDrag: function(aWidgetId, aArea) { + CustomizableUIInternal.notifyListeners("onWidgetDrag", aWidgetId, aArea); + }, + isAreaOverflowable: function(aAreaId) { + let area = gAreas.get(aAreaId); + return area ? area.get("type") == this.TYPE_TOOLBAR && area.get("overflowable") + : false; + }, +}; +Object.freeze(this.CustomizableUI); + + +/** + * All external consumers of widgets are really interacting with these wrappers + * which provide a common interface. + */ + +/** + * WidgetGroupWrapper is the common interface for interacting with an entire + * widget group - AKA, all instances of a widget across a series of windows. + * This particular wrapper is only used for widgets created via the provider + * API. + */ +function WidgetGroupWrapper(aWidget) { + this.isGroup = true; + + const kBareProps = ["id", "source", "type", "disabled", "label", "tooltiptext", + "showInPrivateBrowsing"]; + for (let prop of kBareProps) { + let propertyName = prop; + this.__defineGetter__(propertyName, function() aWidget[propertyName]); + } + + this.__defineGetter__("provider", function() CustomizableUI.PROVIDER_API); + + this.__defineSetter__("disabled", function(aValue) { + aValue = !!aValue; + aWidget.disabled = aValue; + for (let [,instance] of aWidget.instances) { + instance.disabled = aValue; + } + }); + + this.forWindow = function WidgetGroupWrapper_forWindow(aWindow) { + let wrapperMap; + if (!gSingleWrapperCache.has(aWindow)) { + wrapperMap = new Map(); + gSingleWrapperCache.set(aWindow, wrapperMap); + } else { + wrapperMap = gSingleWrapperCache.get(aWindow); + } + if (wrapperMap.has(aWidget.id)) { + return wrapperMap.get(aWidget.id); + } + + let instance = aWidget.instances.get(aWindow.document); + if (!instance && + (aWidget.showInPrivateBrowsing || !PrivateBrowsingUtils.isWindowPrivate(aWindow))) { + instance = CustomizableUIInternal.buildWidget(aWindow.document, + aWidget); + } + + let wrapper = new WidgetSingleWrapper(aWidget, instance); + wrapperMap.set(aWidget.id, wrapper); + return wrapper; + }; + + this.__defineGetter__("instances", function() { + // Can't use gBuildWindows here because some areas load lazily: + let placement = CustomizableUIInternal.getPlacementOfWidget(aWidget.id); + if (!placement) { + return []; + } + let area = placement.area; + return [this.forWindow(node.ownerDocument.defaultView) for (node of gBuildAreas.get(area))]; + }); + + this.__defineGetter__("areaType", function() { + return gAreas.get(aWidget.currentArea).get("type"); + }); + + Object.freeze(this); +} + +/** + * A WidgetSingleWrapper is a wrapper around a single instance of a widget in + * a particular window. + */ +function WidgetSingleWrapper(aWidget, aNode) { + this.isGroup = false; + + this.node = aNode; + this.provider = CustomizableUI.PROVIDER_API; + + const kGlobalProps = ["id", "type"]; + for (let prop of kGlobalProps) { + this[prop] = aWidget[prop]; + } + + const nodeProps = ["label", "tooltiptext"]; + for (let prop of nodeProps) { + let propertyName = prop; + // Look at the node for these, instead of the widget data, to ensure the + // wrapper always reflects this live instance. + this.__defineGetter__(propertyName, + function() aNode.getAttribute(propertyName)); + } + + this.__defineGetter__("disabled", function() aNode.disabled); + this.__defineSetter__("disabled", function(aValue) { + aNode.disabled = !!aValue; + }); + + this.__defineGetter__("anchor", function() { + let anchorId; + // First check for an anchor for the area: + let placement = CustomizableUIInternal.getPlacementOfWidget(aWidgetId); + if (placement) { + anchorId = gAreas.get(placement.area).get("anchor"); + } + if (!anchorId) { + anchorId = aNode.getAttribute("cui-anchorid"); + } + + return anchorId ? aNode.ownerDocument.getElementById(anchorId) + : aNode; + }); + + this.__defineGetter__("overflowed", function() { + return aNode.classList.contains("overflowedItem"); + }); + + Object.freeze(this); +} + +/** + * XULWidgetGroupWrapper is the common interface for interacting with an entire + * widget group - AKA, all instances of a widget across a series of windows. + * This particular wrapper is only used for widgets created via the old-school + * XUL method (overlays, or programmatically injecting toolbaritems, or other + * such things). + */ +//XXXunf Going to need to hook this up to some events to keep it all live. +function XULWidgetGroupWrapper(aWidgetId) { + this.isGroup = true; + this.id = aWidgetId; + this.type = "custom"; + this.provider = CustomizableUI.PROVIDER_XUL; + + this.forWindow = function XULWidgetGroupWrapper_forWindow(aWindow) { + let wrapperMap; + if (!gSingleWrapperCache.has(aWindow)) { + wrapperMap = new Map(); + gSingleWrapperCache.set(aWindow, wrapperMap); + } else { + wrapperMap = gSingleWrapperCache.get(aWindow); + } + if (wrapperMap.has(aWidgetId)) { + return wrapperMap.get(aWidgetId); + } + + let instance = aWindow.document.getElementById(aWidgetId); + if (!instance) { + // Toolbar palettes aren't part of the document, so elements in there + // won't be found via document.getElementById(). + instance = aWindow.gNavToolbox.palette.querySelector(idToSelector(aWidgetId)); + } + + let wrapper = new XULWidgetSingleWrapper(aWidgetId, instance); + wrapperMap.set(aWidgetId, wrapper); + return wrapper; + }; + + this.__defineGetter__("areaType", function() { + let placement = CustomizableUIInternal.getPlacementOfWidget(aWidgetId); + if (!placement) { + return null; + } + + return gAreas.get(placement.area).get("type"); + }); + + this.__defineGetter__("instances", function() { + return [this.forWindow(win) for ([win,] of gBuildWindows)]; + }); + + Object.freeze(this); +} + +/** + * A XULWidgetSingleWrapper is a wrapper around a single instance of a XUL + * widget in a particular window. + */ +function XULWidgetSingleWrapper(aWidgetId, aNode) { + this.isGroup = false; + + this.id = aWidgetId; + this.type = "custom"; + this.provider = CustomizableUI.PROVIDER_XUL; + + this.node = aNode; + + this.__defineGetter__("anchor", function() { + let anchorId; + // First check for an anchor for the area: + let placement = CustomizableUIInternal.getPlacementOfWidget(aWidgetId); + if (placement) { + anchorId = gAreas.get(placement.area).get("anchor"); + } + if (!anchorId) { + anchorId = aNode.getAttribute("cui-anchorid"); + } + + return anchorId ? aNode.ownerDocument.getElementById(anchorId) + : aNode; + }); + + this.__defineGetter__("overflowed", function() { + return aNode.classList.contains("overflowedItem"); + }); + + Object.freeze(this); +} + +const LAZY_RESIZE_INTERVAL_MS = 200; + +function OverflowableToolbar(aToolbarNode) { + this._toolbar = aToolbarNode; + this._collapsed = new Map(); + this._enabled = true; + + this._toolbar.setAttribute("overflowable", "true"); + Services.obs.addObserver(this, "browser-delayed-startup-finished", false); +} + +OverflowableToolbar.prototype = { + initialized: false, + _forceOnOverflow: false, + + observe: function(aSubject, aTopic, aData) { + if (aTopic == "browser-delayed-startup-finished" && + aSubject == this._toolbar.ownerDocument.defaultView) { + Services.obs.removeObserver(this, "browser-delayed-startup-finished"); + this.init(); + } + }, + + init: function() { + this._target = this._toolbar.customizationTarget; + let doc = this._toolbar.ownerDocument; + this._list = doc.getElementById(this._toolbar.getAttribute("overflowtarget")); + this._list.toolbox = this._toolbar.toolbox; + this._list.customizationTarget = this._list; + + let window = doc.defaultView; + window.addEventListener("resize", this); + window.gNavToolbox.addEventListener("customizationstarting", this); + window.gNavToolbox.addEventListener("aftercustomization", this); + + let chevronId = this._toolbar.getAttribute("overflowbutton"); + this._chevron = doc.getElementById(chevronId); + this._chevron.addEventListener("command", this); + + this._panel = doc.getElementById("widget-overflow"); + this._panel.addEventListener("popuphiding", this); + CustomizableUIInternal.addPanelCloseListeners(this._panel); + + CustomizableUI.addListener(this); + + // The 'overflow' event may have been fired before init was called. + if (this._toolbar.overflowedDuringConstruction) { + this.onOverflow(this._toolbar.overflowedDuringConstruction); + this._toolbar.overflowedDuringConstruction = null; + } + + this.initialized = true; + }, + + uninit: function() { + this._toolbar.removeEventListener("overflow", this._toolbar); + this._toolbar.removeEventListener("underflow", this._toolbar); + this._toolbar.removeAttribute("overflowable"); + + if (!this.initialized) { + Services.obs.removeObserver(this, "browser-delayed-startup-finished"); + return; + } + + this._disable(); + + let window = this._toolbar.ownerDocument.defaultView; + window.removeEventListener("resize", this); + window.gNavToolbox.removeEventListener("customizationstarting", this); + window.gNavToolbox.removeEventListener("aftercustomization", this); + this._chevron.removeEventListener("command", this); + this._panel.removeEventListener("popuphiding", this); + CustomizableUI.removeListener(this); + CustomizableUIInternal.removePanelCloseListeners(this._panel); + }, + + handleEvent: function(aEvent) { + switch(aEvent.type) { + case "resize": + this._onResize(aEvent); + break; + case "command": + this._onClickChevron(aEvent); + break; + case "popuphiding": + this._onPanelHiding(aEvent); + break; + case "customizationstarting": + this._disable(); + break; + case "aftercustomization": + this._enable(); + break; + } + }, + + _onClickChevron: function(aEvent) { + if (this._chevron.open) + this._panel.hidePopup(); + else { + let doc = aEvent.target.ownerDocument; + this._panel.hidden = false; + let anchor = doc.getAnonymousElementByAttribute(this._chevron, "class", "toolbarbutton-icon"); + this._panel.openPopup(anchor || this._chevron, "bottomcenter topright"); + } + this._chevron.open = !this._chevron.open; + }, + + _onPanelHiding: function(aEvent) { + this._chevron.open = false; + }, + + onOverflow: function(aEvent) { + if (!this._enabled || + (aEvent && aEvent.target != this._toolbar.customizationTarget)) + return; + + let child = this._target.lastChild; + + while (child && this._target.scrollLeftMax > 0) { + let prevChild = child.previousSibling; + + if (child.getAttribute("overflows") != "false") { + this._collapsed.set(child.id, this._target.clientWidth); + child.classList.add("overflowedItem"); + child.setAttribute("cui-anchorid", this._chevron.id); + + this._list.insertBefore(child, this._list.firstChild); + if (!this._toolbar.hasAttribute("overflowing")) { + CustomizableUI.addListener(this); + } + this._toolbar.setAttribute("overflowing", "true"); + } + child = prevChild; + }; + + let win = this._target.ownerDocument.defaultView; + win.UpdateUrlbarSearchSplitterState(); + }, + + _onResize: function(aEvent) { + if (!this._lazyResizeHandler) { + this._lazyResizeHandler = new DeferredTask(this._onLazyResize.bind(this), + LAZY_RESIZE_INTERVAL_MS); + } + this._lazyResizeHandler.start(); + }, + + _moveItemsBackToTheirOrigin: function(shouldMoveAllItems) { + let placements = gPlacements.get(this._toolbar.id); + while (this._list.firstChild) { + let child = this._list.firstChild; + let minSize = this._collapsed.get(child.id); + + if (!shouldMoveAllItems && + minSize && + this._target.clientWidth <= minSize) { + return; + } + + this._collapsed.delete(child.id); + let beforeNodeIndex = placements.indexOf(child.id) + 1; + // If this is a skipintoolbarset item, meaning it doesn't occur in the placements list, + // we're inserting it at the end. This will mean first-in, first-out (more or less) + // leading to as little change in order as possible. + if (beforeNodeIndex == 0) { + beforeNodeIndex = placements.length; + } + let inserted = false; + for (; beforeNodeIndex < placements.length; beforeNodeIndex++) { + let beforeNode = this._target.querySelector(idToSelector(placements[beforeNodeIndex])); + if (beforeNode) { + this._target.insertBefore(child, beforeNode); + inserted = true; + break; + } + } + if (!inserted) { + this._target.appendChild(child); + } + child.removeAttribute("cui-anchorid"); + child.classList.remove("overflowedItem"); + } + + let win = this._target.ownerDocument.defaultView; + win.UpdateUrlbarSearchSplitterState(); + + if (!this._collapsed.size) { + this._toolbar.removeAttribute("overflowing"); + CustomizableUI.removeListener(this); + } + }, + + _onLazyResize: function() { + if (!this._enabled) + return; + + this._moveItemsBackToTheirOrigin(); + }, + + _disable: function() { + this._enabled = false; + this._moveItemsBackToTheirOrigin(true); + if (this._lazyResizeHandler) { + this._lazyResizeHandler.cancel(); + } + }, + + _enable: function() { + this._enabled = true; + this.onOverflow(); + }, + + onWidgetBeforeDOMChange: function(aNode, aNextNode, aContainer) { + if (aContainer != this._target) { + return; + } + // When we (re)move an item, update all the items that come after it in the list + // with the minsize *of the item before the to-be-removed node*. This way, we + // ensure that we try to move items back as soon as that's possible. + if (aNode.parentNode == this._list) { + let updatedMinSize; + if (aNode.previousSibling) { + updatedMinSize = this._collapsed.get(aNode.previousSibling.id); + } else { + // Force (these) items to try to flow back into the bar: + updatedMinSize = 1; + } + let nextItem = aNode.nextSibling; + while (nextItem) { + this._collapsed.set(nextItem.id, updatedMinSize); + nextItem = nextItem.nextSibling; + } + } + }, + + onWidgetAfterDOMChange: function(aNode, aNextNode, aContainer) { + if (aContainer != this._target) { + return; + } + + let nowInBar = aNode.parentNode == aContainer; + let nowOverflowed = aNode.parentNode == this._list; + let wasOverflowed = this._collapsed.has(aNode.id); + + // If this wasn't overflowed before... + if (!wasOverflowed) { + // ... but it is now, then we added to the overflow panel. Exciting stuff: + if (nowOverflowed) { + // NB: we're guaranteed that it has a previousSibling, because if it didn't, + // we would have added it to the toolbar instead. See getOverflowedNextNode. + let prevId = aNode.previousSibling.id; + let minSize = this._collapsed.get(prevId); + this._collapsed.set(aNode.id, minSize); + aNode.setAttribute("cui-anchorid", this._chevron.id); + aNode.classList.add("overflowedItem"); + } + // If it is not overflowed and not in the toolbar, and was not overflowed + // either, it moved out of the toolbar. That means there's now space in there! + // Let's try to move stuff back: + else if (!nowInBar) { + this._moveItemsBackToTheirOrigin(true); + } + // If it's in the toolbar now, then we don't care. An overflow event may + // fire afterwards; that's ok! + } + // If it used to be overflowed... + else { + // ... and isn't anymore, let's remove our bookkeeping: + if (!nowOverflowed) { + this._collapsed.delete(aNode.id); + aNode.removeAttribute("cui-anchorid"); + aNode.classList.remove("overflowedItem"); + + if (!this._collapsed.size) { + this._toolbar.removeAttribute("overflowing"); + CustomizableUI.removeListener(this); + } + } + // but if it still is, it must have changed places. Bookkeep: + else { + if (aNode.previousSibling) { + let prevId = aNode.previousSibling.id; + let minSize = this._collapsed.get(prevId); + this._collapsed.set(aNode.id, minSize); + } else { + // If it's now the first item in the overflow list, + // maybe we can return it: + this._moveItemsBackToTheirOrigin(); + } + } + } + }, + + getOverflowedInsertionPoints: function(aNode, aNextNodeId) { + if (aNode.getAttribute("overflows") == "false") { + return [this._target, null]; + } + // Inserting at the end means we're in the overflow list by definition: + if (!aNextNodeId) { + return [this._list, null]; + } + + let nextNode = this._list.querySelector(idToSelector(aNextNodeId)); + // If this is the first item, we can actually just append the node + // to the end of the toolbar. If it results in an overflow event, we'll move + // the new node to the overflow target. + if (!nextNode.previousSibling) { + return [this._target, null]; + } + return [this._list, nextNode]; + } +}; + +// When IDs contain special characters, we need to escape them for use with querySelector: +function idToSelector(aId) { + return "#" + aId.replace(/[ !"'#$%&\(\)*+\-,.\/:;<=>?@\[\\\]^`{|}~]/g, '\\$&'); +} + +CustomizableUIInternal.initialize(); diff --git a/browser/components/customizableui/src/CustomizableWidgets.jsm b/browser/components/customizableui/src/CustomizableWidgets.jsm new file mode 100644 index 0000000000000000000000000000000000000000..5f1fd8e23a66533dc64444f03add4aa14944ae33 --- /dev/null +++ b/browser/components/customizableui/src/CustomizableWidgets.jsm @@ -0,0 +1,778 @@ +/* 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"; +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; + +this.EXPORTED_SYMBOLS = ["CustomizableWidgets"]; + +Cu.import("resource:///modules/CustomizableUI.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", + "resource://gre/modules/PlacesUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "RecentlyClosedTabsAndWindowsMenuUtils", + "resource:///modules/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm"); +XPCOMUtils.defineLazyServiceGetter(this, "CharsetManager", + "@mozilla.org/charset-converter-manager;1", + "nsICharsetConverterManager"); + +const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; +const kPrefCustomizationDebug = "browser.uiCustomization.debug"; +const kWidePanelItemClass = "panel-wide-item"; + +let gModuleName = "[CustomizableWidgets]"; +#include logging.js + +function setAttributes(aNode, aAttrs) { + for (let [name, value] of Iterator(aAttrs)) { + if (!value) { + if (aNode.hasAttribute(name)) + aNode.removeAttribute(name); + } else { + if (name == "label" || name == "tooltiptext") + value = CustomizableUI.getLocalizedProperty({id: aAttrs.id}, name); + aNode.setAttribute(name, value); + } + } +} + +function updateCombinedWidgetStyle(aNode, aArea, aModifyAutoclose) { + let inPanel = (aArea == CustomizableUI.AREA_PANEL); + let cls = inPanel ? "panel-combined-button" : "toolbarbutton-1"; + if (!aArea) + cls = null; + let attrs = {class: cls}; + if (aModifyAutoclose) { + attrs.noautoclose = inPanel ? true : null; + } + for (let i = 0, l = aNode.childNodes.length; i < l; ++i) { + setAttributes(aNode.childNodes[i], attrs); + } +} + +const CustomizableWidgets = [{ + id: "history-panelmenu", + type: "view", + viewId: "PanelUI-history", + shortcutId: "key_gotoHistory", + removable: true, + defaultArea: CustomizableUI.AREA_PANEL, + onViewShowing: function(aEvent) { + // Populate our list of history + const kMaxResults = 15; + let doc = aEvent.detail.ownerDocument; + + let options = PlacesUtils.history.getNewQueryOptions(); + options.excludeQueries = true; + options.includeHidden = false; + options.resultType = options.RESULTS_AS_URI; + options.queryType = options.QUERY_TYPE_HISTORY; + options.sortingMode = options.SORT_BY_DATE_DESCENDING; + options.maxResults = kMaxResults; + let query = PlacesUtils.history.getNewQuery(); + + let items = doc.getElementById("PanelUI-historyItems"); + // Clear previous history items. + while (items.firstChild) { + items.removeChild(items.firstChild); + } + + PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase) + .asyncExecuteLegacyQueries([query], 1, options, { + handleResult: function (aResultSet) { + let onHistoryVisit = function (aUri, aEvent, aItem) { + doc.defaultView.openUILink(aUri, aEvent); + CustomizableUI.hidePanelForNode(aItem); + }; + let fragment = doc.createDocumentFragment(); + for (let row, i = 0; (row = aResultSet.getNextRow()); i++) { + try { + let uri = row.getResultByIndex(1); + let title = row.getResultByIndex(2); + let icon = row.getResultByIndex(6); + + let item = doc.createElementNS(kNSXUL, "toolbarbutton"); + item.setAttribute("label", title || uri); + item.setAttribute("tabindex", "0"); + item.addEventListener("command", function (aEvent) { + onHistoryVisit(uri, aEvent, item); + }); + item.addEventListener("click", function (aEvent) { + onHistoryVisit(uri, aEvent, item); + }); + if (icon) + item.setAttribute("image", "moz-anno:favicon:" + icon); + fragment.appendChild(item); + } catch (e) { + ERROR("Error while showing history subview: " + e); + } + } + items.appendChild(fragment); + }, + handleError: function (aError) { + LOG("History view tried to show but had an error: " + aError); + }, + handleCompletion: function (aReason) { + LOG("History view is being shown!"); + }, + }); + + let recentlyClosedTabs = doc.getElementById("PanelUI-recentlyClosedTabs"); + while (recentlyClosedTabs.firstChild) { + recentlyClosedTabs.removeChild(recentlyClosedTabs.firstChild); + } + + let recentlyClosedWindows = doc.getElementById("PanelUI-recentlyClosedWindows"); + while (recentlyClosedWindows.firstChild) { + recentlyClosedWindows.removeChild(recentlyClosedWindows.firstChild); + } + + let tabsFragment = RecentlyClosedTabsAndWindowsMenuUtils.getTabsFragment(doc.defaultView, "toolbarbutton"); + let separator = doc.getElementById("PanelUI-recentlyClosedTabs-separator"); + separator.hidden = !tabsFragment.childElementCount; + recentlyClosedTabs.appendChild(tabsFragment); + + let windowsFragment = RecentlyClosedTabsAndWindowsMenuUtils.getWindowsFragment(doc.defaultView, "toolbarbutton"); + separator = doc.getElementById("PanelUI-recentlyClosedWindows-separator"); + separator.hidden = !windowsFragment.childElementCount; + recentlyClosedWindows.appendChild(windowsFragment); + }, + onViewHiding: function(aEvent) { + LOG("History view is being hidden!"); + } + }, { + id: "privatebrowsing-button", + removable: true, + shortcutId: "key_privatebrowsing", + defaultArea: CustomizableUI.AREA_PANEL, + onCommand: function(e) { + if (e.target && e.target.ownerDocument && e.target.ownerDocument.defaultView) { + let win = e.target.ownerDocument.defaultView; + if (typeof win.OpenBrowserWindow == "function") { + win.OpenBrowserWindow({private: true}); + } + } + } + }, { + id: "save-page-button", + removable: true, + shortcutId: "key_savePage", + defaultArea: CustomizableUI.AREA_PANEL, + onCommand: function(aEvent) { + let win = aEvent.target && + aEvent.target.ownerDocument && + aEvent.target.ownerDocument.defaultView; + if (win && typeof win.saveDocument == "function") { + win.saveDocument(win.content.document); + } + } + }, { + id: "find-button", + removable: true, + shortcutId: "key_find", + defaultArea: CustomizableUI.AREA_PANEL, + onCommand: function(aEvent) { + let win = aEvent.target && + aEvent.target.ownerDocument && + aEvent.target.ownerDocument.defaultView; + if (win && win.gFindBar) { + win.gFindBar.onFindCommand(); + } + } + }, { + id: "open-file-button", + removable: true, + shortcutId: "openFileKb", + defaultArea: CustomizableUI.AREA_PANEL, + onCommand: function(aEvent) { + let win = aEvent.target + && aEvent.target.ownerDocument + && aEvent.target.ownerDocument.defaultView; + if (win && typeof win.BrowserOpenFileWindow == "function") { + win.BrowserOpenFileWindow(); + } + } + }, { + id: "developer-button", + type: "view", + viewId: "PanelUI-developer", + removable: true, + shortcutId: "key_devToolboxMenuItem", + defaultArea: CustomizableUI.AREA_PANEL, + onViewShowing: function(aEvent) { + // Populate the subview with whatever menuitems are in the developer + // menu. We skip menu elements, because the menu panel has no way + // of dealing with those right now. + let doc = aEvent.target.ownerDocument; + let win = doc.defaultView; + + let items = doc.getElementById("PanelUI-developerItems"); + let menu = doc.getElementById("menuWebDeveloperPopup"); + let attrs = ["oncommand", "onclick", "label", "key", "disabled", + "command", "observes"]; + + let fragment = doc.createDocumentFragment(); + let itemsToDisplay = [...menu.children]; + // Hardcode the addition of the "work offline" menuitem at the bottom: + itemsToDisplay.push({localName: "menuseparator", getAttribute: () => {}}); + itemsToDisplay.push(doc.getElementById("goOfflineMenuitem")); + for (let node of itemsToDisplay) { + if (node.hidden) + continue; + + let item; + if (node.localName == "menuseparator") { + item = doc.createElementNS(kNSXUL, "menuseparator"); + } else if (node.localName == "menuitem") { + item = doc.createElementNS(kNSXUL, "toolbarbutton"); + item.setAttribute("tabindex", "0"); + } else { + continue; + } + for (let attr of attrs) { + let attrVal = node.getAttribute(attr); + if (attrVal) + item.setAttribute(attr, attrVal); + } + fragment.appendChild(item); + } + items.appendChild(fragment); + + aEvent.target.addEventListener("command", win.PanelUI.onCommandHandler); + }, + onViewHiding: function(aEvent) { + let doc = aEvent.target.ownerDocument; + let win = doc.defaultView; + let items = doc.getElementById("PanelUI-developerItems"); + let parent = items.parentNode; + // We'll take the container out of the document before cleaning it out + // to avoid reflowing each time we remove something. + parent.removeChild(items); + + while (items.firstChild) { + items.firstChild.remove(); + } + + parent.appendChild(items); + aEvent.target.removeEventListener("command", + win.PanelUI.onCommandHandler); + } + }, { + id: "add-ons-button", + removable: true, + shortcutId: "key_openAddons", + defaultArea: CustomizableUI.AREA_PANEL, + onCommand: function(aEvent) { + let win = aEvent.target && + aEvent.target.ownerDocument && + aEvent.target.ownerDocument.defaultView; + if (win && typeof win.BrowserOpenAddonsMgr == "function") { + win.BrowserOpenAddonsMgr(); + } + } + }, { + id: "preferences-button", + removable: true, + defaultArea: CustomizableUI.AREA_PANEL, +#ifdef XP_WIN + label: "preferences-button.labelWin", + tooltiptext: "preferences-button.tooltipWin", +#endif + onCommand: function(aEvent) { + let win = aEvent.target && + aEvent.target.ownerDocument && + aEvent.target.ownerDocument.defaultView; + if (win && typeof win.openPreferences == "function") { + win.openPreferences(); + } + } + }, { + id: "zoom-controls", + type: "custom", + removable: true, + defaultArea: CustomizableUI.AREA_PANEL, + onBuild: function(aDocument) { + const kPanelId = "PanelUI-popup"; + let inPanel = (this.currentArea == CustomizableUI.AREA_PANEL); + let noautoclose = inPanel ? "true" : null; + let cls = inPanel ? "panel-combined-button" : "toolbarbutton-1"; + + if (!this.currentArea) + cls = null; + + let buttons = [{ + id: "zoom-out-button", + noautoclose: noautoclose, + command: "cmd_fullZoomReduce", + class: cls, + label: true, + tooltiptext: true + }, { + id: "zoom-reset-button", + noautoclose: noautoclose, + command: "cmd_fullZoomReset", + class: cls, + tooltiptext: true + }, { + id: "zoom-in-button", + noautoclose: noautoclose, + command: "cmd_fullZoomEnlarge", + class: cls, + label: true, + tooltiptext: true + }]; + + let node = aDocument.createElementNS(kNSXUL, "toolbaritem"); + node.setAttribute("id", "zoom-controls"); + node.setAttribute("title", CustomizableUI.getLocalizedProperty(this, "tooltiptext")); + // Set this as an attribute in addition to the property to make sure we can style correctly. + node.setAttribute("removable", "true"); + node.classList.add("chromeclass-toolbar-additional"); + node.classList.add("toolbaritem-combined-buttons"); + node.classList.add(kWidePanelItemClass); + + buttons.forEach(function(aButton) { + let btnNode = aDocument.createElementNS(kNSXUL, "toolbarbutton"); + setAttributes(btnNode, aButton); + if (inPanel) + btnNode.setAttribute("tabindex", "0"); + node.appendChild(btnNode); + }); + + // The middle node is the 'Reset Zoom' button. + let zoomResetButton = node.childNodes[1]; + let window = aDocument.defaultView; + function updateZoomResetButton() { + //XXXgijs in some tests we get called very early, and there's no docShell on the + // tabbrowser. This breaks the zoom toolkit code (see bug 897410). Don't let that happen: + let zoomFactor = 100; + if (window.gBrowser.docShell) { + zoomFactor = Math.floor(window.ZoomManager.zoom * 100); + } + zoomResetButton.setAttribute("label", CustomizableUI.getLocalizedProperty( + buttons[1], "label", [zoomFactor] + )); + }; + + // Register ourselves with the service so we know when the zoom prefs change. + Services.obs.addObserver(updateZoomResetButton, "browser-fullZoom:zoomChange", false); + Services.obs.addObserver(updateZoomResetButton, "browser-fullZoom:zoomReset", false); + + if (inPanel && this.currentArea) { + let panel = aDocument.getElementById(kPanelId); + panel.addEventListener("popupshowing", updateZoomResetButton); + } else { + updateZoomResetButton(); + } + + let listener = { + onWidgetAdded: function(aWidgetId, aArea, aPosition) { + if (aWidgetId != this.id) + return; + + updateCombinedWidgetStyle(node, aArea, true); + updateZoomResetButton(); + + if (aArea == CustomizableUI.AREA_PANEL) { + let panel = aDocument.getElementById(kPanelId); + panel.addEventListener("popupshowing", updateZoomResetButton); + } + }.bind(this), + + onWidgetRemoved: function(aWidgetId, aPrevArea) { + if (aWidgetId != this.id) + return; + + if (aPrevArea == CustomizableUI.AREA_PANEL) { + let panel = aDocument.getElementById(kPanelId); + panel.removeEventListener("popupshowing", updateZoomResetButton); + } + + // When a widget is demoted to the palette ('removed'), it's visual + // style should change. + updateCombinedWidgetStyle(node, null, true); + updateZoomResetButton(); + }.bind(this), + + onWidgetReset: function(aWidgetId) { + if (aWidgetId != this.id) + return; + updateCombinedWidgetStyle(node, this.currentArea, true); + updateZoomResetButton(); + }.bind(this), + + onWidgetMoved: function(aWidgetId, aArea) { + if (aWidgetId != this.id) + return; + updateCombinedWidgetStyle(node, aArea, true); + updateZoomResetButton(); + }.bind(this), + + onWidgetInstanceRemoved: function(aWidgetId, aDoc) { + if (aWidgetId != this.id || aDoc != aDocument) + return; + + CustomizableUI.removeListener(listener); + Services.obs.removeObserver(updateZoomResetButton, "browser-fullZoom:zoomChange"); + Services.obs.removeObserver(updateZoomResetButton, "browser-fullZoom:zoomReset"); + let panel = aDoc.getElementById(kPanelId); + panel.removeEventListener("popupshowing", updateZoomResetButton); + }.bind(this), + + onWidgetDrag: function(aWidgetId, aArea) { + if (aWidgetId != this.id) + return; + aArea = aArea || this.currentArea; + updateCombinedWidgetStyle(node, aArea, true); + }.bind(this) + }; + CustomizableUI.addListener(listener); + + return node; + } + }, { + id: "edit-controls", + type: "custom", + removable: true, + defaultArea: CustomizableUI.AREA_PANEL, + onBuild: function(aDocument) { + let inPanel = (this.currentArea == CustomizableUI.AREA_PANEL); + let cls = inPanel ? "panel-combined-button" : "toolbarbutton-1"; + + if (!this.currentArea) + cls = null; + + let buttons = [{ + id: "cut-button", + command: "cmd_cut", + class: cls, + label: true, + tooltiptext: true + }, { + id: "copy-button", + command: "cmd_copy", + class: cls, + label: true, + tooltiptext: true + }, { + id: "paste-button", + command: "cmd_paste", + class: cls, + label: true, + tooltiptext: true + }]; + + let node = aDocument.createElementNS(kNSXUL, "toolbaritem"); + node.setAttribute("id", "edit-controls"); + node.setAttribute("title", CustomizableUI.getLocalizedProperty(this, "tooltiptext")); + // Set this as an attribute in addition to the property to make sure we can style correctly. + node.setAttribute("removable", "true"); + node.classList.add("chromeclass-toolbar-additional"); + node.classList.add("toolbaritem-combined-buttons"); + node.classList.add(kWidePanelItemClass); + + buttons.forEach(function(aButton) { + let btnNode = aDocument.createElementNS(kNSXUL, "toolbarbutton"); + setAttributes(btnNode, aButton); + if (inPanel) + btnNode.setAttribute("tabindex", "0"); + node.appendChild(btnNode); + }); + + let listener = { + onWidgetAdded: function(aWidgetId, aArea, aPosition) { + if (aWidgetId != this.id) + return; + updateCombinedWidgetStyle(node, aArea); + }.bind(this), + + onWidgetRemoved: function(aWidgetId, aPrevArea) { + if (aWidgetId != this.id) + return; + // When a widget is demoted to the palette ('removed'), it's visual + // style should change. + updateCombinedWidgetStyle(node); + }.bind(this), + + onWidgetReset: function(aWidgetId) { + if (aWidgetId != this.id) + return; + updateCombinedWidgetStyle(node, this.currentArea); + }.bind(this), + + onWidgetMoved: function(aWidgetId, aArea) { + if (aWidgetId != this.id) + return; + updateCombinedWidgetStyle(node, aArea); + }.bind(this), + + onWidgetInstanceRemoved: function(aWidgetId, aDoc) { + if (aWidgetId != this.id || aDoc != aDocument) + return; + CustomizableUI.removeListener(listener); + }.bind(this), + + onWidgetDrag: function(aWidgetId, aArea) { + if (aWidgetId != this.id) + return; + aArea = aArea || this.currentArea; + updateCombinedWidgetStyle(node, aArea); + }.bind(this) + }; + CustomizableUI.addListener(listener); + + return node; + } + }, + { + id: "feed-button", + type: "view", + viewId: "PanelUI-feeds", + removable: true, + defaultArea: CustomizableUI.AREA_PANEL, + onClick: function(aEvent) { + let win = aEvent.target.ownerDocument.defaultView; + let feeds = win.gBrowser.selectedBrowser.feeds; + + // Here, we only care about the case where we have exactly 1 feed and the + // user clicked... + let isClick = (aEvent.button == 0 || aEvent.button == 1); + if (feeds && feeds.length == 1 && isClick) { + aEvent.preventDefault(); + aEvent.stopPropagation(); + win.FeedHandler.subscribeToFeed(feeds[0].href, aEvent); + CustomizableUI.hidePanelForNode(aEvent.target); + } + }, + onViewShowing: function(aEvent) { + let doc = aEvent.detail.ownerDocument; + let container = doc.getElementById("PanelUI-feeds"); + let gotView = doc.defaultView.FeedHandler.buildFeedList(container, true); + + // For no feeds or only a single one, don't show the panel. + if (!gotView) { + aEvent.preventDefault(); + aEvent.stopPropagation(); + return; + } + }, + onCreated: function(node) { + let win = node.ownerDocument.defaultView; + let selectedBrowser = win.gBrowser.selectedBrowser; + let feeds = selectedBrowser && selectedBrowser.feeds; + if (!feeds || !feeds.length) { + node.setAttribute("disabled", "true"); + } + } + }, { + id: "characterencoding-button", + type: "view", + viewId: "PanelUI-characterEncodingView", + removable: true, + defaultArea: CustomizableUI.AREA_PANEL, + maybeDisableMenu: function(aDocument) { + let window = aDocument.defaultView; + return !(window.gBrowser && + window.gBrowser.docShell && + window.gBrowser.docShell.mayEnableCharacterEncodingMenu); + }, + getCharsetList: function(aSection, aDocument) { + let currCharset = aDocument.defaultView.content.document.characterSet; + + let list = ""; + try { + let pref = "intl.charsetmenu.browser." + aSection; + list = Services.prefs.getComplexValue(pref, + Ci.nsIPrefLocalizedString).data; + } catch (e) {} + + list = list.trim(); + if (!list) + return []; + + list = list.split(","); + + let items = []; + for (let charset of list) { + charset = charset.trim(); + + let notForBrowser = false; + try { + notForBrowser = CharsetManager.getCharsetData(charset, + "notForBrowser"); + } catch (e) {} + + if (notForBrowser) + continue; + + let title = charset; + try { + title = CharsetManager.getCharsetTitle(charset); + } catch (e) {} + + items.push({value: charset, name: title, current: charset == currCharset}); + } + + return items; + }, + getAutoDetectors: function(aDocument) { + let detectorEnum = CharsetManager.GetCharsetDetectorList(); + let currDetector; + try { + currDetector = Services.prefs.getComplexValue( + "intl.charset.detector", Ci.nsIPrefLocalizedString).data; + } catch (e) {} + if (!currDetector) + currDetector = "off"; + currDetector = "chardet." + currDetector; + + let items = []; + + while (detectorEnum.hasMore()) { + let detector = detectorEnum.getNext(); + + let title = detector; + try { + title = CharsetManager.getCharsetTitle(detector); + } catch (e) {} + + items.push({value: detector, name: title, current: detector == currDetector}); + } + + items.sort((aItem1, aItem2) => { + return aItem1.name.localeCompare(aItem2.name); + }); + + return items; + }, + populateList: function(aDocument, aContainerId, aSection) { + let containerElem = aDocument.getElementById(aContainerId); + + while (containerElem.firstChild) { + containerElem.removeChild(containerElem.firstChild); + } + + containerElem.addEventListener("command", this.onCommand, false); + + let list = []; + if (aSection == "autodetect") { + list = this.getAutoDetectors(aDocument); + } else if (aSection == "browser") { + let staticList = this.getCharsetList("static", aDocument); + let cacheList = this.getCharsetList("cache", aDocument); + // Combine lists, and de-duplicate. + let checkedIn = new Set(); + for (let item of staticList.concat(cacheList)) { + let itemName = item.name.toLowerCase(); + if (!checkedIn.has(itemName)) { + list.push(item); + checkedIn.add(itemName); + } + } + } + + // Update the appearance of the buttons when it's not possible to + // customize encoding. + let disabled = this.maybeDisableMenu(aDocument); + for (let item of list) { + let elem = aDocument.createElementNS(kNSXUL, "toolbarbutton"); + elem.setAttribute("label", item.name); + elem.section = aSection; + elem.value = item.value; + if (item.current) + elem.setAttribute("current", "true"); + if (disabled) + elem.setAttribute("disabled", "true"); + containerElem.appendChild(elem); + } + }, + onViewShowing: function(aEvent) { + let document = aEvent.target.ownerDocument; + + this.populateList(document, + "PanelUI-characterEncodingView-customlist", + "browser"); + this.populateList(document, + "PanelUI-characterEncodingView-autodetect", + "autodetect"); + }, + onCommand: function(aEvent) { + let node = aEvent.target; + if (!node.hasAttribute || !node.section) { + return; + } + + CustomizableUI.hidePanelForNode(node); + let window = node.ownerDocument.defaultView; + let section = node.section; + let value = node.value; + + // The behavior as implemented here is directly based off of the + // `MultiplexHandler()` method in browser.js. + if (section == "browser") { + window.BrowserSetForcedCharacterSet(value); + } else if (section == "autodetect") { + value = value.replace(/^chardet\./, ""); + if (value == "off") { + value = ""; + } + // Set the detector pref. + try { + let str = Cc["@mozilla.org/supports-string;1"] + .createInstance(Ci.nsISupportsString); + str.data = value; + Services.prefs.setComplexValue("intl.charset.detector", Ci.nsISupportsString, str); + } catch (e) { + Cu.reportError("Failed to set the intl.charset.detector preference."); + } + // Prepare a browser page reload with a changed charset. + window.BrowserCharsetReload(); + } + }, + onCreated: function(aNode) { + const kPanelId = "PanelUI-popup"; + let document = aNode.ownerDocument; + + let updateButton = () => { + if (this.maybeDisableMenu(document)) + aNode.setAttribute("disabled", "true"); + else + aNode.removeAttribute("disabled"); + }; + + if (this.currentArea == CustomizableUI.AREA_PANEL) { + let panel = document.getElementById(kPanelId); + panel.addEventListener("popupshowing", updateButton); + } + + let listener = { + onWidgetAdded: (aWidgetId, aArea) => { + if (aWidgetId != this.id) + return; + if (aArea == CustomizableUI.AREA_PANEL) { + let panel = document.getElementById(kPanelId); + panel.addEventListener("popupshowing", updateButton); + } + }, + onWidgetRemoved: (aWidgetId, aPrevArea) => { + if (aWidgetId != this.id) + return; + if (aPrevArea == CustomizableUI.AREA_PANEL) { + let panel = document.getElementById(kPanelId); + panel.removeEventListener("popupshowing", updateButton); + } + }, + onWidgetInstanceRemoved: (aWidgetId, aDoc) => { + if (aWidgetId != this.id || aDoc != document) + return; + + CustomizableUI.removeListener(listener); + let panel = aDoc.getElementById(kPanelId); + panel.removeEventListener("popupshowing", updateButton); + } + }; + CustomizableUI.addListener(listener); + } + }]; diff --git a/browser/components/customizableui/src/CustomizeMode.jsm b/browser/components/customizableui/src/CustomizeMode.jsm new file mode 100644 index 0000000000000000000000000000000000000000..27e5d768aa95749f0b97397cfdf5d3bdab379856 --- /dev/null +++ b/browser/components/customizableui/src/CustomizeMode.jsm @@ -0,0 +1,1430 @@ +/* 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"; + +this.EXPORTED_SYMBOLS = ["CustomizeMode"]; + +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; + +const kPrefCustomizationDebug = "browser.uiCustomization.debug"; +const kPrefCustomizationAnimation = "browser.uiCustomization.disableAnimation"; +const kPaletteId = "customization-palette"; +const kAboutURI = "about:customizing"; +const kDragDataTypePrefix = "text/toolbarwrapper-id/"; +const kPlaceholderClass = "panel-customization-placeholder"; +const kWidePanelItemClass = "panel-wide-item"; +// TODO(bug 885574): Merge this constant with the one in CustomizableWidgets.jsm, +// maybe just use a pref for this. +const kColumnsInMenuPanel = 3; +const kSkipSourceNodePref = "browser.uiCustomization.skipSourceNodeCheck"; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource:///modules/CustomizableUI.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Task.jsm"); +Cu.import("resource://gre/modules/Promise.jsm"); + +let gModuleName = "[CustomizeMode]"; +#include logging.js + +let gDisableAnimation = null; + +function CustomizeMode(aWindow) { + if (gDisableAnimation === null) { + gDisableAnimation = Services.prefs.getPrefType(kPrefCustomizationAnimation) == Ci.nsIPrefBranch.PREF_BOOL && + Services.prefs.getBoolPref(kPrefCustomizationAnimation); + } + this.window = aWindow; + this.document = aWindow.document; + this.browser = aWindow.gBrowser; + + // There are two palettes - there's the palette that can be overlayed with + // toolbar items in browser.xul. This is invisible, and never seen by the + // user. Then there's the visible palette, which gets populated and displayed + // to the user when in customizing mode. + this.visiblePalette = this.document.getElementById(kPaletteId); +}; + +CustomizeMode.prototype = { + _changed: false, + _transitioning: false, + window: null, + document: null, + // areas is used to cache the customizable areas when in customization mode. + areas: null, + // When in customizing mode, we swap out the reference to the invisible + // palette in gNavToolbox.palette for our visiblePalette. This way, for the + // customizing browser window, when widgets are removed from customizable + // areas and added to the palette, they're added to the visible palette. + // _stowedPalette is a reference to the old invisible palette so we can + // restore gNavToolbox.palette to its original state after exiting + // customization mode. + _stowedPalette: null, + _dragOverItem: null, + _customizing: false, + _skipSourceNodeCheck: null, + + get panelUIContents() { + return this.document.getElementById("PanelUI-contents"); + }, + + toggle: function() { + if (this._transitioning) { + return; + } + if (this._customizing) { + this.exit(); + } else { + this.enter(); + } + }, + + enter: function() { + if (this._customizing || this._transitioning) { + return; + } + + // We don't need to switch to kAboutURI, or open a new tab at + // kAboutURI if we're already on it. + if (this.browser.selectedBrowser.currentURI.spec != kAboutURI) { + this.window.switchToTabHavingURI(kAboutURI, true); + return; + } + + Task.spawn(function() { + // We shouldn't start customize mode until after browser-delayed-startup has finished: + if (!this.window.gBrowserInit.delayedStartupFinished) { + let delayedStartupDeferred = Promise.defer(); + let delayedStartupObserver = function(aSubject) { + if (aSubject == this.window) { + Services.obs.removeObserver(delayedStartupObserver, "browser-delayed-startup-finished"); + delayedStartupDeferred.resolve(); + } + }.bind(this); + Services.obs.addObserver(delayedStartupObserver, "browser-delayed-startup-finished", false); + yield delayedStartupDeferred.promise; + } + + // Disable lightweight themes while in customization mode since + // they don't have large enough images to pad the full browser window. + if (this.document.documentElement._lightweightTheme) + this.document.documentElement._lightweightTheme.disable(); + + this.dispatchToolboxEvent("beforecustomization"); + + let window = this.window; + let document = this.document; + + // Add a keypress listener to the document so that we can quickly exit + // customization mode when pressing ESC. + document.addEventListener("keypress", this); + + // Same goes for the menu button - if we're customizing, a mousedown to the + // menu button means a quick exit from customization mode. + window.PanelUI.hide(); + window.PanelUI.menuButton.addEventListener("mousedown", this); + window.PanelUI.menuButton.open = true; + window.PanelUI.beginBatchUpdate(); + + // Move the mainView in the panel to the holder so that we can see it + // while customizing. + let panelHolder = document.getElementById("customization-panelHolder"); + panelHolder.appendChild(window.PanelUI.mainView); + + this._transitioning = true; + + let customizer = document.getElementById("customization-container"); + customizer.parentNode.selectedPanel = customizer; + customizer.hidden = false; + + yield this._doTransition(true); + + // Let everybody in this window know that we're about to customize. + this.dispatchToolboxEvent("customizationstarting"); + + // The menu panel is lazy, and registers itself when the popup shows. We + // need to force the menu panel to register itself, or else customization + // is really not going to work. We pass "true" to ensureRegistered to + // indicate that we're handling calling startBatchUpdate and + // endBatchUpdate. + yield window.PanelUI.ensureReady(true); + + this._showPanelCustomizationPlaceholders(); + CustomizableUI.addListener(this); + + yield this._wrapToolbarItems(); + yield this.populatePalette(); + + window.PanelUI.mainView.addEventListener("contextmenu", this, true); + this.visiblePalette.addEventListener("dragstart", this, true); + this.visiblePalette.addEventListener("dragover", this, true); + this.visiblePalette.addEventListener("dragexit", this, true); + this.visiblePalette.addEventListener("drop", this, true); + this.visiblePalette.addEventListener("dragend", this, true); + + window.gNavToolbox.addEventListener("toolbarvisibilitychange", this); + + document.getElementById("PanelUI-help").setAttribute("disabled", true); + document.getElementById("PanelUI-quit").setAttribute("disabled", true); + + this._updateResetButton(); + + this._skipSourceNodeCheck = Services.prefs.getPrefType(kSkipSourceNodePref) == Ci.nsIPrefBranch.PREF_BOOL && + Services.prefs.getBoolPref(kSkipSourceNodePref); + + let customizableToolbars = document.querySelectorAll("toolbar[customizable=true]:not([autohide=true]):not([collapsed=true])"); + for (let toolbar of customizableToolbars) + toolbar.setAttribute("customizing", true); + + window.PanelUI.endBatchUpdate(); + this._customizing = true; + this._transitioning = false; + this.dispatchToolboxEvent("customizationready"); + }.bind(this)).then(null, ERROR); + }, + + exit: function() { + if (!this._customizing || this._transitioning) { + return; + } + + CustomizableUI.removeListener(this); + + this.document.removeEventListener("keypress", this); + this.window.PanelUI.menuButton.removeEventListener("mousedown", this); + this.window.PanelUI.menuButton.open = false; + + this.window.PanelUI.beginBatchUpdate(); + + this._removePanelCustomizationPlaceholders(); + + this._transitioning = true; + + let window = this.window; + let document = this.document; + let documentElement = document.documentElement; + + Task.spawn(function() { + yield this.depopulatePalette(); + + yield this._doTransition(false); + + let customizer = document.getElementById("customization-container"); + customizer.hidden = true; + let browser = document.getElementById("browser"); + browser.parentNode.selectedPanel = browser; + + window.gNavToolbox.removeEventListener("toolbarvisibilitychange", this); + + window.PanelUI.mainView.removeEventListener("contextmenu", this, true); + this.visiblePalette.removeEventListener("dragstart", this, true); + this.visiblePalette.removeEventListener("dragover", this, true); + this.visiblePalette.removeEventListener("dragexit", this, true); + this.visiblePalette.removeEventListener("drop", this, true); + this.visiblePalette.removeEventListener("dragend", this, true); + + yield this._unwrapToolbarItems(); + + if (this._changed) { + // XXXmconley: At first, it seems strange to also persist the old way with + // currentset - but this might actually be useful for switching + // to old builds. We might want to keep this around for a little + // bit. + this.persistCurrentSets(); + } + + // And drop all area references. + this.areas = []; + + // Let everybody in this window know that we're starting to + // exit customization mode. + this.dispatchToolboxEvent("customizationending"); + + window.PanelUI.setMainView(window.PanelUI.mainView); + window.PanelUI.menuButton.disabled = false; + + // We have to use setAttribute/removeAttribute here instead of the + // property because the XBL property will be set later, and right + // now we'd be setting an expando, which breaks the XBL property. + document.getElementById("PanelUI-help").removeAttribute("disabled"); + document.getElementById("PanelUI-quit").removeAttribute("disabled"); + + // We need to set this._customizing to false before removing the tab + // or the TabSelect event handler will think that we are exiting + // customization mode for a second time. + this._customizing = false; + + if (this.browser.selectedBrowser.currentURI.spec == kAboutURI) { + let custBrowser = this.browser.selectedBrowser; + if (custBrowser.canGoBack) { + // If there's history to this tab, just go back. + custBrowser.goBack(); + } else { + // If we can't go back, we're removing the about:customization tab. + // We only do this if we're the top window for this window (so not + // a dialog window, for example). + if (window.getTopWin(true) == window) { + let customizationTab = this.browser.selectedTab; + if (this.browser.browsers.length == 1) { + window.BrowserOpenTab(); + } + this.browser.removeTab(customizationTab); + } + } + } + + if (this.document.documentElement._lightweightTheme) + this.document.documentElement._lightweightTheme.enable(); + + let customizableToolbars = document.querySelectorAll("toolbar[customizable=true]:not([autohide=true])"); + for (let toolbar of customizableToolbars) + toolbar.removeAttribute("customizing"); + + this.window.PanelUI.endBatchUpdate(); + this._changed = false; + this._transitioning = false; + this.dispatchToolboxEvent("aftercustomization"); + }.bind(this)).then(null, ERROR); + }, + + /** + * The customize mode transition has 3 phases when entering: + * 1) Pre-customization mode + * This is the starting phase of the browser. + * 2) customize-entering + * This phase is a transition, optimized for smoothness. + * 3) customize-entered + * After the transition completes, this phase draws all of the + * expensive detail that isn't necessary during the second phase. + * + * Exiting customization mode has a similar set of phases, but in reverse + * order - customize-entered, customize-exiting, pre-customization mode. + * + * When in the customize-entering, customize-entered, or customize-exiting + * phases, there is a "customizing" attribute set on the main-window to simplify + * excluding certain styles while in any phase of customize mode. + */ + _doTransition: function(aEntering) { + let deferred = Promise.defer(); + let deck = this.document.getElementById("tab-view-deck"); + + let customizeTransitionEnd = function(aEvent) { + if (aEvent.originalTarget != deck || aEvent.propertyName != "padding-bottom") { + return; + } + deck.removeEventListener("transitionend", customizeTransitionEnd); + + if (!aEntering) { + this.document.documentElement.removeAttribute("customize-exiting"); + this.document.documentElement.removeAttribute("customizing"); + } else { + this.document.documentElement.setAttribute("customize-entered", true); + this.document.documentElement.removeAttribute("customize-entering"); + } + this.dispatchToolboxEvent("customization-transitionend", aEntering); + + deferred.resolve(); + }.bind(this); + deck.addEventListener("transitionend", customizeTransitionEnd); + + if (gDisableAnimation) { + deck.setAttribute("fastcustomizeanimation", true); + } + if (aEntering) { + this.document.documentElement.setAttribute("customizing", true); + this.document.documentElement.setAttribute("customize-entering", true); + } else { + this.document.documentElement.setAttribute("customize-exiting", true); + this.document.documentElement.removeAttribute("customize-entered"); + } + return deferred.promise; + }, + + dispatchToolboxEvent: function(aEventType, aDetails={}) { + let evt = this.document.createEvent("CustomEvent"); + evt.initCustomEvent(aEventType, true, true, {changed: this._changed}); + let result = this.window.gNavToolbox.dispatchEvent(evt); + }, + + addToToolbar: function(aNode) { + CustomizableUI.addWidgetToArea(aNode.id, CustomizableUI.AREA_NAVBAR); + }, + + removeFromPanel: function(aNode) { + CustomizableUI.removeWidgetFromArea(aNode.id); + }, + + populatePalette: function() { + let fragment = this.document.createDocumentFragment(); + let toolboxPalette = this.window.gNavToolbox.palette; + + return Task.spawn(function() { + let unusedWidgets = CustomizableUI.getUnusedWidgets(toolboxPalette); + for (let widget of unusedWidgets) { + let paletteItem = this.makePaletteItem(widget, "palette"); + fragment.appendChild(paletteItem); + } + + this.visiblePalette.appendChild(fragment); + this._stowedPalette = this.window.gNavToolbox.palette; + this.window.gNavToolbox.palette = this.visiblePalette; + }.bind(this)).then(null, ERROR); + }, + + //XXXunf Maybe this should use -moz-element instead of wrapping the node? + // Would ensure no weird interactions/event handling from original node, + // and makes it possible to put this in a lazy-loaded iframe/real tab + // while still getting rid of the need for overlays. + makePaletteItem: function(aWidget, aPlace) { + let widgetNode = aWidget.forWindow(this.window).node; + let wrapper = this.createWrapper(widgetNode, aPlace); + wrapper.appendChild(widgetNode); + return wrapper; + }, + + depopulatePalette: function() { + return Task.spawn(function() { + this.visiblePalette.hidden = true; + let paletteChild = this.visiblePalette.firstChild; + let nextChild; + while (paletteChild) { + nextChild = paletteChild.nextElementSibling; + let provider = CustomizableUI.getWidget(paletteChild.id).provider; + if (provider == CustomizableUI.PROVIDER_XUL) { + let unwrappedPaletteItem = + yield this.deferredUnwrapToolbarItem(paletteChild); + this._stowedPalette.appendChild(unwrappedPaletteItem); + } else if (provider == CustomizableUI.PROVIDER_API) { + //XXXunf Currently this doesn't destroy the (now unused) node. It would + // be good to do so, but we need to keep strong refs to it in + // CustomizableUI (can't iterate of WeakMaps), and there's the + // question of what behavior wrappers should have if consumers + // keep hold of them. + //widget.destroyInstance(widgetNode); + } else if (provider == CustomizableUI.PROVIDER_SPECIAL) { + this.visiblePalette.removeChild(paletteChild); + } + + paletteChild = nextChild; + } + this.visiblePalette.hidden = false; + this.window.gNavToolbox.palette = this._stowedPalette; + }.bind(this)).then(null, ERROR); + }, + + isCustomizableItem: function(aNode) { + return aNode.localName == "toolbarbutton" || + aNode.localName == "toolbaritem" || + aNode.localName == "toolbarseparator" || + aNode.localName == "toolbarspring" || + aNode.localName == "toolbarspacer"; + }, + + isWrappedToolbarItem: function(aNode) { + return aNode.localName == "toolbarpaletteitem"; + }, + + deferredWrapToolbarItem: function(aNode, aPlace) { + let deferred = Promise.defer(); + + dispatchFunction(function() { + let wrapper = this.wrapToolbarItem(aNode, aPlace); + deferred.resolve(wrapper); + }.bind(this)) + + return deferred.promise; + }, + + wrapToolbarItem: function(aNode, aPlace) { + if (!this.isCustomizableItem(aNode)) { + return aNode; + } + let wrapper = this.createWrapper(aNode, aPlace); + // It's possible that this toolbar node is "mid-flight" and doesn't have + // a parent, in which case we skip replacing it. This can happen if a + // toolbar item has been dragged into the palette. In that case, we tell + // CustomizableUI to remove the widget from its area before putting the + // widget in the palette - so the node will have no parent. + if (aNode.parentNode) { + aNode = aNode.parentNode.replaceChild(wrapper, aNode); + } + wrapper.appendChild(aNode); + return wrapper; + }, + + createWrapper: function(aNode, aPlace) { + let wrapper = this.document.createElement("toolbarpaletteitem"); + + // "place" is used by toolkit to add the toolbarpaletteitem-palette + // binding to a toolbarpaletteitem, which gives it a label node for when + // it's sitting in the palette. + wrapper.setAttribute("place", aPlace); + + // Ensure the wrapped item doesn't look like it's in any special state, and + // can't be interactved with when in the customization palette. + if (aNode.hasAttribute("command")) { + wrapper.setAttribute("itemcommand", aNode.getAttribute("command")); + aNode.removeAttribute("command"); + } + + if (aNode.checked) { + wrapper.setAttribute("itemchecked", "true"); + aNode.checked = false; + } + + if (aNode.hasAttribute("id")) { + wrapper.setAttribute("id", "wrapper-" + aNode.getAttribute("id")); + } + + if (aNode.hasAttribute("title")) { + wrapper.setAttribute("title", aNode.getAttribute("title")); + } else if (aNode.hasAttribute("label")) { + wrapper.setAttribute("title", aNode.getAttribute("label")); + } + + if (aNode.hasAttribute("flex")) { + wrapper.setAttribute("flex", aNode.getAttribute("flex")); + } + + wrapper.addEventListener("mousedown", this); + wrapper.addEventListener("mouseup", this); + + return wrapper; + }, + + deferredUnwrapToolbarItem: function(aWrapper) { + let deferred = Promise.defer(); + dispatchFunction(function() { + deferred.resolve(this.unwrapToolbarItem(aWrapper)); + }.bind(this)); + return deferred.promise; + }, + + unwrapToolbarItem: function(aWrapper) { + if (aWrapper.nodeName != "toolbarpaletteitem") { + return aWrapper; + } + aWrapper.removeEventListener("mousedown", this); + aWrapper.removeEventListener("mouseup", this); + + let toolbarItem = aWrapper.firstChild; + if (!toolbarItem) { + ERROR("no toolbarItem child for " + aWrapper.tagName + "#" + aWrapper.id); + } + + if (aWrapper.hasAttribute("itemchecked")) { + toolbarItem.checked = true; + } + + if (aWrapper.hasAttribute("itemcommand")) { + let commandID = aWrapper.getAttribute("itemcommand"); + toolbarItem.setAttribute("command", commandID); + + //XXX Bug 309953 - toolbarbuttons aren't in sync with their commands after customizing + let command = this.document.getElementById(commandID); + if (command && command.hasAttribute("disabled")) { + toolbarItem.setAttribute("disabled", command.getAttribute("disabled")); + } + } + + if (aWrapper.parentNode) { + aWrapper.parentNode.replaceChild(toolbarItem, aWrapper); + } + return toolbarItem; + }, + + _wrapToolbarItems: function() { + let window = this.window; + // Add drag-and-drop event handlers to all of the customizable areas. + return Task.spawn(function() { + this.areas = []; + for (let area of CustomizableUI.areas) { + let target = CustomizableUI.getCustomizeTargetForArea(area, window); + target.addEventListener("dragstart", this, true); + target.addEventListener("dragover", this, true); + target.addEventListener("dragexit", this, true); + target.addEventListener("drop", this, true); + target.addEventListener("dragend", this, true); + for (let child of target.children) { + if (this.isCustomizableItem(child)) { + yield this.deferredWrapToolbarItem(child, getPlaceForItem(child)); + } + } + this.areas.push(target); + } + }.bind(this)).then(null, ERROR); + }, + + _wrapItemsInArea: function(target) { + for (let child of target.children) { + if (this.isCustomizableItem(child)) { + this.wrapToolbarItem(child, getPlaceForItem(child)); + } + } + }, + + _unwrapItemsInArea: function(target) { + for (let toolbarItem of target.children) { + if (this.isWrappedToolbarItem(toolbarItem)) { + this.unwrapToolbarItem(toolbarItem); + } + } + }, + + _unwrapToolbarItems: function() { + return Task.spawn(function() { + for (let target of this.areas) { + for (let toolbarItem of target.children) { + if (this.isWrappedToolbarItem(toolbarItem)) { + yield this.deferredUnwrapToolbarItem(toolbarItem); + } + } + target.removeEventListener("dragstart", this, true); + target.removeEventListener("dragover", this, true); + target.removeEventListener("dragexit", this, true); + target.removeEventListener("drop", this, true); + target.removeEventListener("dragend", this, true); + } + }.bind(this)).then(null, ERROR); + }, + + persistCurrentSets: function(aSetBeforePersisting) { + let document = this.document; + let toolbars = document.querySelectorAll("toolbar[customizable='true'][currentset]"); + for (let toolbar of toolbars) { + if (aSetBeforePersisting) { + let set = toolbar.currentSet; + toolbar.setAttribute("currentset", set); + } + // Persist the currentset attribute directly on hardcoded toolbars. + document.persist(toolbar.id, "currentset"); + } + }, + + reset: function() { + this.resetting = true; + return Task.spawn(function() { + this._removePanelCustomizationPlaceholders(); + yield this.depopulatePalette(); + yield this._unwrapToolbarItems(); + + CustomizableUI.reset(); + + yield this._wrapToolbarItems(); + yield this.populatePalette(); + + this.persistCurrentSets(true); + + this._updateResetButton(); + this._showPanelCustomizationPlaceholders(); + this.resetting = false; + }.bind(this)).then(null, ERROR); + }, + + _onToolbarVisibilityChange: function(aEvent) { + let toolbar = aEvent.target; + if (aEvent.detail.visible) { + toolbar.setAttribute("customizing", "true"); + } else { + toolbar.removeAttribute("customizing"); + } + }, + + onWidgetMoved: function(aWidgetId, aArea, aOldPosition, aNewPosition) { + this._onUIChange(); + }, + + onWidgetAdded: function(aWidgetId, aArea, aPosition) { + this._onUIChange(); + }, + + onWidgetRemoved: function(aWidgetId, aArea) { + this._onUIChange(); + }, + + onWidgetBeforeDOMChange: function(aNodeToChange, aSecondaryNode, aContainer) { + if (aContainer.ownerDocument.defaultView != this.window || this.resetting) { + return; + } + if (aContainer.id == CustomizableUI.AREA_PANEL) { + this._removePanelCustomizationPlaceholders(); + } + // If we get called for widgets that aren't in the window yet, they might not have + // a parentNode at all. + if (aNodeToChange.parentNode) { + this.unwrapToolbarItem(aNodeToChange.parentNode); + } + if (aSecondaryNode) { + this.unwrapToolbarItem(aSecondaryNode.parentNode); + } + }, + + onWidgetAfterDOMChange: function(aNodeToChange, aSecondaryNode, aContainer) { + if (aContainer.ownerDocument.defaultView != this.window || this.resetting) { + return; + } + // If the node is still attached to the container, wrap it again: + if (aNodeToChange.parentNode) { + let place = getPlaceForItem(aNodeToChange); + this.wrapToolbarItem(aNodeToChange, place); + if (aSecondaryNode) { + this.wrapToolbarItem(aSecondaryNode, place); + } + } else { + // If not, it got removed. + + // If an API-based widget is removed while customizing, append it to the palette. + // The _applyDrop code itself will take care of positioning it correctly, if + // applicable. We need the code to be here so removing widgets using CustomizableUI's + // API also does the right thing (and adds it to the palette) + let widgetId = aNodeToChange.id; + let widget = CustomizableUI.getWidget(widgetId); + if (widget.provider == CustomizableUI.PROVIDER_API) { + let paletteItem = this.makePaletteItem(widget, "palette"); + this.visiblePalette.appendChild(paletteItem); + } + } + if (aContainer.id == CustomizableUI.AREA_PANEL) { + this._showPanelCustomizationPlaceholders(); + } + }, + + onWidgetDestroyed: function(aWidgetId) { + let wrapper = this.document.getElementById("wrapper-" + aWidgetId); + if (wrapper) { + let wasInPanel = wrapper.parentNode == this.panelUIContents; + wrapper.remove(); + if (wasInPanel) { + this._showPanelCustomizationPlaceholders(); + } + } + }, + + onWidgetAfterCreation: function(aWidgetId, aArea) { + // If the node was added to an area, we would have gotten an onWidgetAdded notification, + // plus associated DOM change notifications, so only do stuff for the palette: + if (!aArea) { + let widgetNode = this.document.getElementById(aWidgetId); + if (widgetNode) { + this.wrapToolbarItem(widgetNode, "palette"); + } else { + let widget = CustomizableUI.getWidget(aWidgetId); + this.visiblePalette.appendChild(this.makePaletteItem(widget, "palette")); + } + } + }, + + _onUIChange: function() { + this._changed = true; + this._updateResetButton(); + this.dispatchToolboxEvent("customizationchange"); + }, + + _updateResetButton: function() { + let btn = this.document.getElementById("customization-reset-button"); + btn.disabled = CustomizableUI.inDefaultState; + }, + + handleEvent: function(aEvent) { + switch(aEvent.type) { + case "toolbarvisibilitychange": + this._onToolbarVisibilityChange(aEvent); + break; + case "contextmenu": + aEvent.preventDefault(); + aEvent.stopPropagation(); + break; + case "dragstart": + this._onDragStart(aEvent); + break; + case "dragover": + this._onDragOver(aEvent); + break; + case "drop": + this._onDragDrop(aEvent); + break; + case "dragexit": + this._onDragExit(aEvent); + break; + case "dragend": + this._onDragEnd(aEvent); + break; + case "mousedown": + if (aEvent.button == 0 && + (aEvent.originalTarget == this.window.PanelUI.menuButton)) { + this.exit(); + aEvent.preventDefault(); + return; + } + this._onMouseDown(aEvent); + break; + case "mouseup": + this._onMouseUp(aEvent); + break; + case "keypress": + if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE) { + this.exit(); + } + break; + } + }, + + _onDragStart: function(aEvent) { + __dumpDragData(aEvent); + let item = aEvent.target; + while (item && item.localName != "toolbarpaletteitem") { + if (item.localName == "toolbar" || + item.classList.contains(kPlaceholderClass)) { + return; + } + item = item.parentNode; + } + + let dt = aEvent.dataTransfer; + let documentId = aEvent.target.ownerDocument.documentElement.id; + let draggedItem = item.firstChild; + + dt.mozSetDataAt(kDragDataTypePrefix + documentId, draggedItem.id, 0); + dt.effectAllowed = "move"; + + let itemRect = draggedItem.getBoundingClientRect(); + let itemCenter = {x: itemRect.left + itemRect.width / 2, + y: itemRect.top + itemRect.height / 2}; + this._dragOffset = {x: aEvent.clientX - itemCenter.x, + y: aEvent.clientY - itemCenter.y}; + + // Hack needed so that the dragimage will still show the + // item as it appeared before it was hidden. + let win = aEvent.target.ownerDocument.defaultView; + win.setTimeout(function() { + // For automated tests, we sometimes start exiting customization mode + // before this fires, which leaves us with placeholders inserted after + // we've exited. So we need to check that we are indeed customizing. + if (this._customizing && !this._transitioning) { + item.hidden = true; + this._showPanelCustomizationPlaceholders(); + } + }.bind(this), 0); + }, + + _onDragOver: function(aEvent) { + if (this._isUnwantedDragDrop(aEvent)) { + return; + } + + __dumpDragData(aEvent); + + let document = aEvent.target.ownerDocument; + let documentId = document.documentElement.id; + if (!aEvent.dataTransfer.mozTypesAt(0)) { + return; + } + + let draggedItemId = + aEvent.dataTransfer.mozGetDataAt(kDragDataTypePrefix + documentId, 0); + let draggedWrapper = document.getElementById("wrapper-" + draggedItemId); + let targetArea = this._getCustomizableParent(aEvent.currentTarget); + let originArea = this._getCustomizableParent(draggedWrapper); + + // Do nothing if the target or origin are not customizable. + if (!targetArea || !originArea) { + return; + } + + // Do nothing if the widget is not allowed to be removed. + if (targetArea.id == kPaletteId && + !CustomizableUI.isWidgetRemovable(draggedItemId)) { + return; + } + + // Do nothing if the widget is not allowed to move to the target area. + if (targetArea.id != kPaletteId && + !CustomizableUI.canWidgetMoveToArea(draggedItemId, targetArea.id)) { + return; + } + + let targetNode = this._getDragOverNode(aEvent, targetArea); + + // We need to determine the place that the widget is being dropped in + // the target. + let dragOverItem, dragValue; + if (targetNode == targetArea.customizationTarget) { + // We'll assume if the user is dragging directly over the target, that + // they're attempting to append a child to that target. + dragOverItem = targetNode.lastChild || targetNode; + dragValue = "after"; + } else { + let targetParent = targetNode.parentNode; + let position = Array.indexOf(targetParent.children, targetNode); + if (position == -1) { + dragOverItem = targetParent.lastChild; + dragValue = "after"; + } else { + dragOverItem = targetParent.children[position]; + // Check if the aDraggedItem is hovered past the first half of dragOverItem + let window = dragOverItem.ownerDocument.defaultView; + let direction = window.getComputedStyle(dragOverItem, null).direction; + let itemRect = dragOverItem.getBoundingClientRect(); + let dropTargetCenter = itemRect.left + (itemRect.width / 2); + if (targetParent == window.PanelUI.contents) { + dragValue = "true"; + if (direction == "ltr" && aEvent.clientX > dropTargetCenter) { + position++; + } else if (direction == "rtl" && aEvent.clientX < dropTargetCenter) { + position--; + } + dragOverItem = position == -1 ? targetParent.firstChild : targetParent.children[position]; + } else { + let existingDir = dragOverItem.getAttribute("dragover"); + if ((existingDir == "before") == (direction == "ltr")) { + dropTargetCenter += (parseInt(dragOverItem.style.borderLeftWidth) || 0) / 2; + } else { + dropTargetCenter -= (parseInt(dragOverItem.style.borderRightWidth) || 0) / 2; + } + let before = direction == "ltr" ? aEvent.clientX < dropTargetCenter : aEvent.clientX > dropTargetCenter; + dragValue = before ? "before" : "after"; + } + } + } + + if (this._dragOverItem && dragOverItem != this._dragOverItem) { + this._setDragActive(this._dragOverItem, false); + } + + if (dragOverItem != this._dragOverItem || dragValue != dragOverItem.getAttribute("dragover")) { + if (dragOverItem != targetArea.customizationTarget) { + this._setDragActive(dragOverItem, dragValue, draggedItemId); + } + this._dragOverItem = dragOverItem; + } + + aEvent.preventDefault(); + aEvent.stopPropagation(); + }, + + _onDragDrop: function(aEvent) { + if (this._isUnwantedDragDrop(aEvent)) { + return; + } + + __dumpDragData(aEvent); + + let targetArea = this._getCustomizableParent(aEvent.currentTarget); + let document = aEvent.target.ownerDocument; + let documentId = document.documentElement.id; + let draggedItemId = + aEvent.dataTransfer.mozGetDataAt(kDragDataTypePrefix + documentId, 0); + let draggedWrapper = document.getElementById("wrapper-" + draggedItemId); + let originArea = this._getCustomizableParent(draggedWrapper); + if (this._dragWidthMap) { + this._dragWidthMap.clear(); + } + // Do nothing if the target area or origin area are not customizable. + if (!targetArea || !originArea) { + return; + } + let targetNode = this._dragOverItem; + let dropDir = targetNode.getAttribute("dragover"); + // Need to insert *after* this node if we promised the user that: + if (targetNode != targetArea && dropDir == "after") { + if (targetNode.nextSibling) { + targetNode = targetNode.nextSibling; + } else { + targetNode = targetArea; + } + } + // If the target node is a placeholder, get its sibling as the real target. + while (targetNode.classList.contains(kPlaceholderClass) && targetNode.nextSibling) { + targetNode = targetNode.nextSibling; + } + if (targetNode.tagName == "toolbarpaletteitem") { + targetNode = targetNode.firstChild; + } + + this._setDragActive(this._dragOverItem, false); + this._removePanelCustomizationPlaceholders(); + + try { + this._applyDrop(aEvent, targetArea, originArea, draggedItemId, targetNode); + } catch (ex) { + ERROR(ex, ex.stack); + } + + this._showPanelCustomizationPlaceholders(); + }, + + _applyDrop: function(aEvent, aTargetArea, aOriginArea, aDraggedItemId, aTargetNode) { + let document = aEvent.target.ownerDocument; + let draggedItem = document.getElementById(aDraggedItemId); + draggedItem.hidden = false; + draggedItem.removeAttribute("mousedown"); + + // Do nothing if the target was dropped onto itself (ie, no change in area + // or position). + if (draggedItem == aTargetNode) { + return; + } + + // Is the target area the customization palette? + if (aTargetArea.id == kPaletteId) { + // Did we drag from outside the palette? + if (aOriginArea.id !== kPaletteId) { + if (!CustomizableUI.isWidgetRemovable(aDraggedItemId)) { + return; + } + + CustomizableUI.removeWidgetFromArea(aDraggedItemId); + } + draggedItem = draggedItem.parentNode; + + // If the target node is the palette itself, just append + if (aTargetNode == this.visiblePalette) { + this.visiblePalette.appendChild(draggedItem); + } else { + // The items in the palette are wrapped, so we need the target node's parent here: + this.visiblePalette.insertBefore(draggedItem, aTargetNode.parentNode); + } + return; + } + + if (!CustomizableUI.canWidgetMoveToArea(aDraggedItemId, aTargetArea.id)) { + return; + } + + // Skipintoolbarset items won't really be moved: + if (draggedItem.getAttribute("skipintoolbarset") == "true") { + // These items should never leave their area: + if (aTargetArea != aOriginArea) { + return; + } + let place = draggedItem.parentNode.getAttribute("place"); + this.unwrapToolbarItem(draggedItem.parentNode); + if (aTargetNode == aTargetArea.customizationTarget) { + aTargetArea.customizationTarget.appendChild(draggedItem); + } else { + this.unwrapToolbarItem(aTargetNode.parentNode); + aTargetArea.customizationTarget.insertBefore(draggedItem, aTargetNode); + this.wrapToolbarItem(aTargetNode, place); + } + this.wrapToolbarItem(draggedItem, place); + return; + } + + // Is the target the customization area itself? If so, we just add the + // widget to the end of the area. + if (aTargetNode == aTargetArea.customizationTarget) { + CustomizableUI.addWidgetToArea(aDraggedItemId, aTargetArea.id); + return; + } + + // We need to determine the place that the widget is being dropped in + // the target. + let placement; + let itemForPlacement = aTargetNode; + // Skip the skipintoolbarset items when determining the place of the item: + while (itemForPlacement && itemForPlacement.getAttribute("skipintoolbarset") == "true" && + itemForPlacement.parentNode && + itemForPlacement.parentNode.nodeName == "toolbarpaletteitem") { + itemForPlacement = itemForPlacement.parentNode.nextSibling; + if (itemForPlacement && itemForPlacement.nodeName == "toolbarpaletteitem") { + itemForPlacement = itemForPlacement.firstChild; + } + } + if (itemForPlacement && !itemForPlacement.classList.contains(kPlaceholderClass)) { + let targetNodeId = (itemForPlacement.nodeName == "toolbarpaletteitem") ? + itemForPlacement.firstChild && itemForPlacement.firstChild.id : + itemForPlacement.id; + placement = CustomizableUI.getPlacementOfWidget(targetNodeId); + } + if (!placement) { + LOG("Could not get a position for " + aTargetNode.nodeName + "#" + aTargetNode.id + "." + aTargetNode.className); + } + let position = placement ? placement.position : null; + + + // Is the target area the same as the origin? Since we've already handled + // the possibility that the target is the customization palette, we know + // that the widget is moving within a customizable area. + if (aTargetArea == aOriginArea) { + CustomizableUI.moveWidgetWithinArea(aDraggedItemId, position); + } else { + CustomizableUI.addWidgetToArea(aDraggedItemId, aTargetArea.id, position); + } + // If we dropped onto a skipintoolbarset item, manually correct the drop location: + if (aTargetNode != itemForPlacement) { + let draggedWrapper = draggedItem.parentNode; + let container = draggedWrapper.parentNode; + container.insertBefore(draggedWrapper, aTargetNode.parentNode); + } + }, + + _onDragExit: function(aEvent) { + if (this._isUnwantedDragDrop(aEvent)) { + return; + } + + __dumpDragData(aEvent); + + if (this._dragOverItem) { + this._setDragActive(this._dragOverItem, false); + } + }, + + _onDragEnd: function(aEvent) { + if (this._isUnwantedDragDrop(aEvent)) { + return; + } + + __dumpDragData(aEvent); + let document = aEvent.target.ownerDocument; + document.documentElement.removeAttribute("customizing-movingItem"); + + let documentId = document.documentElement.id; + if (!aEvent.dataTransfer.mozTypesAt(0)) { + return; + } + + let draggedItemId = + aEvent.dataTransfer.mozGetDataAt(kDragDataTypePrefix + documentId, 0); + + let draggedWrapper = document.getElementById("wrapper-" + draggedItemId); + draggedWrapper.hidden = false; + draggedWrapper.removeAttribute("mousedown"); + this._showPanelCustomizationPlaceholders(); + }, + + _isUnwantedDragDrop: function(aEvent) { + // The simulated events generated by synthesizeDragStart/synthesizeDrop in + // mochitests are used only for testing whether the right data is being put + // into the dataTransfer. Neither cause a real drop to occur, so they don't + // set the source node. There isn't a means of testing real drag and drops, + // so this pref skips the check but it should only be set by test code. + if (this._skipSourceNodeCheck) { + return false; + } + + /* Discard drag events that originated from a separate window to + prevent content->chrome privilege escalations. */ + let mozSourceNode = aEvent.dataTransfer.mozSourceNode; + // mozSourceNode is null in the dragStart event handler or if + // the drag event originated in an external application. + return !mozSourceNode || + mozSourceNode.ownerDocument.defaultView != this.window; + }, + + _setDragActive: function(aItem, aValue, aDraggedItemId) { + if (!aItem) { + return; + } + + if (aValue) { + if (aItem.hasAttribute("dragover") != aValue) { + aItem.setAttribute("dragover", aValue); + + // Calculate width of the item when it'd be dropped in this position + let window = aItem.ownerDocument.defaultView; + let draggedItem = window.document.getElementById(aDraggedItemId); + let width = this._getDragItemWidth(aItem, draggedItem); + if (width) { + let panelContents = window.PanelUI.contents; + if (aItem.parentNode == panelContents) { + this._setPanelDragActive(aItem, draggedItem, width); + } else { + let direction = window.getComputedStyle(aItem).direction; + let prop, otherProp; + // If we're inserting before in ltr, or after in rtl: + if ((aValue == "before") == (direction == "ltr")) { + prop = "borderLeftWidth"; + otherProp = "border-right-width"; + } else { + // otherwise: + prop = "borderRightWidth"; + otherProp = "border-left-width"; + } + aItem.style[prop] = width; + aItem.style.removeProperty(otherProp); + } + } + } + } else { + aItem.removeAttribute("dragover"); + // Remove both property values in the case that the end padding + // had been set. + aItem.style.removeProperty("border-left-width"); + aItem.style.removeProperty("border-right-width"); + } + }, + + _setPanelDragActive: function(aDragOverNode, aDraggedItem, aWidth) { + let document = aDragOverNode.ownerDocument; + let window = document.defaultView; + let panelContents = window.PanelUI.contents; + while (!aDragOverNode.id && aDragOverNode.parentNode != panelContents) + aDragOverNode = aDragOverNode.parentNode; + if (!aDragOverNode.id) + return; + + if (!aDragOverNode.previousSibling || + !aDragOverNode.previousSibling.classList.contains(kPlaceholderClass)) { + let isPlaceholderAtEnd = function(aPlaceholder) { + do { + aPlaceholder = aPlaceholder.nextSibling; + if (!aPlaceholder) + return true; + if (!aPlaceholder.classList.contains(kPlaceholderClass)) + return false; + } while (aPlaceholder.nextSibling) + return true; + } + + let resetAnimAttributes = function(aPlaceholder) { + if (!aPlaceholder) + return; + aPlaceholder.removeAttribute("expand"); + aPlaceholder.removeAttribute("contract"); + aPlaceholder.removeAttribute("hidden"); + aPlaceholder.style.removeProperty("width"); + } + + let placeholders = Array.slice(panelContents.getElementsByClassName(kPlaceholderClass)); + + let toExpand = placeholders.shift(); + let toContract = placeholders.shift(); + if (toContract && isPlaceholderAtEnd(toContract)) + toContract = null; + // Seek to find hidden placeholders first to use for the expand transition. + while (toExpand.getAttribute("hidden") != "true" && placeholders.length) + toExpand = placeholders.shift(); + + if (toExpand.transitioning || (toContract && toContract.transitioning)) + return; + + let wasHidden = (toContract && toContract.getAttribute("hidden") == "true") || + toExpand.getAttribute("hidden") == "true"; + resetAnimAttributes(toContract); + resetAnimAttributes(toExpand); + + aDragOverNode.parentNode.insertBefore(toExpand, aDragOverNode); + toExpand.style.width = "0px"; + toExpand.setAttribute("expand", "true"); + toExpand.transitioning = true; + if (toContract) { + toContract.style.width = aWidth; + toContract.setAttribute("contract", "true"); + toContract.transitioning = true; + } + + window.mozRequestAnimationFrame(() => { + if (toContract) + toContract.style.width = "0px"; + toExpand.style.width = aWidth; + }); + toExpand.addEventListener("transitionend", function expandTransitionEnd() { + toExpand.removeEventListener("transitionend", expandTransitionEnd, false); + toExpand.transitioning = false; + }); + if (toContract) { + toContract.addEventListener("transitionend", function contractTransitionEnd() { + toContract.removeEventListener("transitionend", contractTransitionEnd, false); + panelContents.appendChild(toContract); + if (wasHidden) + toContract.setAttribute("hidden", "true"); + toContract.transitioning = false; + }); + } + } + }, + + _getDragItemWidth: function(aDragOverNode, aDraggedItem) { + // Cache it good, cache it real good. + if (!this._dragWidthMap) + this._dragWidthMap = new WeakMap(); + if (!this._dragWidthMap.has(aDraggedItem)) + this._dragWidthMap.set(aDraggedItem, new WeakMap()); + let itemMap = this._dragWidthMap.get(aDraggedItem); + let targetArea = this._getCustomizableParent(aDragOverNode); + if (!targetArea) + return; + // Return the width for this target from cache, if it exists. + let width = itemMap.get(targetArea); + if (width) + return width; + + // Calculate width of the item when it'd be dropped in this position. + let currentParent = aDraggedItem.parentNode; + let currentSibling = aDraggedItem.nextSibling; + + // Move the widget temporarily next to the placeholder. + aDragOverNode.parentNode.insertBefore(aDraggedItem, aDragOverNode); + // Update the node's areaType. + let areaType = CustomizableUI.getAreaType(targetArea.id); + const kAreaType = "cui-areatype"; + let currentType = aDraggedItem.hasAttribute(kAreaType) && + aDraggedItem.getAttribute(kAreaType); + if (areaType) + aDraggedItem.setAttribute(kAreaType, areaType); + CustomizableUI.onWidgetDrag(aDraggedItem.id, targetArea.id); + // Fetch the new width. + width = Math.floor(aDraggedItem.getBoundingClientRect().width) + "px"; + // Put the item back into its previous position. + if (currentSibling) + currentParent.insertBefore(aDraggedItem, currentSibling); + else + currentParent.appendChild(aDraggedItem); + // restore the areaType + if (areaType) { + if (currentType === false) + aDraggedItem.removeAttribute(kAreaType); + else + aDraggedItem.setAttribute(kAreaType, currentType); + } + CustomizableUI.onWidgetDrag(aDraggedItem.id); + // Cache the found value of width for this target. + itemMap.set(targetArea, width); + return width; + }, + + _getCustomizableParent: function(aElement) { + let areas = CustomizableUI.areas; + areas.push(kPaletteId); + while (aElement) { + if (areas.indexOf(aElement.id) != -1) { + return aElement; + } + aElement = aElement.parentNode; + } + return null; + }, + + _getDragOverNode: function(aEvent, aAreaElement) { + let expectedParent = aAreaElement.customizationTarget || aAreaElement; + // Our tests are stupid. Cope: + if (!aEvent.clientX && !aEvent.clientY) { + return aEvent.target; + } + // Offset the drag event's position with the offset to the center of + // the thing we're dragging + let dragX = aEvent.clientX - this._dragOffset.x; + let dragY = aEvent.clientY - this._dragOffset.y; + + // Ensure this is within the container + let bounds = expectedParent.getBoundingClientRect(); + dragX = Math.min(bounds.right, Math.max(dragX, bounds.left)); + dragY = Math.min(bounds.bottom, Math.max(dragY, bounds.top)); + + let targetNode = aAreaElement.ownerDocument.elementFromPoint(dragX, dragY); + while (targetNode && targetNode.parentNode != expectedParent) { + targetNode = targetNode.parentNode; + } + return targetNode || aEvent.target; + }, + + _onMouseDown: function(aEvent) { + LOG("_onMouseDown"); + let doc = aEvent.target.ownerDocument; + doc.documentElement.setAttribute("customizing-movingItem", true); + let item = this._getWrapper(aEvent.target); + if (item) { + item.setAttribute("mousedown", "true"); + } + }, + + _onMouseUp: function(aEvent) { + LOG("_onMouseUp"); + let doc = aEvent.target.ownerDocument; + doc.documentElement.removeAttribute("customizing-movingItem"); + let item = this._getWrapper(aEvent.target); + if (item) { + item.removeAttribute("mousedown"); + } + }, + + _getWrapper: function(aElement) { + while (aElement && aElement.localName != "toolbarpaletteitem") { + if (aElement.localName == "toolbar") + return null; + aElement = aElement.parentNode; + } + return aElement; + }, + + _showPanelCustomizationPlaceholders: function() { + this._removePanelCustomizationPlaceholders(); + let doc = this.document; + let contents = this.panelUIContents; + let visibleWideItems = contents.querySelectorAll("toolbarpaletteitem:not([hidden]) > ." + kWidePanelItemClass); + let visibleChildren = contents.querySelectorAll("toolbarpaletteitem:not([hidden])"); + // TODO(bug 885578): Still doesn't handle a hole when there is a wide + // widget located at the bottom of the panel. + let narrowItemsAfterWideItem = 0; + let node = contents.lastChild; + while (node && !node.classList.contains(kWidePanelItemClass) && + (!node.firstChild || !node.firstChild.classList.contains(kWidePanelItemClass))) { + if (!node.hidden) { + narrowItemsAfterWideItem++; + } + node = node.previousSibling; + } + + let orphanedItems = narrowItemsAfterWideItem % kColumnsInMenuPanel; + let placeholders = kColumnsInMenuPanel - orphanedItems; + + while (placeholders--) { + let placeholder = doc.createElement("toolbarpaletteitem"); + placeholder.classList.add(kPlaceholderClass); + //XXXjaws The toolbarbutton child here is only necessary to get + // the styling right here. + let placeholderChild = doc.createElement("toolbarbutton"); + placeholderChild.classList.add(kPlaceholderClass + "-child"); + placeholder.appendChild(placeholderChild); + contents.appendChild(placeholder); + } + }, + + _removePanelCustomizationPlaceholders: function() { + let contents = this.panelUIContents; + let oldPlaceholders = contents.getElementsByClassName(kPlaceholderClass); + while (oldPlaceholders.length) { + contents.removeChild(oldPlaceholders[0]); + } + } +}; + +function getPlaceForItem(aElement) { + let place; + let node = aElement; + while (node && !place) { + if (node.localName == "toolbar") + place = "toolbar"; + else if (node.id == CustomizableUI.AREA_PANEL) + place = "panel"; + else if (node.id == kPaletteId) + place = "palette"; + + node = node.parentNode; + } + return place; +} + +function __dumpDragData(aEvent, caller) { + let str = "Dumping drag data (CustomizeMode.jsm) {\n"; + str += " type: " + aEvent["type"] + "\n"; + for (let el of ["target", "currentTarget", "relatedTarget"]) { + if (aEvent[el]) { + str += " " + el + ": " + aEvent[el] + "(localName=" + aEvent[el].localName + "; id=" + aEvent[el].id + ")\n"; + } + } + for (let prop in aEvent.dataTransfer) { + if (typeof aEvent.dataTransfer[prop] != "function") { + str += " dataTransfer[" + prop + "]: " + aEvent.dataTransfer[prop] + "\n"; + } + } + str += "}"; + LOG(str); +} + +function dispatchFunction(aFunc) { + Services.tm.currentThread.dispatch(aFunc, Ci.nsIThread.DISPATCH_NORMAL); +} diff --git a/browser/components/customizableui/src/PanelWideWidgetTracker.jsm b/browser/components/customizableui/src/PanelWideWidgetTracker.jsm new file mode 100644 index 0000000000000000000000000000000000000000..8aa28a7ab0f7188620c0cee10c0b9621397e912a --- /dev/null +++ b/browser/components/customizableui/src/PanelWideWidgetTracker.jsm @@ -0,0 +1,183 @@ +/* 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"; +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; + +this.EXPORTED_SYMBOLS = ["PanelWideWidgetTracker"]; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI", + "resource:///modules/CustomizableUI.jsm"); + +let gModuleName = "[PanelWideWidgetTracker]"; +#include logging.js + +let gPanel = CustomizableUI.AREA_PANEL; +// We keep track of the widget placements for the panel locally: +let gPanelPlacements = []; + +// All the wide widgets we know of: +let gWideWidgets = new Set(); +// All the widgets we know of: +let gSeenWidgets = new Set(); + +// The class by which we recognize wide widgets: +const kWidePanelItemClass = "panel-wide-item"; + +// TODO(bug 885574): Merge this constant with the one in CustomizeMode.jsm, +// maybe just use a pref for this. +const kColumnsInMenuPanel = 3; + +let PanelWideWidgetTracker = { + // Listeners used to validate panel contents whenever they change: + onWidgetAdded: function(aWidgetId, aArea, aPosition) { + if (aArea == gPanel) { + gPanelPlacements = CustomizableUI.getWidgetIdsInArea(gPanel); + let moveForward = this.shouldMoveForward(aWidgetId, aPosition); + this.adjustWidgets(aWidgetId, moveForward); + } + }, + onWidgetMoved: function(aWidgetId, aArea, aOldPosition, aNewPosition) { + if (aArea == gPanel) { + gPanelPlacements = CustomizableUI.getWidgetIdsInArea(gPanel); + let moveForward = this.shouldMoveForward(aWidgetId, aNewPosition); + this.adjustWidgets(aWidgetId, moveForward); + } + }, + onWidgetRemoved: function(aWidgetId, aPrevArea) { + if (aPrevArea == gPanel) { + gPanelPlacements = CustomizableUI.getWidgetIdsInArea(gPanel); + let pos = gPanelPlacements.indexOf(aWidgetId); + this.adjustWidgets(aWidgetId, false); + } + }, + onWidgetReset: function(aWidgetId) { + gPanelPlacements = CustomizableUI.getWidgetIdsInArea(gPanel); + }, + // Listener to keep abreast of any new nodes. We use the DOM one because + // we need access to the actual node's classlist, so we can't use the ones above. + // Furthermore, onWidgetCreated only fires for API-based widgets, not for XUL ones. + onWidgetAfterDOMChange: function(aNode, aNextNode, aContainer) { + if (!gSeenWidgets.has(aNode.id)) { + if (aNode.classList.contains(kWidePanelItemClass)) { + gWideWidgets.add(aNode.id); + } + gSeenWidgets.add(aNode.id); + } + }, + // When widgets get destroyed, we remove them from our sets of stuff we care about: + onWidgetDestroyed: function(aWidgetId) { + gSeenWidgets.delete(aWidgetId); + gWideWidgets.delete(aWidgetId); + }, + shouldMoveForward: function(aWidgetId, aPosition) { + let currentWidgetAtPosition = gPanelPlacements[aPosition + 1]; + let rv = gWideWidgets.has(currentWidgetAtPosition) && !gWideWidgets.has(aWidgetId); + // We might now think we can move forward, but for that we need at least 2 more small + // widgets to be present: + if (rv) { + let furtherWidgets = gPanelPlacements.slice(aPosition + 2); + let realWidgets = 0; + if (furtherWidgets.length >= 2) { + while (furtherWidgets.length && realWidgets < 2) { + let w = furtherWidgets.shift(); + if (!gWideWidgets.has(w) && this.checkWidgetStatus(w)) { + realWidgets++; + } + } + } + if (realWidgets < 2) { + rv = false; + } + } + return rv; + }, + adjustWidgets: function(aWidgetId, aMoveForwards) { + if (this.adjusting) { + return; + } + this.adjusting = true; + let widgetsAffected = [w for (w of gPanelPlacements) if (gWideWidgets.has(w))]; + // If we're moving the wide widgets forwards (down/to the right in the panel) + // we want to start with the last widgets. Otherwise we move widgets over other wide + // widgets, which might mess up their order. Likewise, if moving backwards we should start with + // the first widget and work our way down/right from there. + let compareFn = aMoveForwards ? (function(a, b) a < b) : (function(a, b) a > b) + widgetsAffected.sort(function(a, b) compareFn(gPanelPlacements.indexOf(a), + gPanelPlacements.indexOf(b))); + for (let widget of widgetsAffected) { + this.adjustPosition(widget, aMoveForwards); + } + this.adjusting = false; + }, + // This function is called whenever an item gets moved in the menu panel. It + // adjusts the position of widgets within the panel to prevent "gaps" between + // wide widgets that could be filled up with single column widgets + adjustPosition: function(aWidgetId, aMoveForwards) { + // Make sure that there are n % columns = 0 narrow buttons before the widget. + let placementIndex = gPanelPlacements.indexOf(aWidgetId); + let prevSiblingCount = 0; + let fixedPos = null; + while (placementIndex--) { + let thisWidgetId = gPanelPlacements[placementIndex]; + if (gWideWidgets.has(thisWidgetId)) { + continue; + } + let widgetStatus = this.checkWidgetStatus(thisWidgetId); + if (!widgetStatus) { + continue; + } + if (widgetStatus == "public-only") { + fixedPos = !fixedPos ? placementIndex : Math.min(fixedPos, placementIndex); + prevSiblingCount = 0; + } else { + prevSiblingCount++; + } + } + + if (fixedPos !== null || prevSiblingCount % kColumnsInMenuPanel) { + let desiredPos = (fixedPos !== null) ? fixedPos : gPanelPlacements.indexOf(aWidgetId); + let desiredChange = -(prevSiblingCount % kColumnsInMenuPanel); + if (aMoveForwards && fixedPos == null) { + // +1 because otherwise we'd count ourselves: + desiredChange = kColumnsInMenuPanel + desiredChange + 1; + } + desiredPos += desiredChange; + CustomizableUI.moveWidgetWithinArea(aWidgetId, desiredPos); + } + }, + + /* + * Check whether a widget id is actually known anywhere. + * @returns false if the widget doesn't exist, + * "public-only" if it's not shown in private windows + * "real" if it does exist and is shown even in private windows + */ + checkWidgetStatus: function(aWidgetId) { + let widgetWrapper = CustomizableUI.getWidget(aWidgetId); + // This widget might not actually exist: + if (!widgetWrapper) { + return false; + } + // This widget might still not actually exist: + if (widgetWrapper.provider == CustomizableUI.PROVIDER_XUL && + widgetWrapper.instances.length == 0) { + return false; + } + + // Or it might only be there some of the time: + if (widgetWrapper.provider == CustomizableUI.PROVIDER_API && + widgetWrapper.showInPrivateBrowsing === false) { + return "public-only"; + } + return "real"; + }, + + init: function() { + // Initialize our local placements copy and register the listener + gPanelPlacements = CustomizableUI.getWidgetIdsInArea(gPanel); + CustomizableUI.addListener(this); + }, +}; diff --git a/browser/components/customizableui/src/ScrollbarSampler.jsm b/browser/components/customizableui/src/ScrollbarSampler.jsm new file mode 100644 index 0000000000000000000000000000000000000000..374d918113d4eea771bb27a5d94fe069b2658df8 --- /dev/null +++ b/browser/components/customizableui/src/ScrollbarSampler.jsm @@ -0,0 +1,66 @@ +/* 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"; + +this.EXPORTED_SYMBOLS = ["ScrollbarSampler"]; + +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Promise", + "resource://gre/modules/Promise.jsm"); + +let gSystemScrollbarWidth = null; + +this.ScrollbarSampler = { + getSystemScrollbarWidth: function() { + let deferred = Promise.defer(); + + if (gSystemScrollbarWidth !== null) { + deferred.resolve(gSystemScrollbarWidth); + return deferred.promise; + } + + this._sampleSystemScrollbarWidth().then(function(systemScrollbarWidth) { + gSystemScrollbarWidth = systemScrollbarWidth; + deferred.resolve(gSystemScrollbarWidth); + }); + return deferred.promise; + }, + + _sampleSystemScrollbarWidth: function() { + let deferred = Promise.defer(); + let hwin = Services.appShell.hiddenDOMWindow; + let hdoc = hwin.document.documentElement; + let iframe = hwin.document.createElementNS("http://www.w3.org/1999/xhtml", + "html:iframe"); + iframe.setAttribute("srcdoc", '<body style="overflow-y: scroll"></body>'); + hdoc.appendChild(iframe); + + let cwindow = iframe.contentWindow; + let utils = cwindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + + cwindow.addEventListener("load", function onLoad(aEvent) { + cwindow.removeEventListener("load", onLoad); + let sbWidth = {}; + try { + utils.getScrollbarSize(true, sbWidth, {}); + } catch(e) { + Cu.reportError("Could not sample scrollbar size: " + e + " -- " + + e.stack); + sbWidth.value = 0; + } + // Minimum width of 10 so that we have enough padding: + sbWidth.value = Math.max(sbWidth.value, 10); + deferred.resolve(sbWidth.value); + iframe.remove(); + }); + + return deferred.promise; + } +}; +Object.freeze(this.ScrollbarSampler); diff --git a/browser/components/customizableui/src/logging.js b/browser/components/customizableui/src/logging.js new file mode 100644 index 0000000000000000000000000000000000000000..6998dc04e82d6288a6479b6e59c02f7dc65ba461 --- /dev/null +++ b/browser/components/customizableui/src/logging.js @@ -0,0 +1,25 @@ +#if 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/. */ +#endif + +XPCOMUtils.defineLazyModuleGetter(this, "console", + "resource://gre/modules/devtools/Console.jsm"); + +let gDebug = false; +try { + gDebug = Services.prefs.getBoolPref(kPrefCustomizationDebug); +} catch (e) {} + +function LOG(...args) { + if (gDebug) { + args.unshift(gModuleName); + console.log.apply(console, args); + } +} + +function ERROR(...args) { + args.unshift(gModuleName); + console.error.apply(console, args); +} diff --git a/browser/components/customizableui/src/moz.build b/browser/components/customizableui/src/moz.build new file mode 100644 index 0000000000000000000000000000000000000000..d82151e22573aa65f99de7f97385e025470a6509 --- /dev/null +++ b/browser/components/customizableui/src/moz.build @@ -0,0 +1,16 @@ +# -*- 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 += [ + 'ScrollbarSampler.jsm', +] + +EXTRA_PP_JS_MODULES += [ + 'CustomizableUI.jsm', + 'CustomizableWidgets.jsm', + 'CustomizeMode.jsm', + 'PanelWideWidgetTracker.jsm', +] diff --git a/browser/components/customizableui/test/browser.ini b/browser/components/customizableui/test/browser.ini new file mode 100644 index 0000000000000000000000000000000000000000..5b05e094b063d161dbabecfceac9b4db3ee50482 --- /dev/null +++ b/browser/components/customizableui/test/browser.ini @@ -0,0 +1,38 @@ +[DEFAULT] +support-files = + head.js + +[browser_873501_handle_specials.js] +[browser_876926_customize_mode_wrapping.js] +[browser_876944_customize_mode_create_destroy.js] +[browser_877006_missing_view.js] +[browser_877178_unregisterArea.js] +[browser_877447_skip_missing_ids.js] +[browser_878452_drag_to_panel.js] +[browser_880382_drag_wide_widgets_in_panel.js] +[browser_885530_showInPrivateBrowsing.js] +[browser_886323_buildArea_removable_nodes.js] +[browser_887438_currentset_shim.js] +[browser_888817_currentset_updating.js] +[browser_890140_orphaned_placeholders.js] +[browser_890262_destroyWidget_after_add_to_panel.js] +[browser_892955_isWidgetRemovable_for_removed_widgets.js] +[browser_892956_destroyWidget_defaultPlacements.js] +[browser_909779_overflow_toolbars_new_window.js] +[browser_913972_currentset_overflow.js] + +[browser_914138_widget_API_overflowable_toolbar.js] +# Because of the specific widths, this test is fragile and has been disabled. +# NB: it was designed for mac only, but started randomly failing there. +skip-if = true + +[browser_914863_disabled_help_quit_buttons.js] +[browser_918049_skipintoolbarset_dnd.js] +[browser_923857_customize_mode_event_wrapping_during_reset.js] +[browser_927717_customize_drag_empty_toolbar.js] + +[browser_934113_menubar_removable.js] +# Because this test is about the menubar, it can't be run on mac +skip-if = os == "mac" + +[browser_panel_toggle.js] diff --git a/browser/components/customizableui/test/browser_873501_handle_specials.js b/browser/components/customizableui/test/browser_873501_handle_specials.js new file mode 100644 index 0000000000000000000000000000000000000000..d518c1af0951f4d6bcdf7e652dfb15e0e70a0f9c --- /dev/null +++ b/browser/components/customizableui/test/browser_873501_handle_specials.js @@ -0,0 +1,91 @@ +/* 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/. */ + +const kToolbarName = "test-specials-toolbar"; + +let gTests = [ + { + desc: "Add a toolbar with two springs and the downloads button.", + run: function() { + // Create the toolbar with a single spring: + createToolbarWithPlacements(kToolbarName, ["spring"]); + ok(document.getElementById(kToolbarName), "Toolbar should be created."); + + // Check it's there with a generated ID: + assertAreaPlacements(kToolbarName, [/customizableui-special-spring\d+/]); + let [springId] = getAreaWidgetIds(kToolbarName); + + // Add a second spring, check if that's there and doesn't share IDs + CustomizableUI.addWidgetToArea("spring", kToolbarName); + assertAreaPlacements(kToolbarName, [springId, + /customizableui-special-spring\d+/]); + let [, spring2Id] = getAreaWidgetIds(kToolbarName); + + isnot(springId, spring2Id, "Springs shouldn't have identical IDs."); + + // Try moving the downloads button to this new toolbar, between the two springs: + CustomizableUI.addWidgetToArea("downloads-button", kToolbarName, 1); + assertAreaPlacements(kToolbarName, [springId, "downloads-button", spring2Id]); + }, + teardown: removeCustomToolbars + }, + { + desc: "Add separators around the downloads button.", + run: function() { + createToolbarWithPlacements(kToolbarName, ["separator"]); + ok(document.getElementById(kToolbarName), "Toolbar should be created."); + + // Check it's there with a generated ID: + assertAreaPlacements(kToolbarName, [/customizableui-special-separator\d+/]); + let [separatorId] = getAreaWidgetIds(kToolbarName); + + CustomizableUI.addWidgetToArea("separator", kToolbarName); + assertAreaPlacements(kToolbarName, [separatorId, + /customizableui-special-separator\d+/]); + let [, separator2Id] = getAreaWidgetIds(kToolbarName); + + isnot(separatorId, separator2Id, "Separator ids shouldn't be equal."); + + CustomizableUI.addWidgetToArea("downloads-button", kToolbarName, 1); + assertAreaPlacements(kToolbarName, [separatorId, "downloads-button", separator2Id]); + }, + teardown: removeCustomToolbars + }, + { + desc: "Add spacers around the downloads button.", + run: function() { + createToolbarWithPlacements(kToolbarName, ["spacer"]); + ok(document.getElementById(kToolbarName), "Toolbar should be created."); + + // Check it's there with a generated ID: + assertAreaPlacements(kToolbarName, [/customizableui-special-spacer\d+/]); + let [spacerId] = getAreaWidgetIds(kToolbarName); + + CustomizableUI.addWidgetToArea("spacer", kToolbarName); + assertAreaPlacements(kToolbarName, [spacerId, + /customizableui-special-spacer\d+/]); + let [, spacer2Id] = getAreaWidgetIds(kToolbarName); + + isnot(spacerId, spacer2Id, "Spacer ids shouldn't be equal."); + + CustomizableUI.addWidgetToArea("downloads-button", kToolbarName, 1); + assertAreaPlacements(kToolbarName, [spacerId, "downloads-button", spacer2Id]); + }, + teardown: removeCustomToolbars + } +]; + +function asyncCleanup() { + yield resetCustomization(); +} + +function cleanup() { + removeCustomToolbars(); +} + +function test() { + waitForExplicitFinish(); + registerCleanupFunction(cleanup); + runTests(gTests, asyncCleanup); +} diff --git a/browser/components/customizableui/test/browser_876926_customize_mode_wrapping.js b/browser/components/customizableui/test/browser_876926_customize_mode_wrapping.js new file mode 100644 index 0000000000000000000000000000000000000000..9d4d4289e90ff46ca0627037017414e272d8a0fb --- /dev/null +++ b/browser/components/customizableui/test/browser_876926_customize_mode_wrapping.js @@ -0,0 +1,161 @@ +/* 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/. */ + +const kXULWidgetId = "sync-button"; +const kAPIWidgetId = "feed-button"; +const kPanel = CustomizableUI.AREA_PANEL; +const kToolbar = CustomizableUI.AREA_NAVBAR; +const kVisiblePalette = "customization-palette"; +const kPlaceholderClass = "panel-customization-placeholder"; + +function checkWrapper(id) { + is(document.querySelectorAll("#wrapper-" + id).length, 1, "There should be exactly 1 wrapper for " + id + " in the customizing window."); +} + +let move = { + "drag": function(id, target) { + let targetNode = document.getElementById(target); + if (targetNode.customizationTarget) { + targetNode = targetNode.customizationTarget; + } + simulateItemDrag(document.getElementById(id), targetNode); + }, + "dragToItem": function(id, target) { + let targetNode = document.getElementById(target); + if (targetNode.customizationTarget) { + targetNode = targetNode.customizationTarget; + } + let items = targetNode.querySelectorAll("toolbarpaletteitem:not(." + kPlaceholderClass + ")"); + if (target == kPanel) { + targetNode = items[items.length - 1]; + } else { + targetNode = items[0]; + } + simulateItemDrag(document.getElementById(id), targetNode); + }, + "API": function(id, target) { + if (target == kVisiblePalette) { + return CustomizableUI.removeWidgetFromArea(id); + } + return CustomizableUI.addWidgetToArea(id, target, null); + } +} + +function isLast(containerId, defaultPlacements, id) { + assertAreaPlacements(containerId, defaultPlacements.concat([id])); + is(document.getElementById(containerId).customizationTarget.lastChild.firstChild.id, id, + "Widget " + id + " should be in " + containerId + " in customizing window."); + is(otherWin.document.getElementById(containerId).customizationTarget.lastChild.id, id, + "Widget " + id + " should be in " + containerId + " in other window."); +} + +function isFirst(containerId, defaultPlacements, id) { + assertAreaPlacements(containerId, [id].concat(defaultPlacements)); + is(document.getElementById(containerId).customizationTarget.firstChild.firstChild.id, id, + "Widget " + id + " should be in " + containerId + " in customizing window."); + is(otherWin.document.getElementById(containerId).customizationTarget.firstChild.id, id, + "Widget " + id + " should be in " + containerId + " in other window."); +} + +function checkToolbar(id, method) { + // Place at start of the toolbar: + let toolbarPlacements = getAreaWidgetIds(kToolbar); + move[method](id, kToolbar); + if (method == "dragToItem") { + isFirst(kToolbar, toolbarPlacements, id); + } else { + isLast(kToolbar, toolbarPlacements, id); + } + checkWrapper(id); +} + +function checkPanel(id, method) { + let panelPlacements = getAreaWidgetIds(kPanel); + move[method](id, kPanel); + let children = document.getElementById(kPanel).querySelectorAll("toolbarpaletteitem:not(." + kPlaceholderClass + ")"); + let otherChildren = otherWin.document.getElementById(kPanel).children; + let newPlacements = panelPlacements.concat([id]); + // Relative position of the new item from the end: + let position = -1; + // For the drag to item case, we drag to the last item, making the dragged item the + // penultimate item. We can't well use the first item because the panel has complicated + // rules about rearranging wide items (which, by default, the first two items are). + if (method == "dragToItem") { + newPlacements.pop(); + newPlacements.splice(panelPlacements.length - 1, 0, id); + position = -2; + } + assertAreaPlacements(kPanel, newPlacements); + is(children[children.length + position].firstChild.id, id, + "Widget " + id + " should be in " + kPanel + " in customizing window."); + is(otherChildren[otherChildren.length + position].id, id, + "Widget " + id + " should be in " + kPanel + " in other window."); + checkWrapper(id); +} + +function checkPalette(id, method) { + // Move back to palette: + move[method](id, kVisiblePalette); + ok(CustomizableUI.inDefaultState, "Should end in default state"); + let visibleChildren = gCustomizeMode.visiblePalette.children; + let expectedChild = method == "dragToItem" ? visibleChildren[0] : visibleChildren[visibleChildren.length - 1]; + is(expectedChild.firstChild.id, id, "Widget " + id + " was moved using " + method + " and should now be wrapped in palette in customizing window."); + if (id == kXULWidgetId) { + ok(otherWin.gNavToolbox.palette.querySelector("#" + id), "Widget " + id + " should be in invisible palette in other window."); + } + checkWrapper(id); +} + +let otherWin; +let gTests = [ + { + desc: "Moving widgets in two windows, one with customize mode and one without, should work", + setup: startCustomizing, + run: function() { + otherWin = yield openAndLoadWindow(null, true); + // Open and close the panel to force its construction: + let shownPromise = promisePanelShown(otherWin); + otherWin.PanelUI.toggle({type: "command"}); + yield shownPromise; + let hiddenPromise = promisePanelHidden(otherWin); + otherWin.PanelUI.toggle({type: "command"}); + yield hiddenPromise; + + ok(CustomizableUI.inDefaultState, "Should start in default state"); + + for (let widgetId of [kXULWidgetId, kAPIWidgetId]) { + for (let method of ["API", "drag", "dragToItem"]) { + info("Moving widget " + widgetId + " using " + method); + checkToolbar(widgetId, method); + checkPanel(widgetId, method); + checkPalette(widgetId, method); + checkPanel(widgetId, method); + checkToolbar(widgetId, method); + checkPalette(widgetId, method); + } + } + + otherWin.close(); + otherWin = null; + }, + teardown: function() { + if (otherWin) { + otherWin.close(); + } + yield endCustomizing(); + } + } +]; + +function asyncCleanup() { + Services.prefs.clearUserPref("browser.uiCustomization.skipSourceNodeCheck"); + yield resetCustomization(); +} + +function test() { + Services.prefs.setBoolPref("browser.uiCustomization.skipSourceNodeCheck", true); + waitForExplicitFinish(); + runTests(gTests, asyncCleanup); +} + diff --git a/browser/components/customizableui/test/browser_876944_customize_mode_create_destroy.js b/browser/components/customizableui/test/browser_876944_customize_mode_create_destroy.js new file mode 100644 index 0000000000000000000000000000000000000000..1c25cf345b2e107c511b468f7dbfea331410310b --- /dev/null +++ b/browser/components/customizableui/test/browser_876944_customize_mode_create_destroy.js @@ -0,0 +1,65 @@ +/* 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/. */ + +const kTestWidget1 = "test-customize-mode-create-destroy1"; +const kTestWidget2 = "test-customize-mode-create-destroy2"; + +let gTests = [ + { + desc: "Creating and destroying a widget should correctly wrap/unwrap stuff", + setup: startCustomizing, + run: function() { + CustomizableUI.createWidget({id: kTestWidget1, label: 'Pretty label', tooltiptext: 'Pretty tooltip'}); + let elem = document.getElementById(kTestWidget1); + let wrapper = document.getElementById("wrapper-" + kTestWidget1); + ok(elem, "There should be an item"); + ok(wrapper, "There should be a wrapper"); + is(wrapper.firstChild.id, kTestWidget1, "Wrapper should have test widget"); + is(wrapper.parentNode.id, "customization-palette", "Wrapper should be in palette"); + CustomizableUI.destroyWidget(kTestWidget1); + wrapper = document.getElementById("wrapper-" + kTestWidget1); + ok(!wrapper, "There should be a wrapper"); + let item = document.getElementById(kTestWidget1); + ok(!item, "There should no longer be an item"); + }, + }, + { + desc: "Creating and destroying a widget should correctly deal with panel placeholders", + run: function() { + let panel = document.getElementById(CustomizableUI.AREA_PANEL); + is(panel.querySelectorAll(".panel-customization-placeholder").length, 3, "The number of placeholders should be correct."); + CustomizableUI.createWidget({id: kTestWidget2, label: 'Pretty label', tooltiptext: 'Pretty tooltip', defaultArea: CustomizableUI.AREA_PANEL}); + let elem = document.getElementById(kTestWidget2); + let wrapper = document.getElementById("wrapper-" + kTestWidget2); + ok(elem, "There should be an item"); + ok(wrapper, "There should be a wrapper"); + is(wrapper.firstChild.id, kTestWidget2, "Wrapper should have test widget"); + is(wrapper.parentNode, panel, "Wrapper should be in panel"); + is(panel.querySelectorAll(".panel-customization-placeholder").length, 2, "The number of placeholders should be correct."); + CustomizableUI.destroyWidget(kTestWidget2); + wrapper = document.getElementById("wrapper-" + kTestWidget2); + ok(!wrapper, "There should be a wrapper"); + let item = document.getElementById(kTestWidget2); + ok(!item, "There should no longer be an item"); + }, + teardown: endCustomizing + }, +]; + +function asyncCleanup() { + yield endCustomizing(); + try { + CustomizableUI.destroyWidget(kTestWidget1); + } catch (ex) {} + try { + CustomizableUI.destroyWidget(kTestWidget2); + } catch (ex) {} + yield resetCustomization(); +} + + +function test() { + waitForExplicitFinish(); + runTests(gTests, asyncCleanup); +} diff --git a/browser/components/customizableui/test/browser_877006_missing_view.js b/browser/components/customizableui/test/browser_877006_missing_view.js new file mode 100644 index 0000000000000000000000000000000000000000..f65861d6314e40dc5212e5e09627b2549a2fa441 --- /dev/null +++ b/browser/components/customizableui/test/browser_877006_missing_view.js @@ -0,0 +1,50 @@ +/* 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/. */ + +let gTests = [ + { + desc: "Should be able to add broken view widget", + run: function() { + const kWidgetId = 'test-877006-broken-widget'; + let widgetSpec = { + id: kWidgetId, + type: 'view', + viewId: 'idontexist', + /* Empty handler so we try to attach it maybe? */ + onViewShowing: function() { + }, + }; + + let noError = true; + try { + CustomizableUI.createWidget(widgetSpec); + CustomizableUI.addWidgetToArea(kWidgetId, CustomizableUI.AREA_NAVBAR); + } catch (ex) { + Cu.reportError(ex); + noError = false; + } + ok(noError, "Should not throw an exception trying to add a broken view widget."); + + noError = true; + try { + CustomizableUI.destroyWidget(kWidgetId); + } catch (ex) { + Cu.reportError(ex); + noError = false; + } + ok(noError, "Should not throw an exception trying to remove the broken view widget."); + } + } +]; + + +function asyncCleanup() { + yield resetCustomization(); +} + +function test() { + waitForExplicitFinish(); + runTests(gTests, asyncCleanup); +} + diff --git a/browser/components/customizableui/test/browser_877178_unregisterArea.js b/browser/components/customizableui/test/browser_877178_unregisterArea.js new file mode 100644 index 0000000000000000000000000000000000000000..eb458ac152959627c2389b94009079c0688c2161 --- /dev/null +++ b/browser/components/customizableui/test/browser_877178_unregisterArea.js @@ -0,0 +1,67 @@ +/* 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/. */ + +let gTests = [ + { + desc: "Sanity checks", + run: function() { + SimpleTest.doesThrow(function() CustomizableUI.registerArea("@foo"), + "Registering areas with an invalid ID should throw."); + + SimpleTest.doesThrow(function() CustomizableUI.registerArea([]), + "Registering areas with an invalid ID should throw."); + + SimpleTest.doesThrow(function() CustomizableUI.registerArea(CustomizableUI.AREA_NAVBAR), + "Registering an area with an ID that's already registered should throw."); + + SimpleTest.doesThrow(function() CustomizableUI.unregisterArea("@foo"), + "Unregistering areas with an invalid ID should throw."); + + SimpleTest.doesThrow(function() CustomizableUI.unregisterArea([]), + "Unregistering areas with an invalid ID should throw."); + + SimpleTest.doesThrow(function() CustomizableUI.unregisterArea("unknown"), + "Unregistering an area that's not registered should throw."); + } + }, + { + desc: "Check areas are loaded with their default placements.", + run: function() { + ok(CustomizableUI.inDefaultState, "Everything should be in its default state."); + } + }, + { + desc: "Check registering and unregistering a new area.", + run: function() { + const kToolbarId = "test-registration-toolbar"; + const kButtonId = "test-registration-button"; + createDummyXULButton(kButtonId); + createToolbarWithPlacements(kToolbarId, ["spring", kButtonId, "spring"]); + assertAreaPlacements(kToolbarId, + [/customizableui-special-spring\d+/, + kButtonId, + /customizableui-special-spring\d+/]); + ok(CustomizableUI.inDefaultState, "With a new toolbar and default placements, " + + "everything should still be in a default state."); + removeCustomToolbars(); // Will call unregisterArea for us + ok(CustomizableUI.inDefaultState, "When the toolbar is unregistered, " + + "everything should still be in a default state."); + } + } +]; + +function asyncCleanup() { + yield resetCustomization(); +} + +function cleanup() { + removeCustomToolbars(); +} + +function test() { + waitForExplicitFinish(); + registerCleanupFunction(cleanup); + runTests(gTests, asyncCleanup); +} + diff --git a/browser/components/customizableui/test/browser_877447_skip_missing_ids.js b/browser/components/customizableui/test/browser_877447_skip_missing_ids.js new file mode 100644 index 0000000000000000000000000000000000000000..038dc4f295a707fe17e54274fc4669807ac4dddf --- /dev/null +++ b/browser/components/customizableui/test/browser_877447_skip_missing_ids.js @@ -0,0 +1,35 @@ +/* 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/. */ + +let gTests = [ + { + run: function() { + const kButtonId = "look-at-me-disappear-button"; + CustomizableUI.reset(); + ok(CustomizableUI.inDefaultState, "Should be in the default state."); + let btn = createDummyXULButton(kButtonId, "Gone!"); + CustomizableUI.addWidgetToArea(kButtonId, CustomizableUI.AREA_NAVBAR); + ok(!CustomizableUI.inDefaultState, "Should no longer be in the default state."); + is(btn.parentNode.parentNode.id, CustomizableUI.AREA_NAVBAR, "Button should be in navbar"); + btn.remove(); + is(btn.parentNode, null, "Button is no longer in the navbar"); + ok(CustomizableUI.inDefaultState, "Should be back in the default state, " + + "despite unknown button ID in placements."); + } + } +]; + +function asyncCleanup() { + yield resetCustomization(); +} + +function cleanup() { + removeCustomToolbars(); +} + +function test() { + waitForExplicitFinish(); + registerCleanupFunction(cleanup); + runTests(gTests, asyncCleanup); +} diff --git a/browser/components/customizableui/test/browser_878452_drag_to_panel.js b/browser/components/customizableui/test/browser_878452_drag_to_panel.js new file mode 100644 index 0000000000000000000000000000000000000000..f70501035b133ecd8ff32884e43a7a47573b90f1 --- /dev/null +++ b/browser/components/customizableui/test/browser_878452_drag_to_panel.js @@ -0,0 +1,80 @@ +/* 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/. */ + +let gTests = [ + { + desc: "Dragging an item from the palette to another button in the panel should work.", + setup: startCustomizing, + run: function() { + let btn = document.getElementById("developer-button"); + let panel = document.getElementById(CustomizableUI.AREA_PANEL); + let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL); + + let lastButtonIndex = placements.length - 1; + let lastButton = placements[lastButtonIndex]; + let placementsAfterInsert = placements.slice(0, lastButtonIndex).concat(["developer-button", lastButton]); + let lastButtonNode = document.getElementById(lastButton); + simulateItemDrag(btn, lastButtonNode); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterInsert); + ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); + let palette = document.getElementById("customization-palette"); + simulateItemDrag(btn, palette); + ok(CustomizableUI.inDefaultState, "Should be in default state again."); + }, + }, + { + desc: "Dragging an item from the palette to the panel itself should also work.", + setup: startCustomizing, + run: function() { + let btn = document.getElementById("developer-button"); + let panel = document.getElementById(CustomizableUI.AREA_PANEL); + let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL); + + let placementsAfterAppend = placements.concat(["developer-button"]); + simulateItemDrag(btn, panel); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend); + ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); + let palette = document.getElementById("customization-palette"); + simulateItemDrag(btn, palette); + ok(CustomizableUI.inDefaultState, "Should be in default state again."); + }, + }, + { + desc: "Dragging an item from the palette to an empty panel should also work.", + setup: function() { + let widgetIds = getAreaWidgetIds(CustomizableUI.AREA_PANEL); + while (widgetIds.length) { + CustomizableUI.removeWidgetFromArea(widgetIds.shift()); + } + return startCustomizing() + }, + run: function() { + let btn = document.getElementById("developer-button"); + let panel = document.getElementById(CustomizableUI.AREA_PANEL); + + assertAreaPlacements(panel.id, []); + + let placementsAfterAppend = ["developer-button"]; + simulateItemDrag(btn, panel); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend); + ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); + let palette = document.getElementById("customization-palette"); + simulateItemDrag(btn, palette); + assertAreaPlacements(panel.id, []); + }, + } +]; + +function asyncCleanup() { + yield endCustomizing(); + Services.prefs.clearUserPref("browser.uiCustomization.skipSourceNodeCheck"); + yield resetCustomization(); +} + +function test() { + Services.prefs.setBoolPref("browser.uiCustomization.skipSourceNodeCheck", true); + waitForExplicitFinish(); + runTests(gTests, asyncCleanup); +} + diff --git a/browser/components/customizableui/test/browser_880382_drag_wide_widgets_in_panel.js b/browser/components/customizableui/test/browser_880382_drag_wide_widgets_in_panel.js new file mode 100644 index 0000000000000000000000000000000000000000..9c1af8191522281c185bad7fbaaa2a9fa9a3f21c --- /dev/null +++ b/browser/components/customizableui/test/browser_880382_drag_wide_widgets_in_panel.js @@ -0,0 +1,458 @@ +/* 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/. */ + +let gTests = [ + { + desc: "Dragging the zoom controls to be before the print button " + + "should not move any controls.", + setup: startCustomizing, + run: function() { + let zoomControls = document.getElementById("zoom-controls"); + let printButton = document.getElementById("print-button"); + let placementsAfterMove = ["edit-controls", + "new-window-button", + "privatebrowsing-button", + "save-page-button", + "zoom-controls", + "print-button", + "history-panelmenu", + "fullscreen-button", + "find-button", + "preferences-button", + "add-ons-button"]; + simulateItemDrag(zoomControls, printButton); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); + ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); + let newWindowButton = document.getElementById("new-window-button"); + simulateItemDrag(zoomControls, newWindowButton); + ok(CustomizableUI.inDefaultState, "Should be in default state again."); + }, + }, + { + desc: "Dragging the zoom controls to be before the save button " + + "should not move any controls.", + setup: startCustomizing, + run: function() { + let zoomControls = document.getElementById("zoom-controls"); + let savePageButton = document.getElementById("save-page-button"); + let placementsAfterMove = ["edit-controls", + "zoom-controls", + "new-window-button", + "privatebrowsing-button", + "save-page-button", + "print-button", + "history-panelmenu", + "fullscreen-button", + "find-button", + "preferences-button", + "add-ons-button"]; + simulateItemDrag(zoomControls, savePageButton); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); + ok(CustomizableUI.inDefaultState, "Should be in default state."); + }, + }, + { + desc: "Dragging the zoom controls to be before the new-window " + + "button should not move any widgets.", + setup: startCustomizing, + run: function() { + let zoomControls = document.getElementById("zoom-controls"); + let newWindowButton = document.getElementById("new-window-button"); + let placementsAfterMove = ["edit-controls", + "zoom-controls", + "new-window-button", + "privatebrowsing-button", + "save-page-button", + "print-button", + "history-panelmenu", + "fullscreen-button", + "find-button", + "preferences-button", + "add-ons-button"]; + simulateItemDrag(zoomControls, newWindowButton); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); + ok(CustomizableUI.inDefaultState, "Should still be in default state."); + }, + }, + { + desc: "Dragging the zoom controls to be before the history-panelmenu " + + "should move the zoom-controls in to the row higher than the " + + "history-panelmenu.", + setup: startCustomizing, + run: function() { + let zoomControls = document.getElementById("zoom-controls"); + let historyPanelMenu = document.getElementById("history-panelmenu"); + let placementsAfterMove = ["edit-controls", + "new-window-button", + "privatebrowsing-button", + "save-page-button", + "zoom-controls", + "print-button", + "history-panelmenu", + "fullscreen-button", + "find-button", + "preferences-button", + "add-ons-button"]; + simulateItemDrag(zoomControls, historyPanelMenu); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); + ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); + let newWindowButton = document.getElementById("new-window-button"); + simulateItemDrag(zoomControls, newWindowButton); + ok(CustomizableUI.inDefaultState, "Should be in default state again."); + }, + }, + { + desc: "Dragging the zoom controls to be before the preferences-button " + + "should move the zoom-controls in to the row higher than the " + + "preferences-button.", + setup: startCustomizing, + run: function() { + let zoomControls = document.getElementById("zoom-controls"); + let preferencesButton = document.getElementById("preferences-button"); + let placementsAfterMove = ["edit-controls", + "new-window-button", + "privatebrowsing-button", + "save-page-button", + "print-button", + "history-panelmenu", + "fullscreen-button", + "zoom-controls", + "find-button", + "preferences-button", + "add-ons-button"]; + simulateItemDrag(zoomControls, preferencesButton); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); + ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); + let newWindowButton = document.getElementById("new-window-button"); + simulateItemDrag(zoomControls, newWindowButton); + ok(CustomizableUI.inDefaultState, "Should be in default state again."); + }, + }, + { + desc: "Dragging an item from the palette to before the zoom-controls " + + "should move it and two other buttons before the zoom controls.", + setup: startCustomizing, + run: function() { + let developerButton = document.getElementById("developer-button"); + let zoomControls = document.getElementById("zoom-controls"); + let placementsAfterInsert = ["edit-controls", + "developer-button", + "new-window-button", + "privatebrowsing-button", + "zoom-controls", + "save-page-button", + "print-button", + "history-panelmenu", + "fullscreen-button", + "find-button", + "preferences-button", + "add-ons-button"]; + simulateItemDrag(developerButton, zoomControls); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterInsert); + ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); + let palette = document.getElementById("customization-palette"); + // Check that the palette items are re-wrapped correctly. + let feedWrapper = document.getElementById("wrapper-feed-button"); + let feedButton = document.getElementById("feed-button"); + is(feedButton.parentNode, feedWrapper, + "feed-button should be a child of wrapper-feed-button"); + is(feedWrapper.getAttribute("place"), "palette", + "The feed-button wrapper should have it's place set to 'palette'"); + simulateItemDrag(developerButton, palette); + is(developerButton.parentNode.tagName, "toolbarpaletteitem", + "The developer-button should be wrapped by a toolbarpaletteitem"); + let newWindowButton = document.getElementById("new-window-button"); + simulateItemDrag(zoomControls, newWindowButton); + ok(CustomizableUI.inDefaultState, "Should be in default state again."); + }, + }, + { + desc: "Dragging an item from the palette to before the edit-controls " + + "should move it and two other buttons before the edit and zoom controls.", + setup: startCustomizing, + run: function() { + let developerButton = document.getElementById("developer-button"); + let editControls = document.getElementById("edit-controls"); + let placementsAfterInsert = ["developer-button", + "new-window-button", + "privatebrowsing-button", + "edit-controls", + "zoom-controls", + "save-page-button", + "print-button", + "history-panelmenu", + "fullscreen-button", + "find-button", + "preferences-button", + "add-ons-button"]; + simulateItemDrag(developerButton, editControls); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterInsert); + ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); + let palette = document.getElementById("customization-palette"); + // Check that the palette items are re-wrapped correctly. + let feedWrapper = document.getElementById("wrapper-feed-button"); + let feedButton = document.getElementById("feed-button"); + is(feedButton.parentNode, feedWrapper, + "feed-button should be a child of wrapper-feed-button"); + is(feedWrapper.getAttribute("place"), "palette", + "The feed-button wrapper should have it's place set to 'palette'"); + simulateItemDrag(developerButton, palette); + is(developerButton.parentNode.tagName, "toolbarpaletteitem", + "The developer-button should be wrapped by a toolbarpaletteitem"); + ok(CustomizableUI.inDefaultState, "Should be in default state again."); + }, + }, + { + desc: "Dragging the edit-controls to be before the zoom-controls button " + + "should not move any widgets.", + setup: startCustomizing, + run: function() { + let editControls = document.getElementById("edit-controls"); + let zoomControls = document.getElementById("zoom-controls"); + let placementsAfterMove = ["edit-controls", + "zoom-controls", + "new-window-button", + "privatebrowsing-button", + "save-page-button", + "print-button", + "history-panelmenu", + "fullscreen-button", + "find-button", + "preferences-button", + "add-ons-button"]; + simulateItemDrag(editControls, zoomControls); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); + ok(CustomizableUI.inDefaultState, "Should still be in default state."); + }, + }, + { + desc: "Dragging the edit-controls to be before the new-window-button should " + + "move the zoom-controls before the edit-controls.", + setup: startCustomizing, + run: function() { + let editControls = document.getElementById("edit-controls"); + let newWindowButton = document.getElementById("new-window-button"); + let placementsAfterMove = ["zoom-controls", + "edit-controls", + "new-window-button", + "privatebrowsing-button", + "save-page-button", + "print-button", + "history-panelmenu", + "fullscreen-button", + "find-button", + "preferences-button", + "add-ons-button"]; + simulateItemDrag(editControls, newWindowButton); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); + let zoomControls = document.getElementById("zoom-controls"); + simulateItemDrag(editControls, zoomControls); + ok(CustomizableUI.inDefaultState, "Should still be in default state."); + }, + }, + { + desc: "Dragging the edit-controls to be before the privatebrowsing-button " + + "should move the edit-controls in to the row higher than the " + + "privatebrowsing-button.", + setup: startCustomizing, + run: function() { + let editControls = document.getElementById("edit-controls"); + let privateBrowsingButton = document.getElementById("privatebrowsing-button"); + let placementsAfterMove = ["zoom-controls", + "edit-controls", + "new-window-button", + "privatebrowsing-button", + "save-page-button", + "print-button", + "history-panelmenu", + "fullscreen-button", + "find-button", + "preferences-button", + "add-ons-button"]; + simulateItemDrag(editControls, privateBrowsingButton); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); + let zoomControls = document.getElementById("zoom-controls"); + simulateItemDrag(editControls, zoomControls); + ok(CustomizableUI.inDefaultState, "Should still be in default state."); + }, + }, + { + desc: "Dragging the edit-controls to be before the save-page-button " + + "should move the edit-controls in to the row higher than the " + + "save-page-button.", + setup: startCustomizing, + run: function() { + let editControls = document.getElementById("edit-controls"); + let savePageButton = document.getElementById("save-page-button"); + let placementsAfterMove = ["zoom-controls", + "edit-controls", + "new-window-button", + "privatebrowsing-button", + "save-page-button", + "print-button", + "history-panelmenu", + "fullscreen-button", + "find-button", + "preferences-button", + "add-ons-button"]; + simulateItemDrag(editControls, savePageButton); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); + let zoomControls = document.getElementById("zoom-controls"); + simulateItemDrag(editControls, zoomControls); + ok(CustomizableUI.inDefaultState, "Should still be in default state."); + }, + }, + { + desc: "Dragging the edit-controls to the panel itself should append " + + "the edit controls to the bottom of the panel.", + setup: startCustomizing, + run: function() { + let editControls = document.getElementById("edit-controls"); + let panel = document.getElementById(CustomizableUI.AREA_PANEL); + let placementsAfterMove = ["zoom-controls", + "new-window-button", + "privatebrowsing-button", + "save-page-button", + "print-button", + "history-panelmenu", + "fullscreen-button", + "find-button", + "preferences-button", + "add-ons-button", + "edit-controls"]; + simulateItemDrag(editControls, panel); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); + let zoomControls = document.getElementById("zoom-controls"); + simulateItemDrag(editControls, zoomControls); + ok(CustomizableUI.inDefaultState, "Should still be in default state."); + }, + }, + { + desc: "Dragging the edit-controls to the customization-palette and " + + "back should work.", + setup: startCustomizing, + run: function() { + let editControls = document.getElementById("edit-controls"); + let palette = document.getElementById("customization-palette"); + let placementsAfterMove = ["zoom-controls", + "new-window-button", + "privatebrowsing-button", + "save-page-button", + "print-button", + "history-panelmenu", + "fullscreen-button", + "find-button", + "preferences-button", + "add-ons-button"]; + let paletteChildElementCount = palette.childElementCount; + simulateItemDrag(editControls, palette); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); + is(paletteChildElementCount + 1, palette.childElementCount, + "The palette should have a new child, congratulations!"); + is(editControls.parentNode.id, "wrapper-edit-controls", + "The edit-controls should be properly wrapped."); + is(editControls.parentNode.getAttribute("place"), "palette", + "The edit-controls should have the place of 'palette'."); + let zoomControls = document.getElementById("zoom-controls"); + simulateItemDrag(editControls, zoomControls); + is(paletteChildElementCount, palette.childElementCount, + "The palette child count should have returned to its prior value."); + ok(CustomizableUI.inDefaultState, "Should still be in default state."); + }, + }, + { + desc: "Dragging the edit-controls to each of the panel placeholders " + + "should append the edit-controls to the bottom of the panel.", + setup: startCustomizing, + run: function() { + let editControls = document.getElementById("edit-controls"); + let panel = document.getElementById(CustomizableUI.AREA_PANEL); + for (let i = 0; i < 3; i++) { + // NB: We can't just iterate over all of the placeholders + // because each drag-drop action recreates them. + let placeholder = panel.getElementsByClassName("panel-customization-placeholder")[i]; + let placementsAfterMove = ["zoom-controls", + "new-window-button", + "privatebrowsing-button", + "save-page-button", + "print-button", + "history-panelmenu", + "fullscreen-button", + "find-button", + "preferences-button", + "add-ons-button", + "edit-controls"]; + simulateItemDrag(editControls, placeholder); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); + let zoomControls = document.getElementById("zoom-controls"); + simulateItemDrag(editControls, zoomControls); + ok(CustomizableUI.inDefaultState, "Should still be in default state."); + } + }, + }, + { + desc: "Dragging the developer-button back on to itself should work.", + setup: startCustomizing, + run: function() { + let developerButton = document.getElementById("developer-button"); + is(developerButton.parentNode.tagName, "toolbarpaletteitem", + "developer-button should be wrapped by a toolbarpaletteitem"); + simulateItemDrag(developerButton, developerButton); + is(developerButton.parentNode.tagName, "toolbarpaletteitem", + "developer-button should be wrapped by a toolbarpaletteitem"); + let editControls = document.getElementById("edit-controls"); + is(editControls.parentNode.tagName, "toolbarpaletteitem", + "edit-controls should be wrapped by a toolbarpaletteitem"); + ok(CustomizableUI.inDefaultState, "Should still be in default state."); + }, + }, + { + desc: "Dragging a small button onto the last big button should work.", + setup: startCustomizing, + run: function() { + let editControls = document.getElementById("edit-controls"); + let panel = document.getElementById(CustomizableUI.AREA_PANEL); + let target = panel.getElementsByClassName("panel-customization-placeholder")[0]; + let placementsAfterMove = ["zoom-controls", + "new-window-button", + "privatebrowsing-button", + "save-page-button", + "print-button", + "history-panelmenu", + "fullscreen-button", + "find-button", + "preferences-button", + "add-ons-button", + "edit-controls"]; + simulateItemDrag(editControls, target); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); + let itemToDrag = "sync-button"; + let button = document.getElementById(itemToDrag); + placementsAfterMove.push(itemToDrag); + simulateItemDrag(button, editControls); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); + + // Put stuff back: + let palette = document.getElementById("customization-palette"); + let zoomControls = document.getElementById("zoom-controls"); + simulateItemDrag(button, palette); + simulateItemDrag(editControls, zoomControls); + ok(CustomizableUI.inDefaultState, "Should be in default state again."); + }, + }, +]; + +function asyncCleanup() { + yield endCustomizing(); + Services.prefs.clearUserPref("browser.uiCustomization.skipSourceNodeCheck"); + yield resetCustomization(); +} + +function test() { + Services.prefs.setBoolPref("browser.uiCustomization.skipSourceNodeCheck", true); + waitForExplicitFinish(); + requestLongerTimeout(5); + runTests(gTests, asyncCleanup); +} + diff --git a/browser/components/customizableui/test/browser_885530_showInPrivateBrowsing.js b/browser/components/customizableui/test/browser_885530_showInPrivateBrowsing.js new file mode 100644 index 0000000000000000000000000000000000000000..1203c2bf801a43b0917579d6d025fe3587b18fba --- /dev/null +++ b/browser/components/customizableui/test/browser_885530_showInPrivateBrowsing.js @@ -0,0 +1,151 @@ +/* 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/. */ + +const kWidgetId = "some-widget"; + +function assertWidgetExists(aWindow, aExists) { + if (aExists) { + ok(aWindow.document.getElementById(kWidgetId), + "Should have found test widget in the window"); + } else { + is(aWindow.document.getElementById(kWidgetId), null, + "Should not have found test widget in the window"); + } +} + +let gTests = [ + { + desc: "A widget that is created with showInPrivateBrowsing undefined should " + + "have that value default to false.", + run: function() { + let wrapper = CustomizableUI.createWidget({ + id: kWidgetId + }); + ok(wrapper.showInPrivateBrowsing, + "showInPrivateBrowsing should have defaulted to true."); + CustomizableUI.destroyWidget(kWidgetId); + }, + }, + { + desc: "Add a widget via the API with showInPrivateBrowsing set to false " + + "and ensure it does not appear in pre-existing or newly created " + + "private windows.", + run: function() { + let plain = yield openAndLoadWindow(); + let private = yield openAndLoadWindow({private: true}); + + CustomizableUI.createWidget({ + id: kWidgetId, + removable: true, + showInPrivateBrowsing: false + }); + CustomizableUI.addWidgetToArea(kWidgetId, + CustomizableUI.AREA_NAVBAR); + assertWidgetExists(plain, true); + assertWidgetExists(private, false); + + // Now open up some new windows. The widget should exist in the new + // plain window, but not the new private window. + let plain2 = yield openAndLoadWindow(); + let private2 = yield openAndLoadWindow({private: true}); + + assertWidgetExists(plain2, true); + assertWidgetExists(private2, false); + + // Try moving the widget around and make sure it doesn't get added + // to the private windows. We'll start by appending it to the tabstrip. + CustomizableUI.addWidgetToArea(kWidgetId, + CustomizableUI.AREA_TABSTRIP); + assertWidgetExists(plain, true); + assertWidgetExists(plain2, true); + assertWidgetExists(private, false); + assertWidgetExists(private2, false); + + // And then move it to the beginning of the tabstrip. + CustomizableUI.moveWidgetWithinArea(kWidgetId, 0); + assertWidgetExists(plain, true); + assertWidgetExists(plain2, true); + assertWidgetExists(private, false); + assertWidgetExists(private2, false); + + CustomizableUI.removeWidgetFromArea("some-widget"); + assertWidgetExists(plain, false); + assertWidgetExists(plain2, false); + assertWidgetExists(private, false); + assertWidgetExists(private2, false); + + plain.close(); + plain2.close(); + private.close(); + private2.close(); + + CustomizableUI.destroyWidget("some-widget"); + }, + }, + { + desc: "Add a widget via the API with showInPrivateBrowsing set to true, " + + "and ensure that it appears in pre-existing or newly created " + + "private browsing windows.", + run: function() { + let plain = yield openAndLoadWindow(); + let private = yield openAndLoadWindow({private: true}); + + CustomizableUI.createWidget({ + id: kWidgetId, + removable: true, + showInPrivateBrowsing: true + }); + CustomizableUI.addWidgetToArea(kWidgetId, + CustomizableUI.AREA_NAVBAR); + assertWidgetExists(plain, true); + assertWidgetExists(private, true); + + // Now open up some new windows. The widget should exist in the new + // plain window, but not the new private window. + let plain2 = yield openAndLoadWindow(); + let private2 = yield openAndLoadWindow({private: true}); + + assertWidgetExists(plain2, true); + assertWidgetExists(private2, true); + + // Try moving the widget around and make sure it doesn't get added + // to the private windows. We'll start by appending it to the tabstrip. + CustomizableUI.addWidgetToArea(kWidgetId, + CustomizableUI.AREA_TABSTRIP); + assertWidgetExists(plain, true); + assertWidgetExists(plain2, true); + assertWidgetExists(private, true); + assertWidgetExists(private2, true); + + // And then move it to the beginning of the tabstrip. + CustomizableUI.moveWidgetWithinArea(kWidgetId, 0); + assertWidgetExists(plain, true); + assertWidgetExists(plain2, true); + assertWidgetExists(private, true); + assertWidgetExists(private2, true); + + CustomizableUI.removeWidgetFromArea("some-widget"); + assertWidgetExists(plain, false); + assertWidgetExists(plain2, false); + assertWidgetExists(private, false); + assertWidgetExists(private2, false); + + plain.close(); + plain2.close(); + private.close(); + private2.close(); + + CustomizableUI.destroyWidget("some-widget"); + }, + } +]; + +function asyncCleanup() { + yield resetCustomization(); +} + +function test() { + waitForExplicitFinish(); + runTests(gTests, asyncCleanup); +} diff --git a/browser/components/customizableui/test/browser_886323_buildArea_removable_nodes.js b/browser/components/customizableui/test/browser_886323_buildArea_removable_nodes.js new file mode 100644 index 0000000000000000000000000000000000000000..6296a975a82cdcd4fba3f2b6d71116a4226e97fd --- /dev/null +++ b/browser/components/customizableui/test/browser_886323_buildArea_removable_nodes.js @@ -0,0 +1,56 @@ +/* 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/. */ + +const kButtonId = "test-886323-removable-moved-node"; +const kLazyAreaId = "test-886323-lazy-area-for-removability-testing"; + +let gNavBar = document.getElementById(CustomizableUI.AREA_NAVBAR); +let gLazyArea; +let gTests = [ + { + desc: "Removable nodes shouldn't be moved by buildArea", + setup: function() { + let dummyBtn = createDummyXULButton(kButtonId, "Dummy"); + dummyBtn.setAttribute("removable", "true"); + gNavBar.customizationTarget.appendChild(dummyBtn); + let popupSet = document.getElementById("mainPopupSet"); + gLazyArea = document.createElementNS(kNSXUL, "panel"); + gLazyArea.id = kLazyAreaId; + gLazyArea.setAttribute("hidden", "true"); + popupSet.appendChild(gLazyArea); + CustomizableUI.registerArea(kLazyAreaId, { + type: CustomizableUI.TYPE_MENU_PANEL, + defaultPlacements: [] + }); + }, + run: function() { + CustomizableUI.addWidgetToArea(kButtonId, kLazyAreaId); + assertAreaPlacements(kLazyAreaId, [kButtonId], + "Placements should have changed because widget is removable."); + let btn = document.getElementById(kButtonId); + btn.setAttribute("removable", "false"); + gLazyArea.customizationTarget = gLazyArea; + CustomizableUI.registerToolbarNode(gLazyArea, []); + assertAreaPlacements(kLazyAreaId, [], "Placements should no longer include widget."); + is(btn.parentNode.id, gNavBar.customizationTarget.id, + "Button shouldn't actually have moved as it's not removable"); + }, + teardown: function() { + let btn = document.getElementById(kButtonId); + if (btn) btn.remove(); + CustomizableUI.removeWidgetFromArea(kButtonId); + CustomizableUI.unregisterArea(kLazyAreaId); + gLazyArea.remove(); + } + } +]; + +function asyncCleanup() { + yield resetCustomization(); +} + +function test() { + waitForExplicitFinish(); + runTests(gTests, asyncCleanup); +} diff --git a/browser/components/customizableui/test/browser_887438_currentset_shim.js b/browser/components/customizableui/test/browser_887438_currentset_shim.js new file mode 100644 index 0000000000000000000000000000000000000000..f469df0aa7d5f017505b2ab620555ffa8804e02e --- /dev/null +++ b/browser/components/customizableui/test/browser_887438_currentset_shim.js @@ -0,0 +1,84 @@ +/* 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/. */ + +let navbar = document.getElementById("nav-bar") +let navbarCT = navbar.customizationTarget; +let overflowPanelList = document.getElementById("widget-overflow-list"); +let gTests = [ + { + desc: "Reading currentset", + run: function() { + let nodeIds = []; + for (let node of navbarCT.childNodes) { + if (node.getAttribute("skipintoolbarset") != "true") { + nodeIds.push(node.id); + } + } + for (let node of overflowPanelList.childNodes) { + if (node.getAttribute("skipintoolbarset") != "true") { + nodeIds.push(node.id); + } + } + let currentSet = navbar.currentSet; + is(currentSet.split(',').length, nodeIds.length, "Should be just as many nodes as there are."); + is(currentSet, nodeIds.join(','), "Current set and node IDs should match."); + } + }, + { + desc: "Insert, then remove items", + run: function() { + let currentSet = navbar.currentSet; + let newCurrentSet = currentSet.replace('home-button', 'feed-button,sync-button,home-button'); + navbar.currentSet = newCurrentSet; + is(newCurrentSet, navbar.currentSet, "Current set should match expected current set."); + let feedBtn = document.getElementById("feed-button"); + let syncBtn = document.getElementById("sync-button"); + ok(feedBtn, "Feed button should have been added."); + ok(syncBtn, "Sync button should have been added."); + if (feedBtn && syncBtn) { + let feedParent = feedBtn.parentNode; + let syncParent = syncBtn.parentNode; + ok(feedParent == navbarCT || feedParent == overflowPanelList, + "Feed button should be in navbar or overflow"); + ok(syncParent == navbarCT || syncParent == overflowPanelList, + "Feed button should be in navbar or overflow"); + is(feedBtn.nextElementSibling, syncBtn, "Feed button should be next to sync button."); + let homeBtn = document.getElementById("home-button"); + is(syncBtn.nextElementSibling, homeBtn, "Sync button should be next to home button."); + } + navbar.currentSet = currentSet; + is(currentSet, navbar.currentSet, "Should be able to remove the added items."); + } + }, + { + desc: "Simultaneous insert/remove:", + run: function() { + let currentSet = navbar.currentSet; + let newCurrentSet = currentSet.replace('home-button', 'feed-button'); + navbar.currentSet = newCurrentSet; + is(newCurrentSet, navbar.currentSet, "Current set should match expected current set."); + let feedBtn = document.getElementById("feed-button"); + ok(feedBtn, "Feed button should have been added."); + let homeBtn = document.getElementById("home-button"); + ok(!homeBtn, "Home button should have been removed."); + if (feedBtn) { + let feedParent = feedBtn.parentNode; + ok(feedParent == navbarCT || feedParent == overflowPanelList, + "Feed button should be in navbar or overflow"); + } + navbar.currentSet = currentSet; + is(currentSet, navbar.currentSet, "Should be able to return to original state."); + } + } +]; + +function asyncCleanup() { + yield resetCustomization(); +} + +function test() { + waitForExplicitFinish(); + runTests(gTests, asyncCleanup); +} + diff --git a/browser/components/customizableui/test/browser_888817_currentset_updating.js b/browser/components/customizableui/test/browser_888817_currentset_updating.js new file mode 100644 index 0000000000000000000000000000000000000000..2d70a6152267b289a210aff30b1f10f744fad1af --- /dev/null +++ b/browser/components/customizableui/test/browser_888817_currentset_updating.js @@ -0,0 +1,65 @@ +/* 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/. */ + +let gTests = [ + { + desc: "Adding, moving and removing items should update the relevant currentset attributes", + setup: function() { + let personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS); + setToolbarVisibility(personalbar, true); + }, + run: function() { + ok(CustomizableUI.inDefaultState, "Should be in the default state when we start"); + + let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR); + let personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS); + let navbarCurrentset = navbar.getAttribute("currentset") || navbar.currentSet; + let personalbarCurrentset = personalbar.getAttribute("currentset") || personalbar.currentSet; + + let otherWin = yield openAndLoadWindow(); + let otherNavbar = otherWin.document.getElementById(CustomizableUI.AREA_NAVBAR); + let otherPersonalbar = otherWin.document.getElementById(CustomizableUI.AREA_BOOKMARKS); + + CustomizableUI.moveWidgetWithinArea("home-button", 0); + navbarCurrentset = "home-button," + navbarCurrentset.replace(",home-button", ""); + is(navbar.getAttribute("currentset"), navbarCurrentset, + "Should have updated currentSet after move."); + is(otherNavbar.getAttribute("currentset"), navbarCurrentset, + "Should have updated other window's currentSet after move."); + + CustomizableUI.addWidgetToArea("home-button", CustomizableUI.AREA_BOOKMARKS); + navbarCurrentset = navbarCurrentset.replace("home-button,", ""); + personalbarCurrentset = personalbarCurrentset + ",home-button"; + is(navbar.getAttribute("currentset"), navbarCurrentset, + "Should have updated navbar currentSet after implied remove."); + is(otherNavbar.getAttribute("currentset"), navbarCurrentset, + "Should have updated other window's navbar currentSet after implied remove."); + is(personalbar.getAttribute("currentset"), personalbarCurrentset, + "Should have updated personalbar currentSet after add."); + is(otherPersonalbar.getAttribute("currentset"), personalbarCurrentset, + "Should have updated other window's personalbar currentSet after add."); + + CustomizableUI.removeWidgetFromArea("home-button"); + personalbarCurrentset = personalbarCurrentset.replace(",home-button", ""); + is(personalbar.getAttribute("currentset"), personalbarCurrentset, + "Should have updated currentSet after remove."); + is(otherPersonalbar.getAttribute("currentset"), personalbarCurrentset, + "Should have updated other window's currentSet after remove."); + + otherWin.close(); + // Reset in asyncCleanup will put our button back for us. + } + } +]; + +function asyncCleanup() { + let personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS); + setToolbarVisibility(personalbar, false); + yield resetCustomization(); +} + +function test() { + waitForExplicitFinish(); + runTests(gTests, asyncCleanup); +} diff --git a/browser/components/customizableui/test/browser_890140_orphaned_placeholders.js b/browser/components/customizableui/test/browser_890140_orphaned_placeholders.js new file mode 100644 index 0000000000000000000000000000000000000000..601c59ecd5c2b6f0c715a240895e0dcf15609fb9 --- /dev/null +++ b/browser/components/customizableui/test/browser_890140_orphaned_placeholders.js @@ -0,0 +1,135 @@ +/* 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/. */ + +let gTests = [ + { + desc: "One orphaned item should have two placeholders next to it.", + setup: startCustomizing, + run: function() { + let btn = document.getElementById("developer-button"); + let panel = document.getElementById(CustomizableUI.AREA_PANEL); + let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL); + + let placementsAfterAppend = placements.concat(["developer-button"]); + simulateItemDrag(btn, panel); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend); + ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); + is(getVisiblePlaceholderCount(panel), 2, "Should only have 2 visible placeholders before exiting"); + + yield endCustomizing(); + yield startCustomizing(); + is(getVisiblePlaceholderCount(panel), 2, "Should only have 2 visible placeholders after re-entering"); + + let palette = document.getElementById("customization-palette"); + simulateItemDrag(btn, palette); + ok(CustomizableUI.inDefaultState, "Should be in default state again."); + }, + }, + { + desc: "Two orphaned items should have one placeholder next to them (case 1).", + setup: startCustomizing, + run: function() { + let btn = document.getElementById("developer-button"); + let panel = document.getElementById(CustomizableUI.AREA_PANEL); + let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL); + + let placementsAfterAppend = placements.concat(["developer-button", "sync-button"]); + simulateItemDrag(btn, panel); + btn = document.getElementById("sync-button"); + simulateItemDrag(btn, panel); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend); + ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); + is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholders before exiting"); + + yield endCustomizing(); + yield startCustomizing(); + is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholders after re-entering"); + + let palette = document.getElementById("customization-palette"); + simulateItemDrag(btn, palette); + btn = document.getElementById("developer-button"); + simulateItemDrag(btn, palette); + ok(CustomizableUI.inDefaultState, "Should be in default state again."); + }, + }, + { + desc: "Two orphaned items should have one placeholder next to them (case 2).", + setup: startCustomizing, + run: function() { + let btn = document.getElementById("add-ons-button"); + let panel = document.getElementById(CustomizableUI.AREA_PANEL); + let palette = document.getElementById("customization-palette"); + let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL); + + let placementsAfterAppend = placements.filter(p => p != btn.id); + simulateItemDrag(btn, palette); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend); + ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); + is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholders before exiting"); + + yield endCustomizing(); + yield startCustomizing(); + is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholders after re-entering"); + + simulateItemDrag(btn, panel); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placements); + ok(CustomizableUI.inDefaultState, "Should be in default state again."); + }, + }, + { + desc: "A wide widget at the bottom of the panel should have three placeholders after it.", + setup: startCustomizing, + run: function() { + let btn = document.getElementById("edit-controls"); + let panel = document.getElementById(CustomizableUI.AREA_PANEL); + let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL); + + let placementsAfterAppend = placements.concat([placements.shift()]); + simulateItemDrag(btn, panel); + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend); + ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); + is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders before exiting"); + + yield endCustomizing(); + yield startCustomizing(); + is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders after re-entering"); + + let zoomControls = document.getElementById("zoom-controls"); + simulateItemDrag(btn, zoomControls); + ok(CustomizableUI.inDefaultState, "Should be in default state again."); + }, + }, + { + desc: "The default placements should have three placeholders at the bottom.", + setup: startCustomizing, + run: function() { + let panel = document.getElementById(CustomizableUI.AREA_PANEL); + ok(CustomizableUI.inDefaultState, "Should be in default state."); + is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders before exiting"); + + yield endCustomizing(); + yield startCustomizing(); + is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders after re-entering"); + + ok(CustomizableUI.inDefaultState, "Should still be in default state."); + }, + }, +]; + +function asyncCleanup() { + yield endCustomizing(); + Services.prefs.clearUserPref("browser.uiCustomization.skipSourceNodeCheck"); + yield resetCustomization(); +} + +function test() { + Services.prefs.setBoolPref("browser.uiCustomization.skipSourceNodeCheck", true); + waitForExplicitFinish(); + runTests(gTests, asyncCleanup); +} + +function getVisiblePlaceholderCount(aPanel) { + let visiblePlaceholders = aPanel.querySelectorAll(".panel-customization-placeholder:not([hidden=true])"); + return visiblePlaceholders.length; +} diff --git a/browser/components/customizableui/test/browser_890262_destroyWidget_after_add_to_panel.js b/browser/components/customizableui/test/browser_890262_destroyWidget_after_add_to_panel.js new file mode 100644 index 0000000000000000000000000000000000000000..d3bcf96b01eb5c74bfef6d5c10005fd3f0898ed9 --- /dev/null +++ b/browser/components/customizableui/test/browser_890262_destroyWidget_after_add_to_panel.js @@ -0,0 +1,75 @@ +/* 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/. */ + +const kLazyAreaId = "test-890262-lazy-area"; +const kWidget1Id = "test-890262-widget1"; +const kWidget2Id = "test-890262-widget2"; + +let gTests = [ + { + desc: "Destroying a widget after defaulting it to a non-legacy area should work.", + run: function() { + CustomizableUI.createWidget({ + id: kWidget1Id, + removable: true, + defaultArea: kLazyAreaId + }); + let noError = true; + try { + CustomizableUI.destroyWidget(kWidget1Id); + } catch (ex) { + Cu.reportError(ex); + noError = false; + } + ok(noError, "Shouldn't throw an exception for a widget that was created in a not-yet-constructed area"); + } + }, + { + desc: "Destroying a widget after moving it to a non-legacy area should work.", + run: function() { + CustomizableUI.createWidget({ + id: kWidget2Id, + removable: true, + defaultArea: CustomizableUI.AREA_NAVBAR + }); + + CustomizableUI.addWidgetToArea(kWidget2Id, kLazyAreaId); + let noError = true; + try { + CustomizableUI.destroyWidget(kWidget2Id); + } catch (ex) { + Cu.reportError(ex); + noError = false; + } + ok(noError, "Shouldn't throw an exception for a widget that was added to a not-yet-constructed area"); + } + } +]; + +function asyncCleanup() { + let lazyArea = document.getElementById(kLazyAreaId); + if (lazyArea) { + lazyArea.remove(); + } + try { + CustomizableUI.unregisterArea(kLazyAreaId); + } catch (ex) {} // If we didn't register successfully for some reason + yield resetCustomization(); +} + +function setupArea() { + let lazyArea = document.createElementNS(kNSXUL, "hbox"); + lazyArea.id = kLazyAreaId; + document.getElementById("nav-bar").appendChild(lazyArea); + CustomizableUI.registerArea(kLazyAreaId, { + type: CustomizableUI.TYPE_TOOLBAR, + defaultPlacements: [] + }); +} + +function test() { + waitForExplicitFinish(); + setupArea(); + runTests(gTests, asyncCleanup); +} diff --git a/browser/components/customizableui/test/browser_892955_isWidgetRemovable_for_removed_widgets.js b/browser/components/customizableui/test/browser_892955_isWidgetRemovable_for_removed_widgets.js new file mode 100644 index 0000000000000000000000000000000000000000..b8023845dab57bfc03e60a0de1ea2bbc551bc702 --- /dev/null +++ b/browser/components/customizableui/test/browser_892955_isWidgetRemovable_for_removed_widgets.js @@ -0,0 +1,37 @@ +/* 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/. */ + +const kWidgetId = "test-892955-remove-widget"; + +let gTests = [ + { + desc: "Removing a destroyed widget should work.", + run: function() { + let widgetSpec = { + id: kWidgetId, + defaultArea: CustomizableUI.AREA_NAVBAR + }; + + CustomizableUI.createWidget(widgetSpec); + CustomizableUI.destroyWidget(kWidgetId); + let noError = true; + try { + CustomizableUI.removeWidgetFromArea(kWidgetId); + } catch (ex) { + noError = false; + Cu.reportError(ex); + } + ok(noError, "Shouldn't throw an error removing a destroyed widget."); + } + } +]; + +function asyncCleanup() { + yield resetCustomization(); +} + +function test() { + waitForExplicitFinish(); + runTests(gTests, asyncCleanup); +} diff --git a/browser/components/customizableui/test/browser_892956_destroyWidget_defaultPlacements.js b/browser/components/customizableui/test/browser_892956_destroyWidget_defaultPlacements.js new file mode 100644 index 0000000000000000000000000000000000000000..c678fd7130dc18e87579e70ea00b5ff29bc53529 --- /dev/null +++ b/browser/components/customizableui/test/browser_892956_destroyWidget_defaultPlacements.js @@ -0,0 +1,31 @@ +/* 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/. */ + +const kWidgetId = "test-892956-destroyWidget-defaultPlacement"; + +let gTests = [ + { + desc: "destroyWidget should clean up defaultPlacements if the widget had a defaultArea", + run: function() { + ok(CustomizableUI.inDefaultState, "Should be in the default state when we start"); + + let widgetSpec = { + id: kWidgetId, + defaultArea: CustomizableUI.AREA_NAVBAR + }; + CustomizableUI.createWidget(widgetSpec); + CustomizableUI.destroyWidget(kWidgetId); + ok(CustomizableUI.inDefaultState, "Should be in the default state when we finish"); + } + } +]; + +function asyncCleanup() { + yield resetCustomization(); +} + +function test() { + waitForExplicitFinish(); + runTests(gTests, asyncCleanup); +} diff --git a/browser/components/customizableui/test/browser_909779_overflow_toolbars_new_window.js b/browser/components/customizableui/test/browser_909779_overflow_toolbars_new_window.js new file mode 100644 index 0000000000000000000000000000000000000000..30a07c73918608df7bf7d49958c6a8cd6c0d9479 --- /dev/null +++ b/browser/components/customizableui/test/browser_909779_overflow_toolbars_new_window.js @@ -0,0 +1,38 @@ +/* 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/. */ + +let gTests = [ + { + desc: "Resize to a small window, open a new window, check that new window handles overflow properly", + run: function() { + let originalWindowWidth = window.outerWidth; + let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR); + ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar."); + let oldChildCount = navbar.customizationTarget.childElementCount; + window.resizeTo(400, window.outerHeight); + yield waitForCondition(() => navbar.hasAttribute("overflowing")); + ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar."); + + ok(navbar.customizationTarget.childElementCount < oldChildCount, "Should have fewer children."); + let newWindow = yield openAndLoadWindow(); + let otherNavBar = newWindow.document.getElementById(CustomizableUI.AREA_NAVBAR); + yield waitForCondition(() => otherNavBar.hasAttribute("overflowing")); + ok(otherNavBar.hasAttribute("overflowing"), "Other window should have an overflowing toolbar."); + newWindow.close(); + + window.resizeTo(originalWindowWidth, window.outerHeight); + yield waitForCondition(() => !navbar.hasAttribute("overflowing")); + ok(!navbar.hasAttribute("overflowing"), "Should no longer have an overflowing toolbar."); + } + } +]; + +function asyncCleanup() { + yield resetCustomization(); +} + +function test() { + waitForExplicitFinish(); + runTests(gTests, asyncCleanup); +} diff --git a/browser/components/customizableui/test/browser_913972_currentset_overflow.js b/browser/components/customizableui/test/browser_913972_currentset_overflow.js new file mode 100644 index 0000000000000000000000000000000000000000..4c16166e2b5625a4ad89fcacce07e570b04a5e82 --- /dev/null +++ b/browser/components/customizableui/test/browser_913972_currentset_overflow.js @@ -0,0 +1,62 @@ +/* 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/. */ + +let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR); +let gTests = [ + { + desc: "Resize to a small window, resize back, shouldn't affect currentSet", + run: function() { + let originalWindowWidth = window.outerWidth; + let oldCurrentSet = navbar.currentSet; + ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar."); + ok(CustomizableUI.inDefaultState, "Should start in default state."); + let oldChildCount = navbar.customizationTarget.childElementCount; + window.resizeTo(400, window.outerHeight); + yield waitForCondition(() => navbar.hasAttribute("overflowing")); + ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar."); + is(navbar.currentSet, oldCurrentSet, "Currentset should be the same when overflowing."); + ok(CustomizableUI.inDefaultState, "Should still be in default state when overflowing."); + ok(navbar.customizationTarget.childElementCount < oldChildCount, "Should have fewer children."); + window.resizeTo(originalWindowWidth, window.outerHeight); + yield waitForCondition(() => !navbar.hasAttribute("overflowing")); + ok(!navbar.hasAttribute("overflowing"), "Should no longer have an overflowing toolbar."); + is(navbar.currentSet, oldCurrentSet, "Currentset should still be the same now we're no longer overflowing."); + ok(CustomizableUI.inDefaultState, "Should still be in default state now we're no longer overflowing."); + + // Verify actual physical placements match those of the placement array: + let placementCounter = 0; + let placements = CustomizableUI.getWidgetIdsInArea(CustomizableUI.AREA_NAVBAR); + for (let node of navbar.customizationTarget.childNodes) { + if (node.getAttribute("skipintoolbarset") == "true") { + continue; + } + is(placements[placementCounter++], node.id, "Nodes should match after overflow"); + } + is(placements.length, placementCounter, "Should have as many nodes as expected"); + is(navbar.customizationTarget.childElementCount, oldChildCount, "Number of nodes should match"); + } + }, + { + desc: "Enter and exit customization mode, check that currentSet works", + run: function() { + let oldCurrentSet = navbar.currentSet; + ok(CustomizableUI.inDefaultState, "Should start in default state."); + yield startCustomizing(); + ok(CustomizableUI.inDefaultState, "Should be in default state in customization mode."); + is(navbar.currentSet, oldCurrentSet, "Currentset should be the same in customization mode."); + yield endCustomizing(); + ok(CustomizableUI.inDefaultState, "Should be in default state after customization mode."); + is(navbar.currentSet, oldCurrentSet, "Currentset should be the same after customization mode."); + } + } +]; + +function asyncCleanup() { + yield resetCustomization(); +} + +function test() { + waitForExplicitFinish(); + runTests(gTests, asyncCleanup); +} diff --git a/browser/components/customizableui/test/browser_914138_widget_API_overflowable_toolbar.js b/browser/components/customizableui/test/browser_914138_widget_API_overflowable_toolbar.js new file mode 100644 index 0000000000000000000000000000000000000000..7534f617c7580e187fa1c520b1a43684e12d267a --- /dev/null +++ b/browser/components/customizableui/test/browser_914138_widget_API_overflowable_toolbar.js @@ -0,0 +1,171 @@ +/* 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/. */ + +let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR); +let overflowList = document.getElementById(navbar.getAttribute("overflowtarget")); + +const kTestBtn1 = "test-addWidgetToArea-overflow"; +const kTestBtn2 = "test-removeWidgetFromArea-overflow"; +const kHomeBtn = "home-button"; +const kDownloadsBtn = "downloads-button"; +const kSearchBox = "search-container"; +const kStarBtn = "bookmarks-menu-button"; + +let originalWindowWidth; + +let gTests = [ + { + desc: "Adding a widget should add it next to the widget it's being inserted next to.", + setup: function() { + originalWindowWidth = window.outerWidth; + createDummyXULButton(kTestBtn1, "Test"); + }, + run: function() { + ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar."); + ok(CustomizableUI.inDefaultState, "Should start in default state."); + + window.resizeTo(400, window.outerHeight); + yield waitForCondition(() => navbar.hasAttribute("overflowing")); + ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar."); + ok(!navbar.querySelector("#" + kHomeBtn), "Home button should no longer be in the navbar"); + ok(overflowList.querySelector("#" + kHomeBtn), "Home button should be overflowing"); + + let placementOfHomeButton = CustomizableUI.getWidgetIdsInArea(navbar.id).indexOf(kHomeBtn); + CustomizableUI.addWidgetToArea(kTestBtn1, navbar.id, placementOfHomeButton); + ok(!navbar.querySelector("#" + kTestBtn1), "New button should not be in the navbar"); + ok(overflowList.querySelector("#" + kTestBtn1), "New button should be overflowing"); + let nextEl = document.getElementById(kTestBtn1).nextSibling; + is(nextEl && nextEl.id, kHomeBtn, "Test button should be next to home button."); + + window.resizeTo(originalWindowWidth, window.outerHeight); + yield waitForCondition(() => !navbar.hasAttribute("overflowing")); + ok(!navbar.hasAttribute("overflowing"), "Should not have an overflowing toolbar."); + ok(navbar.querySelector("#" + kHomeBtn), "Home button should be in the navbar"); + ok(!overflowList.querySelector("#" + kHomeBtn), "Home button should no longer be overflowing"); + ok(navbar.querySelector("#" + kTestBtn1), "Test button should be in the navbar"); + ok(!overflowList.querySelector("#" + kTestBtn1), "Test button should no longer be overflowing"); + }, + teardown: function() { + let el = document.getElementById(kTestBtn1); + if (el) { + CustomizableUI.removeWidgetFromArea(kTestBtn1); + el.remove(); + } + window.resizeTo(originalWindowWidth, window.outerHeight); + } + }, + { + desc: "Removing a widget from the toolbar should try to move items back.", + setup: function() { + // This is pretty weird. We're going to try to move only the home button into the overlay: + let downloadsBtn = document.getElementById(kDownloadsBtn); + // Guarantee overflow of too much stuff: + window.resizeTo(700, window.outerHeight); + let inc = 15; + while (window.outerWidth < originalWindowWidth && + downloadsBtn.parentNode != navbar.customizationTarget) { + window.resizeTo(window.outerWidth + inc, window.outerHeight); + yield waitFor(500); + } + }, + run: function() { + ok(overflowList.querySelector("#home-button"), "Home button should be overflowing"); + CustomizableUI.removeWidgetFromArea("downloads-button"); + is(document.getElementById("home-button").parentNode, navbar.customizationTarget, "Home button should move back."); + ok(!navbar.hasAttribute("overflowing"), "Navbar is no longer overflowing"); + }, + teardown: function() { + window.resizeTo(originalWindowWidth, window.outerHeight); + yield waitForCondition(function() !navbar.hasAttribute("overflowing")); + CustomizableUI.reset(); + } + }, + { + desc: "Removing a widget should remove it from the overflow list if that is where it is, and update it accordingly.", + setup: function() { + createDummyXULButton(kTestBtn2, "Test"); + }, + run: function() { + ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar."); + ok(CustomizableUI.inDefaultState, "Should start in default state."); + CustomizableUI.addWidgetToArea(kTestBtn2, navbar.id); + ok(!navbar.hasAttribute("overflowing"), "Should still have a non-overflowing toolbar."); + + window.resizeTo(400, window.outerHeight); + yield waitForCondition(() => navbar.hasAttribute("overflowing")); + ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar."); + ok(!navbar.querySelector("#" + kTestBtn2), "Test button should not be in the navbar"); + ok(overflowList.querySelector("#" + kTestBtn2), "Test button should be overflowing"); + + CustomizableUI.removeWidgetFromArea(kTestBtn2); + + ok(!overflowList.querySelector("#" + kTestBtn2), "Test button should not be overflowing."); + ok(!navbar.querySelector("#" + kTestBtn2), "Test button should not be in the navbar"); + ok(gNavToolbox.palette.querySelector("#" + kTestBtn2), "Test button should be in the palette"); + + window.resizeTo(originalWindowWidth, window.outerHeight); + yield waitForCondition(() => !navbar.hasAttribute("overflowing")); + ok(!navbar.hasAttribute("overflowing"), "Should not have an overflowing toolbar."); + }, + teardown: function() { + let el = document.getElementById(kTestBtn2); + if (el) { + CustomizableUI.removeWidgetFromArea(kTestBtn2); + el.remove(); + } + window.resizeTo(originalWindowWidth, window.outerHeight); + } + }, + { + desc: "Overflow everything that can, then reorganize that list", + setup: function() { + ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar."); + ok(CustomizableUI.inDefaultState, "Should start in default state."); + + window.resizeTo(480, window.outerHeight); + yield waitForCondition(() => navbar.hasAttribute("overflowing")); + ok(!navbar.querySelector("#" + kSearchBox), "Search container should be overflowing"); + }, + run: function() { + let placements = CustomizableUI.getWidgetIdsInArea(navbar.id); + let searchboxPlacement = placements.indexOf(kSearchBox); + CustomizableUI.moveWidgetWithinArea(kHomeBtn, searchboxPlacement); + yield waitForCondition(() => navbar.querySelector("#" + kHomeBtn)); + ok(navbar.querySelector("#" + kHomeBtn), "Home button should have moved back"); + let inc = 15; + window.resizeTo(640, window.outerHeight); + while (window.outerWidth < originalWindowWidth && + !navbar.querySelector("#" + kSearchBox)) { + window.resizeTo(window.outerWidth + inc, window.outerHeight); + yield waitFor(500); + } + ok(!navbar.querySelector("#" + kStarBtn), "Star button should still be overflowed"); + CustomizableUI.moveWidgetWithinArea(kStarBtn); + let starButtonOverflowed = overflowList.querySelector("#" + kStarBtn); + ok(starButtonOverflowed && !starButtonOverflowed.nextSibling, "Star button should be last item"); + window.resizeTo(window.outerWidth + 15, window.outerHeight); + yield waitForCondition(() => navbar.querySelector("#" + kDownloadsBtn) && navbar.hasAttribute("overflowing")); + ok(navbar.hasAttribute("overflowing"), "navbar should still be overflowing"); + CustomizableUI.moveWidgetWithinArea(kHomeBtn); + let homeButtonOverflowed = overflowList.querySelector("#" + kHomeBtn); + ok(homeButtonOverflowed, "Home button should be in overflow list"); + ok(navbar.hasAttribute("overflowing"), "navbar should still be overflowing"); + ok(homeButtonOverflowed && !homeButtonOverflowed.nextSibling, "Home button should be last item"); + }, + teardown: function() { + window.resizeTo(originalWindowWidth, window.outerHeight); + yield waitForCondition(() => !navbar.hasAttribute("overflowing")); + ok(!navbar.hasAttribute("overflowing"), "Should not have an overflowing toolbar."); + } + } +]; + +function asyncCleanup() { + yield resetCustomization(); +} + +function test() { + waitForExplicitFinish(); + runTests(gTests, asyncCleanup); +} diff --git a/browser/components/customizableui/test/browser_914863_disabled_help_quit_buttons.js b/browser/components/customizableui/test/browser_914863_disabled_help_quit_buttons.js new file mode 100644 index 0000000000000000000000000000000000000000..e3d3f23b4860482a4dad702e46be844974f2b388 --- /dev/null +++ b/browser/components/customizableui/test/browser_914863_disabled_help_quit_buttons.js @@ -0,0 +1,26 @@ +/* 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/. */ + +let gTests = [ + { + desc: "Entering then exiting customization mode should reenable the Help and Exit buttons.", + run: function() { + yield startCustomizing(); + let helpButton = document.getElementById("PanelUI-help"); + let quitButton = document.getElementById("PanelUI-quit"); + ok(helpButton.getAttribute("disabled") == "true", "Help button should be disabled while in customization mode."); + ok(quitButton.getAttribute("disabled") == "true", "Quit button should be disabled while in customization mode."); + yield endCustomizing(); + + ok(!helpButton.hasAttribute("disabled"), "Help button should not be disabled."); + ok(!quitButton.hasAttribute("disabled"), "Quit button should not be disabled."); + } + }, +]; + +function test() { + waitForExplicitFinish(); + runTests(gTests); +} + diff --git a/browser/components/customizableui/test/browser_918049_skipintoolbarset_dnd.js b/browser/components/customizableui/test/browser_918049_skipintoolbarset_dnd.js new file mode 100644 index 0000000000000000000000000000000000000000..291133a72a2b0c0557a4a86dca5462968bbf428d --- /dev/null +++ b/browser/components/customizableui/test/browser_918049_skipintoolbarset_dnd.js @@ -0,0 +1,46 @@ +/* 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/. */ + +let navbar; +let skippedItem; +let gTests = [ + { + desc: "Attempting to drag a skipintoolbarset item should work.", + setup: function() { + navbar = document.getElementById("nav-bar"); + skippedItem = document.createElement("toolbarbutton"); + skippedItem.id = "test-skipintoolbarset-item"; + skippedItem.setAttribute("label", "Test"); + skippedItem.setAttribute("skipintoolbarset", "true"); + navbar.customizationTarget.appendChild(skippedItem); + }, + run: function() { + let downloadsButton = document.getElementById("downloads-button"); + yield startCustomizing(); + ok(CustomizableUI.inDefaultState, "Should still be in default state"); + simulateItemDrag(skippedItem, downloadsButton); + ok(CustomizableUI.inDefaultState, "Should still be in default state"); + let skippedItemWrapper = skippedItem.parentNode; + is(skippedItemWrapper.nextSibling && skippedItemWrapper.nextSibling.id, + downloadsButton.parentNode.id, "Should be next to downloads button"); + simulateItemDrag(downloadsButton, skippedItem); + let downloadWrapper = downloadsButton.parentNode; + is(downloadWrapper.nextSibling && downloadWrapper.nextSibling.id, + skippedItem.parentNode.id, "Should be next to skipintoolbarset item"); + ok(CustomizableUI.inDefaultState, "Should still be in default state"); + } + }, +]; +function asyncCleanup() { + yield endCustomizing(); + skippedItem.remove(); + Services.prefs.clearUserPref("browser.uiCustomization.skipSourceNodeCheck"); + yield resetCustomization(); +} + +function test() { + Services.prefs.setBoolPref("browser.uiCustomization.skipSourceNodeCheck", true); + waitForExplicitFinish(); + runTests(gTests, asyncCleanup); +} diff --git a/browser/components/customizableui/test/browser_923857_customize_mode_event_wrapping_during_reset.js b/browser/components/customizableui/test/browser_923857_customize_mode_event_wrapping_during_reset.js new file mode 100644 index 0000000000000000000000000000000000000000..8f6d523799e5a1291e421a71603543cce10bffa0 --- /dev/null +++ b/browser/components/customizableui/test/browser_923857_customize_mode_event_wrapping_during_reset.js @@ -0,0 +1,38 @@ +/* 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/. */ + +let gTests = [ + { + desc: "Customize mode reset button should revert correctly", + setup: function() { + yield startCustomizing(); + }, + run: function() { + let devButton = document.getElementById("developer-button"); + let downloadsButton = document.getElementById("downloads-button"); + let searchBox = document.getElementById("search-container"); + let palette = document.getElementById("customization-palette"); + ok(devButton && downloadsButton && searchBox && palette, "Stuff should exist"); + simulateItemDrag(devButton, downloadsButton); + simulateItemDrag(searchBox, palette); + gCustomizeMode.reset(); + yield waitForCondition(function() !gCustomizeMode.resetting); + ok(CustomizableUI.inDefaultState, "Should be back in default state"); + }, + teardown: function() { + yield endCustomizing(); + } + } +]; + +function asyncCleanup() { + Services.prefs.clearUserPref("browser.uiCustomization.skipSourceNodeCheck"); + yield resetCustomization(); +} + +function test() { + Services.prefs.setBoolPref("browser.uiCustomization.skipSourceNodeCheck", true); + waitForExplicitFinish(); + runTests(gTests, asyncCleanup); +} diff --git a/browser/components/customizableui/test/browser_927717_customize_drag_empty_toolbar.js b/browser/components/customizableui/test/browser_927717_customize_drag_empty_toolbar.js new file mode 100644 index 0000000000000000000000000000000000000000..1f39e2971da83857a326d66c7a66e3253d96e6fd --- /dev/null +++ b/browser/components/customizableui/test/browser_927717_customize_drag_empty_toolbar.js @@ -0,0 +1,37 @@ +/* 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/. */ + +const kTestToolbarId = "test-empty-drag"; +let gTests = [ + { + desc: "Attempting to drag an item to an empty container should work.", + setup: function() { + createToolbarWithPlacements(kTestToolbarId, ""); + }, + run: function() { + yield startCustomizing(); + let downloadButton = document.getElementById("downloads-button"); + let customToolbar = document.getElementById(kTestToolbarId); + simulateItemDrag(downloadButton, customToolbar); + assertAreaPlacements(kTestToolbarId, ["downloads-button"]); + ok(downloadButton.parentNode && downloadButton.parentNode.parentNode == customToolbar, + "Button should really be in toolbar"); + }, + teardown: function() { + yield endCustomizing(); + removeCustomToolbars(); + } + }, +]; +function asyncCleanup() { + yield endCustomizing(); + Services.prefs.clearUserPref("browser.uiCustomization.skipSourceNodeCheck"); + yield resetCustomization(); +} + +function test() { + Services.prefs.setBoolPref("browser.uiCustomization.skipSourceNodeCheck", true); + waitForExplicitFinish(); + runTests(gTests, asyncCleanup); +} diff --git a/browser/components/customizableui/test/browser_934113_menubar_removable.js b/browser/components/customizableui/test/browser_934113_menubar_removable.js new file mode 100644 index 0000000000000000000000000000000000000000..bb08283c6a764172d492411143cff6fc71b324af --- /dev/null +++ b/browser/components/customizableui/test/browser_934113_menubar_removable.js @@ -0,0 +1,32 @@ +/* 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/. */ + +let gTests = [ + { + desc: "Attempting to drag the menubar to the navbar shouldn't work.", + setup: startCustomizing, + run: function() { + let menuItems = document.getElementById("menubar-items"); + let navbar = document.getElementById("nav-bar"); + let menubar = document.getElementById("toolbar-menubar"); + simulateItemDrag(menuItems, navbar.customizationTarget); + is(getAreaWidgetIds("nav-bar").indexOf("menubar-items"), -1, "Menu bar shouldn't be in the navbar."); + ok(!navbar.querySelector("#menubar-items"), "Shouldn't find menubar items in the navbar."); + ok(menubar.querySelector("#menubar-items"), "Should find menubar items in the menubar."); + isnot(getAreaWidgetIds("toolbar-menubar").indexOf("menubar-items"), -1, "Menubar items shouldn't be missing from the navbar."); + }, + teardown: endCustomizing + }, +]; +function asyncCleanup() { + yield endCustomizing(); + Services.prefs.clearUserPref("browser.uiCustomization.skipSourceNodeCheck"); + yield resetCustomization(); +} + +function test() { + Services.prefs.setBoolPref("browser.uiCustomization.skipSourceNodeCheck", true); + waitForExplicitFinish(); + runTests(gTests, asyncCleanup); +} diff --git a/browser/components/customizableui/test/browser_panel_toggle.js b/browser/components/customizableui/test/browser_panel_toggle.js new file mode 100644 index 0000000000000000000000000000000000000000..2e6ef6ce84b4f2ce686bc938f02205017e3260dd --- /dev/null +++ b/browser/components/customizableui/test/browser_panel_toggle.js @@ -0,0 +1,53 @@ +/* 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/. */ + +/** + * Test opening and closing the menu panel UI. + */ + +let gTests = [ + { + desc: "Show and hide the menu panel programmatically without an event (like UITour.jsm would)", + setup: null, + run: function() { + let shownPromise = promisePanelShown(window); + PanelUI.show(); + yield shownPromise; + + is(PanelUI.panel.getAttribute("panelopen"), "true", "Check that panel has panelopen attribute"); + is(PanelUI.panel.state, "open", "Check that panel state is 'open'"); + + let hiddenPromise = promisePanelHidden(window); + PanelUI.hide(); + yield hiddenPromise; + + ok(!PanelUI.panel.hasAttribute("panelopen"), "Check that panel doesn't have the panelopen attribute"); + is(PanelUI.panel.state, "closed", "Check that panel state is 'closed'"); + }, + }, + { + desc: "Toggle the menu panel open and closed", + setup: null, + run: function() { + let shownPromise = promisePanelShown(window); + PanelUI.toggle({type: "command"}); + yield shownPromise; + + is(PanelUI.panel.getAttribute("panelopen"), "true", "Check that panel has panelopen attribute"); + is(PanelUI.panel.state, "open", "Check that panel state is 'open'"); + + let hiddenPromise = promisePanelHidden(window); + PanelUI.toggle({type: "command"}); + yield hiddenPromise; + + ok(!PanelUI.panel.hasAttribute("panelopen"), "Check that panel doesn't have the panelopen attribute"); + is(PanelUI.panel.state, "closed", "Check that panel state is 'closed'"); + }, + }, +]; + +function test() { + waitForExplicitFinish(); + runTests(gTests); +} diff --git a/browser/components/customizableui/test/head.js b/browser/components/customizableui/test/head.js new file mode 100644 index 0000000000000000000000000000000000000000..3e92df81e3879669e7fedbb523e2f8faa9c01515 --- /dev/null +++ b/browser/components/customizableui/test/head.js @@ -0,0 +1,254 @@ +/* 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/. */ + + +// Avoid leaks by using tmp for imports... +let tmp = {}; +Cu.import("resource://gre/modules/Promise.jsm", tmp); +Cu.import("resource://gre/modules/Task.jsm", tmp); +Cu.import("resource:///modules/CustomizableUI.jsm", tmp); +let {Promise, Task, CustomizableUI} = tmp; + +let ChromeUtils = {}; +let scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader); +scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js", ChromeUtils); + +let {synthesizeDragStart, synthesizeDrop} = ChromeUtils; + +const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + +function createDummyXULButton(id, label) { + let btn = document.createElementNS(kNSXUL, "toolbarbutton"); + btn.id = id; + btn.setAttribute("label", label || id); + btn.className = "toolbarbutton-1 chromeclass-toolbar-additional"; + window.gNavToolbox.palette.appendChild(btn); + return btn; +} + +let gAddedToolbars = new Set(); + +function createToolbarWithPlacements(id, placements) { + gAddedToolbars.add(id); + let tb = document.createElementNS(kNSXUL, "toolbar"); + tb.id = id; + tb.setAttribute("customizable", "true"); + CustomizableUI.registerArea(id, { + type: CustomizableUI.TYPE_TOOLBAR, + defaultPlacements: placements + }); + gNavToolbox.appendChild(tb); +} + +function removeCustomToolbars() { + CustomizableUI.reset(); + for (let toolbarId of gAddedToolbars) { + CustomizableUI.unregisterArea(toolbarId); + document.getElementById(toolbarId).remove(); + } + gAddedToolbars.clear(); +} + +function resetCustomization() { + return CustomizableUI.reset(); +} + +function assertAreaPlacements(areaId, expectedPlacements) { + let actualPlacements = getAreaWidgetIds(areaId); + is(actualPlacements.length, expectedPlacements.length, + "Area " + areaId + " should have " + expectedPlacements.length + " items."); + let minItems = Math.min(expectedPlacements.length, actualPlacements.length); + for (let i = 0; i < minItems; i++) { + if (typeof expectedPlacements[i] == "string") { + is(actualPlacements[i], expectedPlacements[i], + "Item " + i + " in " + areaId + " should match expectations."); + } else if (expectedPlacements[i] instanceof RegExp) { + ok(expectedPlacements[i].test(actualPlacements[i]), + "Item " + i + " (" + actualPlacements[i] + ") in " + + areaId + " should match " + expectedPlacements[i]); + } else { + ok(false, "Unknown type of expected placement passed to " + + " assertAreaPlacements. Is your test broken?"); + } + } +} + +function todoAssertAreaPlacements(areaId, expectedPlacements) { + let actualPlacements = getAreaWidgetIds(areaId); + let isPassing = actualPlacements.length == expectedPlacements.length; + let minItems = Math.min(expectedPlacements.length, actualPlacements.length); + for (let i = 0; i < minItems; i++) { + if (typeof expectedPlacements[i] == "string") { + isPassing = isPassing && actualPlacements[i] == expectedPlacements[i]; + } else if (expectedPlacements[i] instanceof RegExp) { + isPassing = isPassing && expectedPlacements[i].test(actualPlacements[i]); + } else { + ok(false, "Unknown type of expected placement passed to " + + " assertAreaPlacements. Is your test broken?"); + } + } + todo(isPassing, "The area placements for " + areaId + + " should equal the expected placements.") +} + +function getAreaWidgetIds(areaId) { + return CustomizableUI.getWidgetIdsInArea(areaId); +} + +function simulateItemDrag(toDrag, target) { + let docId = toDrag.ownerDocument.documentElement.id; + let dragData = [[{type: 'text/toolbarwrapper-id/' + docId, + data: toDrag.id}]]; + synthesizeDragStart(toDrag.parentNode, dragData); + synthesizeDrop(target, target, dragData); +} + +function endCustomizing() { + if (document.documentElement.getAttribute("customizing") != "true") { + return true; + } + let deferredEndCustomizing = Promise.defer(); + function onCustomizationEnds() { + window.gNavToolbox.removeEventListener("aftercustomization", onCustomizationEnds); + deferredEndCustomizing.resolve(); + } + window.gNavToolbox.addEventListener("aftercustomization", onCustomizationEnds); + window.gCustomizeMode.exit(); + + return deferredEndCustomizing.promise.then(function() { + let deferredLoadNewTab = Promise.defer(); + + //XXXgijs so some tests depend on this tab being about:blank. Make it so. + let newTabBrowser = window.gBrowser.selectedBrowser; + newTabBrowser.stop(); + + // If we stop early enough, this might actually be about:blank. + if (newTabBrowser.contentDocument.location.href == "about:blank") { + return; + } + + // Otherwise, make it be about:blank, and wait for that to be done. + function onNewTabLoaded(e) { + newTabBrowser.removeEventListener("load", onNewTabLoaded, true); + deferredLoadNewTab.resolve(); + } + newTabBrowser.addEventListener("load", onNewTabLoaded, true); + newTabBrowser.contentDocument.location.replace("about:blank"); + return deferredLoadNewTab.promise; + }); +} + +function startCustomizing() { + if (document.documentElement.getAttribute("customizing") == "true") { + return; + } + let deferred = Promise.defer(); + function onCustomizing() { + window.gNavToolbox.removeEventListener("customizationready", onCustomizing); + deferred.resolve(); + } + window.gNavToolbox.addEventListener("customizationready", onCustomizing); + window.gCustomizeMode.enter(); + return deferred.promise; +} + +function openAndLoadWindow(aOptions, aWaitForDelayedStartup=false) { + let deferred = Promise.defer(); + let win = OpenBrowserWindow(aOptions); + if (aWaitForDelayedStartup) { + Services.obs.addObserver(function onDS(aSubject, aTopic, aData) { + if (aSubject != win) { + return; + } + Services.obs.removeObserver(onDS, "browser-delayed-startup-finished"); + deferred.resolve(win); + }, "browser-delayed-startup-finished", false); + + } else { + win.addEventListener("load", function onLoad() { + win.removeEventListener("load", onLoad); + deferred.resolve(win); + }); + } + return deferred.promise; +} + +function promisePanelShown(win) { + let panelEl = win.PanelUI.panel; + let deferred = Promise.defer(); + function onPanelOpen(e) { + panelEl.removeEventListener("popupshown", onPanelOpen); + deferred.resolve(); + }; + panelEl.addEventListener("popupshown", onPanelOpen); + return deferred.promise; +} + +function promisePanelHidden(win) { + let panelEl = win.PanelUI.panel; + let deferred = Promise.defer(); + function onPanelClose(e) { + panelEl.removeEventListener("popuphidden", onPanelClose); + deferred.resolve(); + } + panelEl.addEventListener("popuphidden", onPanelClose); + return deferred.promise; +} + +function waitForCondition(aConditionFn, aMaxTries=50, aCheckInterval=100) { + function tryNow() { + tries++; + if (aConditionFn()) { + deferred.resolve(); + } else if (tries < aMaxTries) { + tryAgain(); + } else { + deferred.reject("Condition timed out: " + aConditionFn.toSource()); + } + } + function tryAgain() { + setTimeout(tryNow, aCheckInterval); + } + let deferred = Promise.defer(); + let tries = 0; + tryAgain(); + return deferred.promise; +} + +function waitFor(aTimeout=100) { + let deferred = Promise.defer(); + setTimeout(function() deferred.resolve(), aTimeout); + return deferred.promise; +} + +function testRunner(testAry, asyncCleanup) { + Services.prefs.setBoolPref("browser.uiCustomization.disableAnimation", true); + for (let test of testAry) { + info(test.desc); + + if (test.setup) + yield test.setup(); + + info("Running test"); + yield test.run(); + info("Cleanup"); + if (test.teardown) + yield test.teardown(); + ok(!document.getElementById(CustomizableUI.AREA_NAVBAR).hasAttribute("overflowing"), "Shouldn't overflow"); + } + if (asyncCleanup) { + yield asyncCleanup(); + } + ok(CustomizableUI.inDefaultState, "Should remain in default state"); + Services.prefs.clearUserPref("browser.uiCustomization.disableAnimation"); +} + +function runTests(testAry, asyncCleanup) { + Task.spawn(testRunner(gTests, asyncCleanup)).then(finish, ex => { + // The stack of ok() here is misleading due to Promises. The stack of the + // actual exception is likely much more valuable, hence concatentating it. + ok(false, "Unexpected exception: " + ex + " With stack: " + ex.stack); + finish(); + }).then(null, Cu.reportError); +} diff --git a/browser/components/downloads/content/downloads.js b/browser/components/downloads/content/downloads.js index eca4a94c6d5b02d73c80dd6bf907c33989590f07..1ec5cdbeec31dfedc1325d7d16ee43ff627366f9 100644 --- a/browser/components/downloads/content/downloads.js +++ b/browser/components/downloads/content/downloads.js @@ -641,11 +641,6 @@ const DownloadsOverlayLoader = { this._overlayLoading = false; this._loadedOverlays[aOverlay] = true; - // Loading the overlay causes all the persisted XUL attributes to be - // reapplied, including "iconsize" on the toolbars. Until bug 640158 is - // fixed, we must recalculate the correct "iconsize" attributes manually. - retrieveToolbarIconsizesFromTheme(); - this.processPendingRequests(); } diff --git a/browser/components/downloads/content/indicator.js b/browser/components/downloads/content/indicator.js index 6d31504ae61a5d0e37418910c08356fc62b9fe9e..7547b53c7a1c629fb1c6cc22f5bc6ec05b493272 100644 --- a/browser/components/downloads/content/indicator.js +++ b/browser/components/downloads/content/indicator.js @@ -110,10 +110,12 @@ const DownloadsButton = { indicator.open = this._anchorRequested; - // Determine if we're located on an invisible toolbar. - if (!isElementVisible(indicator.parentNode)) { - return null; - } + let widget = CustomizableUI.getWidget("downloads-button") + .forWindow(window); + // Determine if the indicator is located on an invisible toolbar. + if (!isElementVisible(indicator.parentNode) && !widget.overflowed) { + return null; + } return DownloadsIndicatorView.indicatorAnchor; }, @@ -317,10 +319,20 @@ const DownloadsIndicatorView = { return; } - // If the anchor is not there or its container is hidden, don't show - // a notification let anchor = DownloadsButton._placeholder; + let widgetGroup = CustomizableUI.getWidget("downloads-button"); + let widgetInWindow = widgetGroup.forWindow(window); + if (widgetInWindow.overflowed || widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL) { + if (anchor && isElementVisible(anchor.parentNode)) { + // If the panel is open, don't do anything: + return; + } + + // Otherwise, try to use the anchor of the panel: + anchor = widgetInWindow.anchor; + } if (!anchor || !isElementVisible(anchor.parentNode)) { + // Our container isn't visible, so can't show the animation: return; } @@ -481,7 +493,14 @@ const DownloadsIndicatorView = { onCommand: function DIV_onCommand(aEvent) { - DownloadsPanel.showPanel(); + // If the downloads button is in the menu panel, open the Library + let widgetGroup = CustomizableUI.getWidget("downloads-button"); + if (widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL) { + DownloadsPanel.showDownloadsHistory(); + } else { + DownloadsPanel.showPanel(); + } + aEvent.stopPropagation(); }, @@ -512,7 +531,6 @@ const DownloadsIndicatorView = { }, _indicator: null, - _indicatorAnchor: null, __indicatorCounter: null, __indicatorProgress: null, @@ -536,8 +554,12 @@ const DownloadsIndicatorView = { get indicatorAnchor() { - return this._indicatorAnchor || - (this._indicatorAnchor = document.getElementById("downloads-indicator-anchor")); + let widget = CustomizableUI.getWidget("downloads-button") + .forWindow(window); + if (widget.overflowed) { + return widget.anchor; + } + return document.getElementById("downloads-indicator-anchor"); }, get _indicatorCounter() @@ -560,7 +582,6 @@ const DownloadsIndicatorView = { _onCustomizedAway: function() { this._indicator = null; - this._indicatorAnchor = null; this.__indicatorCounter = null; this.__indicatorProgress = null; }, diff --git a/browser/components/downloads/test/browser/browser.ini b/browser/components/downloads/test/browser/browser.ini index 4a6cb36249a576549560697152cfcf044b392abe..11e1c49fda63b24bf6a309897dbf1aed4661fac4 100644 --- a/browser/components/downloads/test/browser/browser.ini +++ b/browser/components/downloads/test/browser/browser.ini @@ -3,3 +3,4 @@ support-files = head.js [browser_basic_functionality.js] [browser_first_download_panel.js] +[browser_overflow_anchor.js] diff --git a/browser/components/downloads/test/browser/browser_overflow_anchor.js b/browser/components/downloads/test/browser/browser_overflow_anchor.js new file mode 100644 index 0000000000000000000000000000000000000000..682c39ffd967e6eb8daffceaa7ec11f772181a66 --- /dev/null +++ b/browser/components/downloads/test/browser/browser_overflow_anchor.js @@ -0,0 +1,115 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Make sure the downloads button and indicator overflows into the nav-bar + * chevron properly, and then when those buttons are clicked in the overflow + * panel that the downloads panel anchors to the chevron. + */ +function test_task() { + try { + // Ensure that state is reset in case previous tests didn't finish. + yield task_resetState(); + + // Record the original width of the window so we can put it back when + // this test finishes. + let oldWidth = window.outerWidth; + + // The downloads button should not be overflowed to begin with. + let button = CustomizableUI.getWidget("downloads-button") + .forWindow(window); + ok(!button.overflowed, "Downloads button should not be overflowed."); + + // Hack - we lock the size of the default flex-y items in the nav-bar, + // namely, the URL and search inputs. That way we can resize the + // window without worrying about them flexing. + const kFlexyItems = ["urlbar-container", "search-container"]; + registerCleanupFunction(() => unlockWidth(kFlexyItems)); + lockWidth(kFlexyItems); + + // Resize the window to half of its original size. That should + // be enough to overflow the downloads button. + window.resizeTo(oldWidth / 2, window.outerHeight); + yield waitForOverflowed(button, true); + + let promise = promisePanelOpened(); + button.node.doCommand(); + yield promise; + + let panel = DownloadsPanel.panel; + let chevron = document.getElementById("nav-bar-overflow-button"); + is(panel.anchorNode, chevron, "Panel should be anchored to the chevron."); + + DownloadsPanel.hidePanel(); + + // Unlock the widths on the flex-y items. + unlockWidth(kFlexyItems); + + // Put the window back to its original dimensions. + window.resizeTo(oldWidth, window.outerHeight); + + // The downloads button should eventually be un-overflowed. + yield waitForOverflowed(button, false); + + // Now try opening the panel again. + promise = promisePanelOpened(); + button.node.doCommand(); + yield promise; + + is(panel.anchorNode.id, "downloads-indicator-anchor"); + + DownloadsPanel.hidePanel(); + } finally { + // Clean up when the test finishes. + yield task_resetState(); + } +} + +/** + * For some node IDs, finds the nodes and sets their min-width's to their + * current width, preventing them from flex-shrinking. + * + * @param aItemIDs an array of item IDs to set min-width on. + */ +function lockWidth(aItemIDs) { + for (let itemID of aItemIDs) { + let item = document.getElementById(itemID); + let curWidth = item.getBoundingClientRect().width + "px"; + item.style.minWidth = curWidth; + } +} + +/** + * Clears the min-width's set on a set of IDs by lockWidth. + * + * @param aItemIDs an array of ItemIDs to remove min-width on. + */ +function unlockWidth(aItemIDs) { + for (let itemID of aItemIDs) { + let item = document.getElementById(itemID); + item.style.minWidth = ""; + } +} + +/** + * Waits for a node to enter or exit the overflowed state. + * + * @param aItem the node to wait for. + * @param aIsOverflowed if we're waiting for the item to be overflowed. + */ +function waitForOverflowed(aItem, aIsOverflowed) { + let deferOverflow = Promise.defer(); + if (aItem.overflowed == aIsOverflowed) { + return deferOverflow.resolve(); + } + + let observer = new MutationObserver(function(aMutations) { + if (aItem.overflowed == aIsOverflowed) { + observer.disconnect(); + deferOverflow.resolve(); + } + }); + observer.observe(aItem.node, {attributes: true}); + + return deferOverflow.promise; +} diff --git a/browser/components/moz.build b/browser/components/moz.build index 0b7ceb049df846e13f8f3503733d0bd7c7b63f11..7284adb906f2542bbb7aedd39ddadeb7b8b2e99e 100644 --- a/browser/components/moz.build +++ b/browser/components/moz.build @@ -7,6 +7,7 @@ PARALLEL_DIRS += [ 'about', 'certerror', + 'customizableui', 'dirprovider', 'downloads', 'feeds', diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js index 0faef0444a310cde5457a3984184a3da3c6c3812..f5faade1039c4b6c7f9843bc3697cd0fbada168c 100644 --- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -1285,57 +1285,17 @@ BrowserGlue.prototype = { }, _migrateUI: function BG__migrateUI() { - const UI_VERSION = 14; + const UI_VERSION = 17; const BROWSER_DOCURL = "chrome://browser/content/browser.xul#"; - - let wasCustomizedAndOnAustralis = Services.prefs.prefHasUserValue("browser.uiCustomization.state"); let currentUIVersion = 0; try { currentUIVersion = Services.prefs.getIntPref("browser.migration.version"); } catch(ex) {} - if (!wasCustomizedAndOnAustralis && currentUIVersion >= UI_VERSION) + if (currentUIVersion >= UI_VERSION) return; this._rdf = Cc["@mozilla.org/rdf/rdf-service;1"].getService(Ci.nsIRDFService); this._dataSource = this._rdf.GetDataSource("rdf:local-store"); - - // No version check for this as this code should run until we have Australis everywhere: - if (wasCustomizedAndOnAustralis) { - // This profile's been on australis! If it's missing the back/fwd button - // or go/stop/reload button, then put them back: - let currentsetResource = this._rdf.GetResource("currentset"); - let toolbarResource = this._rdf.GetResource(BROWSER_DOCURL + "nav-bar"); - let currentset = this._getPersist(toolbarResource, currentsetResource); - let oldCurrentset = currentset; - if (currentset) { - if (currentset.indexOf("unified-back-forward-button") == -1) { - currentset = currentset.replace("urlbar-container", - "unified-back-forward-button,urlbar-container"); - } - if (currentset.indexOf("reload-button") == -1) { - currentset = currentset.replace("urlbar-container", "urlbar-container,reload-button"); - } - if (currentset.indexOf("stop-button") == -1) { - currentset = currentset.replace("reload-button", "reload-button,stop-button"); - } - } - Services.prefs.clearUserPref("browser.uiCustomization.state"); - - if (oldCurrentset != currentset) { - this._setPersist(toolbarResource, currentsetResource, currentset); - } - // If we don't have anything else to do, we can bail here: - if (currentUIVersion >= UI_VERSION) { - if (this._dirty) { - this._dataSource.QueryInterface(Ci.nsIRDFRemoteDataSource).Flush(); - } - delete this._rdf; - delete this._dataSource; - return; - } - } - - this._dirty = false; if (currentUIVersion < 2) { @@ -1519,6 +1479,60 @@ BrowserGlue.prototype = { OS.File.remove(path); } + if (currentUIVersion < 15) { + // Migrate users from text or text&icons mode to icons mode. + let updateToolbars = function (aToolbarIds, aResourceName, aResourceValue) { + let resource = this._rdf.GetResource(aResourceName); + for (toolbarId of aToolbarIds) { + let toolbar = this._rdf.GetResource(BROWSER_DOCURL + toolbarId); + let oldValue = this._getPersist(toolbar, resource); + if (oldValue && oldValue != aResourceValue) { + this._setPersist(toolbar, resource, aResourceValue); + } + } + }.bind(this); + + updateToolbars(["navigator-toolbox", "nav-bar", "PersonalToolbar", "addon-bar"], "mode", "icons"); + // Exclude PersonalToolbar and addon-bar since they have lockiconsize="true". + updateToolbars(["navigator-toolbox", "nav-bar"], "iconsize", "large"); + } + + if (currentUIVersion < 16) { + let toolbarResource = this._rdf.GetResource(BROWSER_DOCURL + "nav-bar"); + let collapsedResource = this._rdf.GetResource("collapsed"); + let isCollapsed = this._getPersist(toolbarResource, collapsedResource); + if (isCollapsed == "true") { + this._setPersist(toolbarResource, collapsedResource, "false"); + } + } + + // Insert the bookmarks-menu-button into the nav-bar if it isn't already + // there. + if (currentUIVersion < 17) { + let currentsetResource = this._rdf.GetResource("currentset"); + let toolbarResource = this._rdf.GetResource(BROWSER_DOCURL + "nav-bar"); + let currentset = this._getPersist(toolbarResource, currentsetResource); + // Need to migrate only if toolbar is customized. + if (currentset) { + if (!currentset.contains("bookmarks-menu-button")) { + // The button isn't in the nav-bar, so let's look for an appropriate + // place to put it. + if (currentset.contains("downloads-button")) { + currentset = currentset.replace(/(^|,)downloads-button($|,)/, + "$1bookmarks-menu-button,downloads-button$2"); + } else if (currentset.contains("home-button")) { + currentset = currentset.replace(/(^|,)home-button($|,)/, + "$1bookmarks-menu-button,home-button$2"); + } else { + // Just append. + currentset = currentset.replace(/(^|,)window-controls($|,)/, + "$1bookmarks-menu-button,window-controls$2") + } + this._setPersist(toolbarResource, currentsetResource, currentset); + } + } + } + if (this._dirty) this._dataSource.QueryInterface(Ci.nsIRDFRemoteDataSource).Flush(); diff --git a/browser/components/places/content/browserPlacesViews.js b/browser/components/places/content/browserPlacesViews.js index 33006fc3250e683b463cf3e09a9fcd5fa802ad4d..8c5900b26c523c53cf3a38860e20df756fb21e01 100644 --- a/browser/components/places/content/browserPlacesViews.js +++ b/browser/components/places/content/browserPlacesViews.js @@ -1745,3 +1745,157 @@ PlacesMenu.prototype = { } }; +function PlacesPanelMenuView(aPlace, aViewId, aRootId) { + this._viewElt = document.getElementById(aViewId); + this._rootElt = document.getElementById(aRootId); + this._viewElt._placesView = this; + + PlacesViewBase.call(this, aPlace); +} + +PlacesPanelMenuView.prototype = { + __proto__: PlacesViewBase.prototype, + + QueryInterface: function PAMV_QueryInterface(aIID) { + return PlacesViewBase.prototype.QueryInterface.apply(this, arguments); + }, + + uninit: function PAMV_uninit() { + PlacesViewBase.prototype.uninit.apply(this, arguments); + }, + + _insertNewItem: + function PAMV__insertNewItem(aChild, aBefore) { + this._domNodes.delete(aChild); + + let type = aChild.type; + let button; + if (type == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR) { + button = document.createElement("toolbarseparator"); + } + else { + button = document.createElement("toolbarbutton"); + button.className = "bookmark-item"; + button.setAttribute("label", aChild.title); + let icon = aChild.icon; + if (icon) + button.setAttribute("image", icon); + + if (PlacesUtils.containerTypes.indexOf(type) != -1) { + button.setAttribute("container", "true"); + + if (PlacesUtils.nodeIsQuery(aChild)) { + button.setAttribute("query", "true"); + if (PlacesUtils.nodeIsTagQuery(aChild)) + button.setAttribute("tagContainer", "true"); + } + else if (PlacesUtils.nodeIsFolder(aChild)) { + PlacesUtils.livemarks.getLivemark( + { id: aChild.itemId }, + function (aStatus, aLivemark) { + if (Components.isSuccessCode(aStatus)) { + button.setAttribute("livemark", "true"); + this.controller.cacheLivemarkInfo(aChild, aLivemark); + } + }.bind(this) + ); + } + } + else if (PlacesUtils.nodeIsURI(aChild)) { + button.setAttribute("scheme", + PlacesUIUtils.guessUrlSchemeForUI(aChild.uri)); + } + } + + button._placesNode = aChild; + if (!this._domNodes.has(aChild)) + this._domNodes.set(aChild, button); + + this._rootElt.insertBefore(button, aBefore); + }, + + nodeInserted: + function PAMV_nodeInserted(aParentPlacesNode, aPlacesNode, aIndex) { + let parentElt = this._getDOMNodeForPlacesNode(aParentPlacesNode); + if (parentElt != this._rootElt) + return; + + let children = this._rootElt.childNodes; + this._insertNewItem(aPlacesNode, + aIndex < children.length ? children[aIndex] : null); + }, + + nodeRemoved: + function PAMV_nodeRemoved(aParentPlacesNode, aPlacesNode, aIndex) { + let parentElt = this._getDOMNodeForPlacesNode(aParentPlacesNode); + if (parentElt != this._rootElt) + return; + + let elt = this._getDOMNodeForPlacesNode(aPlacesNode); + this._removeChild(elt); + }, + + nodeMoved: + function PAMV_nodeMoved(aPlacesNode, + aOldParentPlacesNode, aOldIndex, + aNewParentPlacesNode, aNewIndex) { + let parentElt = this._getDOMNodeForPlacesNode(aNewParentPlacesNode); + if (parentElt != this._rootElt) + return; + + let elt = this._getDOMNodeForPlacesNode(aPlacesNode); + this._removeChild(elt); + this._rootElt.insertBefore(elt, this._rootElt.childNodes[aNewIndex]); + }, + + nodeAnnotationChanged: + function PAMV_nodeAnnotationChanged(aPlacesNode, aAnno) { + let elt = this._getDOMNodeForPlacesNode(aPlacesNode); + // There's no UI representation for the root node. + if (elt == this._rootElt) + return; + + if (elt.parentNode != this._rootElt) + return; + + // All livemarks have a feedURI, so use it as our indicator. + if (aAnno == PlacesUtils.LMANNO_FEEDURI) { + elt.setAttribute("livemark", true); + + PlacesUtils.livemarks.getLivemark( + { id: aPlacesNode.itemId }, + function (aStatus, aLivemark) { + if (Components.isSuccessCode(aStatus)) { + this.controller.cacheLivemarkInfo(aPlacesNode, aLivemark); + this.invalidateContainer(aPlacesNode); + } + }.bind(this) + ); + } + }, + + nodeTitleChanged: function PAMV_nodeTitleChanged(aPlacesNode, aNewTitle) { + let elt = this._getDOMNodeForPlacesNode(aPlacesNode); + + // There's no UI representation for the root node. + if (elt == this._rootElt) + return; + + PlacesViewBase.prototype.nodeTitleChanged.apply(this, arguments); + }, + + invalidateContainer: function PAMV_invalidateContainer(aPlacesNode) { + let elt = this._getDOMNodeForPlacesNode(aPlacesNode); + if (elt != this._rootElt) + return; + + // Container is the toolbar itself. + while (this._rootElt.hasChildNodes()) { + this._rootElt.removeChild(this._rootElt.firstChild); + } + + for (let i = 0; i < this._resultNode.childCount; ++i) { + this._insertNewItem(this._resultNode.getChild(i), null); + } + } +}; diff --git a/browser/components/places/content/menu.xml b/browser/components/places/content/menu.xml index 3d297be533b94c44773c45fdc5f392d4a39f2de8..16de5cc57666ab96ecfac1d771e965cba218e95b 100644 --- a/browser/components/places/content/menu.xml +++ b/browser/components/places/content/menu.xml @@ -80,8 +80,8 @@ elt = elt.parentNode; // Calculate positions taking care of arrowscrollbox - let eventY = aEvent.layerY; let scrollbox = this._scrollBox; + let eventY = aEvent.layerY + (scrollbox.boxObject.y - this.boxObject.y); let scrollboxOffset = scrollbox.scrollBoxObject.y - (scrollbox.boxObject.y - this.boxObject.y); let eltY = elt.boxObject.y - scrollboxOffset; @@ -485,4 +485,121 @@ </handlers> </binding> + + <!-- Most of this is copied from the arrowpanel binding in popup.xml --> + <binding id="places-popup-arrow" + extends="chrome://browser/content/places/menu.xml#places-popup-base"> + <content flip="both" side="top" position="bottomcenter topleft"> + <xul:box anonid="container" class="panel-arrowcontainer" flex="1" + xbl:inherits="side,panelopen"> + <xul:box anonid="arrowbox" class="panel-arrowbox"> + <xul:image anonid="arrow" class="panel-arrow" xbl:inherits="side"/> + </xul:box> + <xul:box class="panel-arrowcontent" xbl:inherits="side,align,dir,orient,pack" flex="1"> + <xul:vbox class="menupopup-drop-indicator-bar" hidden="true"> + <xul:image class="menupopup-drop-indicator" mousethrough="always"/> + </xul:vbox> + <xul:arrowscrollbox class="popup-internal-box" flex="1" orient="vertical" + smoothscroll="false"> + <children/> + </xul:arrowscrollbox> + </xul:box> + </xul:box> + </content> + + <implementation> + <method name="adjustArrowPosition"> + <body><![CDATA[ + var arrow = document.getAnonymousElementByAttribute(this, "anonid", "arrow"); + + var anchor = this.anchorNode; + if (!anchor) { + arrow.hidden = true; + return; + } + + var container = document.getAnonymousElementByAttribute(this, "anonid", "container"); + var arrowbox = document.getAnonymousElementByAttribute(this, "anonid", "arrowbox"); + + // if this panel has a "sliding" arrow, we may have previously set margins... + arrowbox.style.removeProperty("margin"); + + var position = this.alignmentPosition; + if (position.indexOf("start_") == 0 || position.indexOf("end_") == 0) { + container.orient = ""; + arrowbox.orient = "vertical"; + if (position.indexOf("_after") > 0) { + arrowbox.pack = "end"; + arrowbox.style.marginBottom = this.alignmentOffset + "px"; + } else { + arrowbox.pack = "start"; + arrowbox.style.marginTop = this.alignmentOffset + "px"; + } + + // The assigned side stays the same regardless of direction. + var isRTL = (window.getComputedStyle(this).direction == "rtl"); + + if (position.indexOf("start_") == 0) { + container.dir = "reverse"; + this.setAttribute("side", isRTL ? "left" : "right"); + } + else { + container.dir = ""; + this.setAttribute("side", isRTL ? "right" : "left"); + } + } + else if (position.indexOf("before_") == 0 || position.indexOf("after_") == 0) { + container.orient = "vertical"; + arrowbox.orient = ""; + if (position.indexOf("_end") > 0) { + arrowbox.pack = "end"; + arrowbox.style.marginRight = this.alignmentOffset + "px"; + } else { + arrowbox.pack = "start"; + arrowbox.style.marginLeft = this.alignmentOffset + "px"; + } + + if (position.indexOf("before_") == 0) { + container.dir = "reverse"; + this.setAttribute("side", "bottom"); + } + else { + container.dir = ""; + this.setAttribute("side", "top"); + } + } + arrow.hidden = false; + ]]></body> + </method> + </implementation> + + <handlers> + <handler event="popupshowing" phase="target"><![CDATA[ + this.adjustArrowPosition(); + ]]></handler> + <handler event="popupshown" phase="target"><![CDATA[ + this.setAttribute("panelopen", "true"); + + // Allow anchoring to a specified element inside the anchor. + var anchorClass = this.getAttribute("anonanchorclass"); + if (anchorClass && this.anchorNode) { + let anchor = + document.getAnonymousElementByAttribute(this.anchorNode, "class", + anchorClass); + if (anchor) { + let offsetX = anchor.boxObject.width / 2; + if (this.alignmentPosition.endsWith("_end")) + offsetX *= -1; + this.popupBoxObject.moveToAnchor(anchor, this.alignmentPosition, + offsetX, 0, + false); + this.adjustArrowPosition(); + } + } + ]]></handler> + <handler event="popuphidden" phase="target"><![CDATA[ + this.removeAttribute("panelopen"); + ]]></handler> + </handlers> + </binding> </bindings> diff --git a/browser/components/tabview/test/browser_tabview_bug626791.js b/browser/components/tabview/test/browser_tabview_bug626791.js index d9f885cd8fadfe9a7de2c467d5d61cccd86e329f..2a57d1a2642aa9a171ac9ce788364599a5baed2e 100644 --- a/browser/components/tabview/test/browser_tabview_bug626791.js +++ b/browser/components/tabview/test/browser_tabview_bug626791.js @@ -1,6 +1,9 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ +Cu.import("resource:///modules/CustomizableUI.jsm"); + + function test() { let cw; let win; @@ -31,10 +34,7 @@ function test() { let pos = currentSet.indexOf(buttonId); if (-1 < pos) { - currentSet.splice(pos, 1); - toolbar.setAttribute("currentset", currentSet.join(",")); - toolbar.currentSet = currentSet.join(","); - win.document.persist(toolbar.id, "currentset"); + CustomizableUI.removeWidgetFromArea("tabview-button"); } } diff --git a/browser/locales/en-US/chrome/browser/browser.dtd b/browser/locales/en-US/chrome/browser/browser.dtd index 39bcc493abc8e54d61656599a97bf548829b5255..9b165c1d7fecccbd872e2bbb2699c1a2f6b9f037 100644 --- a/browser/locales/en-US/chrome/browser/browser.dtd +++ b/browser/locales/en-US/chrome/browser/browser.dtd @@ -15,6 +15,9 @@ inside the private browsing mode --> <!ENTITY mainWindow.titlePrivateBrowsingSuffix "(Private Browsing)"> +<!ENTITY appmenu.title "Customize and Control &brandFullName;"> +<!ENTITY navbarOverflow.label "More tools…"> + <!-- Tab context menu --> <!ENTITY reloadTab.label "Reload Tab"> <!ENTITY reloadTab.accesskey "R"> @@ -159,10 +162,8 @@ These should match what Safari and other Apple applications use on OS X Lion. -- <!ENTITY printButton.label "Print"> <!ENTITY printButton.tooltip "Print this page"> -<!ENTITY backForwardItem.title "Back/Forward"> <!ENTITY locationItem.title "Location"> <!ENTITY searchItem.title "Search"> -<!ENTITY bookmarksItem.title "Bookmarks"> <!-- Toolbar items --> <!ENTITY homeButton.label "Home"> @@ -176,7 +177,7 @@ These should match what Safari and other Apple applications use on OS X Lion. -- <!ENTITY bookmarksMenuButton.label "Bookmarks"> <!ENTITY bookmarksMenuButton.tooltip "Display your bookmarks"> <!ENTITY bookmarksMenuButton.unsorted.label "Unsorted Bookmarks"> -<!ENTITY viewBookmarksSidebar.label "Show in Sidebar"> +<!ENTITY viewBookmarksSidebar2.label "View Bookmarks Sidebar"> <!ENTITY viewBookmarksToolbar.label "View Bookmarks Toolbar"> <!-- LOCALIZATION NOTE (bookmarksSidebarGtkCmd.commandkey): This command @@ -328,12 +329,29 @@ These should match what Safari and other Apple applications use on OS X Lion. -- <!ENTITY showAllHistoryCmd.commandkey "H"> <!ENTITY appMenuCustomize.label "Customize"> +<!ENTITY appMenuHistory.label "History"> +<!ENTITY appMenuHistory.showAll.label "Show All History"> +<!ENTITY appMenuHistory.clearRecent.label "Clear Recent History…"> +<!ENTITY appMenuHistory.restoreSession.label "Restore Previous Session"> + +<!ENTITY customizeMenu.addToToolbar.label "Add to Toolbar"> +<!ENTITY customizeMenu.addToToolbar.accesskey "A"> +<!ENTITY customizeMenu.removeFromMenu.label "Remove from Menu"> +<!ENTITY customizeMenu.removeFromMenu.accesskey "R"> +<!ENTITY customizeMenu.addMoreItems.label "Add More Items…"> +<!ENTITY customizeMenu.addMoreItems.accesskey "A"> <!ENTITY openCmd.commandkey "l"> <!ENTITY urlbar.placeholder2 "Search or enter address"> <!ENTITY urlbar.accesskey "d"> <!ENTITY urlbar.switchToTab.label "Switch to tab:"> +<!-- LOCALIZATION NOTE (toggleMenuPanelMac.key) ideally this should be the same as + toggleMenuPanel. However, the modifier is different on mac (cmd+shift rather than ctrl) + and so you may need to pick a different key to avoid conflicts with other shortcuts. --> +<!ENTITY toggleMenuPanel.key "m"> +<!ENTITY toggleMenuPanelMac.key "m"> + <!-- Comment duplicated from browser-sets.inc: @@ -647,6 +665,13 @@ just addresses the organization to follow, e.g. "This site is run by " --> <!ENTITY social.learnMore.accesskey "l"> <!ENTITY social.closeNotificationItem.label "Not Now"> + + +<!ENTITY customizeMode.tabTitle "Customize &brandShortName;"> +<!ENTITY customizeMode.menuAndToolbars.label "Menu and toolbars"> +<!ENTITY customizeMode.menuAndToolbars.header "More Tools to Add to the Menu and Toolbar"> +<!ENTITY customizeMode.restoreDefaults "Restore Defaults"> + <!ENTITY social.chatBar.commandkey "c"> <!ENTITY social.chatBar.label "Focus chats"> <!ENTITY social.chatBar.accesskey "c"> @@ -723,5 +748,8 @@ just addresses the organization to follow, e.g. "This site is run by " --> <!ENTITY zoomControls.label "Zoom Controls"> <!ENTITY addonBarCloseButton.tooltip "Close Add-on Bar"> <!ENTITY toggleAddonBarCmd.key "/"> +<!ENTITY backForwardItem.title "Back/Forward"> +<!ENTITY viewBookmarksSidebar.label "Show in Sidebar"> +<!ENTITY bookmarksItem.title "Bookmarks"> <!-- end of strings to be removed post-Australis --> diff --git a/browser/locales/en-US/chrome/browser/customizableui/customizableWidgets.properties b/browser/locales/en-US/chrome/browser/customizableui/customizableWidgets.properties new file mode 100644 index 0000000000000000000000000000000000000000..58718c02c626302765a03545a962079cde1a3029 --- /dev/null +++ b/browser/locales/en-US/chrome/browser/customizableui/customizableWidgets.properties @@ -0,0 +1,76 @@ +# 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/. + +history-panelmenu.label = History +# LOCALIZATION NOTE (history-panelmenu.tooltiptext): Use the unicode ellipsis char, +# \u2026, or use "..." if \u2026 doesn't suit traditions in your locale. +history-panelmenu.tooltiptext = History… (%S) + +privatebrowsing-button.label = New Private Window +# LOCALIZATION NOTE(privatebrowsing-button.tooltiptext): %S is the keyboard shortcut +privatebrowsing-button.tooltiptext = Open a new Private Browsing window (%S) + +save-page-button.label = Save Page +# LOCALIZATION NOTE(save-page-button.tooltiptext): %S is the keyboard shortcut +save-page-button.tooltiptext = Save this page (%S) + +find-button.label = Find +# LOCALIZATION NOTE(find-button.tooltiptext): %S is the keyboard shortcut +find-button.tooltiptext = Find in this page (%S) + +open-file-button.label = Open File +# LOCALIZATION NOTE(open-file-button.tooltiptext): %S is the keyboard shortcut +open-file-button.tooltiptext = Open file (%S) + +developer-button.label = Developer +# LOCALIZATION NOTE(developer-button.tooltiptext): %S is the keyboard shortcut +developer-button.tooltiptext = Web Developer Tools (%S) + +add-ons-button.label = Add-ons +# LOCALIZATION NOTE(add-ons-button.tooltiptext): %S is the keyboard shortcut +add-ons-button.tooltiptext = Add-ons Manager (%S) + +preferences-button.label = Preferences +# LOCALIZATION NOTE (preferences-button.tooltiptext): Use the unicode ellipsis char, +# \u2026, or use "..." if \u2026 doesn't suit traditions in your locale. +preferences-button.tooltiptext = Preferences… +# LOCALIZATION NOTE (preferences-button.labelWin): Windows-only label for Options +preferences-button.labelWin = Options +# LOCALIZATION NOTE (preferences-button.tooltipWin): Windows-only tooltip for Options +preferences-button.tooltipWin = Options + +zoom-controls.label = Zoom Controls +zoom-controls.tooltiptext = Zoom Controls + +zoom-out-button.label = Zoom out +zoom-out-button.tooltiptext = Zoom out + +# LOCALIZATION NOTE(zoom-reset-button.label): %S is the current zoom level, +# %% will be displayed as a single % character (% is commonly used to define +# format specifiers, so it needs to be escaped). +zoom-reset-button.label = %S%% +zoom-reset-button.tooltiptext = Reset zoom level + +zoom-in-button.label = Zoom in +zoom-in-button.tooltiptext = Zoom in + +edit-controls.label = Edit Controls +edit-controls.tooltiptext = Edit Controls + +cut-button.label = Cut +cut-button.tooltiptext = Cut + +copy-button.label = Copy +copy-button.tooltiptext = Copy + +paste-button.label = Paste +paste-button.tooltiptext = Paste + +# LOCALIZATION NOTE (feed-button.tooltiptext): Use the unicode ellipsis char, +# \u2026, or use "..." if \u2026 doesn't suit traditions in your locale. +feed-button.label = Subscribe +feed-button.tooltiptext = Subscribe to this page… + +characterencoding-button.label = Character Encoding +characterencoding-button.tooltiptext = Character encoding diff --git a/browser/locales/jar.mn b/browser/locales/jar.mn index 99ae32d671d051aa14fac78d269b5e35e51ca29a..23af3724066a53266668629b21d54300dce2311e 100644 --- a/browser/locales/jar.mn +++ b/browser/locales/jar.mn @@ -22,6 +22,7 @@ locale/browser/browser.dtd (%chrome/browser/browser.dtd) locale/browser/baseMenuOverlay.dtd (%chrome/browser/baseMenuOverlay.dtd) locale/browser/browser.properties (%chrome/browser/browser.properties) + locale/browser/customizableui/customizableWidgets.properties (%chrome/browser/customizableui/customizableWidgets.properties) locale/browser/devtools/appcacheutils.properties (%chrome/browser/devtools/appcacheutils.properties) locale/browser/devtools/debugger.dtd (%chrome/browser/devtools/debugger.dtd) locale/browser/devtools/debugger.properties (%chrome/browser/devtools/debugger.properties) diff --git a/browser/modules/UITour.jsm b/browser/modules/UITour.jsm index 67c74a8b1cb439a0b752aa5d1223d7018f2ef9e3..6ae917fb768da1b87bb01342cd876777c222d05f 100644 --- a/browser/modules/UITour.jsm +++ b/browser/modules/UITour.jsm @@ -26,8 +26,8 @@ this.UITour = { highlightEffects: ["wobble", "zoom", "color"], targets: new Map([ - ["backforward", "#unified-back-forward-button"], - ["appmenu", "#appmenu-button"], + ["backforward", "#back-button"], + ["appmenu", "#PanelUI-menu-button"], ["home", "#home-button"], ["urlbar", "#urlbar"], ["bookmarks", "#bookmarks-menu-button"], @@ -388,7 +388,7 @@ this.UITour = { } if (aMenuName == "appmenu") - openMenuButton("appmenu-button"); + aWindow.PanelUI.show(); else if (aMenuName == "bookmarks") openMenuButton("bookmarks-menu-button"); }, diff --git a/browser/modules/webappsUI.jsm b/browser/modules/webappsUI.jsm index 7afbb32d0724cdc9ca76a1de12c16906258bed08..f44555359d140c068f562b05938b5342b253789e 100644 --- a/browser/modules/webappsUI.jsm +++ b/browser/modules/webappsUI.jsm @@ -96,48 +96,6 @@ this.webappsUI = { return someWindow && Services.wm.getOuterWindowWithId(aId); }, - openURL: function(aUrl, aOrigin) { - let browserEnumerator = Services.wm.getEnumerator("navigator:browser"); - let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore); - - // Check each browser instance for our URL - let found = false; - while (!found && browserEnumerator.hasMoreElements()) { - let browserWin = browserEnumerator.getNext(); - if (browserWin.closed) { - continue; - } - let tabbrowser = browserWin.gBrowser; - - // Check each tab of this browser instance - let numTabs = tabbrowser.tabs.length; - for (let index = 0; index < numTabs; index++) { - let tab = tabbrowser.tabs[index]; - let appURL = ss.getTabValue(tab, "appOrigin"); - if (appURL == aOrigin) { - // The URL is already opened. Select this tab. - tabbrowser.selectedTab = tab; - browserWin.focus(); - found = true; - break; - } - } - } - - // Our URL isn't open. Open it now. - if (!found) { - let recentWindow = Services.wm.getMostRecentWindow("navigator:browser"); - if (recentWindow) { - // Use an existing browser window - let browser = recentWindow.gBrowser; - let tab = browser.addTab(aUrl); - browser.pinTab(tab); - browser.selectedTab = tab; - ss.setTabValue(tab, "appOrigin", aOrigin); - } - } - }, - doInstall: function(aData, aWindow) { let browser = aWindow.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebNavigation) diff --git a/browser/themes/linux/Go-arrow.png b/browser/themes/linux/Go-arrow.png deleted file mode 100644 index 259c8a4f01cd6a929a3440a5b579fef5275ce0ae..0000000000000000000000000000000000000000 Binary files a/browser/themes/linux/Go-arrow.png and /dev/null differ diff --git a/browser/themes/linux/Makefile.in b/browser/themes/linux/Makefile.in index 173ca68435c6cf993204e3cca62ac579ab2537ba..67f553d6ef9c39898f407b06a620793765675727 100644 --- a/browser/themes/linux/Makefile.in +++ b/browser/themes/linux/Makefile.in @@ -5,3 +5,23 @@ ICON_FILES := icon.png ICON_DEST = $(FINAL_TARGET)/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd} INSTALL_TARGETS += ICON + +# By default, the pre-processor used for jar.mn will use "%" as a marker for ".css" files and "#" +# otherwise. This falls apart when a file using one marker needs to include a file with the other +# marker since the pre-processor instructions in the included file will not be processed. The +# following SVG files need to include a file which uses "%" as the marker so we invoke the pre- +# processor ourselves here with the marker specified. The resulting SVG files will get packaged by +# the processing of the jar file in this directory. +tab-selected-svg: $(srcdir)/../shared/tab-selected.svg + $(call py_action,preprocessor, \ + --marker "%" -D TAB_SIDE=start \ + $(ACDEFINES) \ + $(srcdir)/../shared/tab-selected.svg -o tab-selected-start.svg) + $(call py_action,preprocessor, \ + --marker "%" -D TAB_SIDE=end \ + $(ACDEFINES) \ + $(srcdir)/../shared/tab-selected.svg -o tab-selected-end.svg) + +.PHONY: tab-selected-svg + +export:: tab-selected-svg diff --git a/browser/themes/linux/Toolbar-inverted.png b/browser/themes/linux/Toolbar-inverted.png new file mode 100644 index 0000000000000000000000000000000000000000..b42fd7475dbe89ff00dfcf875c45f76c839fab05 Binary files /dev/null and b/browser/themes/linux/Toolbar-inverted.png differ diff --git a/browser/themes/linux/Toolbar-small.png b/browser/themes/linux/Toolbar-small.png index bcc8f63dcd9fef85eaec6181a36f75e7519c81b6..8f100a54a7d34d0f754e2908657083598fc75ded 100644 Binary files a/browser/themes/linux/Toolbar-small.png and b/browser/themes/linux/Toolbar-small.png differ diff --git a/browser/themes/linux/Toolbar.png b/browser/themes/linux/Toolbar.png index 2851657ecaf324ffd663dbb6b3e37586c977b939..687cc1b3dad4197e98b3f39a8d75878c954b13f9 100644 Binary files a/browser/themes/linux/Toolbar.png and b/browser/themes/linux/Toolbar.png differ diff --git a/browser/themes/linux/browser-lightweightTheme.css b/browser/themes/linux/browser-lightweightTheme.css new file mode 100644 index 0000000000000000000000000000000000000000..012b7191ce9654796c10b617fdd20843e7f96fbb --- /dev/null +++ b/browser/themes/linux/browser-lightweightTheme.css @@ -0,0 +1,29 @@ +/* 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/. */ + +%include linuxShared.inc +%filter substitution + +/* + * LightweightThemeListener will append the current lightweight theme's header + * image to the background-image for each of the following rulesets. + */ + +/* Lightweight theme on tabs */ +#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start[selected=true]:-moz-lwtheme::before, +#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end[selected=true]:-moz-lwtheme::before { + background-attachment: scroll, fixed; + background-color: transparent; + background-image: @fgTabTextureLWT@;/*, lwtHeader;*/ + background-position: 0 0, right top; +} + +#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme { + background-attachment: scroll, scroll, fixed; + background-color: transparent; + background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png), + @fgTabTextureLWT@;/*, + lwtHeader;*/ + background-position: 0 0, 0 0, right top; +} diff --git a/browser/themes/linux/browser.css b/browser/themes/linux/browser.css index e042ba5994d97c959f75376ec6ed06382153bf7a..1728faf0dd8892b3fc99902e7f894f4962f73a08 100644 --- a/browser/themes/linux/browser.css +++ b/browser/themes/linux/browser.css @@ -10,14 +10,12 @@ @namespace html url("http://www.w3.org/1999/xhtml"); %include ../shared/browser.inc +%include linuxShared.inc %filter substitution -%define toolbarHighlight rgba(255,255,255,.3) -%define selectedTabHighlight rgba(255,255,255,.8) 1px, rgba(255,255,255,.5) 3px + %define forwardTransitionLength 150ms -%define conditionalForwardWithUrlbar window:not([chromehidden~=toolbar]) :-moz-any(#nav-bar[currentset*="unified-back-forward-button,urlbar-container"][mode=icons], #nav-bar:not([currentset])[mode=icons]) > #unified-back-forward-button -%define conditionalForwardWithUrlbar_small window:not([chromehidden~=toolbar]) :-moz-any(#nav-bar[currentset*="unified-back-forward-button,urlbar-container"][mode=icons][iconsize=small],#nav-bar:not([currentset])[mode=icons][iconsize=small]) > #unified-back-forward-button -%define conditionalForwardWithUrlbarWidth 32 -%define conditionalForwardWithUrlbarWidth_small 24 +%define conditionalForwardWithUrlbar window:not([chromehidden~="toolbar"]) #urlbar-container +%define conditionalForwardWithUrlbarWidth 26 #menubar-items { -moz-box-orient: vertical; /* for flex hack */ @@ -31,14 +29,10 @@ -moz-appearance: none; background-color: transparent; border-top: none; -} - -#main-window:not([disablechrome]) #navigator-toolbox[tabsontop=true] { border-bottom: 1px solid ThreeDShadow; } -#navigator-toolbox[tabsontop=true] > toolbar:not(:-moz-lwtheme):not(#toolbar-menubar):not(#TabsToolbar), -#navigator-toolbox[tabsontop=false] > toolbar:not(:-moz-lwtheme):not(#toolbar-menubar) { +#navigator-toolbox > toolbar:not(:-moz-lwtheme):not(#toolbar-menubar):not(#TabsToolbar) { -moz-appearance: none; border-style: none; background-color: -moz-Dialog; @@ -49,13 +43,19 @@ padding-bottom: 1px; } -#nav-bar:not(:-moz-lwtheme), -#nav-bar[collapsed=true] + toolbar:not(:-moz-lwtheme), -#nav-bar[collapsed=true] + #customToolbars + #PersonalToolbar:not(:-moz-lwtheme), -#nav-bar[tabsontop=true], -#nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + toolbar, -#nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + #customToolbars + #PersonalToolbar { +#nav-bar { background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0)); + box-shadow: 0 1px 0 @toolbarHighlight@ inset; + margin-top: -1px; /* Move up 1px into the TabsToolbar */ + padding-top: 2px; + padding-bottom: 2px; + /* Position the toolbar above the bottom of background tabs */ + position: relative; + z-index: 1; +} + +#nav-bar-overflow-button { + -moz-image-region: rect(-5px, 12px, 11px, -4px); } #personal-bookmarks { @@ -73,7 +73,8 @@ } /* Places toolbar */ -toolbarbutton.bookmark-item { +toolbarbutton.bookmark-item, +#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder { margin: 0; padding: 2px 3px; } @@ -86,13 +87,15 @@ toolbarbutton.bookmark-item[open="true"] { -moz-padding-end: 2px; } -.bookmark-item > .toolbarbutton-icon { +.bookmark-item > .toolbarbutton-icon, +#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-icon { width: 16px; height: 16px; } -/* Prevent [mode="icons"] from hiding the label */ -.bookmark-item > .toolbarbutton-text { +/* Force the display of the label for bookmarks */ +.bookmark-item > .toolbarbutton-text, +#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-text { display: -moz-box !important; } @@ -105,12 +108,7 @@ toolbarbutton.bookmark-item[open="true"] { display: -moz-box !important; } -#wrapper-personal-bookmarks[place="palette"] > .toolbarpaletteitem-box { - background: url("chrome://browser/skin/places/bookmarksToolbar.png") no-repeat center; -} - -.bookmarks-toolbar-customize { - max-width: 15em !important; +#bookmarks-toolbar-placeholder { list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png") !important; } @@ -213,7 +211,6 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) { -moz-binding: url("chrome://global/content/bindings/menu.xml#menuitem-iconic"); } -#appmenu_newNavigator, #placesContext_open\:newwindow, #menu_newNavigator, #context-openlink, @@ -222,8 +219,6 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) { -moz-image-region: rect(0px 80px 16px 64px); } -#appmenu_newTab, -#appmenu_newTab_popup, #placesContext_open\:newtab, #placesContext_openContainer\:tabs, #menu_newNavigatorTab, @@ -233,7 +228,6 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) { -moz-image-region: rect(0px 64px 16px 48px); } -#appmenu_openFile, #menu_openFile { list-style-image: url("moz-icon://stock/gtk-open?size=menu"); } @@ -250,7 +244,6 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) { list-style-image: url("moz-icon://stock/gtk-media-pause?size=menu"); } -#appmenu_savePage, #menu_savePage, #context-savelink, #context-saveimage, @@ -261,19 +254,15 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) { list-style-image: url("moz-icon://stock/gtk-save-as?size=menu"); } -#appmenu_printPreview, #menu_printPreview { list-style-image: url("moz-icon://stock/gtk-print-preview?size=menu"); } -#appmenu_print, -#appmenu_print_popup, #menu_print, #context-printframe { list-style-image: url("moz-icon://stock/gtk-print?size=menu"); } -#appmenu-quit, #menu_FileQuitItem { list-style-image: url("moz-icon://stock/gtk-quit?size=menu"); } @@ -356,7 +345,6 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) { list-style-image: url("moz-icon://stock/gtk-select-all?size=menu"); } -#appmenu_find, #menu_find { list-style-image: url("moz-icon://stock/gtk-find?size=menu"); } @@ -365,8 +353,6 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) { list-style-image: url("moz-icon://stock/gtk-find?size=menu&state=disabled"); } -#appmenu_customize, -#appmenu_preferences, #menu_preferences { list-style-image: url("moz-icon://stock/gtk-preferences?size=menu"); } @@ -433,15 +419,11 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) { list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=menu&state=disabled"); } -#appmenu_history, -#appmenu_showAllHistory, #menu_showAllHistory { list-style-image: url("chrome://browser/skin/Toolbar-small.png"); -moz-image-region: rect(0px 32px 16px 16px); } -#appmenu_bookmarks, -#appmenu_showAllBookmarks, #bookmarksShowAll { list-style-image: url("chrome://browser/skin/Toolbar-small.png"); -moz-image-region: rect(0px 48px 16px 32px); @@ -455,25 +437,21 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) { } #bookmarksToolbarFolderMenu, -#BMB_bookmarksToolbar { +#BMB_bookmarksToolbar, +#panelMenu_bookmarksToolbar { list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png"); } -#BMB_bookmarkThisPage { - list-style-image: url("chrome://browser/skin/places/starPage.png"); -} - -#BMB_unsortedBookmarks { +#BMB_unsortedBookmarks, +#panelMenu_unsortedBookmarks { list-style-image: url("chrome://browser/skin/places/unsortedBookmarks.png"); } -#appmenu_downloads, #menu_openDownloads { list-style-image: url("chrome://browser/skin/Toolbar-small.png"); -moz-image-region: rect(0px 16px 16px 0px); } -#appmenu_addons, #menu_openAddons { list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric-16.png"); } @@ -484,8 +462,6 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) { list-style-image: url("moz-icon://stock/gtk-info?size=menu"); } -#appmenu_privateBrowsing, -#appmenu_newPrivateWindow, #privateBrowsingItem { list-style-image: url("chrome://browser/skin/Privacy-16.png"); } @@ -494,18 +470,14 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) { list-style-image: url("moz-icon://stock/gtk-properties?size=menu"); } -#appmenu_sanitizeHistory, #sanitizeItem { list-style-image: url("moz-icon://stock/gtk-clear?size=menu"); } -#appmenu_help, -#appmenu_openHelp, #menu_openHelp { list-style-image: url("moz-icon://stock/gtk-help?size=menu"); } -#appmenu_about, #aboutName { list-style-image: url("moz-icon://stock/gtk-about?size=menu"); } @@ -515,21 +487,10 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) { } /* Primary toolbar buttons */ -.toolbarbutton-1:not([type="menu-button"]) { - -moz-box-orient: vertical; - min-width: 0; - list-style-image: url("chrome://browser/skin/Toolbar.png"); -} - .toolbarbutton-1 > .toolbarbutton-icon { -moz-margin-end: 0; } -toolbar[mode="full"] .toolbarbutton-1:not([type="menu-button"]), -toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button { - min-width: 57px; -} - .toolbarbutton-1:not([type="menu-button"]), .toolbarbutton-1 > .toolbarbutton-menubutton-button { padding: 5px; @@ -539,66 +500,14 @@ toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button { padding: 5px !important; } -/* 24px primary toolbar buttons */ -#back-button { - list-style-image: url("moz-icon://stock/gtk-go-back-ltr?size=toolbar"); -} -#back-button[disabled="true"] { - list-style-image: url("moz-icon://stock/gtk-go-back-ltr?size=toolbar&state=disabled"); -} - -#back-button:-moz-locale-dir(rtl) { - list-style-image: url("moz-icon://stock/gtk-go-back-rtl?size=toolbar"); -} -#back-button[disabled="true"]:-moz-locale-dir(rtl) { - list-style-image: url("moz-icon://stock/gtk-go-back-rtl?size=toolbar&state=disabled"); -} - -#forward-button, -@conditionalForwardWithUrlbar@ > #forward-button { - list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar"); -} -#forward-button:-moz-locale-dir(rtl), -@conditionalForwardWithUrlbar@ > #forward-button:-moz-locale-dir(rtl) { - list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=toolbar"); -} - #forward-button[disabled] { - list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar&state=disabled"); -} -#forward-button[disabled]:-moz-locale-dir(rtl) { - list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=toolbar&state=disabled"); -} - -@conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button { - transition: @forwardTransitionLength@ ease-out; -} - -@conditionalForwardWithUrlbar@ > #forward-button[disabled] { transform: scale(0); opacity: 0; pointer-events: none; } -#reload-button { - list-style-image: url("moz-icon://stock/gtk-refresh?size=toolbar"); -} -#reload-button[disabled="true"] { - list-style-image: url("moz-icon://stock/gtk-refresh?size=toolbar&state=disabled"); -} - -#stop-button { - list-style-image: url("moz-icon://stock/gtk-stop?size=toolbar"); -} -#stop-button[disabled="true"] { - list-style-image: url("moz-icon://stock/gtk-stop?size=toolbar&state=disabled"); -} - -#home-button { - list-style-image: url("moz-icon://stock/gtk-home?size=toolbar"); -} -#home-button[disabled="true"] { - list-style-image: url("moz-icon://stock/gtk-home?size=toolbar&state=disabled"); +@conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button { + transition: @forwardTransitionLength@ ease-out; } /* tabview button */ @@ -629,34 +538,10 @@ toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button { -moz-image-region: rect(0, 64px, 16px, 48px); } -#downloads-button { - -moz-image-region: rect(0px 24px 24px 0px); -} - -#history-button { - -moz-image-region: rect(0px 48px 24px 24px); -} - -#bookmarks-button, -#bookmarks-menu-button { +#bookmarks-button { -moz-image-region: rect(0px 72px 24px 48px); } -#bookmarks-menu-button.bookmark-item { - list-style-image: url("chrome://browser/skin/Toolbar-small.png"); -} - -#bookmarks-menu-button.toolbarbutton-1 { - -moz-box-orient: horizontal; -} - -#print-button { - list-style-image: url("moz-icon://stock/gtk-print?size=toolbar"); -} -#print-button[disabled="true"] { - list-style-image: url("moz-icon://stock/gtk-print?size=toolbar&state=disabled"); -} - #new-tab-button { -moz-image-region: rect(0px 96px 24px 72px); } @@ -665,39 +550,6 @@ toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button { -moz-image-region: rect(0px 120px 24px 96px); } -#cut-button { - list-style-image: url("moz-icon://stock/gtk-cut?size=toolbar"); -} -#cut-button[disabled="true"] { - list-style-image: url("moz-icon://stock/gtk-cut?size=toolbar&state=disabled"); -} - -#copy-button { - list-style-image: url("moz-icon://stock/gtk-copy?size=toolbar"); -} -#copy-button[disabled="true"] { - list-style-image: url("moz-icon://stock/gtk-copy?size=toolbar&state=disabled"); -} - -#paste-button { - list-style-image: url("moz-icon://stock/gtk-paste?size=toolbar"); -} -#paste-button[disabled="true"] { - list-style-image: url("moz-icon://stock/gtk-paste?size=toolbar&state=disabled"); -} - -#fullscreen-button { - list-style-image: url("moz-icon://stock/gtk-fullscreen?size=toolbar"); -} - -#zoom-out-button { - list-style-image: url("moz-icon://stock/gtk-zoom-out?size=toolbar"); -} - -#zoom-in-button { - list-style-image: url("moz-icon://stock/gtk-zoom-in?size=toolbar"); -} - #sync-button { -moz-image-region: rect(0px 144px 24px 120px); } @@ -718,159 +570,36 @@ toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button { -moz-image-region: rect(0px 192px 24px 168px); } -/* 16px primary toolbar buttons */ -toolbar[iconsize="small"] .toolbarbutton-1:not([type="menu-button"]) { - -moz-box-orient: vertical; - min-width: 0; - list-style-image: url("chrome://browser/skin/Toolbar-small.png"); -} - -toolbar[iconsize="small"] .toolbarbutton-1[type="menu-button"] { - border: 0 !important; -} - -toolbar[iconsize="small"] #back-button { - list-style-image: url("moz-icon://stock/gtk-go-back-ltr?size=menu"); -} .unified-nav-back[_moz-menuactive] { list-style-image: url("moz-icon://stock/gtk-go-back-ltr?size=menu") !important; } -toolbar[iconsize="small"] #back-button[disabled="true"] { - list-style-image: url("moz-icon://stock/gtk-go-back-ltr?size=menu&state=disabled"); -} - -toolbar[iconsize="small"] #back-button:-moz-locale-dir(rtl) { - list-style-image: url("moz-icon://stock/gtk-go-back-rtl?size=menu"); -} .unified-nav-back[_moz-menuactive]:-moz-locale-dir(rtl) { list-style-image: url("moz-icon://stock/gtk-go-back-rtl?size=menu") !important; } -toolbar[iconsize="small"] #back-button[disabled="true"]:-moz-locale-dir(rtl) { - list-style-image: url("moz-icon://stock/gtk-go-back-rtl?size=menu&state=disabled"); -} - -toolbar[iconsize=small] #forward-button, -@conditionalForwardWithUrlbar_small@ > #forward-button { - list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=menu"); -} .unified-nav-forward[_moz-menuactive] { list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=menu") !important; } -toolbar[iconsize=small] #forward-button[disabled] { - list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=menu&state=disabled"); -} - -toolbar[iconsize=small] #forward-button:-moz-locale-dir(rtl), -@conditionalForwardWithUrlbar_small@ > #forward-button:-moz-locale-dir(rtl) { - list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=menu"); -} .unified-nav-forward[_moz-menuactive]:-moz-locale-dir(rtl) { list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=menu") !important; } -toolbar[iconsize=small] #forward-button[disabled]:-moz-locale-dir(rtl) { - list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=menu&state=disabled"); -} - -toolbar[iconsize="small"] #stop-button { - list-style-image: url("moz-icon://stock/gtk-stop?size=menu"); -} -toolbar[iconsize="small"] #stop-button[disabled="true"] { - list-style-image: url("moz-icon://stock/gtk-stop?size=menu&state=disabled"); -} - -toolbar[iconsize="small"] #reload-button { - list-style-image: url("moz-icon://stock/gtk-refresh?size=menu"); -} -toolbar[iconsize="small"] #reload-button[disabled="true"] { - list-style-image: url("moz-icon://stock/gtk-refresh?size=menu&state=disabled"); -} - -toolbar[iconsize="small"] #home-button, #home-button.bookmark-item { list-style-image: url("moz-icon://stock/gtk-home?size=menu"); } -toolbar[iconsize="small"] #home-button[disabled="true"], #home-button.bookmark-item[disabled="true"] { list-style-image: url("moz-icon://stock/gtk-home?size=menu&state=disabled"); } -toolbar[iconsize="small"] #downloads-button { - -moz-image-region: rect(0px 16px 16px 0px); -} - -toolbar[iconsize="small"] #webrtc-status-button /* temporary placeholder (bug 824825) */, -toolbar[iconsize="small"] #history-button { - -moz-image-region: rect(0px 32px 16px 16px); -} - -toolbar[iconsize="small"] #bookmarks-button, -toolbar[iconsize="small"] #bookmarks-menu-button, -#bookmarks-menu-button.bookmark-item { - -moz-image-region: rect(0px 48px 16px 32px); -} - -toolbar[iconsize="small"] #print-button { - list-style-image: url("moz-icon://stock/gtk-print?size=menu"); -} -toolbar[iconsize="small"] #print-button[disabled="true"] { - list-style-image: url("moz-icon://stock/gtk-print?size=menu&state=disabled"); -} - -toolbar[iconsize="small"] #new-tab-button { - -moz-image-region: rect(0px 64px 16px 48px); -} - -toolbar[iconsize="small"] #new-window-button { - -moz-image-region: rect(0px 80px 16px 64px); -} - -toolbar[iconsize="small"] #cut-button { - list-style-image: url("moz-icon://stock/gtk-cut?size=menu"); -} -toolbar[iconsize="small"] #cut-button[disabled="true"] { - list-style-image: url("moz-icon://stock/gtk-cut?size=menu&state=disabled"); -} - -toolbar[iconsize="small"] #copy-button { - list-style-image: url("moz-icon://stock/gtk-copy?size=menu"); -} -toolbar[iconsize="small"] #copy-button[disabled="true"] { - list-style-image: url("moz-icon://stock/gtk-copy?size=menu&state=disabled"); -} - -toolbar[iconsize="small"] #paste-button { - list-style-image: url("moz-icon://stock/gtk-paste?size=menu"); -} -toolbar[iconsize="small"] #paste-button[disabled="true"] { - list-style-image: url("moz-icon://stock/gtk-paste?size=menu&state=disabled"); -} - -toolbar[iconsize="small"] #fullscreen-button { - list-style-image: url("moz-icon://stock/gtk-fullscreen?size=menu"); -} - -toolbar[iconsize="small"] #zoom-out-button { - list-style-image: url("moz-icon://stock/gtk-zoom-out?size=menu"); -} - -toolbar[iconsize="small"] #zoom-in-button { - list-style-image: url("moz-icon://stock/gtk-zoom-in?size=menu"); -} - -toolbar[iconsize="small"] #sync-button { - -moz-image-region: rect(0px 96px 16px 80px); -} -toolbar[iconsize="small"] #sync-button[status="active"] { - list-style-image: url("chrome://browser/skin/sync-16-throbber.png"); - -moz-image-region: rect(0px 16px 16px 0px); -} +/* Menu panel buttons */ -toolbar[iconsize="small"] #feed-button { - -moz-image-region: rect(0px 112px 16px 96px); -} +%include ../shared/toolbarbuttons.inc.css +%include ../shared/menupanel.inc.css -toolbar[iconsize="small"] #webrtc-status-button { - -moz-image-region: rect(0px 128px 16px 112px); +#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-icon, +#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-menu-dropmarker, +#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-menubutton-dropmarker, +#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-menubutton-button > .toolbarbutton-icon, +#main-window:not([customizing]) .toolbarbutton-1 > .toolbarbutton-menubutton-button[disabled] > .toolbarbutton-icon { + opacity: 0.4; } /* Fullscreen window controls */ @@ -915,39 +644,28 @@ toolbar[iconsize="small"] #webrtc-status-button { -moz-box-align: stretch; } -@conditionalForwardWithUrlbar@ + #urlbar-container { +@conditionalForwardWithUrlbar@ > #urlbar-wrapper { -moz-padding-start: @conditionalForwardWithUrlbarWidth@px; -moz-margin-start: -@conditionalForwardWithUrlbarWidth@px; position: relative; pointer-events: none; } -@conditionalForwardWithUrlbar_small@ + #urlbar-container { - -moz-padding-start: @conditionalForwardWithUrlbarWidth_small@px; - -moz-margin-start: -@conditionalForwardWithUrlbarWidth_small@px; -} - -@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar { +@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar { pointer-events: all; } -@conditionalForwardWithUrlbar@:not([switchingtabs]) + #urlbar-container > #urlbar { +@conditionalForwardWithUrlbar@:not([switchingtabs]) > #urlbar-wrapper > #urlbar { transition: margin-left @forwardTransitionLength@ ease-out, margin-right @forwardTransitionLength@ ease-out; } -@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar:-moz-locale-dir(ltr) { +@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar:-moz-locale-dir(ltr) { margin-left: -@conditionalForwardWithUrlbarWidth@px; } -@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar:-moz-locale-dir(rtl) { +@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) { margin-right: -@conditionalForwardWithUrlbarWidth@px; } -@conditionalForwardWithUrlbar_small@[forwarddisabled] + #urlbar-container > #urlbar:-moz-locale-dir(ltr) { - margin-left: -@conditionalForwardWithUrlbarWidth_small@px; -} -@conditionalForwardWithUrlbar_small@[forwarddisabled] + #urlbar-container > #urlbar:-moz-locale-dir(rtl) { - margin-right: -@conditionalForwardWithUrlbarWidth_small@px; -} #urlbar-icons { -moz-box-align: center; @@ -964,7 +682,7 @@ toolbar[iconsize="small"] #webrtc-status-button { -moz-margin-start: -4px; } -#urlbar-search-splitter + #urlbar-container > #urlbar , +#urlbar-search-splitter + #urlbar-container > #urlbar-wrapper > #urlbar, #urlbar-search-splitter + #search-container > #searchbar > .searchbar-textbox { -moz-margin-start: 0; } @@ -1433,35 +1151,61 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- /* Combined go/reload/stop button in location bar */ -#go-button { - padding-top: 2px; - padding-bottom: 2px; -} - #urlbar > toolbarbutton { -moz-appearance: none; - padding: 0; - border: none; + padding: 0 2px; cursor: pointer; - width: 22px; + list-style-image: url("chrome://browser/skin/reload-stop-go.png"); +} + +#urlbar-reload-button { + -moz-image-region: rect(0, 14px, 14px, 0); +} + +#urlbar-reload-button:not([disabled]):hover { + background-image: radial-gradient(circle closest-side, hsla(200,100%,70%,.2), hsla(200,100%,70%,0)); + -moz-image-region: rect(14px, 14px, 28px, 0); +} + +#urlbar-reload-button:not([disabled]):hover:active { + background-image: radial-gradient(circle closest-side, hsla(200,100%,60%,.1), hsla(200,100%,60%,0)); + -moz-image-region: rect(28px, 14px, 42px, 0); +} + +#urlbar-reload-button:-moz-locale-dir(rtl) > .toolbarbutton-icon { + transform: scaleX(-1); } -#go-button, #urlbar-go-button { - list-style-image: url("chrome://browser/skin/Go-arrow.png"); + -moz-image-region: rect(0, 42px, 14px, 28px); +} + +#urlbar-go-button:hover { + background-image: radial-gradient(circle closest-side, hsla(110,70%,50%,.2), hsla(110,70%,50%,0)); + -moz-image-region: rect(14px, 42px, 28px, 28px); +} + +#urlbar-go-button:hover:active { + background-image: radial-gradient(circle closest-side, hsla(110,70%,50%,.1), hsla(110,70%,50%,0)); + -moz-image-region: rect(28px, 42px, 42px, 28px); } -#go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon, #urlbar-go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon { transform: scaleX(-1); } -#urlbar-reload-button { - list-style-image: url("moz-icon://stock/gtk-refresh?size=menu"); +#urlbar-stop-button { + -moz-image-region: rect(0, 28px, 14px, 14px); } -#urlbar-stop-button { - list-style-image: url("moz-icon://stock/gtk-stop?size=menu"); +#urlbar-stop-button:not([disabled]):hover { + background-image: radial-gradient(circle closest-side, hsla(5,100%,75%,.3), hsla(5,100%,75%,0)); + -moz-image-region: rect(14px, 28px, 28px, 14px); +} + +#urlbar-stop-button:hover:active { + background-image: radial-gradient(circle closest-side, hsla(5,100%,75%,.1), hsla(5,100%,75%,0)); + -moz-image-region: rect(28px, 28px, 42px, 14px); } /* Popup blocker button */ @@ -1533,25 +1277,53 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- -moz-image-region: rect(0, 16px, 16px, 0); } -/* Star button */ -#star-button { - list-style-image: url("chrome://browser/skin/places/starPage.png"); +/* bookmarks menu-button */ + +#bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker { + -moz-appearance: none !important; } -#star-button[starred="true"] { - list-style-image: url("chrome://browser/skin/places/pageStarred.png"); +#bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { + padding: 9px 3px; } -/* bookmarks menu-button */ +#bookmarks-menu-button[cui-areatype="toolbar"].bookmark-item > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon, +#bookmarks-menu-button.bookmark-item { + list-style-image: url("chrome://browser/skin/Toolbar-small.png"); +} + +#bookmarks-menu-button.bookmark-item { + -moz-image-region: rect(0px 144px 16px 128px); +} -#bookmarks-menu-button[disabled] > .toolbarbutton-icon, -#bookmarks-menu-button[disabled] > .toolbarbutton-menu-dropmarker, -#bookmarks-menu-button[disabled] > .toolbarbutton-menubutton-dropmarker, -#bookmarks-menu-button[disabled] > .toolbarbutton-menubutton-button > .toolbarbutton-icon, -#bookmarks-menu-button > .toolbarbutton-menubutton-button[disabled] > .toolbarbutton-icon { +#bookmarks-menu-button.bookmark-item[starred] { + -moz-image-region: rect(16px 144px 32px 128px); +} + +#bookmarks-menu-button[cui-areatype="toolbar"].bookmark-item > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { + -moz-image-region: rect(0px 160px 16px 144px); +} + +#bookmarks-menu-button[disabled][cui-areatype="toolbar"] > .toolbarbutton-icon, +#bookmarks-menu-button[disabled][cui-areatype="toolbar"] > .toolbarbutton-menu-dropmarker, +#bookmarks-menu-button[disabled][cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker, +#bookmarks-menu-button[disabled][cui-areatype="toolbar"] > .toolbarbutton-menubutton-button > .toolbarbutton-icon, +#bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-button[disabled] > .toolbarbutton-icon { opacity: .4; } +#BMB_bookmarksPopup[side="top"], +#BMB_bookmarksPopup[side="bottom"] { + margin-left: -16px; + margin-right: -16px; +} + +#BMB_bookmarksPopup[side="left"], +#BMB_bookmarksPopup[side="right"] { + margin-top: -16px; + margin-bottom: -16px; +} + /* Bookmarking panel */ #editBookmarkPanelStarIcon { list-style-image: url("chrome://browser/skin/places/starred48.png"); @@ -1612,147 +1384,52 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- text-shadow: none; } -/* Throbber */ -#navigator-throbber { - width: 16px; - min-height: 16px; - margin: 0 3px; -} +/* Tabstrip */ -#navigator-throbber[busy="true"] { - list-style-image: url("chrome://global/skin/icons/loading_16.png"); -} +%include ../shared/tabs.inc.css -#navigator-throbber, -#wrapper-navigator-throbber > #navigator-throbber { - list-style-image: url("chrome://global/skin/icons/notloading_16.png"); +#tabbrowser-tabs { + /* override the global style to allow the selected tab to be above the nav-bar */ + z-index: auto; } -/* Tabstrip */ - #TabsToolbar { min-height: 0; padding: 0; + position: relative; } -#TabsToolbar[tabsontop=true]:not(:-moz-lwtheme) { - -moz-appearance: menubar; - color: -moz-menubartext; - box-shadow: 0 -1px 0 rgba(0,0,0,.1) inset; -} - -#TabsToolbar[tabsontop=true]:not(:-moz-lwtheme):-moz-system-metric(menubar-drag) { - -moz-binding: url("chrome://global/content/bindings/toolbar.xml#toolbar-drag"); -} - -#TabsToolbar[tabsontop=false] { - background-image: linear-gradient(to top, rgba(0,0,0,.3) 1px, rgba(0,0,0,.05) 1px, transparent 50%); -} - -.tabbrowser-tab, -.tabs-newtab-button { - position: static; - -moz-appearance: none; - background: linear-gradient(hsla(0,0%,100%,.2), hsla(0,0%,45%,.2) 2px, hsla(0,0%,32%,.2) 80%); - background-origin: border-box; - background-position: 1px 2px; - background-size: 100% calc(100% - 2px); - background-repeat: no-repeat; - color: inherit; - margin: 0; - padding: 0; - border-width: 4px 5px 3px 6px; - border-style: solid; - border-image: url(tabbrowser/tab.png) 4 5 3 6 fill repeat stretch; - border-radius: 10px 8px 0 0; - min-height: 25px; /* reserve space for the sometimes hidden close button */ -} - -.tabbrowser-tab:hover, -.tabs-newtab-button:hover { - background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.2) 4px, hsla(0,0%,75%,.2) 80%); -} - -.tabbrowser-tab[selected="true"] { - background-image: linear-gradient(@selectedTabHighlight@, @toolbarHighlight@ 32%), - linear-gradient(-moz-dialog, -moz-dialog); - color: -moz-dialogtext; -} - -.tabbrowser-tab[remote] { - text-decoration: underline; -} - -#main-window[tabsontop=false]:not([disablechrome]) .tabbrowser-tab[selected=true]:not(:-moz-lwtheme) { - background-image: linear-gradient(to top, rgba(0,0,0,.3) 1px, transparent 1px), - linear-gradient(@selectedTabHighlight@, @toolbarHighlight@ 32%), - linear-gradient(-moz-dialog, -moz-dialog); -} - -.tabbrowser-tab[selected="true"]:-moz-lwtheme { - background-image: linear-gradient(@selectedTabHighlight@, @toolbarHighlight@ 32%); - color: inherit; -} - -.tabbrowser-tab:-moz-lwtheme-brighttext:not([selected="true"]), -.tabs-newtab-button:-moz-lwtheme-brighttext { - background-image: linear-gradient(hsla(0,0%,60%,.6), hsla(0,0%,40%,.6) 4px, hsla(0,0%,30%,.6) 80%); -} - -.tabbrowser-tab:-moz-lwtheme-brighttext:not([selected="true"]):hover, -.tabs-newtab-button:-moz-lwtheme-brighttext:hover { - background-image: linear-gradient(hsla(0,0%,80%,.6), hsla(0,0%,60%,.6) 4px, hsla(0,0%,45%,.6) 80%); -} - -.tabbrowser-tab:-moz-lwtheme-darktext:not([selected="true"]), -.tabs-newtab-button:-moz-lwtheme-darktext { - background-image: linear-gradient(hsla(0,0%,100%,.5), hsla(0,0%,60%,.5) 4px, hsla(0,0%,45%,.5) 80%); +/* + * Draw the bottom border of the tabstrip: + */ +#TabsToolbar::after { + content: ""; + position: absolute; + bottom: 1px; + left: 0; + right: 0; + z-index: 0; + border-bottom: 1px solid hsla(0,0%,0%,.3); } -.tabbrowser-tab:-moz-lwtheme-darktext:not([selected="true"]):hover, -.tabs-newtab-button:-moz-lwtheme-darktext:hover { - background-image: linear-gradient(hsla(0,0%,100%,.5), hsla(0,0%,80%,.5) 4px, hsla(0,0%,60%,.5) 80%); +#TabsToolbar:not(:-moz-lwtheme) { + -moz-appearance: menubar; + color: -moz-menubartext; } -.tabbrowser-tab[pinned][titlechanged]:not([selected="true"]) { - background-image: radial-gradient(circle farthest-corner at 50% 3px, rgba(233,242,252,1) 3%, rgba(172,206,255,.75) 40%, rgba(87,151,201,.5) 80%, rgba(87,151,201,0)); -} -.tabbrowser-tab[pinned][titlechanged]:not([selected="true"]):hover { - background-image: linear-gradient(hsla(0,0%,100%,.8), hsla(0,0%,100%,.6) 2px, hsla(0,0%,75%,.2) 80%), - radial-gradient(circle farthest-corner at 50% 3px, rgba(233,242,252,1) 3%, rgba(172,206,255,.75) 40%, rgba(87,151,201,.5) 80%, rgba(87,151,201,0)); +#toolbar-menubar:not([autohide="true"]):not(:-moz-lwtheme):-moz-system-metric(menubar-drag), +#TabsToolbar:not(:-moz-lwtheme):-moz-system-metric(menubar-drag) { + -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-drag"); } -#tabbrowser-tabs[positionpinnedtabs] > .tabbrowser-tab > .tab-stack > .tab-content[pinned] { - min-height: 18px; /* corresponds to the max. height of non-textual tab contents, i.e. the tab close button */ +#TabsToolbar:not(:-moz-lwtheme) > #tabbrowser-tabs > .tabbrowser-tab:not([selected]) { + color: -moz-menubartext; } -.tabbrowser-tab:focus > .tab-stack { +.tabbrowser-tab:focus > .tab-stack > .tab-content > .tab-label { outline: 1px dotted; } -.tab-throbber, -.tab-icon-image { - width: 16px; - height: 16px; - -moz-margin-end: 3px; - list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png"); -} - -.tab-throbber { - list-style-image: url("chrome://browser/skin/tabbrowser/connecting.png"); -} - -.tab-throbber[progress] { - list-style-image: url("chrome://browser/skin/tabbrowser/loading.png"); -} - -.tab-throbber[pinned], -.tab-icon-image[pinned], -.tabs-newtab-button > .toolbarbutton-icon { - -moz-margin-start: 2px; - -moz-margin-end: 2px; -} - #context_reloadTab { list-style-image: url("moz-icon://stock/gtk-refresh?size=menu"); } @@ -1776,7 +1453,8 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- /* Tab drag and drop */ .tab-drop-indicator { list-style-image: url(chrome://browser/skin/tabbrowser/tabDragIndicator.png); - margin-bottom: -11px; + margin-bottom: -9px; + z-index: 3; } /* In-tab close button */ @@ -1787,11 +1465,10 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- } .tab-close-button { - padding: 0; list-style-image: url("moz-icon://stock/gtk-close?size=menu"); - margin-top: -1px; + margin-top: 0; margin-bottom: -1px; - -moz-margin-end: -1px; + -moz-margin-end: -4px; } /* Tabstrip new tab button */ @@ -1912,10 +1589,6 @@ toolbarbutton.chevron > .toolbarbutton-icon { margin: 0; } -toolbar[mode="text"] toolbarbutton.chevron > .toolbarbutton-icon { - display: -moz-box; /* display chevron icon in text mode */ -} - /* Ctrl-Tab */ .ctrlTab-preview { @@ -1953,80 +1626,6 @@ toolbar[mode="text"] toolbarbutton.chevron > .toolbarbutton-icon { margin-top: 10px; } -/* Application button menu */ - -.splitmenu-menuitem { - -moz-margin-end: 1px; -} - -#appmenu-toolbar-button:not(:hover):not([open]):not(:-moz-lwtheme) { - color: inherit; -} - -#appmenu-toolbar-button > .toolbarbutton-text, -#appmenu-toolbar-button > .toolbarbutton-menu-dropmarker { - margin-top: -2px !important; - margin-bottom: -2px !important; -} -#appmenuSecondaryPane { - -moz-border-start: 1px solid ThreeDShadow; -} -#appmenuSecondaryPane-spacer { - min-height: 1em; -} -#appmenu-cut, -#appmenu-editmenu-cut { - list-style-image: url("moz-icon://stock/gtk-cut?size=menu"); -} -#appmenu-copy, -#appmenu-editmenu-copy { - list-style-image: url("moz-icon://stock/gtk-copy?size=menu"); -} -#appmenu-paste, -#appmenu-editmenu-paste { - list-style-image: url("moz-icon://stock/gtk-paste?size=menu"); -} -#wrapper-appmenu-toolbar-button, -.appmenu-edit-button[disabled="true"] { - opacity: .3; -} - -/* Add-on bar */ - -#addon-bar { - box-shadow: 0 1px 0 rgba(0,0,0,.15) inset; - padding: 0; - min-height: 20px; -} - -#status-bar { - min-height: 0; - -moz-appearance: none; - background-color: transparent; - border: none; -} - -#addon-bar[customizing] > #status-bar { - opacity: .5; - background-image: repeating-linear-gradient(135deg, - rgba(255,255,255,.3), rgba(255,255,255,.3) 5px, - rgba(0,0,0,.3) 5px, rgba(0,0,0,.3) 10px); -} - -#status-bar > statusbarpanel { - border-width: 0; - -moz-appearance: none; -} - -#addonbar-closebutton { - list-style-image: url("moz-icon://stock/gtk-close?size=menu"); -} - -#addonbar-closebutton > .toolbarbutton-icon { - margin-top: -2px; - margin-bottom: -2px; -} - /* Status panel */ .statuspanel-label { @@ -2228,6 +1827,46 @@ chatbox { border-top-right-radius: 2.5px; } +/* Customization mode */ + +%include ../shared/customizableui/customizeMode.inc.css + +#main-window[customizing] #tab-view-deck { + background-image: url("chrome://browser/skin/customizableui/customizeMode-gridTexture.png"), + url("chrome://browser/skin/customizableui/background-noise-toolbar.png"), + linear-gradient(to bottom, #bcbcbc, #b5b5b5); + background-attachment: fixed; +} + +#main-window:-moz-any([customize-entering],[customize-entered]) #tab-view-deck { + padding: 2em; +} + +#main-window[customize-entered] #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar), +#main-window[customize-entered] #customization-container { + border: 3px solid hsla(0,0%,0%,.1); + border-top-width: 0; + background-clip: padding-box; + background-origin: padding-box; + -moz-border-right-colors: hsla(0,0%,0%,.05) hsla(0,0%,0%,.1) hsla(0,0%,0%,.2); + -moz-border-bottom-colors: hsla(0,0%,0%,.05) hsla(0,0%,0%,.1) hsla(0,0%,0%,.2); + -moz-border-left-colors: hsla(0,0%,0%,.05) hsla(0,0%,0%,.1) hsla(0,0%,0%,.2); +} + +#main-window[customize-entered] #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) { + border-bottom-width: 0; +} + +#main-window[customize-entered] #TabsToolbar { + -moz-appearance: none; + background-clip: padding-box; + border-right: 3px solid transparent; + border-left: 3px solid transparent; +} + +/* End customization mode */ + + #main-window[privatebrowsingmode=temporary] #TabsToolbar::before { display: -moz-box; content: ""; diff --git a/browser/themes/linux/customizableui/background-noise-toolbar.png b/browser/themes/linux/customizableui/background-noise-toolbar.png new file mode 100644 index 0000000000000000000000000000000000000000..d09ba9dafb5ede66e92ce577ecaa6f9575dba104 Binary files /dev/null and b/browser/themes/linux/customizableui/background-noise-toolbar.png differ diff --git a/browser/themes/linux/customizableui/customizeMode-gridTexture.png b/browser/themes/linux/customizableui/customizeMode-gridTexture.png new file mode 100644 index 0000000000000000000000000000000000000000..a7c2775cfc799da31a505b249f5a59b89c148a58 Binary files /dev/null and b/browser/themes/linux/customizableui/customizeMode-gridTexture.png differ diff --git a/browser/themes/linux/customizableui/customizeMode-separatorHorizontal.png b/browser/themes/linux/customizableui/customizeMode-separatorHorizontal.png new file mode 100644 index 0000000000000000000000000000000000000000..5e17cb4db08e310e6c3a9e14c5bd722772dfb639 Binary files /dev/null and b/browser/themes/linux/customizableui/customizeMode-separatorHorizontal.png differ diff --git a/browser/themes/linux/customizableui/customizeMode-separatorVertical.png b/browser/themes/linux/customizableui/customizeMode-separatorVertical.png new file mode 100644 index 0000000000000000000000000000000000000000..dc4caee812878f246c87d71093768eb36c5656fc Binary files /dev/null and b/browser/themes/linux/customizableui/customizeMode-separatorVertical.png differ diff --git a/browser/themes/linux/customizableui/panelUIOverlay.css b/browser/themes/linux/customizableui/panelUIOverlay.css new file mode 100644 index 0000000000000000000000000000000000000000..c9a604c01a47daf133d5a8d370f2f22bf4b2b547 --- /dev/null +++ b/browser/themes/linux/customizableui/panelUIOverlay.css @@ -0,0 +1,9 @@ +/* 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/. */ + +%include ../../shared/customizableui/panelUIOverlay.inc.css + +#BMB_bookmarksPopup > menuitem[type="checkbox"] { + -moz-appearance: none !important; /* important, to override toolkit rule */ +} diff --git a/browser/themes/linux/downloads/indicator.css b/browser/themes/linux/downloads/indicator.css index d7e3f29bbab8dfebd6e6a2b22d6ca562542f7965..086baf4fad6a3bf635593c2c788a27258d255ae0 100644 --- a/browser/themes/linux/downloads/indicator.css +++ b/browser/themes/linux/downloads/indicator.css @@ -17,33 +17,14 @@ z-index: 5; } -toolbar[iconsize="small"] > #downloads-button > #downloads-indicator-anchor { - min-width: 16px; - min-height: 16px; -} - -toolbar[iconsize="large"] > #downloads-button > #downloads-indicator-anchor { - min-width: 24px; - min-height: 24px; -} - /*** Main indicator icon ***/ -toolbar[iconsize="small"] > #downloads-button > #downloads-indicator-anchor > #downloads-indicator-icon { - background: -moz-image-rect(url("chrome://browser/skin/Toolbar-small.png"), - 0, 16, 16, 0) center no-repeat; -} - -toolbar[iconsize="large"] > #downloads-button > #downloads-indicator-anchor > #downloads-indicator-icon { +#downloads-button[cui-areatype="toolbar"] > #downloads-indicator-anchor > #downloads-indicator-icon { background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"), - 0, 24, 24, 0) center no-repeat; -} - -toolbar[iconsize="small"] > #downloads-button[attention] > #downloads-indicator-anchor > #downloads-indicator-icon { - background-image: url("chrome://browser/skin/downloads/download-glow-small.png"); + 0, 198, 18, 180) center no-repeat; } -toolbar[iconsize="large"] > #downloads-button[attention] > #downloads-indicator-anchor > #downloads-indicator-icon { +#downloads-button[cui-areatype="toolbar"][attention] > #downloads-indicator-anchor > #downloads-indicator-icon { background-image: url("chrome://browser/skin/downloads/download-glow.png"); } @@ -159,8 +140,3 @@ toolbar[iconsize="large"] > #downloads-button[attention] > #downloads-indicator- #downloads-button[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-remainder { background-image: linear-gradient(#4b5000, #515700); } - -toolbar[mode="full"] > #downloads-button > .toolbarbutton-text { - margin: 0; - text-align: center; -} diff --git a/browser/themes/linux/jar.mn b/browser/themes/linux/jar.mn index a082f41e0a39f61bac762fb8e69e62ef8821a980..461e6a88af323f7c41e3b9233c9dc8eb55c70483 100644 --- a/browser/themes/linux/jar.mn +++ b/browser/themes/linux/jar.mn @@ -21,12 +21,16 @@ browser.jar: skin/classic/browser/aboutTabCrashed.css skin/classic/browser/actionicon-tab.png * skin/classic/browser/browser.css +* skin/classic/browser/browser-lightweightTheme.css skin/classic/browser/click-to-play-warning-stripes.png + skin/classic/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png) + skin/classic/browser/customizableui/customizeMode-gridTexture.png (customizableui/customizeMode-gridTexture.png) + skin/classic/browser/customizableui/customizeMode-separatorHorizontal.png (customizableui/customizeMode-separatorHorizontal.png) + skin/classic/browser/customizableui/customizeMode-separatorVertical.png (customizableui/customizeMode-separatorVertical.png) * skin/classic/browser/engineManager.css skin/classic/browser/fullscreen-darknoise.png skin/classic/browser/Geolocation-16.png skin/classic/browser/Geolocation-64.png - skin/classic/browser/Go-arrow.png skin/classic/browser/identity.png skin/classic/browser/identity-icons-generic.png skin/classic/browser/identity-icons-https.png @@ -34,6 +38,11 @@ browser.jar: skin/classic/browser/identity-icons-https-mixed-active.png skin/classic/browser/identity-icons-https-mixed-display.png skin/classic/browser/Info.png + skin/classic/browser/menuPanel.png + skin/classic/browser/menuPanel-customize.png + skin/classic/browser/menuPanel-exit.png + skin/classic/browser/menuPanel-help.png + skin/classic/browser/menuPanel-small.png skin/classic/browser/mixed-content-blocked-16.png skin/classic/browser/mixed-content-blocked-64.png skin/classic/browser/monitor.png @@ -50,17 +59,20 @@ browser.jar: skin/classic/browser/Privacy-16.png skin/classic/browser/Privacy-48.png skin/classic/browser/privatebrowsing-mask.png + skin/classic/browser/reload-stop-go.png skin/classic/browser/searchbar.css skin/classic/browser/Secure.png skin/classic/browser/Security-broken.png skin/classic/browser/setDesktopBackground.css skin/classic/browser/slowStartup-16.png skin/classic/browser/Toolbar.png + skin/classic/browser/Toolbar-inverted.png skin/classic/browser/Toolbar-small.png skin/classic/browser/urlbar-arrow.png skin/classic/browser/webRTC-shareDevice-16.png skin/classic/browser/webRTC-shareDevice-64.png skin/classic/browser/webRTC-sharingDevice-16.png +* skin/classic/browser/customizableui/panelUIOverlay.css (customizableui/panelUIOverlay.css) skin/classic/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay.css) skin/classic/browser/downloads/buttons.png (downloads/buttons.png) skin/classic/browser/downloads/contentAreaDownloadsView.css (downloads/contentAreaDownloadsView.css) @@ -85,7 +97,6 @@ browser.jar: skin/classic/browser/places/calendar.png (places/calendar.png) * skin/classic/browser/places/editBookmarkOverlay.css (places/editBookmarkOverlay.css) skin/classic/browser/places/livemark-item.png (places/livemark-item.png) - skin/classic/browser/places/pageStarred.png (places/pageStarred.png) skin/classic/browser/places/star-icons.png (places/star-icons.png) skin/classic/browser/places/starred48.png (places/starred48.png) skin/classic/browser/places/unstarred48.png (places/unstarred48.png) @@ -93,7 +104,6 @@ browser.jar: skin/classic/browser/places/organizer.css (places/organizer.css) skin/classic/browser/places/organizer.xml (places/organizer.xml) skin/classic/browser/places/query.png (places/query.png) - skin/classic/browser/places/starPage.png (places/starPage.png) skin/classic/browser/places/tag.png (places/tag.png) skin/classic/browser/places/toolbarDropMarker.png (places/toolbarDropMarker.png) skin/classic/browser/places/unsortedBookmarks.png (places/unsortedBookmarks.png) @@ -116,8 +126,21 @@ browser.jar: skin/classic/browser/tabbrowser/connecting.png (tabbrowser/connecting.png) skin/classic/browser/tabbrowser/loading.png (tabbrowser/loading.png) skin/classic/browser/tabbrowser/tab.png (tabbrowser/tab.png) - skin/classic/browser/tabbrowser/tab-overflow-border.png (tabbrowser/tab-overflow-border.png) - skin/classic/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png) + skin/classic/browser/tabbrowser/tab-active-middle.png (tabbrowser/tab-active-middle.png) + skin/classic/browser/tabbrowser/tab-background-end.png (tabbrowser/tab-background-end.png) + skin/classic/browser/tabbrowser/tab-background-middle.png (tabbrowser/tab-background-middle.png) + skin/classic/browser/tabbrowser/tab-background-start.png (tabbrowser/tab-background-start.png) + skin/classic/browser/tabbrowser/tab-overflow-border.png (tabbrowser/tab-overflow-border.png) + +# NOTE: The following two files (tab-selected-end.svg, tab-selected-start.svg) get pre-processed in +# Makefile.in with a non-default marker of "%" and the result of that gets packaged. + skin/classic/browser/tabbrowser/tab-selected-end.svg (tab-selected-end.svg) + skin/classic/browser/tabbrowser/tab-selected-start.svg (tab-selected-start.svg) + + skin/classic/browser/tabbrowser/tab-stroke-end.png (tabbrowser/tab-stroke-end.png) + skin/classic/browser/tabbrowser/tab-stroke-start.png (tabbrowser/tab-stroke-start.png) + skin/classic/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png) + skin/classic/browser/tabbrowser/tab-separator.png (tabbrowser/tab-separator.png) skin/classic/browser/tabview/edit-light.png (tabview/edit-light.png) skin/classic/browser/tabview/search.png (tabview/search.png) skin/classic/browser/tabview/stack-expander.png (tabview/stack-expander.png) diff --git a/browser/themes/linux/linuxShared.inc b/browser/themes/linux/linuxShared.inc new file mode 100644 index 0000000000000000000000000000000000000000..fc70d58aab98f9ad0642c07d7c08cdaa590ae226 --- /dev/null +++ b/browser/themes/linux/linuxShared.inc @@ -0,0 +1,10 @@ +/* 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/. */ + +%filter substitution + +%define toolbarHighlight rgba(255,255,255,.3) +%define fgTabTexture linear-gradient(transparent 0px, transparent 2px, hsla(0,0%,100%,0.35) 2px, hsla(0,0%,100%,0.35) 3px, hsla(0,0%,100%,0.65) 3px, hsla(0,0%,100%,0.65) 4px, @toolbarHighlight@) +%define fgTabTextureLWT @fgTabTexture@ +%define fgTabBackgroundColor -moz-dialog diff --git a/browser/themes/linux/menuPanel-customize.png b/browser/themes/linux/menuPanel-customize.png new file mode 100644 index 0000000000000000000000000000000000000000..e0b0a70a3b82a18c974bd1bc5f1dff863405dd61 Binary files /dev/null and b/browser/themes/linux/menuPanel-customize.png differ diff --git a/browser/themes/linux/menuPanel-exit.png b/browser/themes/linux/menuPanel-exit.png new file mode 100644 index 0000000000000000000000000000000000000000..6359d7262a286a34074f6f245636ad15a95993b5 Binary files /dev/null and b/browser/themes/linux/menuPanel-exit.png differ diff --git a/browser/themes/linux/menuPanel-help.png b/browser/themes/linux/menuPanel-help.png new file mode 100644 index 0000000000000000000000000000000000000000..4d23717748de84d681bfabd3c326420931a90e84 Binary files /dev/null and b/browser/themes/linux/menuPanel-help.png differ diff --git a/browser/themes/linux/menuPanel-small.png b/browser/themes/linux/menuPanel-small.png new file mode 100644 index 0000000000000000000000000000000000000000..4cd3e52b13d26ae5c4d85cb3ed3c00cd6c70f2ab Binary files /dev/null and b/browser/themes/linux/menuPanel-small.png differ diff --git a/browser/themes/linux/menuPanel.png b/browser/themes/linux/menuPanel.png new file mode 100644 index 0000000000000000000000000000000000000000..59061ec0aaa38b85dddacb4c31f257c4ad43ecf5 Binary files /dev/null and b/browser/themes/linux/menuPanel.png differ diff --git a/browser/themes/linux/places/pageStarred.png b/browser/themes/linux/places/pageStarred.png deleted file mode 100644 index 61a9f90e05b15a6206727be766294d7baa593995..0000000000000000000000000000000000000000 Binary files a/browser/themes/linux/places/pageStarred.png and /dev/null differ diff --git a/browser/themes/linux/places/starPage.png b/browser/themes/linux/places/starPage.png deleted file mode 100644 index 3193a3535f1e390211aa403ad757b10cc9d5a884..0000000000000000000000000000000000000000 Binary files a/browser/themes/linux/places/starPage.png and /dev/null differ diff --git a/browser/themes/linux/reload-stop-go.png b/browser/themes/linux/reload-stop-go.png new file mode 100644 index 0000000000000000000000000000000000000000..1017be9032a298c8aa1f4a5cd4576087d8bb6f0d Binary files /dev/null and b/browser/themes/linux/reload-stop-go.png differ diff --git a/browser/themes/linux/tabbrowser/tab-active-middle.png b/browser/themes/linux/tabbrowser/tab-active-middle.png new file mode 100644 index 0000000000000000000000000000000000000000..c3e5e18ba3ceddcf098a5b98a5f40c784a7e3d52 Binary files /dev/null and b/browser/themes/linux/tabbrowser/tab-active-middle.png differ diff --git a/browser/themes/linux/tabbrowser/tab-background-end.png b/browser/themes/linux/tabbrowser/tab-background-end.png new file mode 100644 index 0000000000000000000000000000000000000000..2e515a39efeaafc71c8ee00bc29baa7ca952ce0f Binary files /dev/null and b/browser/themes/linux/tabbrowser/tab-background-end.png differ diff --git a/browser/themes/linux/tabbrowser/tab-background-middle.png b/browser/themes/linux/tabbrowser/tab-background-middle.png new file mode 100644 index 0000000000000000000000000000000000000000..addb64b13f422a34d6b87e4e75488f9fa2e35ba3 Binary files /dev/null and b/browser/themes/linux/tabbrowser/tab-background-middle.png differ diff --git a/browser/themes/linux/tabbrowser/tab-background-start.png b/browser/themes/linux/tabbrowser/tab-background-start.png new file mode 100644 index 0000000000000000000000000000000000000000..243bf0099ffe7760843fc75b98d1029d9c9efbef Binary files /dev/null and b/browser/themes/linux/tabbrowser/tab-background-start.png differ diff --git a/browser/themes/linux/tabbrowser/tab-separator.png b/browser/themes/linux/tabbrowser/tab-separator.png new file mode 100644 index 0000000000000000000000000000000000000000..63f77f1b760b2e66e2fab7e739979b7cdede2116 Binary files /dev/null and b/browser/themes/linux/tabbrowser/tab-separator.png differ diff --git a/browser/themes/linux/tabbrowser/tab-stroke-end.png b/browser/themes/linux/tabbrowser/tab-stroke-end.png new file mode 100644 index 0000000000000000000000000000000000000000..099978580391777f4fdd196fc9aa160ebf4123a7 Binary files /dev/null and b/browser/themes/linux/tabbrowser/tab-stroke-end.png differ diff --git a/browser/themes/linux/tabbrowser/tab-stroke-start.png b/browser/themes/linux/tabbrowser/tab-stroke-start.png new file mode 100644 index 0000000000000000000000000000000000000000..e5a7b5ee9aecb73410b5cacdd4951b2520b54bca Binary files /dev/null and b/browser/themes/linux/tabbrowser/tab-stroke-start.png differ diff --git a/browser/themes/osx/Makefile.in b/browser/themes/osx/Makefile.in index 173ca68435c6cf993204e3cca62ac579ab2537ba..67f553d6ef9c39898f407b06a620793765675727 100644 --- a/browser/themes/osx/Makefile.in +++ b/browser/themes/osx/Makefile.in @@ -5,3 +5,23 @@ ICON_FILES := icon.png ICON_DEST = $(FINAL_TARGET)/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd} INSTALL_TARGETS += ICON + +# By default, the pre-processor used for jar.mn will use "%" as a marker for ".css" files and "#" +# otherwise. This falls apart when a file using one marker needs to include a file with the other +# marker since the pre-processor instructions in the included file will not be processed. The +# following SVG files need to include a file which uses "%" as the marker so we invoke the pre- +# processor ourselves here with the marker specified. The resulting SVG files will get packaged by +# the processing of the jar file in this directory. +tab-selected-svg: $(srcdir)/../shared/tab-selected.svg + $(call py_action,preprocessor, \ + --marker "%" -D TAB_SIDE=start \ + $(ACDEFINES) \ + $(srcdir)/../shared/tab-selected.svg -o tab-selected-start.svg) + $(call py_action,preprocessor, \ + --marker "%" -D TAB_SIDE=end \ + $(ACDEFINES) \ + $(srcdir)/../shared/tab-selected.svg -o tab-selected-end.svg) + +.PHONY: tab-selected-svg + +export:: tab-selected-svg diff --git a/browser/themes/osx/Toolbar-background-noise.png b/browser/themes/osx/Toolbar-background-noise.png new file mode 100644 index 0000000000000000000000000000000000000000..aab0a02c84d63603ec1fc3a385a08c5cf5360fd2 Binary files /dev/null and b/browser/themes/osx/Toolbar-background-noise.png differ diff --git a/browser/themes/osx/Toolbar-inverted.png b/browser/themes/osx/Toolbar-inverted.png new file mode 100644 index 0000000000000000000000000000000000000000..b09decd7a34c1eed025073756b885a0c1d0720e3 Binary files /dev/null and b/browser/themes/osx/Toolbar-inverted.png differ diff --git a/browser/themes/osx/Toolbar-inverted@2x.png b/browser/themes/osx/Toolbar-inverted@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4547610430304709a8f23833b15fe82425e7ee53 Binary files /dev/null and b/browser/themes/osx/Toolbar-inverted@2x.png differ diff --git a/browser/themes/osx/Toolbar-lion.png b/browser/themes/osx/Toolbar-lion.png deleted file mode 100644 index a91ba7bfd66d6fc9301e77f111b3aa21aaec5b50..0000000000000000000000000000000000000000 Binary files a/browser/themes/osx/Toolbar-lion.png and /dev/null differ diff --git a/browser/themes/osx/Toolbar-lion@2x.png b/browser/themes/osx/Toolbar-lion@2x.png deleted file mode 100644 index 10b7994858574011d207310e4b79b165f468330a..0000000000000000000000000000000000000000 Binary files a/browser/themes/osx/Toolbar-lion@2x.png and /dev/null differ diff --git a/browser/themes/osx/Toolbar.png b/browser/themes/osx/Toolbar.png index c1868929dd8edf012a0f720931d163309cd9da11..60261520e9b73bb62ebfd0d7562cd47a508ff12a 100644 Binary files a/browser/themes/osx/Toolbar.png and b/browser/themes/osx/Toolbar.png differ diff --git a/browser/themes/osx/Toolbar@2x.png b/browser/themes/osx/Toolbar@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..88ff4569ee336884329d9a07e78fdaaddc3bc432 Binary files /dev/null and b/browser/themes/osx/Toolbar@2x.png differ diff --git a/browser/themes/osx/browser-lightweightTheme.css b/browser/themes/osx/browser-lightweightTheme.css new file mode 100644 index 0000000000000000000000000000000000000000..03d3b3d731c1747cf0d3f0bdb0645bbfbd35cad4 --- /dev/null +++ b/browser/themes/osx/browser-lightweightTheme.css @@ -0,0 +1,28 @@ +/* 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/. */ + +%include shared.inc + +/* + * LightweightThemeListener will append the current lightweight theme's header + * image to the background-image for each of the following rulesets. + */ + +/* Lightweight theme on tabs */ +#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start[selected=true]:-moz-lwtheme::before, +#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end[selected=true]:-moz-lwtheme::before { + background-attachment: scroll, fixed; + background-color: transparent; + background-image: @fgTabTextureLWT@;/*, lwtHeader;*/ + background-position: 0 0, right top; +} + +#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme { + background-attachment: scroll, scroll, fixed; + background-color: transparent; + background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png), + @fgTabTextureLWT@;/*, + lwtHeader;*/ + background-position: 0 0, 0 0, right top; +} diff --git a/browser/themes/osx/browser.css b/browser/themes/osx/browser.css index d3ebbae79d8459990274da5d91033465c4256ba3..ec932255d097b813eeb50b05a18aee7048abb5b3 100644 --- a/browser/themes/osx/browser.css +++ b/browser/themes/osx/browser.css @@ -7,8 +7,10 @@ %include shared.inc %filter substitution %define forwardTransitionLength 150ms -%define conditionalForwardWithUrlbar window:not([chromehidden~=toolbar]) #navigator-toolbox[iconsize=large][mode=icons] > :-moz-any(#nav-bar[currentset*="unified-back-forward-button,urlbar-container"],#nav-bar:not([currentset])) > #unified-back-forward-button +%define conditionalForwardWithUrlbar window:not([chromehidden~="toolbar"]) #urlbar-container %define conditionalForwardWithUrlbarWidth 27 +%define spaceAboveTabbar 9px +%define toolbarButtonPressed :hover:active:not([disabled="true"]):not([cui-areatype="menu-panel"]) @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); @namespace html url("http://www.w3.org/1999/xhtml"); @@ -18,42 +20,65 @@ opacity: .9; } +#navigator-toolbox::after { + -moz-box-ordinal-group: 101; /* tabs toolbar is 100 */ + background-image: linear-gradient(to top, hsla(0,0%,0%,.15), hsla(0,0%,0%,.15) 1px, hsla(0,0%,100%,.15) 1px, hsla(0,0%,100%,.15) 2px, transparent 3px); + content: ""; + display: -moz-box; + height: 2px; + margin-top: -2px; + position: relative; + z-index: 2; /* navbar is at 1 */ +} + #navigator-toolbox toolbarbutton:-moz-lwtheme { color: inherit; text-shadow: inherit; } -#PersonalToolbar:-moz-lwtheme, -#nav-bar:-moz-lwtheme, -#main-window[privatebrowsingmode=temporary] #nav-bar[tabsontop=false] { - -moz-appearance: none !important; - background: none !important; - /* Switching to a lightweight theme shouldn't move the content area, - so avoid changing border widths here. */ - border-color: transparent !important; -} - #main-window { -moz-appearance: none; background-color: #eeeeee; } -#titlebar-buttonbox-container, -#main-window:not([drawintitlebar=true]) > #titlebar { +#titlebar-buttonbox > .titlebar-button { display: none; } -#titlebar { - height: 22px; +/* NB: these would be -moz-margin-start/end if it wasn't for the fact that OS X + * doesn't reverse the order of the items in the titlebar in RTL mode. */ +.titlebar-placeholder[type="caption-buttons"], +#titlebar-buttonbox { + margin-left: 7px; } -#main-window[chromehidden~="toolbar"][chromehidden~="location"][chromehidden~="directories"] { - border-top: 1px solid rgba(0,0,0,0.65); +@media (-moz-mac-lion-theme) { + .titlebar-placeholder[type="fullscreen-button"], + #titlebar-fullscreen-button { + margin-right: 7px; + } } -#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) { - -moz-box-align: center; - padding: 2px 4px; +/* Fullscreen and caption buttons don't move with RTL on OS X so override the automatic ordering. */ +.titlebar-placeholder[type="fullscreen-button"]:-moz-locale-dir(ltr), +.titlebar-placeholder[type="caption-buttons"]:-moz-locale-dir(rtl) { + -moz-box-ordinal-group: 1000; +} +.titlebar-placeholder[type="caption-buttons"]:-moz-locale-dir(ltr), +.titlebar-placeholder[type="fullscreen-button"]:-moz-locale-dir(rtl) { + -moz-box-ordinal-group: 0; +} + +#main-window[chromehidden~="toolbar"] > #titlebar { + padding-top: 22px; +} + +#main-window:not(:-moz-lwtheme):not([privatebrowsingmode=temporary]) > #titlebar { + -moz-appearance: -moz-window-titlebar; +} + +#main-window[chromehidden~="toolbar"][chromehidden~="location"][chromehidden~="directories"] { + border-top: 1px solid rgba(0,0,0,0.65); } /* Because of -moz-box-align: center above, separators will be invisible unless @@ -62,49 +87,54 @@ toolbarseparator { min-height: 22px; } -/* We need more height when toolbar buttons show both icon and text. */ -toolbar[mode="full"] toolbarseparator { - min-height: 36px; +#navigator-toolbox > toolbar:not(#TabsToolbar):not(#nav-bar):not(:-moz-lwtheme) { + -moz-appearance: none; + background: url(chrome://browser/skin/Toolbar-background-noise.png) hsl(0,0%,83%); } #nav-bar { - padding-bottom: 4px !important; + -moz-appearance: none; + background: url(chrome://browser/skin/Toolbar-background-noise.png), + linear-gradient(hsl(0,0%,93%), hsl(0,0%,83%)); + background-clip: border-box; + background-origin: border-box !important; + + /* Move the noise texture out of the top 1px strip because that overlaps + with the tabbar and we don't want to repaint it when animating tabs. + The noise image is at least 100px high, so repeating it only horizontally + is enough. */ + background-repeat: repeat-x, no-repeat; + background-position: 0 1px, 0 0; + + box-shadow: inset 0 1px 0 hsla(0,0%,100%,.4); + margin-top: -1px; + /* Position the toolbar above the bottom of background tabs */ + position: relative; + z-index: 1; } -#PersonalToolbar { - -moz-appearance: none; - margin-top: -2px; /* overlay the bottom border of the toolbar above us */ - padding-top: 1px !important; - background-color: -moz-mac-chrome-active; - border-bottom: 1px solid rgba(0, 0, 0, 0.57); +@media (min-resolution: 2dppx) { + #nav-bar { + background-size: 100px 100px, auto; + } } -#nav-bar[tabsontop=true], -#nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + toolbar, -#nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + #customToolbars + #PersonalToolbar { - -moz-appearance: none; - margin-top: 0; /* don't overlay the bottom border of the tabs toolbar */ - padding-top: 4px !important; - border-bottom: 1px solid rgba(0, 0, 0, 0.57); - background-color: -moz-mac-chrome-active; - background-image: linear-gradient(rgba(255,255,255,.43), rgba(255,255,255,0)) !important; /* override lwtheme style */ - background-origin: border-box !important; +#nav-bar-customization-target { + padding: 4px; } -#PersonalToolbar:-moz-lwtheme, -#nav-bar[tabsontop=true]:-moz-lwtheme, -#nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + toolbar:-moz-lwtheme, -#nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + #customToolbars + #PersonalToolbar:-moz-lwtheme { - background-color: transparent; - border-bottom-color: transparent; +#PersonalToolbar { + padding: 0 4px 4px; +} + +#navigator-toolbox > toolbar:not(#TabsToolbar):-moz-lwtheme { + background-color: @toolbarColorLWT@; + background-image: url(chrome://browser/skin/Toolbar-background-noise.png); } #PersonalToolbar:not(:-moz-lwtheme):-moz-window-inactive, -#nav-bar[tabsontop=true]:not(:-moz-lwtheme):-moz-window-inactive, -#nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + toolbar:not(:-moz-lwtheme):-moz-window-inactive, -#nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + #customToolbars + #PersonalToolbar:not(:-moz-lwtheme):-moz-window-inactive { +#nav-bar:not(:-moz-lwtheme):-moz-window-inactive { background-color: -moz-mac-chrome-inactive; - border-bottom-color: rgba(0, 0, 0, 0.32); } /* ----- BOOKMARK TOOLBAR ----- */ @@ -123,10 +153,6 @@ toolbarbutton.chevron > .toolbarbutton-text { display: none; } -toolbar[mode="text"] toolbarbutton.chevron > .toolbarbutton-icon { - display: -moz-box; /* display chevron icon in text mode */ -} - toolbarbutton.chevron:-moz-locale-dir(rtl) > .toolbarbutton-icon { transform: scaleX(-1); } @@ -143,7 +169,8 @@ toolbarbutton.chevron:-moz-locale-dir(rtl) > .toolbarbutton-icon { /* ----- BOOKMARK BUTTONS ----- */ -toolbarbutton.bookmark-item { +toolbarbutton.bookmark-item, +#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder { font-weight: bold; color: #222; border: 0; @@ -171,8 +198,9 @@ toolbarbutton.bookmark-item { } } -.bookmark-item > .toolbarbutton-text { - display: -moz-box !important; /* prevent [mode="icons"] from hiding the label */ +.bookmark-item > .toolbarbutton-text, +#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-text { + display: -moz-box !important; /* Force the display of the label for bookmarks */ margin: 0 !important; } @@ -210,14 +238,16 @@ toolbarbutton.bookmark-item > menupopup { -moz-margin-start: 3px; } -.bookmark-item > .toolbarbutton-icon { +.bookmark-item > .toolbarbutton-icon, +#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-icon { width: 16px; min-height: 16px; max-height: 16px; } .bookmark-item > .toolbarbutton-icon[label]:not([label=""]), -.bookmark-item > .toolbarbutton-icon[type="menu"] { +.bookmark-item > .toolbarbutton-icon[type="menu"], +#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-icon[label]:not([label=""]) { -moz-margin-end: 5px; } @@ -311,31 +341,22 @@ toolbarbutton.bookmark-item > menupopup { @media (min-resolution: 2dppx) { .bookmark-item > .toolbarbutton-icon, - .bookmark-item > .menu-iconic-left > .menu-iconic-icon { + .bookmark-item > .menu-iconic-left > .menu-iconic-icon, + #personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-icon { image-rendering: -moz-crisp-edges; } } -#wrapper-personal-bookmarks[place="palette"] > .toolbarpaletteitem-box { - background: url("chrome://browser/skin/places/bookmarksToolbar.png") no-repeat center; -} - -.bookmarks-toolbar-customize { - max-width: 15em !important; +#bookmarks-toolbar-placeholder { list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png") !important; } @media (min-resolution: 2dppx) { - #wrapper-personal-bookmarks[place="palette"] > .toolbarpaletteitem-box { - background-image: url("chrome://browser/skin/places/bookmarksToolbar@2x.png"); - background-size: 16px; - } - - .bookmarks-toolbar-customize { + #bookmarks-toolbar-placeholder { list-style-image: url("chrome://browser/skin/places/bookmarksToolbar@2x.png") !important; } - .bookmarks-toolbar-customize > .toolbarbutton-icon { + #bookmarks-toolbar-placeholder > .toolbarbutton-icon { width: 16px; } } @@ -348,11 +369,13 @@ toolbarbutton.bookmark-item > menupopup { } #bookmarksToolbarFolderMenu, -#BMB_bookmarksToolbar { +#BMB_bookmarksToolbar, +#panelMenu_bookmarksToolbar { list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png"); } -#BMB_unsortedBookmarks { +#BMB_unsortedBookmarks, +#panelMenu_unsortedBookmarks { list-style-image: url("chrome://browser/skin/places/unfiledBookmarks.png"); } @@ -374,32 +397,11 @@ toolbarbutton.bookmark-item > menupopup { .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker, #restore-button { -moz-box-orient: vertical; - -moz-appearance: toolbarbutton; height: 22px; padding: 0; border: 0; } -.toolbarbutton-1:not([type="menu-button"]):-moz-lwtheme, -.toolbarbutton-1 > .toolbarbutton-menubutton-button:-moz-lwtheme, -.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-lwtheme, -#restore-button:-moz-lwtheme { - -moz-appearance: none; - padding: 0 3px; - border: 1px solid rgba(0, 0, 0, 0.4); - border-radius: @toolbarbuttonCornerRadius@; - background: linear-gradient(rgba(255,255,255,0.5), rgba(255,255,255,0.2) 50%, rgba(255,255,255,0.1) 50%, rgba(255,255,255,0.2)) repeat-x; - background-origin: border-box; - box-shadow: inset 0 1px rgba(255,255,255,0.3), 0 1px rgba(255,255,255,0.2); -} - -.toolbarbutton-1:not([type="menu-button"]):-moz-lwtheme-darktext, -.toolbarbutton-1 > .toolbarbutton-menubutton-button:-moz-lwtheme-darktext, -.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-lwtheme-darktext, -#restore-button:-moz-lwtheme-darktext { - background-image: linear-gradient(rgba(255,255,255,0.3), rgba(50,50,50,0.2) 50%, rgba(0,0,0,0.2) 50%, rgba(0,0,0,0.13)); -} - .toolbarbutton-1[type="menu-button"] { padding: 0; } @@ -412,668 +414,991 @@ toolbarbutton.bookmark-item > menupopup { .toolbarbutton-1, #restore-button { margin: 0 4px; - list-style-image: url("chrome://browser/skin/Toolbar.png"); } -@media (min-resolution: 2dppx) { - /* Whitelist built-in buttons, instead of .toolbarbutton-1, - to avoid potentially breaking add-on toolbar buttons. */ - :-moz-any(@primaryToolbarButtons@):not(#tabview-button) { - list-style-image: url("chrome://browser/skin/Toolbar@2x.png"); - } - - :-moz-any(@primaryToolbarButtons@):not(#tabview-button) > .toolbarbutton-icon, - :-moz-any(@primaryToolbarButtons@):not(#tabview-button) > .toolbarbutton-menubutton-button > .toolbarbutton-icon { - width: 20px; - } +/** + * Draw seperators before toolbar button dropmarkers, as well as between + * consecutive toolbarbutton-1's within a toolbaritem. + */ +#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker::before, +#nav-bar .toolbaritem-combined-buttons > .toolbarbutton-1 + .toolbarbutton-1::before { + content: ""; + display: -moz-box; + position: absolute; + top: calc(50% - 9px); + width: 1px; + height: 18px; + -moz-margin-end: -1px; + background-image: linear-gradient(hsla(210,54%,20%,.2) 0, hsla(210,54%,20%,.2) 18px); + background-clip: padding-box; + background-position: center; + background-repeat: no-repeat; + background-size: 1px 18px; + box-shadow: 0 0 0 1px hsla(0,0%,100%,.2); } -toolbar:not([mode="icons"]) .toolbarbutton-1:not([type="menu-button"]), -toolbar:not([mode="icons"]) .toolbarbutton-1 > .toolbarbutton-menubutton-button, -toolbar:not([mode="icons"]) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker, -toolbar:not([mode="icons"]) #restore-button { - -moz-appearance: none; - padding: 0; - height: auto; - border: none; - box-shadow: none; - background: none; +#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { + -moz-margin-start: 10px; } -.toolbarbutton-1:not([type="menu-button"]), -.toolbarbutton-1 > .toolbarbutton-menubutton-button, -#restore-button { - min-width: 28px; -} +@media not all and (min-resolution: 2dppx) { +%include ../shared/toolbarbuttons.inc.css +%include ../shared/menupanel.inc.css -toolbar:not([mode="icons"]) .toolbarbutton-1:not([type="menu-button"]), -toolbar:not([mode="icons"]) .toolbarbutton-1 > .toolbarbutton-menubutton-button, -toolbar:not([mode="icons"]) #restore-button { - min-width: 0; -} + #back-button:hover:active:not([disabled="true"]) { + -moz-image-region: rect(18px, 36px, 36px, 18px); + } -.toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon, -.toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon { - margin: 2px; -} + #forward-button:hover:active:not([disabled="true"]) { + -moz-image-region: rect(18px, 72px, 36px, 54px); + } -.toolbarbutton-1[disabled="true"] > .toolbarbutton-icon, -.toolbarbutton-1[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon, -.toolbarbutton-1 > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon, -#restore-button[disabled="true"] > .toolbarbutton-icon { - opacity: .4; -} + #home-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 126px, 36px, 108px); + } -@media (-moz-mac-lion-theme) { - .toolbarbutton-1[disabled="true"] > .toolbarbutton-icon, - .toolbarbutton-1[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon, - .toolbarbutton-1 > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon, - #restore-button[disabled="true"] > .toolbarbutton-icon, - .toolbarbutton-1[disabled="true"] > .toolbarbutton-menu-dropmarker, - .toolbarbutton-1[disabled="true"] > .toolbarbutton-menubutton-dropmarker, - .toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-icon, - .toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-badge-container > .toolbarbutton-icon, - #restore-button:not(:hover):-moz-window-inactive > .toolbarbutton-icon, - .toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menu-dropmarker, - .toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon, - .toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menubutton-button > .toolbarbutton-icon { - opacity: .5; + #bookmarks-menu-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 144px, 36px, 126px); } - .toolbarbutton-1:-moz-window-inactive[disabled="true"] > .toolbarbutton-icon, - .toolbarbutton-1:-moz-window-inactive[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon, - .toolbarbutton-1:-moz-window-inactive > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon, - #restore-button:-moz-window-inactive[disabled="true"] > .toolbarbutton-icon { - opacity: .25; + #bookmarks-menu-button[open] { + -moz-image-region: rect(36px, 144px, 54px, 126px); } -} -.toolbarbutton-1 > .toolbarbutton-menu-dropmarker, -.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker { - list-style-image: url(chrome://browser/skin/toolbarbutton-dropmarker.png); -} + #bookmarks-menu-button[starred]@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 162px, 36px, 144px); + } -@media (min-resolution: 2dppx) { - .toolbarbutton-1 > .toolbarbutton-menu-dropmarker, - .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker { - list-style-image: url(chrome://browser/skin/toolbarbutton-dropmarker@2x.png); + #bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { + -moz-image-region: rect(0px, 630px, 18px, 612px); } - .toolbarbutton-1 > .toolbarbutton-menu-dropmarker > .dropmarker-icon, - .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { - width: 7px; + #bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker:hover:active:not([disabled="true"]) > .dropmarker-icon { + -moz-image-region: rect(18px, 630px, 36px, 612px); } -} -.toolbarbutton-1 > .toolbarbutton-menu-dropmarker { - -moz-margin-end: 1px; -} + #history-panelmenu@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 180px, 36px, 162px); + } -.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker { - padding: 2px 4px 0; - -moz-border-start: none !important; -} + #history-panelmenu[open] { + -moz-image-region: rect(36px, 180px, 54px, 162px); + } -toolbar:not([mode="icons"]) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker { - width: auto; - padding-top: 0; -} + #downloads-indicator@toolbarButtonPressed@, + #downloads-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 198px, 36px, 180px); + } -.toolbarbutton-1 > .toolbarbutton-menubutton-button:-moz-locale-dir(rtl), -.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-locale-dir(ltr) { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} + #add-ons-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 216px, 36px, 198px); + } -.toolbarbutton-1 > .toolbarbutton-menubutton-button:-moz-locale-dir(ltr), -.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-locale-dir(rtl) { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} + #open-file-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 234px, 36px, 216px); + } -toolbar:not([mode="icons"]) .toolbarbutton-1:not([open="true"]) > .toolbarbutton-menubutton-dropmarker { - opacity: .7; -} + #save-page-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 252px, 36px, 234px); + } -.toolbarbutton-1 > .toolbarbutton-text, -.toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-text { - margin: 2px 0 0; -} + #sync-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 270px, 36px, 252px); + } -toolbar[mode="icons"] .toolbarbutton-1:not([type="menu-button"]):not([disabled="true"]):active:hover:-moz-lwtheme, -toolbar[mode="icons"] .toolbarbutton-1:not([type="menu-button"])[open="true"]:-moz-lwtheme, -toolbar[mode="icons"] .toolbarbutton-1:not([disabled="true"]) > .toolbarbutton-menubutton-button:active:hover:-moz-lwtheme, -toolbar[mode="icons"] .toolbarbutton-1[open="true"] > .toolbarbutton-menubutton-dropmarker:-moz-lwtheme, -toolbar[mode="icons"] #restore-button:not([disabled="true"]):active:hover:-moz-lwtheme { - text-shadow: @loweredShadow@; - background-color: rgba(0,0,0,0.2); - box-shadow: inset 0 2px 5px rgba(0,0,0,0.6), 0 1px rgba(255,255,255,0.2); -} + #feed-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 288px, 36px, 270px); + } -toolbar[mode="icons"] .toolbarbutton-1:not([type="menu-button"]):not(#fullscreen-button)[checked="true"]:-moz-lwtheme { - background-color: rgba(0,0,0,0.4); - box-shadow: inset 0 2px 5px rgba(0,0,0,0.7), 0 1px rgba(255,255,255,0.2); -} + #social-share-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 306px, 36px, 288px); + } -toolbar[mode="icons"] .toolbarbutton-1:not([type="menu-button"]):not(#fullscreen-button)[checked="true"]:not([disabled="true"]):active:hover:-moz-lwtheme { - background-color: rgba(0, 0, 0, 0.6); - box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.8), 0 1px rgba(255, 255, 255, 0.2); -} + #characterencoding-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 324px, 36px, 306px); + } -toolbar[mode="icons"] .toolbarbutton-1 > menupopup { - margin-top: 1px; -} + #characterencoding-button[open] { + -moz-image-region: rect(36px, 324px, 54px, 306px); + } -#navigator-toolbox > toolbar { - /* force iconsize="small" on these toolbars */ - counter-reset: smallicons; -} + #new-window-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 342px, 36px, 324px); + } -/* unified back/forward button */ + #new-tab-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 360px, 36px, 342px); + } -#unified-back-forward-button { - -moz-box-align: center; -} + #privatebrowsing-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 378px, 36px, 360px); + } -#back-button, -#forward-button:-moz-locale-dir(rtl), -toolbar[mode="icons"] #back-button:-moz-locale-dir(rtl):-moz-lwtheme { - -moz-image-region: rect(0, 40px, 20px, 20px); -} + #find-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 396px, 36px, 378px); + } -@media (min-resolution: 2dppx) { - #back-button, - #forward-button:-moz-locale-dir(rtl), - toolbar[mode="icons"] #back-button:-moz-locale-dir(rtl):-moz-lwtheme { - -moz-image-region: rect(0, 80px, 40px, 40px); + #print-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 414px, 36px, 396px); } -} -#forward-button, -#back-button:-moz-locale-dir(rtl), -#navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #forward-button:-moz-locale-dir(rtl), -toolbar[mode="icons"] #forward-button:-moz-locale-dir(rtl):-moz-lwtheme { - -moz-image-region: rect(0, 60px, 20px, 40px); -} + #fullscreen-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 432px, 36px, 414px); + } -@media (min-resolution: 2dppx) { - #forward-button, - #back-button:-moz-locale-dir(rtl), - #navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #forward-button:-moz-locale-dir(rtl), - toolbar[mode="icons"] #forward-button:-moz-locale-dir(rtl):-moz-lwtheme { - -moz-image-region: rect(0, 120px, 40px, 80px); + #developer-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 450px, 36px, 432px); } -} -#navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #back-button:-moz-locale-dir(rtl), -#navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #forward-button:-moz-locale-dir(rtl), -toolbar[mode="icons"] #back-button:-moz-locale-dir(rtl):-moz-lwtheme, -toolbar[mode="icons"] #forward-button:-moz-locale-dir(rtl):-moz-lwtheme { - transform: scaleX(-1); -} + #developer-button[open] { + -moz-image-region: rect(36px, 450px, 54px, 432px); + } -#navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #back-button { - -moz-appearance: none; - -moz-margin-end: -7px; - position: relative; - z-index: 1; - -moz-image-region: rect(0, 20px, 20px, 0); - width: 30px; - height: 30px; - padding: 4px 5px 4px 3px; - border-radius: 10000px; -} + #preferences-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 468px, 36px, 450px); + } -@media (min-resolution: 2dppx) { - #navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #back-button { - -moz-image-region: rect(0, 40px, 40px, 0); + #PanelUI-menu-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 486px, 36px, 468px); } -} -#navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #back-button:not(:-moz-lwtheme) { - height: 31px; - padding: 4px 5px 5px 3px; - margin-bottom: -1px; - background: url(chrome://browser/skin/keyhole-circle.png) 0 0 no-repeat; - border-radius: 0; -} + #PanelUI-menu-button[open] { + -moz-image-region: rect(36px, 486px, 54px, 468px); + } -@media (min-resolution: 2dppx) { - #navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #back-button:not(:-moz-lwtheme) { - background-image: url(chrome://browser/skin/keyhole-circle@2x.png); - background-size: 90px; + #cut-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 504px, 36px, 486px); } -} -#navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #back-button:-moz-window-inactive:not(:-moz-lwtheme) { - background-position: -60px 0; -} + #copy-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 522px, 36px, 504px); + } -#navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #back-button:not([disabled="true"]):active:hover:not(:-moz-lwtheme), -#navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #back-button[open="true"]:not(:-moz-lwtheme) { - background-position: -30px 0; -} + #paste-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 540px, 36px, 522px); + } -toolbar[mode="icons"] #forward-button { - -moz-margin-start: 0; -} + #zoom-out-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 558px, 36px, 540px); + } -#navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #forward-button > .toolbarbutton-icon { - /* shift the icon away from the back button */ - margin-left: 3px; - margin-right: -1px; -} + #zoom-in-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 576px, 36px, 558px); + } -#navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #forward-button { - clip-path: url(chrome://browser/content/browser.xul#osx-keyhole-forward-clip-path); -} + #webrtc-status-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 594px, 36px, 576px); + } -@conditionalForwardWithUrlbar@ > #forward-button:not(:-moz-lwtheme) { - -moz-appearance: none; - -moz-padding-start: 2px; - background: linear-gradient(hsl(0,0%,99%), hsl(0,0%,67%)) padding-box; - border: 1px solid; - border-color: hsl(0,0%,31%) hsla(0,0%,29%,.6) hsl(0,0%,27%); - box-shadow: inset 0 1px 0 hsla(0,0%,100%,.35), - 0 1px 0 hsla(0,0%,100%,.2); -} + #nav-bar-overflow-button@toolbarButtonPressed@ { + -moz-image-region: rect(18px, 612px, 36px, 594px); + } -@conditionalForwardWithUrlbar@ > #forward-button { - border-radius: 0; - -moz-margin-end: 0; -} + #nav-bar-overflow-button[open] { + -moz-image-region: rect(36px, 612px, 54px, 594px); + } -@conditionalForwardWithUrlbar@ > #forward-button:-moz-lwtheme { - -moz-padding-start: 2px; - -moz-padding-end: 0; -} + /** + * OSX has a unique set of icons when fullscreen is in the checked state. + */ -@conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button { - transition: opacity @forwardTransitionLength@ ease-out; + #fullscreen-button[checked="true"]:not([cui-areatype="menu-panel"]) { + -moz-image-region: rect(36px, 432px, 54px, 414px); + } + + #fullscreen-button[checked="true"]@toolbarButtonPressed@ { + -moz-image-region: rect(54px, 432px, 72px, 414px); + } } -@conditionalForwardWithUrlbar@ > #forward-button:hover:active:not(:-moz-lwtheme) { - background-image: linear-gradient(hsl(0,0%,74%), hsl(0,0%,61%)); - box-shadow: inset rgba(0,0,0,.3) 0 -6px 10px, - inset #000 0 1px 3px, - inset rgba(0,0,0,.2) 0 1px 3px, - 0 1px 0 hsla(0,0%,100%,.2); -} +@media (min-resolution: 2dppx) { + /* Whitelist built-in buttons, instead of .toolbarbutton-1, + to avoid potentially breaking add-on toolbar buttons. */ -@conditionalForwardWithUrlbar@ > #forward-button:-moz-window-inactive:not(:-moz-lwtheme) { - border-color: hsl(0,0%,64%) hsl(0,0%,65%) hsl(0,0%,66%); - background-image: linear-gradient(hsl(0,0%,99%), hsl(0,0%,82%)); - box-shadow: inset 0 1px 0 hsla(0,0%,100%,.35); -} + :-moz-any(@primaryToolbarButtons@), + #bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { + list-style-image: url("chrome://browser/skin/Toolbar@2x.png"); + } -@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] { - opacity: 0; -} + :-moz-any(@primaryToolbarButtons@):-moz-lwtheme-brighttext, + #bookmarks-menu-button[cui-areatype="toolbar"]:-moz-lwtheme-brighttext > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { + list-style-image: url("chrome://browser/skin/Toolbar-inverted@2x.png"); + } -@media (-moz-mac-lion-theme) { - @conditionalForwardWithUrlbar@ > #forward-button:not(:-moz-lwtheme) { - background-image: linear-gradient(hsla(0,0%,100%,.73), hsla(0,0%,100%,.05) 85%); - border-color: hsla(0,0%,0%,.35) hsla(0,0%,0%,.25) hsla(0,0%,0%,.2); - box-shadow: inset 0 1px 0 hsla(0,0%,100%,.2), - inset 0 0 1px hsla(0,0%,100%,.1), - 0 1px 0 hsla(0,0%,100%,.2); + #back-button { + -moz-image-region: rect(0, 72px, 36px, 36px); } - @conditionalForwardWithUrlbar@ > #forward-button:hover:active:not(:-moz-lwtheme) { - background-image: linear-gradient(hsla(0,0%,60%,.37), hsla(0,0%,100%,.35) 95%); - border-color: hsla(0,0%,0%,.43) hsla(0,0%,0%,.25) hsla(0,0%,0%,.37); - box-shadow: inset 0 1px 0 hsla(0,0%,0%,.02), - inset 0 1px 2px hsla(0,0%,0%,.2), - 0 1px 0 hsla(0,0%,100%,.2); + #back-button:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 72px, 72px, 36px); } - @conditionalForwardWithUrlbar@ > #forward-button:-moz-window-inactive:not(:-moz-lwtheme) { - background-image: none; - border-color: hsla(0,0%,0%,.2); + #forward-button { + -moz-image-region: rect(0, 144px, 36px, 108px); } -} -#navigator-toolbox[iconsize="small"][mode="icons"] > #nav-bar #forward-button { - width: 27px; -} + #forward-button:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 144px, 72px, 108px); + } -#navigator-toolbox[iconsize="small"][mode="icons"] > #nav-bar #forward-button:-moz-lwtheme { - padding-left: 2px; -} + #home-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 252px, 36px, 216px); + } -toolbar[mode="icons"] #forward-button:-moz-lwtheme { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} + #home-button[cui-areatype="toolbar"]:hover:active { + -moz-image-region: rect(36px, 252px, 72px, 216px); + } -#navigator-toolbox[iconsize="small"][mode="icons"] > #nav-bar #back-button { - -moz-margin-end: 0; - width: 26px; -} + #bookmarks-menu-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 288px, 36px, 252px); + } -#navigator-toolbox[iconsize="small"][mode="icons"] > #nav-bar #back-button:-moz-lwtheme { - padding-right: 2px; - border-right-width: 0; - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} + #bookmarks-menu-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 288px, 72px, 252px); + } -.unified-nav-back[_moz-menuactive]:-moz-locale-dir(ltr), -.unified-nav-forward[_moz-menuactive]:-moz-locale-dir(rtl) { - list-style-image: url("chrome://browser/skin/menu-back.png") !important; -} + #bookmarks-menu-button[cui-areatype="toolbar"][open] { + -moz-image-region: rect(72px, 288px, 108px, 252px); + } -.unified-nav-forward[_moz-menuactive]:-moz-locale-dir(ltr), -.unified-nav-back[_moz-menuactive]:-moz-locale-dir(rtl) { - list-style-image: url("chrome://browser/skin/menu-forward.png") !important; -} + #bookmarks-menu-button[cui-areatype="toolbar"][starred] { + -moz-image-region: rect(0, 324px, 36px, 288px); + } + #bookmarks-menu-button[cui-areatype="toolbar"][starred]:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 324px, 72px, 288px); + } -/* reload button */ + #bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { + -moz-image-region: rect(0px, 1260px, 36px, 1224px); + } -#reload-button { - -moz-image-region: rect(0, 80px, 20px, 60px); -} + #bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker:hover:active:not([disabled="true"]) > .dropmarker-icon { + -moz-image-region: rect(36px, 1260px, 72px, 1224px); + } -@media (min-resolution: 2dppx) { - #reload-button { - -moz-image-region: rect(0, 160px, 40px, 120px); + #history-panelmenu[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 360px, 36px, 324px); } -} -/* stop button */ + #history-panelmenu[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 360px, 72px, 324px); + } -#stop-button { - -moz-image-region: rect(0, 100px, 20px, 80px); -} + #history-panelmenu[cui-areatype="toolbar"][open] { + -moz-image-region: rect(72px, 360px, 108px, 324px); + } -@media (min-resolution: 2dppx) { - #stop-button { - -moz-image-region: rect(0, 200px, 40px, 160px); + #downloads-indicator[cui-areatype="toolbar"], + #downloads-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 396px, 36px, 360px); } -} -/* home button */ + #downloads-indicator[cui-areatype="toolbar"]:hover:active:not([disabled="true"]), + #downloads-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 396px, 72px, 360px); + } -#home-button { - -moz-image-region: rect(0, 120px, 20px, 100px); -} + #add-ons-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 432px, 36px, 396px); + } -#home-button.bookmark-item { - list-style-image: url("chrome://browser/skin/home.png"); - -moz-image-region: rect(0, 12px, 12px, 0); -} + #add-ons-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 432px, 72px, 396px); + } -#home-button.bookmark-item:hover { - -moz-image-region: rect(0, 24px, 12px, 12px); -} + #open-file-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 468px, 36px, 432px); + } -#home-button.bookmark-item > .toolbarbutton-icon { - display: -moz-box !important; - -moz-margin-start: -2px; - -moz-margin-end: 3px; -} + #open-file-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 468px, 72px, 432px); + } -@media (min-resolution: 2dppx) { - #home-button:not(.bookmark-item) { - -moz-image-region: rect(0, 240px, 40px, 200px); + #save-page-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 504px, 36px, 468px); } -} -/* tabview button */ + #save-page-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 504px, 72px, 468px); + } -#tabview-button, -#menu_tabview { - list-style-image: url(chrome://browser/skin/tabview/tabview.png); -} + #sync-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 540px, 36px, 504px); + } -#tabview-button { - -moz-image-region: rect(0, 100px, 20px, 80px); + #sync-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 540px, 72px, 504px); + } + + #feed-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 576px, 36px, 540px); + } + + #feed-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 576px, 72px, 540px); + } + + #social-share-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 612px, 36px, 576px); + } + + #social-share-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 612px, 72px, 576px); + } + + #characterencoding-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 648px, 36px, 612px); + } + + #characterencoding-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 648px, 72px, 612px); + } + + #characterencoding-button[cui-areatype="toolbar"][open] { + -moz-image-region: rect(72px, 648px, 108px, 612px); + } + + #new-window-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 684px, 36px, 648px); + } + + #new-window-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 684px, 72px, 648px); + } + + #new-tab-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 720px, 36px, 684px); + } + + #new-tab-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 720px, 72px, 684px); + } + + #privatebrowsing-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 756px, 36px, 720px); + } + + #privatebrowsing-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 756px, 72px, 720px); + } + + #find-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 792px, 36px, 756px); + } + + #find-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 792px, 72px, 756px); + } + + #print-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 828px, 36px, 792px); + } + + #print-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 828px, 72px, 792px); + } + + #fullscreen-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 864px, 36px, 828px); + } + + #fullscreen-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 864px, 72px, 828px); + } + + #fullscreen-button[cui-areatype="toolbar"][checked="true"] { + -moz-image-region: rect(72px, 864px, 108px, 828px); + } + + #fullscreen-button[cui-areatype="toolbar"][checked="true"]:hover:active:not([disabled="true"]) { + -moz-image-region: rect(108px, 864px, 144px, 828px); + } + + #developer-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 900px, 36px, 864px); + } + + #developer-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 900px, 72px, 864px); + } + + #developer-button[cui-areatype="toolbar"][open] { + -moz-image-region: rect(72px, 900px, 108px, 864px); + } + + #preferences-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 936px, 36px, 900px); + } + + #preferences-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 936px, 72px, 900px); + } + + #PanelUI-menu-button { + -moz-image-region: rect(0, 972px, 36px, 936px); + } + + #PanelUI-menu-button:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 972px, 72px, 936px); + } + + #PanelUI-menu-button[open] { + -moz-image-region: rect(72px, 972px, 108px, 936px); + } + + #edit-controls[cui-areatype="toolbar"] > #cut-button { + -moz-image-region: rect(0, 1008px, 36px, 972px); + } + + #edit-controls[cui-areatype="toolbar"] > #cut-button:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 1008px, 72px, 972px); + } + + #edit-controls[cui-areatype="toolbar"] > #copy-button { + -moz-image-region: rect(0, 1044px, 36px, 1008px); + } + + #edit-controls[cui-areatype="toolbar"] > #copy-button:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 1044px, 72px, 1008px); + } + + #edit-controls[cui-areatype="toolbar"] > #paste-button { + -moz-image-region: rect(0, 1080px, 36px, 1044px); + } + + #edit-controls[cui-areatype="toolbar"] > #paste-button:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 1080px, 72px, 1044px); + } + + #zoom-controls[cui-areatype="toolbar"] > #zoom-out-button { + -moz-image-region: rect(0, 1116px, 36px, 1080px); + } + + #zoom-controls[cui-areatype="toolbar"] > #zoom-out-button:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 1116px, 72px, 1080px); + } + + #zoom-controls[cui-areatype="toolbar"] > #zoom-in-button { + -moz-image-region: rect(0, 1152px, 36px, 1116px); + } + + #zoom-controls[cui-areatype="toolbar"] > #zoom-in-button:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 1152px, 72px, 1116px); + } + + #webrtc-status-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 1188px, 36px, 1152px); + } + + #webrtc-status-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 1188px, 72px, 1152px); + } + + #nav-bar-overflow-button { + -moz-image-region: rect(0, 1224px, 36px, 1188px); + } + + #nav-bar-overflow-button:hover:active:not([disabled="true"]) { + -moz-image-region: rect(36px, 1224px, 72px, 1188px); + } + + #nav-bar-overflow-button[open] { + -moz-image-region: rect(72px, 1224px, 108px, 1188px); + } + + :-moz-any(@primaryToolbarButtons@):not(#tabview-button) > .toolbarbutton-icon, + :-moz-any(@primaryToolbarButtons@):not(#tabview-button) > .toolbarbutton-menubutton-button > .toolbarbutton-icon { + width: 18px; + } + + /* Menu panel and palette styles */ + + :-moz-any(@primaryToolbarButtons@)[cui-areatype="menu-panel"], + toolbarpaletteitem[place="palette"] > :-moz-any(@primaryToolbarButtons@) { + list-style-image: url(chrome://browser/skin/menuPanel@2x.png); + } + + #home-button[cui-areatype="menu-panel"], + toolbarpaletteitem[place="palette"] > #home-button { + -moz-image-region: rect(0px, 256px, 64px, 192px); + } + + #bookmarks-menu-button[cui-areatype="menu-panel"], + toolbarpaletteitem[place="palette"] > #bookmarks-menu-button { + -moz-image-region: rect(0px, 320px, 64px, 256px); + } + + #bookmarks-menu-button[starred][cui-areatype="menu-panel"] { + -moz-image-region: rect(0px, 384px, 64px, 320px); + } + + #history-panelmenu[cui-areatype="menu-panel"], + toolbarpaletteitem[place="palette"] > #history-panelmenu { + -moz-image-region: rect(0px, 448px, 64px, 384px); + } + + #downloads-button[cui-areatype="menu-panel"], + #downloads-indicator[cui-areatype="menu-panel"], + toolbarpaletteitem[place="palette"] > #downloads-button { + -moz-image-region: rect(0px, 512px, 64px, 448px); + } + + #add-ons-button[cui-areatype="menu-panel"], + toolbarpaletteitem[place="palette"] > #add-ons-button { + -moz-image-region: rect(0px, 576px, 64px, 512px); + } + + #open-file-button[cui-areatype="menu-panel"], + toolbarpaletteitem[place="palette"] > #open-file-button { + -moz-image-region: rect(0px, 640px, 64px, 576px); + } + + #save-page-button[cui-areatype="menu-panel"], + toolbarpaletteitem[place="palette"] > #save-page-button { + -moz-image-region: rect(0px, 704px, 64px, 640px); + } + + #sync-button[cui-areatype="menu-panel"], + toolbarpaletteitem[place="palette"] > #sync-button { + -moz-image-region: rect(0px, 768px, 64px, 704px); + } + + #feed-button[cui-areatype="menu-panel"], + toolbarpaletteitem[place="palette"] > #feed-button { + -moz-image-region: rect(0px, 832px, 64px, 768px); + } + + #social-share-button[cui-areatype="menu-panel"], + toolbarpaletteitem[place="palette"] > #social-share-button { + -moz-image-region: rect(0px, 896px, 64px, 832px); + } + + #characterencoding-button[cui-areatype="menu-panel"], + toolbarpaletteitem[place="palette"] > #characterencoding-button { + -moz-image-region: rect(0, 960px, 64px, 896px); + } + + #new-window-button[cui-areatype="menu-panel"], + toolbarpaletteitem[place="palette"] > #new-window-button { + -moz-image-region: rect(0px, 1024px, 64px, 960px); + } + + #new-tab-button[cui-areatype="menu-panel"], + toolbarpaletteitem[place="palette"] > #new-tab-button { + -moz-image-region: rect(0px, 1088px, 64px, 1024px); + } + + #privatebrowsing-button[cui-areatype="menu-panel"], + toolbarpaletteitem[place="palette"] > #privatebrowsing-button { + -moz-image-region: rect(0px, 1152px, 64px, 1088px); + } + + #find-button[cui-areatype="menu-panel"], + toolbarpaletteitem[place="palette"] > #find-button { + -moz-image-region: rect(0px, 1280px, 64px, 1216px); + } + + #print-button[cui-areatype="menu-panel"], + toolbarpaletteitem[place="palette"] > #print-button { + -moz-image-region: rect(0px, 1344px, 64px, 1280px); + } + + #fullscreen-button[cui-areatype="menu-panel"], + toolbarpaletteitem[place="palette"] > #fullscreen-button { + -moz-image-region: rect(0px, 1408px, 64px, 1344px); + } + + #developer-button[cui-areatype="menu-panel"], + toolbarpaletteitem[place="palette"] > #developer-button { + -moz-image-region: rect(0px, 1472px, 64px, 1408px); + } + + #preferences-button[cui-areatype="menu-panel"], + toolbarpaletteitem[place="palette"] > #preferences-button { + -moz-image-region: rect(0px, 1536px, 64px, 1472px); + } + + /* Footer and wide panel control icons */ + #edit-controls@inAnyPanel@ > toolbarbutton, + #zoom-controls@inAnyPanel@ > toolbarbutton, + toolbarpaletteitem[place="palette"] > #edit-controls > toolbarbutton, + toolbarpaletteitem[place="palette"] > #zoom-controls > toolbarbutton { + list-style-image: url(chrome://browser/skin/menuPanel-small@2x.png); + } + + #edit-controls@inAnyPanel@ > #cut-button, + toolbarpaletteitem[place="palette"] > #edit-controls > #cut-button { + -moz-image-region: rect(0px, 64px, 32px, 32px); + } + + #edit-controls@inAnyPanel@ > #copy-button, + toolbarpaletteitem[place="palette"] > #edit-controls > #copy-button { + -moz-image-region: rect(0px, 96px, 32px, 64px); + } + + #edit-controls@inAnyPanel@ > #paste-button, + toolbarpaletteitem[place="palette"] > #edit-controls > #paste-button { + -moz-image-region: rect(0px, 128px, 32px, 96px); + } + + #zoom-controls@inAnyPanel@ > #zoom-out-button, + toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-out-button { + -moz-image-region: rect(0px, 160px, 32px, 128px); + } + + #zoom-controls@inAnyPanel@ > #zoom-in-button, + toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-in-button { + -moz-image-region: rect(0px, 192px, 32px, 160px); + } + + #PanelUI-quit > .toolbarbutton-icon, + #PanelUI-customize > .toolbarbutton-icon, + #PanelUI-help > .toolbarbutton-icon { + width: 16px; + } } -#tabview-button[groups="0"] { - -moz-image-region: rect(0, 20px, 20px, 0); +.toolbarbutton-1:not([type="menu-button"]), +.toolbarbutton-1 > .toolbarbutton-menubutton-button, +#restore-button { + min-width: 28px; } -#tabview-button[groups="1"] { - -moz-image-region: rect(0, 40px, 20px, 20px); +.toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon, +.toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon { + margin: 2px; } -#tabview-button[groups="2"] { - -moz-image-region: rect(0, 60px, 20px, 40px); +#main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-icon, +#main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon, +#main-window:not([customizing]) .toolbarbutton-1 > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon, +#restore-button[disabled="true"] > .toolbarbutton-icon { + opacity: .4; } -#tabview-button[groups="3"] { - -moz-image-region: rect(0, 80px, 20px, 60px); +@media (-moz-mac-lion-theme) { + #main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-icon, + #main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon, + #main-window:not([customizing]) .toolbarbutton-1 > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon, + #restore-button[disabled="true"] > .toolbarbutton-icon, + #main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-menu-dropmarker, + #main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-menubutton-dropmarker, + .toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-icon, + .toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-text, + .toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-badge-container > .toolbarbutton-icon, + #restore-button:not(:hover):-moz-window-inactive > .toolbarbutton-icon, + .toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menu-dropmarker, + .toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon, + .toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menubutton-button > .toolbarbutton-icon { + opacity: .5; + } + + #main-window:not([customizing]) .toolbarbutton-1:-moz-window-inactive[disabled="true"] > .toolbarbutton-icon, + #main-window:not([customizing]) .toolbarbutton-1:-moz-window-inactive[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon, + #main-window:not([customizing]) .toolbarbutton-1:-moz-window-inactive > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon, + #restore-button:-moz-window-inactive[disabled="true"] > .toolbarbutton-icon { + opacity: .25; + } } -#menu_tabview { - -moz-image-region: rect(2px, 98px, 18px, 82px); +.toolbarbutton-1 > .toolbarbutton-menu-dropmarker, +.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker { + list-style-image: url(chrome://browser/skin/toolbarbutton-dropmarker.png); } -#menu_tabview[groups="0"] { - -moz-image-region: rect(2px, 18px, 18px, 2px); +@media (min-resolution: 2dppx) { + .toolbarbutton-1 > .toolbarbutton-menu-dropmarker, + .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker { + list-style-image: url(chrome://browser/skin/toolbarbutton-dropmarker@2x.png); + } + + .toolbarbutton-1 > .toolbarbutton-menu-dropmarker > .dropmarker-icon, + .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { + width: 7px; + } } -#menu_tabview[groups="1"] { - -moz-image-region: rect(2px, 38px, 18px, 22px); +.toolbarbutton-1 > .toolbarbutton-menu-dropmarker { + -moz-margin-end: 1px; } -#menu_tabview[groups="2"] { - -moz-image-region: rect(2px, 58px, 18px, 42px); +.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker { + padding: 2px 4px 0; + -moz-border-start: none !important; } -#menu_tabview[groups="3"] { - -moz-image-region: rect(2px, 78px, 18px, 62px); +.toolbarbutton-1 > .toolbarbutton-menubutton-button:-moz-locale-dir(rtl), +.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-locale-dir(ltr) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; } -/* download manager button */ +.toolbarbutton-1 > .toolbarbutton-menubutton-button:-moz-locale-dir(ltr), +.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-locale-dir(rtl) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} -#downloads-button { - -moz-image-region: rect(0, 140px, 20px, 120px); +.toolbarbutton-1 > .toolbarbutton-text, +.toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-text { + margin: 2px 0 0; } -@media (min-resolution: 2dppx) { - #downloads-button { - -moz-image-region: rect(0, 280px, 40px, 240px); - } +.toolbarbutton-1 > menupopup { + margin-top: 1px; } -/* history sidebar button */ +/* Common back and forward button styles */ -#history-button { - -moz-image-region: rect(0, 160px, 20px, 140px); +#back-button, +#forward-button { + background: linear-gradient(rgba(255,255,255,0.5), + rgba(255,255,255,0.2) 50%, + rgba(255,255,255,0.1) 50%, + rgba(255,255,255,0.2)) repeat-x; } -#history-button[checked="true"] { - -moz-image-region: rect(20px, 160px, 40px, 140px); +#back-button:-moz-lwtheme, +#forward-button:-moz-lwtheme { + background-origin: border-box; + border: 1px solid rgba(0,0,0,0.4); + box-shadow: inset 0 1px rgba(255,255,255,0.3), 0 1px rgba(255,255,255,0.2); } -@media (min-resolution: 2dppx) { - #history-button { - -moz-image-region: rect(0, 320px, 40px, 280px); - } - - #history-button[checked="true"] { - -moz-image-region: rect(40px, 320px, 80px, 280px); - } +#back-button:active:hover:-moz-lwtheme, +#forward-button:active:hover:-moz-lwtheme { + background-color: rgba(0,0,0,0.2); + box-shadow: inset 0 2px 5px rgba(0,0,0,0.6), 0 1px rgba(255,255,255,0.2); } -/* bookmark sidebar & menu buttons */ +#back-button:-moz-window-inactive, +#forward-button:-moz-window-inactive { + background-color: rgba(0,0,0,0.04); + border-color: rgba(0,0,0,0.2); +} -#bookmarks-button, -#bookmarks-menu-button { - -moz-image-region: rect(0, 180px, 20px, 160px); +#back-button:-moz-locale-dir(rtl), +#forward-button:-moz-locale-dir(rtl) { + transform: scaleX(-1); } -#bookmarks-button[checked="true"] { - -moz-image-region: rect(20px, 180px, 40px, 160px); +/* Back button styles */ + +#back-button { + -moz-margin-end: -7px; + position: relative; + z-index: 1; + width: 30px; + height: 30px; + padding: 4px 5px 4px 3px; + border-radius: 10000px; } -#bookmarks-menu-button.bookmark-item { - -moz-image-region: rect(2px, 178px, 18px, 162px); - list-style-image: url("chrome://browser/skin/Toolbar.png"); +#back-button:not(:-moz-lwtheme) { + height: 31px; + padding: 4px 5px 5px 3px; + margin-bottom: -1px; + background: url(chrome://browser/skin/keyhole-circle.png) 0 0 no-repeat; } @media (min-resolution: 2dppx) { - #bookmarks-button, - #bookmarks-menu-button { - -moz-image-region: rect(0, 360px, 40px, 320px); + #back-button:not(:-moz-lwtheme) { + background-image: url(chrome://browser/skin/keyhole-circle@2x.png); + background-size: 90px; } +} - #bookmarks-button[checked="true"] { - -moz-image-region: rect(40px, 360px, 80px, 320px); - } +#back-button:-moz-window-inactive:not(:-moz-lwtheme) { + background-position: -60px 0; +} - #bookmarks-menu-button.bookmark-item { - -moz-image-region: rect(4px, 356px, 36px, 324px); - list-style-image: url("chrome://browser/skin/Toolbar@2x.png"); - } +#back-button:not([disabled="true"]):active:hover:not(:-moz-lwtheme), +#back-button[open="true"]:not(:-moz-lwtheme) { + background-position: -30px 0; +} - #bookmarks-menu-button.bookmark-item > .toolbarbutton-icon { - width: 16px; - } +/* Forward button styles */ + +#forward-button { + -moz-margin-start: 0; + -moz-margin-end: 0; + clip-path: url(chrome://browser/content/browser.xul#osx-keyhole-forward-clip-path); } -#bookmarks-menu-button.toolbarbutton-1 { - -moz-box-orient: horizontal; +#forward-button > .toolbarbutton-icon { + /* shift the icon away from the back button */ + margin-left: 3px; + margin-right: -1px; } -/* print button */ +#forward-button:-moz-lwtheme { + -moz-padding-start: 2px; + -moz-padding-end: 0; +} -#print-button { - -moz-image-region: rect(0, 200px, 20px, 180px); +#forward-button:not(:-moz-lwtheme) { + -moz-padding-start: 2px; + background: linear-gradient(hsl(0,0%,99%), hsl(0,0%,67%)) padding-box; + border: 1px solid; + border-color: hsl(0,0%,31%) hsla(0,0%,29%,.6) hsl(0,0%,27%); + box-shadow: inset 0 1px 0 hsla(0,0%,100%,.35), + 0 1px 0 hsla(0,0%,100%,.2); } -@media (min-resolution: 2dppx) { - #print-button { - -moz-image-region: rect(0, 400px, 40px, 360px); - } +#urlbar-container:not([switchingtabs]) > #forward-button { + transition: opacity @forwardTransitionLength@ ease-out; } -/* toolbar new tab button */ +#forward-button:hover:active:not(:-moz-lwtheme) { + background-image: linear-gradient(hsl(0,0%,74%), hsl(0,0%,61%)); + box-shadow: inset rgba(0,0,0,.3) 0 -6px 10px, + inset #000 0 1px 3px, + inset rgba(0,0,0,.2) 0 1px 3px, + 0 1px 0 hsla(0,0%,100%,.2); +} -#new-tab-button { - -moz-image-region: rect(0, 220px, 20px, 200px); +#forward-button:-moz-window-inactive:not(:-moz-lwtheme) { + border-color: hsl(0,0%,64%) hsl(0,0%,65%) hsl(0,0%,66%); + background-image: linear-gradient(hsl(0,0%,99%), hsl(0,0%,82%)); + box-shadow: inset 0 1px 0 hsla(0,0%,100%,.35); } -@media (min-resolution: 2dppx) { - #new-tab-button { - -moz-image-region: rect(0, 440px, 40px, 400px); - } +#urlbar-container:not(:hover) > #forward-button[disabled] { + opacity: 0; } -/* new window button */ +@media (-moz-mac-lion-theme) { + #forward-button:not(:-moz-lwtheme) { + background-image: linear-gradient(hsla(0,0%,100%,.73), hsla(0,0%,100%,.05) 85%); + border-color: hsla(0,0%,0%,.35) hsla(0,0%,0%,.25) hsla(0,0%,0%,.2); + box-shadow: inset 0 1px 0 hsla(0,0%,100%,.2), + inset 0 0 1px hsla(0,0%,100%,.1), + 0 1px 0 hsla(0,0%,100%,.2); + } -#new-window-button { - -moz-image-region: rect(0, 240px, 20px, 220px); -} + #forward-button:hover:active:not(:-moz-lwtheme) { + background-image: linear-gradient(hsla(0,0%,60%,.37), hsla(0,0%,100%,.35) 95%); + border-color: hsla(0,0%,0%,.43) hsla(0,0%,0%,.25) hsla(0,0%,0%,.37); + box-shadow: inset 0 1px 0 hsla(0,0%,0%,.02), + inset 0 1px 2px hsla(0,0%,0%,.2), + 0 1px 0 hsla(0,0%,100%,.2); + } -@media (min-resolution: 2dppx) { - #new-window-button { - -moz-image-region: rect(0, 480px, 40px, 440px); + #forward-button:-moz-window-inactive:not(:-moz-lwtheme) { + background-image: none; + border-color: hsla(0,0%,0%,.2); } } -/* cut button */ - -#cut-button { - -moz-image-region: rect(0, 260px, 20px, 240px); +.unified-nav-back[_moz-menuactive]:-moz-locale-dir(ltr), +.unified-nav-forward[_moz-menuactive]:-moz-locale-dir(rtl) { + list-style-image: url("chrome://browser/skin/menu-back.png") !important; } -@media (min-resolution: 2dppx) { - #cut-button { - -moz-image-region: rect(0, 520px, 40px, 480px); - } +.unified-nav-forward[_moz-menuactive]:-moz-locale-dir(ltr), +.unified-nav-back[_moz-menuactive]:-moz-locale-dir(rtl) { + list-style-image: url("chrome://browser/skin/menu-forward.png") !important; } -/* copy button */ +/* home button */ -#copy-button { - -moz-image-region: rect(0, 280px, 20px, 260px); +#home-button.bookmark-item { + list-style-image: url("chrome://browser/skin/home.png"); + -moz-image-region: rect(0, 12px, 12px, 0); } -@media (min-resolution: 2dppx) { - #copy-button { - -moz-image-region: rect(0, 560px, 40px, 520px); - } +#home-button.bookmark-item:hover { + -moz-image-region: rect(0, 24px, 12px, 12px); +} + +#home-button.bookmark-item > .toolbarbutton-icon { + display: -moz-box !important; + -moz-margin-start: -2px; + -moz-margin-end: 3px; } -/* paste button */ +/* tabview button */ -#paste-button { - -moz-image-region: rect(0, 300px, 20px, 280px); +#tabview-button, +#menu_tabview { + list-style-image: url(chrome://browser/skin/tabview/tabview.png); } -@media (min-resolution: 2dppx) { - #paste-button { - -moz-image-region: rect(0, 600px, 40px, 560px); - } +#tabview-button { + -moz-image-region: rect(0, 100px, 20px, 80px); } -/* alltabs button */ +#tabview-button[groups="0"] { + -moz-image-region: rect(0, 20px, 20px, 0); +} -#alltabs-button { - -moz-image-region: rect(0, 380px, 20px, 360px); +#tabview-button[groups="1"] { + -moz-image-region: rect(0, 40px, 20px, 20px); } -@media (min-resolution: 2dppx) { - #alltabs-button { - -moz-image-region: rect(0, 760px, 40px, 720px); - } +#tabview-button[groups="2"] { + -moz-image-region: rect(0, 60px, 20px, 40px); } -/* fullscreen button */ +#tabview-button[groups="3"] { + -moz-image-region: rect(0, 80px, 20px, 60px); +} -#fullscreen-button { - -moz-image-region: rect(0, 340px, 20px, 320px); +#menu_tabview { + -moz-image-region: rect(2px, 98px, 18px, 82px); } -#fullscreen-button[checked="true"], -#restore-button { - -moz-image-region: rect(0, 360px, 20px, 340px); +#menu_tabview[groups="0"] { + -moz-image-region: rect(2px, 18px, 18px, 2px); } -@media (min-resolution: 2dppx) { - #fullscreen-button { - -moz-image-region: rect(0, 680px, 40px, 640px); - } +#menu_tabview[groups="1"] { + -moz-image-region: rect(2px, 38px, 18px, 22px); +} - #fullscreen-button[checked="true"], - #restore-button { - -moz-image-region: rect(0, 720px, 40px, 680px); - } +#menu_tabview[groups="2"] { + -moz-image-region: rect(2px, 58px, 18px, 42px); } -/* zoom controls */ +#menu_tabview[groups="3"] { + -moz-image-region: rect(2px, 78px, 18px, 62px); +} -#zoom-controls { - -moz-box-align: center; +#cut-button { + -moz-margin-end: 0; } -#zoom-out-button { - -moz-image-region: rect(0, 400px, 20px, 380px); +#paste-button { + -moz-border-start: none; + -moz-margin-start: 0; } -#zoom-in-button { - -moz-image-region: rect(0, 420px, 20px, 400px); +#cut-button:-moz-locale-dir(ltr), +#paste-button:-moz-locale-dir(rtl) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; } -@media (min-resolution: 2dppx) { - #zoom-out-button { - -moz-image-region: rect(0, 800px, 40px, 760px); - } +#cut-button:-moz-locale-dir(rtl), +#paste-button:-moz-locale-dir(ltr) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} - #zoom-in-button { - -moz-image-region: rect(0, 840px, 40px, 800px); - } +#copy-button { + border-radius: 0; + margin-right: 0; + margin-left: 0; } -toolbar[mode="icons"] #zoom-out-button { +/* zoom controls */ + +#zoom-out-button { -moz-margin-end: 0; } -toolbar[mode="icons"] #zoom-in-button { +#zoom-in-button { -moz-border-start: none; -moz-margin-start: 0; } @@ -1090,48 +1415,23 @@ toolbar[mode="icons"] #zoom-in-button { border-bottom-left-radius: 0; } -/* sync button */ +#zoom-controls[cui-areatype="toolbar"] > #zoom-reset-button { + min-width: 0; + margin: 0; +} -#sync-button { - -moz-image-region: rect(0, 440px, 20px, 420px); +#zoom-controls[cui-areatype="toolbar"] > #zoom-reset-button > .toolbarbutton-text { + margin-top: 0; + padding-top: 8px; } +/* sync button */ + #sync-button[status="active"] { list-style-image: url("chrome://browser/skin/sync-throbber.png"); -moz-image-region: rect(0, 20px, 20px, 0px); } -@media (min-resolution: 2dppx) { - #sync-button:not([status="active"]) { - -moz-image-region: rect(0, 880px, 40px, 840px); - } -} - -/* feed button */ - -#feed-button { - -moz-image-region: rect(0, 460px, 20px, 440px); -} - -@media (min-resolution: 2dppx) { - #feed-button { - -moz-image-region: rect(0, 920px, 40px, 880px); - } -} - -/* webRTC indicator button */ - -#webrtc-status-button { - -moz-image-region: rect(0, 480px, 20px, 460px); -} - -@media (min-resolution: 2dppx) { - #webrtc-status-button { - -moz-image-region: rect(0, 960px, 40px, 920px); - } -} - - /* ----- FULLSCREEN WINDOW CONTROLS ----- */ #minimize-button, @@ -1179,58 +1479,62 @@ toolbar[mode="icons"] #zoom-in-button { box-shadow: @focusRingShadow@; } +#urlbar-container { + -moz-box-align: center; +} + #urlbar { -moz-padding-end: 4px; border-radius: @toolbarbuttonCornerRadius@; } -@conditionalForwardWithUrlbar@ + #urlbar-container { +@conditionalForwardWithUrlbar@ > #urlbar-wrapper { padding-left: @conditionalForwardWithUrlbarWidth@px; -moz-margin-start: -@conditionalForwardWithUrlbarWidth@px; position: relative; pointer-events: none; } -@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar { +@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar { -moz-border-start: none; margin-left: 0; pointer-events: all; } -@conditionalForwardWithUrlbar@:not([switchingtabs]) + #urlbar-container > #urlbar { +@conditionalForwardWithUrlbar@:not([switchingtabs]) > #urlbar-wrapper > #urlbar { transition: margin-left @forwardTransitionLength@ ease-out; } -@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(ltr) { +@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(ltr) { border-top-left-radius: 0; border-bottom-left-radius: 0; } -@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(rtl) { +@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) { border-top-right-radius: 0; border-bottom-right-radius: 0; } -@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container { +@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper { clip-path: url("chrome://browser/content/browser.xul#osx-urlbar-back-button-clip-path"); } -@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar { +@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar { margin-left: -@conditionalForwardWithUrlbarWidth@px; } -@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) + #urlbar-container > #urlbar { +@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar { /* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */ transition-delay: 100s; } -@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar { +@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar { /* when not hovered anymore, trigger a new transition to hide the forward button immediately */ margin-left: -@conditionalForwardWithUrlbarWidth@.01px; } -@conditionalForwardWithUrlbar@ + #urlbar-container:-moz-locale-dir(rtl), -@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(rtl) { +@conditionalForwardWithUrlbar@ > #urlbar-wrapper:-moz-locale-dir(rtl), +@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) { /* let osx-urlbar-back-button-clip-path clip the urlbar's right side for RTL */ transform: scaleX(-1); } @@ -1259,30 +1563,30 @@ toolbar[mode="icons"] #zoom-in-button { border-radius: 0; } -@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar > #identity-box { +@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar > #identity-box { border-radius: 0; } -@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) { +@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) { transition: 0s padding-left; padding-left: 10px; } -@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) { +@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) { transition: 0s padding-right; padding-right: 10px; } -@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box { +@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box { /* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */ transition-delay: 100s; } -@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) { +@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) { padding-left: 10.01px; } -@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) { +@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) { padding-right: 10.01px; } @@ -1493,14 +1797,6 @@ richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url- -moz-image-region: rect(11px, 16px, 22px, 0); } -window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon { - -moz-image-region: rect(0, 32px, 11px, 16px); -} - -window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-box > .ac-action-icon { - -moz-image-region: rect(11px, 32px, 22px, 16px); -} - @media (min-resolution: 2dppx) { .ac-result-type-bookmark { list-style-image: url("chrome://browser/skin/places/star-icons@2x.png"); @@ -1525,14 +1821,6 @@ window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][s richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-box > .ac-action-icon { -moz-image-region: rect(22px, 32px, 44px, 0); } - - window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon { - -moz-image-region: rect(0, 64px, 22px, 32px); - } - - window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-box > .ac-action-icon { - -moz-image-region: rect(22px, 64px, 44px, 32px); - } } .autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) { @@ -1559,7 +1847,6 @@ window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][s /* ----- COMBINED GO/RELOAD/STOP BUTTON IN LOCATION BAR ----- */ -#go-button, #urlbar > toolbarbutton { margin: 0; -moz-padding-start: 2px; @@ -1572,21 +1859,14 @@ window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][s background-image: radial-gradient(circle closest-side, hsla(205,100%,70%,.3), hsla(205,100%,70%,0)); } -#go-button { - padding: 0 3px; -} - -#go-button, #urlbar-go-button { -moz-image-region: rect(0, 42px, 14px, 28px); } -#go-button:hover:active, #urlbar-go-button:hover:active { -moz-image-region: rect(14px, 42px, 28px, 28px); } -#go-button:-moz-locale-dir(rtl), #urlbar-go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon { transform: scaleX(-1); } @@ -1611,19 +1891,32 @@ window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][s -moz-image-region: rect(14px, 28px, 28px, 14px); } +#bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { + width: 16px; + height: 16px; +} + +#BMB_bookmarksPopup[side="top"], +#BMB_bookmarksPopup[side="bottom"] { + margin-left: -26px; + margin-right: -26px; +} + +#BMB_bookmarksPopup[side="left"], +#BMB_bookmarksPopup[side="right"] { + margin-top: -26px; + margin-bottom: -26px; +} + @media (min-resolution: 2dppx) { - #go-button, #urlbar > toolbarbutton { list-style-image: url("chrome://browser/skin/reload-stop-go@2x.png"); } - #go-button, #urlbar-go-button { -moz-image-region: rect(0, 84px, 28px, 56px); - height: 14px; } - #go-button:hover:active, #urlbar-go-button:hover:active { -moz-image-region: rect(28px, 84px, 56px, 56px); } @@ -1644,7 +1937,6 @@ window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][s -moz-image-region: rect(28px, 56px, 56px, 28px); } - #go-button > .toolbarbutton-icon, #urlbar > toolbarbutton > .toolbarbutton-icon { width: 14px; } @@ -1684,31 +1976,6 @@ window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][s transition: height 100ms ease-out, width 100ms ease-out; } -#social-share-button { - list-style-image: url("chrome://browser/skin/social/share-button.png"); -} - -#social-share-button[open], -#social-share-button:hover:active { - list-style-image: url("chrome://browser/skin/social/share-button-active.png"); -} - -#social-share-button > .toolbarbutton-icon { - width: 13px; - height: 14px; -} - -@media (min-resolution: 2dppx) { - #social-share-button { - list-style-image: url("chrome://browser/skin/social/share-button@2x.png"); - } - - #social-share-button[open], - #social-share-button:hover:active { - list-style-image: url("chrome://browser/skin/social/share-button-active@2x.png"); - } -} - .social-share-toolbar { border-right: 1px solid #dedede; background: linear-gradient(to bottom, rgba(247,247,247,.99), rgba(247,247,247,.95)); @@ -1752,35 +2019,35 @@ window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][s -moz-image-region: rect(0, 16px, 16px, 0); } -/* Star button */ -#star-button { +/* bookmarks menu-button */ + +#bookmarks-menu-button.bookmark-item, +#bookmarks-menu-button.bookmark-item[open] { list-style-image: url("chrome://browser/skin/places/star-icons.png"); - -moz-image-region: rect(0, 16px, 16px, 0); + -moz-image-region: rect(0px 16px 16px 0px); } -#star-button:hover:active, -#star-button[starred="true"] { - -moz-image-region: rect(0, 32px, 16px, 16px); +#bookmarks-menu-button.bookmark-item[starred] { + -moz-image-region: rect(0px 32px 16px 16px); } -#star-button:hover:active[starred="true"] { - -moz-image-region: rect(0, 48px, 16px, 32px); +#bookmarks-menu-button.bookmark-item > .toolbarbutton-menubutton-button { + padding: 0; } @media (min-resolution: 2dppx) { - #star-button { + #bookmarks-menu-button.bookmark-item, + #bookmarks-menu-button.bookmark-item[open] { list-style-image: url("chrome://browser/skin/places/star-icons@2x.png"); - -moz-image-region: rect(0, 32px, 32px, 0); - width: 22px; + -moz-image-region: rect(0px 32px 32px 0px); } - #star-button:hover:active, - #star-button[starred="true"] { - -moz-image-region: rect(0, 64px, 32px, 32px); + #bookmarks-menu-button.bookmark-item[starred] { + -moz-image-region: rect(0px 64px 32px 32px); } - #star-button:hover:active[starred="true"] { - -moz-image-region: rect(0, 96px, 32px, 64px); + #bookmarks-menu-button.bookmark-item > .toolbarbutton-menubutton-button > .toolbarbutton-icon { + width: 16px; } } @@ -2052,40 +2319,17 @@ window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][s } .panel-promo-closebutton { - list-style-image: url("chrome://global/skin/icons/close.png"); - -moz-image-region: rect(0, 16px, 16px, 0); border: none; -moz-margin-end: -14px; margin-top: -8px; } -.panel-promo-closebutton:hover { - -moz-image-region: rect(0, 32px, 16px, 16px); -} - -.panel-promo-closebutton:hover:active { - -moz-image-region: rect(0, 48px, 16px, 32px); -} - .panel-promo-closebutton > .toolbarbutton-text { padding: 0; margin: 0; } @media (min-resolution: 2dppx) { - .panel-promo-closebutton { - list-style-image: url("chrome://global/skin/icons/close@2x.png"); - -moz-image-region: rect(0, 32px, 32px, 0); - } - - .panel-promo-closebutton:hover { - -moz-image-region: rect(0, 64px, 32px, 32px); - } - - .panel-promo-closebutton:hover:active { - -moz-image-region: rect(0, 96px, 32px, 64px); - } - .panel-promo-closebutton > .toolbarbutton-icon { width: 16px; } @@ -2132,362 +2376,168 @@ sidebarheader { background-image: none !important; background-color: transparent; -moz-margin-start: -3px; - position: relative; -} - -#appcontent ~ .sidebar-splitter { - -moz-border-start: 1px solid #ccc; - -moz-border-end: none; - -moz-margin-start: 0; - -moz-margin-end: -3px; -} - -#sidebar-title { - color: #535f6d; - font-weight: bold; -} - -#sidebar-throbber[loading="true"] { - list-style-image: url("chrome://global/skin/icons/loading_16.png"); -} - -sidebarheader > .tabs-closebutton > .toolbarbutton-text { - display: none; -} - -/* ----- CONTENT ----- */ - -.browserContainer > findbar { - background: @scopeBarBackground@; - border-top: @scopeBarSeparatorBorder@; - color: -moz-DialogText; - text-shadow: none; -} - -/* ----- THROBBER ----- */ - -#navigator-throbber { - width: 17px; - min-height: 16px; - margin: 0 4px; -} - -#navigator-throbber[busy="true"] { - list-style-image: url("chrome://global/skin/icons/loading_16.png"); -} - -#wrapper-navigator-throbber > #navigator-throbber { - list-style-image: url("chrome://global/skin/icons/notloading_16.png"); -} - -toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { - display: none; -} - -.bookmark-item { - list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png"); -} - -@media (min-resolution: 2dppx) { - .bookmark-item { - list-style-image: url("chrome://mozapps/skin/places/defaultFavicon@2x.png"); - } - - image.bookmark-item { - width: 16px; - } -} - -.openintabs-menuitem { - list-style-image: none; -} - -/* ::::: tabbrowser ::::: */ - -.tabbrowser-tabbox { - margin: 0; -} - -.tab-throbber, -.tab-icon-image { - width: 16px; - height: 16px; - list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png"); -} - -.tab-throbber { - list-style-image: url("chrome://browser/skin/tabbrowser/connecting.png"); -} - -.tab-throbber[progress] { - list-style-image: url("chrome://browser/skin/tabbrowser/loading.png"); -} - -@media (min-resolution: 2dppx) { - .tab-icon-image { - list-style-image: url("chrome://mozapps/skin/places/defaultFavicon@2x.png"); - image-rendering: -moz-crisp-edges; - } - - .tab-throbber { - list-style-image: url("chrome://browser/skin/tabbrowser/connecting@2x.png"); - } - - .tab-throbber[progress] { - list-style-image: url("chrome://browser/skin/tabbrowser/loading@2x.png"); - } -} - -.tabbrowser-tab:not(:hover) > .tab-stack > .tab-content > .tab-icon-image:not([selected="true"]) { - opacity: .8; -} - -.tabbrowser-tab:not([pinned]):not([fadein]) { - transition: min-width 200ms ease-out /* copied from browser/base/content/browser.css */, - max-width 250ms ease-out /* copied from browser/base/content/browser.css */, - opacity 50ms ease-out 100ms /* hide the tab for the last 100ms of the max-width transition */; -} - -.tab-stack { - /* ensure stable tab height with and without toolbarbuttons on the tab bar */ - height: 26px; -} - -.tabbrowser-tab, -.tabs-newtab-button { - -moz-appearance: none; - font: message-box; - font-weight: bold; - text-shadow: @loweredShadow@; - margin: 0; - padding: 0; - border: none; - text-align: center; - -moz-box-align: stretch; -} - -.tabbrowser-tab[remote] { - text-decoration: underline; -} - -%define TABSONTOP_TAB #tabbrowser-tabs[tabsontop="true"] > .tabbrowser-tab -%define TABSONBOTTOM_TAB #tabbrowser-tabs[tabsontop="false"] > .tabbrowser-tab -%define TABSONTOP_TAB_STACK #tabbrowser-tabs[tabsontop="true"] > .tabbrowser-tab > .tab-stack -%define TABSONBOTTOM_TAB_STACK #tabbrowser-tabs[tabsontop="false"] > .tabbrowser-tab > .tab-stack -%define TABSONTOP_NEWTAB_BUTTON #tabbrowser-tabs[tabsontop="true"] > .tabbrowser-arrowscrollbox > .tabs-newtab-button -%define TABSONBOTTOM_NEWTAB_BUTTON #tabbrowser-tabs[tabsontop="false"] > .tabbrowser-arrowscrollbox > .tabs-newtab-button - -@TABSONTOP_TAB_STACK@ > .tab-background { - margin-top: 3px; -} - -@TABSONBOTTOM_TAB_STACK@ > .tab-background { - margin-bottom: 3px; -} - -@TABSONTOP_TAB_STACK@ > .tab-background:not([selected="true"]):not(:-moz-lwtheme) { - margin-bottom: 2px; -} - -@TABSONBOTTOM_TAB_STACK@ > .tab-background:not([selected="true"]) { - margin-top: 2px; -} - -.tab-background, -.tab-content, -.tabs-newtab-button > .toolbarbutton-icon { - -moz-margin-start: -5px; - -moz-margin-end: -4px; - pointer-events: none; -} - -.tab-close-button { - pointer-events: auto; -} - -.tabbrowser-tabs[closebuttons="hidden"] > * > * > * > .tab-close-button:not([pinned]) { - display: -moz-box; - visibility: hidden; + position: relative; } -.tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox { - -moz-padding-start: 5px; - -moz-padding-end: 4px; +#appcontent ~ .sidebar-splitter { + -moz-border-start: 1px solid #ccc; + -moz-border-end: none; + -moz-margin-start: 0; + -moz-margin-end: -3px; } -.tab-content, -.tabs-newtab-button > .toolbarbutton-icon { - -moz-box-align: center; - border: solid transparent; - border-width: 0 11px; +#sidebar-title { + color: #535f6d; + font-weight: bold; } -.tab-background-start, -.tab-background-end { - width: 12px; - height: 21px; +#sidebar-throbber[loading="true"] { + list-style-image: url("chrome://global/skin/icons/loading_16.png"); } -.tab-background-middle { - -moz-box-flex: 1; +sidebarheader > .tabs-closebutton > .toolbarbutton-text { + display: none; } -@TABSONTOP_TAB_STACK@ > .tab-background > .tab-background-start:-moz-locale-dir(ltr), -@TABSONTOP_TAB_STACK@ > .tab-background > .tab-background-end:-moz-locale-dir(rtl) { - clip-path: url(chrome://browser/content/browser.xul#osx-tab-ontop-left-curve-clip-path); -} +/* ----- CONTENT ----- */ -@TABSONTOP_TAB_STACK@ > .tab-background > .tab-background-end:-moz-locale-dir(ltr), -@TABSONTOP_TAB_STACK@ > .tab-background > .tab-background-start:-moz-locale-dir(rtl) { - clip-path: url(chrome://browser/content/browser.xul#osx-tab-ontop-right-curve-clip-path); +.browserContainer > findbar { + background: @scopeBarBackground@; + border-top: @scopeBarSeparatorBorder@; + color: -moz-DialogText; + text-shadow: none; } -@TABSONBOTTOM_TAB_STACK@ > .tab-background > .tab-background-start:-moz-locale-dir(ltr), -@TABSONBOTTOM_TAB_STACK@ > .tab-background > .tab-background-end:-moz-locale-dir(rtl) { - clip-path: url(chrome://browser/content/browser.xul#osx-tab-onbottom-left-curve-clip-path); +toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { + display: none; } -@TABSONBOTTOM_TAB_STACK@ > .tab-background > .tab-background-end:-moz-locale-dir(ltr), -@TABSONBOTTOM_TAB_STACK@ > .tab-background > .tab-background-start:-moz-locale-dir(rtl) { - clip-path: url(chrome://browser/content/browser.xul#osx-tab-onbottom-right-curve-clip-path); +.bookmark-item { + list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png"); } -.tab-background-start[selected="true"]:not(:-moz-lwtheme), -.tab-background-middle[selected="true"]:not(:-moz-lwtheme), -.tab-background-end[selected="true"]:not(:-moz-lwtheme) { - background-color: -moz-mac-chrome-active; -} +@media (min-resolution: 2dppx) { + .bookmark-item { + list-style-image: url("chrome://mozapps/skin/places/defaultFavicon@2x.png"); + } -.tab-background-start[selected="true"]:not(:-moz-lwtheme):-moz-window-inactive, -.tab-background-middle[selected="true"]:not(:-moz-lwtheme):-moz-window-inactive, -.tab-background-end[selected="true"]:not(:-moz-lwtheme):-moz-window-inactive { - background-color: -moz-mac-chrome-inactive; + image.bookmark-item { + width: 16px; + } } -.tab-background-start[pinned][titlechanged]:not([selected="true"]), -.tab-background-end[pinned][titlechanged]:not([selected="true"]) { - background-image: linear-gradient(rgba(148,205,253,.2), rgba(148,205,253,.2)) !important; +.openintabs-menuitem { + list-style-image: none; } -@TABSONBOTTOM_TAB_STACK@ > .tab-background > .tab-background-middle[pinned][titlechanged]:not([selected="true"]) { - background-image: radial-gradient(circle farthest-corner at 50% 99%, rgba(254,254,255,1) 3%, rgba(210,235,255,.9) 12%, rgba(148,205,253,.6) 30%, rgba(148,205,253,.2) 70%); -} +/* ::::: tabbrowser ::::: */ -@TABSONTOP_TAB_STACK@ > .tab-background > .tab-background-middle[pinned][titlechanged]:not([selected="true"]) { - background-image: radial-gradient(circle farthest-corner at 50% 2px, rgba(254,254,255,1) 3%, rgba(210,235,255,.9) 12%, rgba(148,205,253,.6) 30%, rgba(148,205,253,.2) 70%); +.tabbrowser-tabbox { + margin: 0; } -.tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start:-moz-lwtheme-brighttext:not([selected="true"]), -.tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle:-moz-lwtheme-brighttext:not([selected="true"]), -.tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end:-moz-lwtheme-brighttext:not([selected="true"]) { - background-image: linear-gradient(hsla(0,0%,40%,.6), hsla(0,0%,30%,.6) 50%); -} +%include ../shared/tabs.inc.css -.tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start:-moz-lwtheme-darktext:not([selected="true"]), -.tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle:-moz-lwtheme-darktext:not([selected="true"]), -.tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end:-moz-lwtheme-darktext:not([selected="true"]) { - background-image: linear-gradient(hsla(0,0%,60%,.5), hsla(0,0%,45%,.5) 50%); +.tab-label { + margin-top: 1px; + margin-bottom: 0; + text-align: center; } -@TABSONTOP_TAB_STACK@ > .tab-content, -@TABSONTOP_NEWTAB_BUTTON@ > .toolbarbutton-icon { - border-image: url(chrome://browser/skin/tabbrowser/tab-top-normal-active.png) 0 11 fill repeat stretch; -} +@media (min-resolution: 2dppx) { + /* image preloading hack from shared/tabs.inc.css */ + #TabsToolbar::before { + background-image: + url(chrome://browser/skin/tabbrowser/tab-background-end@2x.png), + url(chrome://browser/skin/tabbrowser/tab-background-middle@2x.png), + url(chrome://browser/skin/tabbrowser/tab-background-start@2x.png); + } -@TABSONTOP_TAB@:hover > .tab-stack > .tab-content:not([selected="true"]), -@TABSONTOP_NEWTAB_BUTTON@:hover > .toolbarbutton-icon { - border-image: url(chrome://browser/skin/tabbrowser/tab-top-hover-active.png) 0 11 fill repeat stretch; -} + .tabbrowser-tab:hover > .tab-stack > .tab-background:not([selected=true]), + .tabs-newtab-button:hover { + background-image: url(chrome://browser/skin/tabbrowser/tab-background-start@2x.png), + url(chrome://browser/skin/tabbrowser/tab-background-middle@2x.png), + url(chrome://browser/skin/tabbrowser/tab-background-end@2x.png); + } -@TABSONTOP_TAB_STACK@ > .tab-content[selected="true"] { - border-image: url(chrome://browser/skin/tabbrowser/tab-top-selected-active.png) 0 11 fill repeat stretch; -} + .tab-background-middle[selected=true] { + background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle@2x.png), + @fgTabTexture@, + none; + } -@TABSONBOTTOM_TAB_STACK@ > .tab-content, -@TABSONBOTTOM_NEWTAB_BUTTON@ > .toolbarbutton-icon { - border-image: url(chrome://browser/skin/tabbrowser/tab-bottom-normal-active.png) 0 11 fill repeat stretch; -} + .tab-background-start[selected=true]:-moz-locale-dir(ltr)::after, + .tab-background-end[selected=true]:-moz-locale-dir(rtl)::after { + background-image: url(chrome://browser/skin/tabbrowser/tab-stroke-start@2x.png); + } -@media (min-resolution: 2dppx) { - @TABSONTOP_TAB_STACK@ > .tab-content, - @TABSONTOP_NEWTAB_BUTTON@ > .toolbarbutton-icon { - border-image: url(chrome://browser/skin/tabbrowser/tab-top-normal-active@2x.png) 0 22 fill repeat stretch; + .tab-background-end[selected=true]:-moz-locale-dir(ltr)::after, + .tab-background-start[selected=true]:-moz-locale-dir(rtl)::after { + background-image: url(chrome://browser/skin/tabbrowser/tab-stroke-end@2x.png); + } + + .tab-icon-image { + list-style-image: url("chrome://mozapps/skin/places/defaultFavicon@2x.png"); + image-rendering: -moz-crisp-edges; + } + + .tab-throbber { + list-style-image: url("chrome://browser/skin/tabbrowser/connecting@2x.png"); } - @TABSONTOP_TAB@:hover > .tab-stack > .tab-content:not([selected="true"]), - @TABSONTOP_NEWTAB_BUTTON@:hover > .toolbarbutton-icon { - border-image: url(chrome://browser/skin/tabbrowser/tab-top-hover-active@2x.png) 0 22 fill repeat stretch; + .tab-throbber[progress] { + list-style-image: url("chrome://browser/skin/tabbrowser/loading@2x.png"); } - @TABSONTOP_TAB_STACK@ > .tab-content[selected="true"] { - border-image: url(chrome://browser/skin/tabbrowser/tab-top-selected-active@2x.png) 0 22 fill repeat stretch; + /* Background tab separators */ + #tabbrowser-tabs[movingtab] > .tabbrowser-tab[beforeselected]:not([last-visible-tab])::after, + .tabbrowser-tab:not([selected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before, + #tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([selected]):not([beforehovered]):not(:hover)::after { + background-image: url(chrome://browser/skin/tabbrowser/tab-separator@2x.png); } } -@TABSONBOTTOM_TAB@:hover > .tab-stack > .tab-content:not([selected="true"]), -@TABSONBOTTOM_NEWTAB_BUTTON@:hover > .toolbarbutton-icon { - border-image: url(chrome://browser/skin/tabbrowser/tab-bottom-hover-active.png) 0 11 fill repeat stretch; +.tabbrowser-tab:not(:hover) > .tab-stack > .tab-content > .tab-icon-image:not([selected="true"]) { + opacity: .9; } -@TABSONBOTTOM_TAB_STACK@ > .tab-content[selected="true"] { - border-image: url(chrome://browser/skin/tabbrowser/tab-bottom-selected-active.png) 0 11 fill repeat stretch; +.tab-label:not([selected="true"]) { + opacity: .7; } -/* preloading hack */ -#TabsToolbar::after { - content: ''; - display: block; - background-image: - url(chrome://browser/skin/tabbrowser/tab-top-normal-active.png), - url(chrome://browser/skin/tabbrowser/tab-top-hover-active.png), - url(chrome://browser/skin/tabbrowser/tab-top-selected-active.png), - url(chrome://browser/skin/tabbrowser/tab-bottom-normal-active.png), - url(chrome://browser/skin/tabbrowser/tab-bottom-hover-active.png), - url(chrome://browser/skin/tabbrowser/tab-bottom-selected-active.png), - url(chrome://browser/skin/tabbrowser/tabbar-top-bg-active.png), - url(chrome://browser/skin/tabbrowser/tabbar-top-bg-inactive.png), - url(chrome://browser/skin/tabbrowser/tabbar-bottom-bg-active.png), - url(chrome://browser/skin/tabbrowser/tabbar-bottom-bg-inactive.png); +.tabbrowser-tab, +.tabs-newtab-button { + font: message-box; + font-weight: bold; + border: none; } -@media (min-resolution: 2dppx) { - #TabsToolbar::after { - content: ''; - display: block; - background-image: - url(chrome://browser/skin/tabbrowser/tab-top-normal-active@2x.png), - url(chrome://browser/skin/tabbrowser/tab-top-hover-active@2x.png), - url(chrome://browser/skin/tabbrowser/tab-top-selected-active@2x.png), - url(chrome://browser/skin/tabbrowser/tab-bottom-normal-active.png), - url(chrome://browser/skin/tabbrowser/tab-bottom-hover-active.png), - url(chrome://browser/skin/tabbrowser/tab-bottom-selected-active.png), - url(chrome://browser/skin/tabbrowser/tabbar-top-bg-active.png), - url(chrome://browser/skin/tabbrowser/tabbar-top-bg-inactive.png), - url(chrome://browser/skin/tabbrowser/tabbar-bottom-bg-active.png), - url(chrome://browser/skin/tabbrowser/tabbar-bottom-bg-inactive.png); - } +.tabbrowser-tab:not(:-moz-lwtheme) { + color: #333; + text-shadow: @loweredShadow@; } -.tabbrowser-tab:focus > .tab-stack { - box-shadow: @focusRingShadow@; +.tabbrowser-tabs[closebuttons="hidden"] > * > * > * > .tab-close-button:not([pinned]) { + display: -moz-box; + visibility: hidden; } -.tabbrowser-tab:not([selected="true"]):not(:hover):not(:-moz-lwtheme) { - color: #222; +.tabs-newtab-button > .toolbarbutton-icon { + -moz-box-align: center; + border: solid transparent; + border-width: 0 11px; } -.tabbrowser-tab[selected="true"] { - color: #000; - z-index: 1; - position: relative; +.tabbrowser-tab:focus > .tab-stack > .tab-content > .tab-label { + box-shadow: @focusRingShadow@; } -.tabbrowser-tab:-moz-lwtheme { - color: inherit; - text-shadow: inherit; +#titlebar { + padding-top: @spaceAboveTabbar@; + min-height: @tabHeight@; } -#main-window:not([privatebrowsingmode=temporary]) #navigator-toolbox[tabsontop="true"]:not(:-moz-lwtheme)::before { +#main-window:not(:-moz-any([privatebrowsingmode=temporary],[customizing],[tabsintitlebar])) #navigator-toolbox:not(:-moz-lwtheme)::before { /* We want the titlebar to be unified, but we still want to be able * to give #TabsToolbar a background. So we can't set -moz-appearance: * toolbar on #TabsToolbar itself. Instead, we set it on a box of the @@ -2496,74 +2546,43 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { content: ''; display: block; -moz-appearance: toolbar; - height: 25px; - margin-bottom: -25px; + height: calc(@tabHeight@ + 1px); + margin-bottom: calc(-1px - @tabHeight@); } #TabsToolbar { + position: relative; -moz-appearance: none; - height: 26px; background-repeat: repeat-x; } -#TabsToolbar[tabsontop="false"] { - margin-top: -2px; - padding-top: 2px; -} - -/* For tabs-on-top, only fill the bottom 2px with the chrome background - * color, so that the borders in tabbar-top-bg-*.png can mix with it. - * In the top 24px the unified toolbar (from the ::before above) will show. - */ -#TabsToolbar[tabsontop="true"]:not(:-moz-lwtheme) { - padding-bottom: 2px; - background: url(chrome://browser/skin/tabbrowser/tabbar-top-bg-active.png), - linear-gradient(to top, -moz-mac-chrome-active 2px, transparent 2px); -} - -#TabsToolbar[tabsontop="true"]:not(:-moz-lwtheme):-moz-window-inactive { - background: url(chrome://browser/skin/tabbrowser/tabbar-top-bg-inactive.png), - linear-gradient(to top, -moz-mac-chrome-inactive 2px, transparent 2px); -} - -/* In tabs-on-bottom mode, fill the whole toolbar with the chrome - * background color. +/* + * Draw the bottom border of the tabstrip when core doesn't do it for us: */ -#TabsToolbar[tabsontop="false"]:not(:-moz-lwtheme) { - background: url(chrome://browser/skin/tabbrowser/tabbar-bottom-bg-active.png) -moz-mac-chrome-active; -} - -#TabsToolbar[tabsontop="false"]:not(:-moz-lwtheme):-moz-window-inactive { - background: url(chrome://browser/skin/tabbrowser/tabbar-bottom-bg-inactive.png) -moz-mac-chrome-inactive; +#main-window:-moz-any([privatebrowsingmode=temporary],[sizemode="fullscreen"],[customizing],[customize-exiting]) #TabsToolbar::after, +#main-window:not([tabsintitlebar]) #TabsToolbar::after, +#TabsToolbar:-moz-lwtheme::after { + content: ''; + /* Because we use placeholders for window controls etc. in the tabstrip, + * and position those with ordinal attributes, and because our layout code + * expects :before/:after nodes to come first/last in the frame list, + * we have to reorder this element to come last, hence the + * ordinal group value (see bug 853415). */ + -moz-box-ordinal-group: 1001; + position: absolute; + bottom: 1px; + left: 0; + right: 0; + z-index: 0; + border-bottom: 1px solid hsla(0,0%,0%,.3); } #tabbrowser-tabs { -moz-box-align: stretch; - height: 26px; -} - -#tabbrowser-tabs[tabsontop="true"] > .tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox:not(:-moz-lwtheme) { - margin-bottom: -2px; -} - -#tabbrowser-tabs[tabsontop="false"] > .tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox { - margin-top: -2px; -} - -@TABSONTOP_NEWTAB_BUTTON@ > .toolbarbutton-icon { - padding: 4px 0 2px; -} - -@TABSONTOP_TAB_STACK@ > .tab-content { - padding-top: 2px; } -@TABSONBOTTOM_NEWTAB_BUTTON@ > .toolbarbutton-icon { - padding: 2px 0 4px; -} - -@TABSONBOTTOM_TAB_STACK@ > .tab-content { - padding-bottom: 2px; +.tabs-newtab-button > .toolbarbutton-icon { + padding: 6px 0 4px; } /** @@ -2572,7 +2591,8 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { .tab-drop-indicator { list-style-image: url(chrome://browser/skin/tabbrowser/tabDragIndicator.png); - margin-bottom: -8px; + margin-top: -2px; + z-index: 3; } @media (min-resolution: 2dppx) { @@ -2591,38 +2611,13 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { } .tab-close-button { - list-style-image: url("chrome://global/skin/icons/close.png"); -moz-appearance: none; border: none !important; - padding: 0; - margin: 0; background: none; cursor: default; - -moz-image-region: rect(0, 16px, 16px, 0); -} - -.tab-close-button:hover { - -moz-image-region: rect(0, 32px, 16px, 16px); -} - -.tab-close-button:hover:active { - -moz-image-region: rect(0, 48px, 16px, 32px); } @media (min-resolution: 2dppx) { - .tab-close-button { - list-style-image: url("chrome://global/skin/icons/close@2x.png"); - -moz-image-region: rect(0, 32px, 32px, 0); - } - - .tab-close-button:hover { - -moz-image-region: rect(0, 64px, 32px, 32px); - } - - .tab-close-button:hover:active { - -moz-image-region: rect(0, 96px, 32px, 64px); - } - .tab-close-button > .toolbarbutton-icon { width: 16px; } @@ -2636,13 +2631,6 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { border: none; } -#tabbrowser-tabs[tabsontop=false] > .tabbrowser-arrowscrollbox > .scrollbutton-up, -#tabbrowser-tabs[tabsontop=false] > .tabbrowser-arrowscrollbox > .scrollbutton-down, -#tabbrowser-tabs[tabsontop=false] > .tabbrowser-arrowscrollbox > .scrollbutton-up > .toolbarbutton-icon, -#tabbrowser-tabs[tabsontop=false] > .tabbrowser-arrowscrollbox > .scrollbutton-down > .toolbarbutton-icon { - transform: scaleY(-1); -} - .tabbrowser-arrowscrollbox > .scrollbutton-up { -moz-border-end: 2px solid transparent; } @@ -2667,6 +2655,16 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { list-style-image: url("chrome://browser/skin/tabbrowser/tab-arrow-right.png"); } +.tabbrowser-arrowscrollbox > .scrollbutton-up:-moz-locale-dir(ltr):-moz-lwtheme-brighttext, +.tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-locale-dir(rtl):-moz-lwtheme-brighttext { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-arrow-left-inverted.png"); +} + +.tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-locale-dir(ltr):-moz-lwtheme-brighttext, +.tabbrowser-arrowscrollbox > .scrollbutton-up:-moz-locale-dir(rtl):-moz-lwtheme-brighttext { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-arrow-right-inverted.png"); +} + .tabbrowser-arrowscrollbox > .scrollbutton-up:hover, .tabbrowser-arrowscrollbox > .scrollbutton-down:hover { -moz-image-region: rect(0, 26px, 20px, 13px); @@ -2699,6 +2697,16 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { list-style-image: url("chrome://browser/skin/tabbrowser/tab-arrow-right@2x.png"); } + .tabbrowser-arrowscrollbox > .scrollbutton-up:-moz-locale-dir(ltr):-moz-lwtheme-brighttext, + .tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-locale-dir(rtl):-moz-lwtheme-brighttext { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-arrow-left-inverted@2x.png"); + } + + .tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-locale-dir(ltr):-moz-lwtheme-brighttext, + .tabbrowser-arrowscrollbox > .scrollbutton-up:-moz-locale-dir(rtl):-moz-lwtheme-brighttext { + list-style-image: url("chrome://browser/skin/tabbrowser/tab-arrow-right-inverted@2x.png"); + } + .tabbrowser-arrowscrollbox > .scrollbutton-up:hover, .tabbrowser-arrowscrollbox > .scrollbutton-down:hover { -moz-image-region: rect(0, 52px, 40px, 26px); @@ -2738,9 +2746,9 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { * Tabstrip & add-on bar toolbar buttons */ -:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1, -:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button, -:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker { +#TabsToolbar .toolbarbutton-1, +#TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button, +#TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker { -moz-appearance: none; /* !important flags needed because of bug 561154: */ margin: 0 !important; @@ -2751,31 +2759,31 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { box-shadow: none !important; } -:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1:not([type="menu-button"]), -:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button { +#TabsToolbar .toolbarbutton-1:not([type="menu-button"]), +#TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button { margin: 0; padding: 0 1px; } -:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker { +#TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker { padding-left: 4px; padding-right: 4px; } .tabbrowser-arrowscrollbox > .scrollbutton-up:not([disabled]):hover, .tabbrowser-arrowscrollbox > .scrollbutton-down:not([disabled]):hover, -:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1:not([type="menu-button"]):not([disabled]):not([open]):hover, -:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):hover, -:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1:not([disabled]):not([buttonover]):hover > .toolbarbutton-menubutton-dropmarker { +#TabsToolbar .toolbarbutton-1:not([type="menu-button"]):not([disabled]):not([open]):hover, +#TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):hover, +#TabsToolbar .toolbarbutton-1:not([disabled]):not([buttonover]):hover > .toolbarbutton-menubutton-dropmarker { background-image: linear-gradient(transparent, rgba(0,0,0,.15)) !important; } .tabbrowser-arrowscrollbox > .scrollbutton-up:not([disabled]):hover:active, .tabbrowser-arrowscrollbox > .scrollbutton-down:not([disabled]):hover:active, -:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1:not([type="menu-button"]):not([disabled]):hover:active, -:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1[type="menu"][open], -:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):hover:active, -:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1[open]:not([disabled]):hover > .toolbarbutton-menubutton-dropmarker { +#TabsToolbar .toolbarbutton-1:not([type="menu-button"]):not([disabled]):hover:active, +#TabsToolbar .toolbarbutton-1[type="menu"][open], +#TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):hover:active, +#TabsToolbar .toolbarbutton-1[open]:not([disabled]):hover > .toolbarbutton-menubutton-dropmarker { background-image: linear-gradient(transparent, rgba(0,0,0,.3)) !important; } @@ -2786,6 +2794,12 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { -moz-image-region: rect(0, 18px, 20px, 0); } +.tabs-newtab-button:-moz-lwtheme-brighttext, +#TabsToolbar > #new-tab-button:-moz-lwtheme-brighttext, +#TabsToolbar > toolbarpaletteitem > #new-tab-button:-moz-lwtheme-brighttext { + list-style-image: url(chrome://browser/skin/tabbrowser/newtab-inverted.png); +} + .tabs-newtab-button:hover, #TabsToolbar > #new-tab-button:hover { -moz-image-region: rect(0, 36px, 20px, 18px); @@ -2804,6 +2818,12 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { -moz-image-region: rect(0, 36px, 40px, 0); } + .tabs-newtab-button:-moz-lwtheme-brighttext, + #TabsToolbar > #new-tab-button:-moz-lwtheme-brighttext, + #TabsToolbar > toolbarpaletteitem > #new-tab-button:-moz-lwtheme-brighttext { + list-style-image: url(chrome://browser/skin/tabbrowser/newtab-inverted@2x.png); + } + .tabs-newtab-button:hover, #TabsToolbar > #new-tab-button:hover { -moz-image-region: rect(0, 72px, 40px, 36px); @@ -2824,36 +2844,44 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { } } -#TabsToolbar #alltabs-button { +#alltabs-button { list-style-image: url(chrome://browser/skin/tabbrowser/alltabs-box-bkgnd-icon.png); -moz-image-region: rect(0, 17px, 20px, 0); } -#TabsToolbar > #alltabs-button:not([disabled="true"]):hover { +#alltabs-button:-moz-lwtheme-brighttext { + list-style-image: url(chrome://browser/skin/tabbrowser/alltabs-box-bkgnd-icon-inverted.png); +} + +#alltabs-button:not([disabled="true"]):hover { -moz-image-region: rect(0, 34px, 20px, 17px); } -#TabsToolbar > #alltabs-button[open="true"]:not([disabled="true"]), -#TabsToolbar > #alltabs-button:not([disabled="true"]):hover:active { +#alltabs-button[open="true"]:not([disabled="true"]), +#alltabs-button:not([disabled="true"]):hover:active { -moz-image-region: rect(0, 51px, 20px, 34px); } @media (min-resolution: 2dppx) { - #TabsToolbar #alltabs-button { + #alltabs-button { list-style-image: url(chrome://browser/skin/tabbrowser/alltabs-box-bkgnd-icon@2x.png); -moz-image-region: rect(0, 34px, 40px, 0); } - #TabsToolbar > #alltabs-button:not([disabled="true"]):hover { + #alltabs-button:-moz-lwtheme-brighttext { + list-style-image: url(chrome://browser/skin/tabbrowser/alltabs-box-bkgnd-icon-inverted@2x.png); + } + + #alltabs-button:not([disabled="true"]):hover { -moz-image-region: rect(0, 68px, 40px, 34px); } - #TabsToolbar > #alltabs-button[open="true"]:not([disabled="true"]), - #TabsToolbar > #alltabs-button:not([disabled="true"]):hover:active { + #alltabs-button[open="true"]:not([disabled="true"]), + #alltabs-button:not([disabled="true"]):hover:active { -moz-image-region: rect(0, 102px, 40px, 68px); } - #TabsToolbar #alltabs-button > .toolbarbutton-icon { + #alltabs-button > .toolbarbutton-icon { width: 17px; } } @@ -2889,38 +2917,11 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { /* Tabstrip close button */ .tabs-closebutton { -moz-padding-end: 4px; - list-style-image: url("chrome://global/skin/icons/close.png"); - -moz-image-region: rect(0, 16px, 16px, 0); border: none; } -#sidebar-header > .tabs-closebutton { - list-style-image: url("chrome://global/skin/icons/close-sidebar.png"); -} - -.tabs-closebutton:hover { - -moz-image-region: rect(0, 32px, 16px, 16px); -} - -.tabs-closebutton:hover:active { - -moz-image-region: rect(0, 48px, 16px, 32px); -} - @media (min-resolution: 2dppx) { - :not(#sidebar-header) > .tabs-closebutton { - list-style-image: url("chrome://global/skin/icons/close@2x.png"); - -moz-image-region: rect(0, 32px, 32px, 0); - } - - :not(#sidebar-header) > .tabs-closebutton:hover { - -moz-image-region: rect(0, 64px, 32px, 32px); - } - - :not(#sidebar-header) > .tabs-closebutton:hover:active { - -moz-image-region: rect(0, 96px, 32px, 64px); - } - - :not(#sidebar-header) > .tabs-closebutton > .toolbarbutton-icon { + .tabs-closebutton > .toolbarbutton-icon { width: 16px; } } @@ -2952,10 +2953,6 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { background-color: Highlight; } -#customizeToolbarSheetPopup { - -moz-window-shadow: sheet; -} - /* Popup Icons */ #identity-popup-icon { height: 64px; @@ -3107,7 +3104,7 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { } } -@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box { +@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box { padding-left: 7px; } @@ -3549,69 +3546,6 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { margin-top: .5em; } -/* Add-on bar */ - -#addon-bar { - min-height: 18px; - padding-right: 16px; /* replace with -moz-padding-end when/if bug 631729 gets fixed */ -} - -#addon-bar:not(:-moz-lwtheme) { - -moz-appearance: statusbar; -} - -#status-bar { - -moz-appearance: none; - padding-right: 0; -} - -#addon-bar[customizing] > #status-bar { - opacity: .5; - background-image: repeating-linear-gradient(135deg, - rgba(255,255,255,.3), rgba(255,255,255,.3) 5px, - rgba(0,0,0,.3) 5px, rgba(0,0,0,.3) 10px); -} - -#status-bar > statusbarpanel { - border-width: 0; - -moz-appearance: none; -} - -#addonbar-closebutton { - padding: 0; - margin: 0 6px; - list-style-image: url("chrome://global/skin/icons/close.png"); - border: none; - -moz-image-region: rect(0, 16px, 16px, 0); -} - -#addonbar-closebutton:hover { - -moz-image-region: rect(0, 32px, 16px, 16px); -} - -#addonbar-closebutton:hover:active { - -moz-image-region: rect(0, 48px, 16px, 32px); -} - -@media (min-resolution: 2dppx) { - #addonbar-closebutton { - list-style-image: url("chrome://global/skin/icons/close@2x.png"); - -moz-image-region: rect(0, 32px, 32px, 0); - } - - #addonbar-closebutton:hover { - -moz-image-region: rect(0, 64px, 32px, 32px); - } - - #addonbar-closebutton:hover:active { - -moz-image-region: rect(0, 96px, 32px, 64px); - } - - #addonbar-closebutton > .toolbarbutton-icon { - width: 16px; - } -} - /* Status panel */ .statuspanel-label { @@ -3640,8 +3574,8 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { /* Lion Fullscreen window styling */ @media (-moz-mac-lion-theme) { - #navigator-toolbox[inFullscreen][tabsontop="true"]:not(:-moz-lwtheme)::before { - height: 36px; + #navigator-toolbox[inFullscreen]:not(:-moz-lwtheme)::before { + height: calc(@tabHeight@ + 11px) !important; } #main-window[inFullscreen]:-moz-lwtheme { /* This additional padding matches the change in height in the pseudo-element @@ -3780,7 +3714,7 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { position: relative; } .toolbarbutton-badge-container > .toolbarbutton-icon { - margin: 2px; + margin: 7px 2px; } .toolbarbutton-badge[badge]:not([badge=""]) { @@ -3975,6 +3909,49 @@ window > chatbox { border-bottom-right-radius: @toolbarbuttonCornerRadius@; } +/* Customization mode */ + +%include ../shared/customizableui/customizeMode.inc.css + +#main-window[customizing] #titlebar { + padding-top: 0; +} + +#main-window:-moz-any([customize-entering],[customize-entered]) #tab-view-deck { + padding: 0 2em 2em; +} + +#main-window[customizing] #tab-view-deck { + background-image: url("chrome://browser/skin/customizableui/customizeMode-gridTexture.png"), + url("chrome://browser/skin/customizableui/background-noise-toolbar.png"), + linear-gradient(to bottom, rgb(233,233,233), rgb(178,178,178) 21px); + background-attachment: fixed; +} + +#main-window[customize-entered] #navigator-toolbox > toolbar:not(#TabsToolbar), +#main-window[customize-entered] #customization-container { + border: 3px solid hsla(0,0%,0%,.1); + border-top-width: 0; + background-clip: padding-box; + background-origin: padding-box; + -moz-border-right-colors: hsla(0,0%,0%,.05) hsla(0,0%,0%,.1) hsla(0,0%,0%,.2); + -moz-border-bottom-colors: hsla(0,0%,0%,.05) hsla(0,0%,0%,.1) hsla(0,0%,0%,.2); + -moz-border-left-colors: hsla(0,0%,0%,.05) hsla(0,0%,0%,.1) hsla(0,0%,0%,.2); +} + +#main-window[customize-entered] #navigator-toolbox > toolbar:not(#TabsToolbar) { + border-bottom-width: 0; +} + +#main-window[customize-entered] #TabsToolbar { + margin-top: 9px; + background-clip: padding-box; + border-right: 3px solid transparent; + border-left: 3px solid transparent; +} + +/* End customization mode */ + panel[type="arrow"][popupid="click-to-play-plugins"] > .panel-arrowcontainer > .panel-arrowbox > .panel-arrow[side="top"], panel[type="arrow"][popupid="click-to-play-plugins"] > .panel-arrowcontainer > .panel-arrowbox > .panel-arrow[side="bottom"] { list-style-image: url("chrome://global/skin/arrow/panelarrow-light-vertical.png"); @@ -4001,13 +3978,11 @@ panel[type="arrow"][popupid="click-to-play-plugins"] > .panel-arrowcontainer > . } #main-window[privatebrowsingmode=temporary] { - background-position: top right 40px; -} - -#main-window[privatebrowsingmode=temporary][inFullscreen] { - background-position: top right 10px; + background-position: top right 20px; } +/* Note that the caption and fullscreen buttons stay in the same position for LTR and RTL but we + move the private browsing indicator to the left in RTL. */ #main-window[privatebrowsingmode=temporary]:-moz-locale-dir(rtl) { background-position: top left 70px; } @@ -4016,28 +3991,31 @@ panel[type="arrow"][popupid="click-to-play-plugins"] > .panel-arrowcontainer > . background-position: top left 10px; } +#main-window[privatebrowsingmode=temporary][inFullscreen] .titlebar-placeholder[type="fullscreen-button"]:-moz-locale-dir(ltr) { + /* Override display:none for .titlebar-placeholder in fullscreen so we can have consistent + position and padding for the private browsing indicator. */ + display: -moz-box; +} + #main-window[privatebrowsingmode=temporary]:-moz-window-inactive { background-color: -moz-mac-chrome-inactive; } -#main-window[privatebrowsingmode=temporary][inFullscreen] #nav-bar[tabsontop=false] { - -moz-padding-end: 50px !important; +#main-window[privatebrowsingmode=temporary] #TabsToolbar { + -moz-padding-end: 46px; } @media (-moz-mac-lion-theme) { - #main-window[privatebrowsingmode=temporary][inFullscreen] #TabsToolbar[tabsontop=true] { - -moz-padding-end: 50px; + #main-window[privatebrowsingmode=temporary] #TabsToolbar:-moz-locale-dir(ltr) { + -moz-padding-end: 36px; } } @media not all and (-moz-mac-lion-theme) { + /* There is no OS fullscreen button prior to Lion so the PB indicator can move closer. */ #main-window[privatebrowsingmode=temporary] { background-position: top right 10px; } - - #main-window[privatebrowsingmode=temporary][inFullscreen][tabsontop=true] #window-controls { - -moz-padding-end: 50px; - } } %include ../shared/UITour.inc.css diff --git a/browser/themes/osx/customizableui/background-noise-toolbar.png b/browser/themes/osx/customizableui/background-noise-toolbar.png new file mode 100644 index 0000000000000000000000000000000000000000..d09ba9dafb5ede66e92ce577ecaa6f9575dba104 Binary files /dev/null and b/browser/themes/osx/customizableui/background-noise-toolbar.png differ diff --git a/browser/themes/osx/customizableui/customizeMode-gridTexture.png b/browser/themes/osx/customizableui/customizeMode-gridTexture.png new file mode 100644 index 0000000000000000000000000000000000000000..a7c2775cfc799da31a505b249f5a59b89c148a58 Binary files /dev/null and b/browser/themes/osx/customizableui/customizeMode-gridTexture.png differ diff --git a/browser/themes/osx/customizableui/customizeMode-separatorHorizontal.png b/browser/themes/osx/customizableui/customizeMode-separatorHorizontal.png new file mode 100644 index 0000000000000000000000000000000000000000..5e17cb4db08e310e6c3a9e14c5bd722772dfb639 Binary files /dev/null and b/browser/themes/osx/customizableui/customizeMode-separatorHorizontal.png differ diff --git a/browser/themes/osx/customizableui/customizeMode-separatorVertical.png b/browser/themes/osx/customizableui/customizeMode-separatorVertical.png new file mode 100644 index 0000000000000000000000000000000000000000..dc4caee812878f246c87d71093768eb36c5656fc Binary files /dev/null and b/browser/themes/osx/customizableui/customizeMode-separatorVertical.png differ diff --git a/browser/themes/osx/customizableui/panelUIOverlay.css b/browser/themes/osx/customizableui/panelUIOverlay.css new file mode 100644 index 0000000000000000000000000000000000000000..97ffa35df2d15636a31ed943392805a50ba9dd86 --- /dev/null +++ b/browser/themes/osx/customizableui/panelUIOverlay.css @@ -0,0 +1,78 @@ +/* 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/. */ + +%include ../../shared/customizableui/panelUIOverlay.inc.css + +@media (min-resolution: 2dppx) { + #customization-palette toolbarbutton > .toolbarbutton-icon, + #PanelUI-contents toolbarbutton > .toolbarbutton-icon { + width: 20px; + } + + #PanelUI-customize { + list-style-image: url(chrome://browser/skin/menuPanel-customize@2x.png); + } + + #PanelUI-help { + list-style-image: url(chrome://browser/skin/menuPanel-help@2x.png); + } + + #PanelUI-quit { + list-style-image: url(chrome://browser/skin/menuPanel-exit@2x.png); + } + + #PanelUI-customize, + #PanelUI-help, + #PanelUI-quit { + -moz-image-region: rect(0, 32px, 32px, 0); + } + + #PanelUI-customize:hover, + #PanelUI-help:not([disabled]):hover, + #PanelUI-quit:not([disabled]):hover { + -moz-image-region: rect(0, 64px, 32px, 32px); + } + + #PanelUI-customize:hover:active, + #PanelUI-help:not([disabled]):hover:active, + #PanelUI-quit:not([disabled]):hover:active { + -moz-image-region: rect(0, 96px, 32px, 64px); + } +} + +#edit-controls@inAnyPanel@ > toolbarbutton:not(:first-child), +#zoom-controls@inAnyPanel@ > toolbarbutton:not(:first-child) { + margin-left: 0; + margin-right: 0; +} +#edit-controls@inAnyPanel@ > toolbarbutton:not(:first-child):not(:last-child), +#zoom-controls@inAnyPanel@ > toolbarbutton:not(:first-child):not(:last-child) { + margin-left: 0; + margin-right: 0; +} + +#zoom-controls@inAnyPanel@ > #zoom-in-button, +#zoom-controls@inAnyPanel@ > #zoom-out-button, +toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-in-button, +toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-out-button { + padding-left: 12px; + padding-right: 12px; +} + +.panel-wide-item[cui-areatype="menu-panel"] > toolbarbutton, +toolbarbutton[cui-areatype="menu-panel"] { + margin: 0; +} + +#BMB_bookmarksPopup > menu, +#BMB_bookmarksPopup > menuitem { + padding-top: 5px; + padding-bottom: 5px; +} + +/* Override OSX-specific toolkit styles for the bookmarks panel */ +#BMB_bookmarksPopup > menuitem > .menu-accel-container, +#BMB_bookmarksPopup > menu > .menu-right { + -moz-margin-end: 0; +} diff --git a/browser/themes/osx/downloads/indicator.css b/browser/themes/osx/downloads/indicator.css index c5a2308ab2fe6c8e4551716284b9548096603944..142f034cb9a3058712289789316c54912fedf9d5 100644 --- a/browser/themes/osx/downloads/indicator.css +++ b/browser/themes/osx/downloads/indicator.css @@ -26,47 +26,58 @@ #downloads-indicator-icon { background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"), - 0, 140, 20, 120) center no-repeat; + 0, 198, 18, 180) center no-repeat; } -#downloads-button[attention] -#downloads-indicator-icon { +#downloads-indicator-icon:-moz-lwtheme-brighttext { + background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"), 0, 198, 18, 180); +} + +#downloads-button[attention] #downloads-indicator-icon { background-image: url("chrome://browser/skin/downloads/download-glow.png"); } /* In the next few rules, we use :not([counter]) as a shortcut that is equivalent to -moz-any([progress], [paused]). */ -#downloads-button:not([counter]) -#downloads-indicator-counter { +#downloads-button:not([counter]) #downloads-indicator-counter { background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"), - 0, 140, 20, 120) center no-repeat; + 0, 198, 18, 180) center no-repeat; background-size: 12px; } -#downloads-button:not([counter])[attention] -#downloads-indicator-counter { +#downloads-button:not([counter]) #downloads-indicator-counter:-moz-lwtheme-brighttext { + background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"), 0, 198, 18, 180); +} + +#downloads-button:not([counter])[attention] #downloads-indicator-counter { background-image: url("chrome://browser/skin/downloads/download-glow.png"); } @media (min-resolution: 2dppx) { - #downloads-indicator-icon:not(:-moz-lwtheme-brighttext) { - background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar@2x.png"), 0, 280, 40, 240); - background-size: 20px; + #downloads-indicator-icon { + background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar@2x.png"), 0, 396, 36, 360); + background-size: 18px; } - #downloads-button:not([counter]) > #downloads-indicator-anchor > - #downloads-indicator-progress-area > #downloads-indicator-counter { - background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar@2x.png"), 0, 280, 40, 240); + #downloads-indicator-icon:-moz-lwtheme-brighttext { + background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted@2x.png"), 0, 396, 36, 360); } - #downloads-button[attention] > #downloads-indicator-anchor > - #downloads-indicator-icon { + #downloads-button:not([counter]) > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter { + background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar@2x.png"), 0, 396, 36, 360); + } + + #downloads-button:not([counter]) > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter:-moz-lwtheme-brighttext { + background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted@2x.png"), + 0, 396, 36, 360); + } + + #downloads-button[attention] > #downloads-indicator-anchor > #downloads-indicator-icon { background-image: url("chrome://browser/skin/downloads/download-glow@2x.png"); } - #downloads-button:not([counter])[attention] > #downloads-indicator-anchor > - #downloads-indicator-progress-area > #downloads-indicator-counter { + #downloads-button:not([counter])[attention] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter { background-image: url("chrome://browser/skin/downloads/download-glow@2x.png"); } } @@ -182,10 +193,3 @@ #downloads-button[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-remainder { background-image: linear-gradient(#4b5000, #515700); } - -toolbar[mode="full"] > #downloads-button[indicator] > .toolbarbutton-text { - margin: 2px 0 0; - padding: 0; - text-align: center; - vertical-align: middle; -} diff --git a/browser/themes/osx/jar.mn b/browser/themes/osx/jar.mn index 25b0b822334b577a8a8a1b9513e0392891ca1d75..140a2048036154b442f7cf74988d55db5f1e9300 100644 --- a/browser/themes/osx/jar.mn +++ b/browser/themes/osx/jar.mn @@ -21,7 +21,12 @@ browser.jar: skin/classic/browser/actionicon-tab.png skin/classic/browser/actionicon-tab@2x.png * skin/classic/browser/browser.css (browser.css) +* skin/classic/browser/browser-lightweightTheme.css skin/classic/browser/click-to-play-warning-stripes.png + skin/classic/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png) + skin/classic/browser/customizableui/customizeMode-gridTexture.png (customizableui/customizeMode-gridTexture.png) + skin/classic/browser/customizableui/customizeMode-separatorHorizontal.png (customizableui/customizeMode-separatorHorizontal.png) + skin/classic/browser/customizableui/customizeMode-separatorVertical.png (customizableui/customizeMode-separatorVertical.png) * skin/classic/browser/engineManager.css (engineManager.css) skin/classic/browser/fullscreen-darknoise.png skin/classic/browser/Geolocation-16.png @@ -51,6 +56,16 @@ browser.jar: skin/classic/browser/notification-16@2x.png skin/classic/browser/notification-64.png skin/classic/browser/notification-64@2x.png + skin/classic/browser/menuPanel.png + skin/classic/browser/menuPanel@2x.png + skin/classic/browser/menuPanel-customize.png + skin/classic/browser/menuPanel-customize@2x.png + skin/classic/browser/menuPanel-exit.png + skin/classic/browser/menuPanel-exit@2x.png + skin/classic/browser/menuPanel-help.png + skin/classic/browser/menuPanel-help@2x.png + skin/classic/browser/menuPanel-small.png + skin/classic/browser/menuPanel-small@2x.png skin/classic/browser/mixed-content-blocked-16.png skin/classic/browser/mixed-content-blocked-16@2x.png skin/classic/browser/mixed-content-blocked-64.png @@ -86,6 +101,9 @@ browser.jar: skin/classic/browser/Secure-Glyph@2x.png skin/classic/browser/slowStartup-16.png skin/classic/browser/Toolbar.png + skin/classic/browser/Toolbar@2x.png + skin/classic/browser/Toolbar-inverted.png + skin/classic/browser/Toolbar-inverted@2x.png skin/classic/browser/toolbarbutton-dropmarker.png skin/classic/browser/urlbar-history-dropmarker.png skin/classic/browser/urlbar-history-dropmarker@2x.png @@ -99,10 +117,10 @@ browser.jar: skin/classic/browser/webRTC-shareDevice-64@2x.png skin/classic/browser/webRTC-sharingDevice-16.png skin/classic/browser/webRTC-sharingDevice-16@2x.png +* skin/classic/browser/customizableui/panelUIOverlay.css (customizableui/panelUIOverlay.css) skin/classic/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay.css) skin/classic/browser/downloads/buttons.png (downloads/buttons.png) skin/classic/browser/downloads/buttons@2x.png (downloads/buttons@2x.png) - skin/classic/browser/downloads/contentAreaDownloadsView.css (downloads/contentAreaDownloadsView.css) skin/classic/browser/downloads/download-glow.png (downloads/download-glow.png) skin/classic/browser/downloads/download-glow@2x.png (downloads/download-glow@2x.png) skin/classic/browser/downloads/download-notification-finish.png (downloads/download-notification-finish.png) @@ -176,39 +194,54 @@ browser.jar: skin/classic/browser/social/services-16@2x.png (social/services-16@2x.png) skin/classic/browser/social/services-64.png (social/services-64.png) skin/classic/browser/social/services-64@2x.png (social/services-64@2x.png) - skin/classic/browser/social/share-button.png (social/share-button.png) - skin/classic/browser/social/share-button@2x.png (social/share-button@2x.png) - skin/classic/browser/social/share-button-active.png (social/share-button-active.png) - skin/classic/browser/social/share-button-active@2x.png (social/share-button-active@2x.png) skin/classic/browser/social/chat-icons.png (social/chat-icons.png) skin/classic/browser/social/chat-icons@2x.png (social/chat-icons@2x.png) skin/classic/browser/tabbrowser/alltabs-box-bkgnd-icon.png (tabbrowser/alltabs-box-bkgnd-icon.png) + skin/classic/browser/tabbrowser/alltabs-box-bkgnd-icon-inverted.png (tabbrowser/alltabs-box-bkgnd-icon-inverted.png) + skin/classic/browser/tabbrowser/alltabs-box-bkgnd-icon-inverted@2x.png (tabbrowser/alltabs-box-bkgnd-icon-inverted@2x.png) skin/classic/browser/tabbrowser/newtab.png (tabbrowser/newtab.png) skin/classic/browser/tabbrowser/newtab@2x.png (tabbrowser/newtab@2x.png) + skin/classic/browser/tabbrowser/newtab-inverted.png (tabbrowser/newtab-inverted.png) + skin/classic/browser/tabbrowser/newtab-inverted@2x.png (tabbrowser/newtab-inverted@2x.png) skin/classic/browser/tabbrowser/connecting.png (tabbrowser/connecting.png) skin/classic/browser/tabbrowser/connecting@2x.png (tabbrowser/connecting@2x.png) skin/classic/browser/tabbrowser/loading.png (tabbrowser/loading.png) skin/classic/browser/tabbrowser/loading@2x.png (tabbrowser/loading@2x.png) + skin/classic/browser/tabbrowser/tab-active-middle.png (tabbrowser/tab-active-middle.png) + skin/classic/browser/tabbrowser/tab-active-middle@2x.png (tabbrowser/tab-active-middle@2x.png) skin/classic/browser/tabbrowser/tab-arrow-left.png (tabbrowser/tab-arrow-left.png) skin/classic/browser/tabbrowser/tab-arrow-left@2x.png (tabbrowser/tab-arrow-left@2x.png) + skin/classic/browser/tabbrowser/tab-arrow-left-inverted.png (tabbrowser/tab-arrow-left-inverted.png) + skin/classic/browser/tabbrowser/tab-arrow-left-inverted@2x.png (tabbrowser/tab-arrow-left-inverted@2x.png) skin/classic/browser/tabbrowser/tab-arrow-right.png (tabbrowser/tab-arrow-right.png) skin/classic/browser/tabbrowser/tab-arrow-right@2x.png (tabbrowser/tab-arrow-right@2x.png) + skin/classic/browser/tabbrowser/tab-arrow-right-inverted.png (tabbrowser/tab-arrow-right-inverted.png) + skin/classic/browser/tabbrowser/tab-arrow-right-inverted@2x.png (tabbrowser/tab-arrow-right-inverted@2x.png) + skin/classic/browser/tabbrowser/tab-background-end.png (tabbrowser/tab-background-end.png) + skin/classic/browser/tabbrowser/tab-background-end@2x.png (tabbrowser/tab-background-end@2x.png) + skin/classic/browser/tabbrowser/tab-background-middle.png (tabbrowser/tab-background-middle.png) + skin/classic/browser/tabbrowser/tab-background-middle@2x.png (tabbrowser/tab-background-middle@2x.png) + skin/classic/browser/tabbrowser/tab-background-start.png (tabbrowser/tab-background-start.png) + skin/classic/browser/tabbrowser/tab-background-start@2x.png (tabbrowser/tab-background-start@2x.png) + +# NOTE: The following two files (tab-selected-end.svg, tab-selected-start.svg) get pre-processed in +# Makefile.in with a non-default marker of "%" and the result of that gets packaged. + skin/classic/browser/tabbrowser/tab-selected-end.svg (tab-selected-end.svg) + skin/classic/browser/tabbrowser/tab-selected-start.svg (tab-selected-start.svg) + + skin/classic/browser/tabbrowser/tab-stroke-end.png (tabbrowser/tab-stroke-end.png) + skin/classic/browser/tabbrowser/tab-stroke-end@2x.png (tabbrowser/tab-stroke-end@2x.png) + skin/classic/browser/tabbrowser/tab-stroke-start.png (tabbrowser/tab-stroke-start.png) + skin/classic/browser/tabbrowser/tab-stroke-start@2x.png (tabbrowser/tab-stroke-start@2x.png) skin/classic/browser/tabbrowser/tabbar-bottom-bg-active.png (tabbrowser/tabbar-bottom-bg-active.png) skin/classic/browser/tabbrowser/tabbar-bottom-bg-inactive.png (tabbrowser/tabbar-bottom-bg-inactive.png) - skin/classic/browser/tabbrowser/tab-bottom-normal-active.png (tabbrowser/tab-bottom-normal-active.png) - skin/classic/browser/tabbrowser/tab-bottom-hover-active.png (tabbrowser/tab-bottom-hover-active.png) - skin/classic/browser/tabbrowser/tab-bottom-selected-active.png (tabbrowser/tab-bottom-selected-active.png) skin/classic/browser/tabbrowser/tabbar-top-bg-active.png (tabbrowser/tabbar-top-bg-active.png) skin/classic/browser/tabbrowser/tabbar-top-bg-inactive.png (tabbrowser/tabbar-top-bg-inactive.png) - skin/classic/browser/tabbrowser/tab-top-normal-active.png (tabbrowser/tab-top-normal-active.png) - skin/classic/browser/tabbrowser/tab-top-normal-active@2x.png (tabbrowser/tab-top-normal-active@2x.png) - skin/classic/browser/tabbrowser/tab-top-hover-active.png (tabbrowser/tab-top-hover-active.png) - skin/classic/browser/tabbrowser/tab-top-hover-active@2x.png (tabbrowser/tab-top-hover-active@2x.png) - skin/classic/browser/tabbrowser/tab-top-selected-active.png (tabbrowser/tab-top-selected-active.png) - skin/classic/browser/tabbrowser/tab-top-selected-active@2x.png (tabbrowser/tab-top-selected-active@2x.png) skin/classic/browser/tabbrowser/tab-overflow-border.png (tabbrowser/tab-overflow-border.png) skin/classic/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png) skin/classic/browser/tabbrowser/tabDragIndicator@2x.png (tabbrowser/tabDragIndicator@2x.png) + skin/classic/browser/tabbrowser/tab-separator.png (tabbrowser/tab-separator.png) + skin/classic/browser/tabbrowser/tab-separator@2x.png (tabbrowser/tab-separator@2x.png) skin/classic/browser/tabview/close.png (tabview/close.png) skin/classic/browser/tabview/edit-light.png (tabview/edit-light.png) skin/classic/browser/tabview/search.png (tabview/search.png) @@ -349,8 +382,7 @@ browser.jar: #endif skin/classic/browser/lion/keyhole-circle.png (keyhole-circle-lion.png) skin/classic/browser/keyhole-circle@2x.png (keyhole-circle-lion@2x.png) - skin/classic/browser/lion/Toolbar.png (Toolbar-lion.png) - skin/classic/browser/Toolbar@2x.png (Toolbar-lion@2x.png) + skin/classic/browser/Toolbar-background-noise.png (Toolbar-background-noise.png) skin/classic/browser/lion/toolbarbutton-dropmarker.png (toolbarbutton-dropmarker-lion.png) skin/classic/browser/toolbarbutton-dropmarker@2x.png (toolbarbutton-dropmarker-lion@2x.png) skin/classic/browser/lion/tabbrowser/alltabs-box-bkgnd-icon.png (tabbrowser/alltabs-box-bkgnd-icon-lion.png) @@ -373,7 +405,6 @@ browser.jar: skin/classic/browser/devtools/tooltip/arrow-vertical-light@2x.png (../shared/devtools/tooltip/arrow-vertical-light@2x.png) % override chrome://browser/skin/keyhole-circle.png chrome://browser/skin/lion/keyhole-circle.png os=Darwin osversion>=10.7 -% override chrome://browser/skin/Toolbar.png chrome://browser/skin/lion/Toolbar.png os=Darwin osversion>=10.7 % override chrome://browser/skin/toolbarbutton-dropmarker.png chrome://browser/skin/lion/toolbarbutton-dropmarker.png os=Darwin osversion>=10.7 % override chrome://browser/skin/tabbrowser/alltabs-box-bkgnd-icon.png chrome://browser/skin/lion/tabbrowser/alltabs-box-bkgnd-icon.png os=Darwin osversion>=10.7 % override chrome://browser/skin/tabview/tabview.png chrome://browser/skin/lion/tabview/tabview.png os=Darwin osversion>=10.7 diff --git a/browser/themes/osx/menuPanel-customize.png b/browser/themes/osx/menuPanel-customize.png new file mode 100644 index 0000000000000000000000000000000000000000..e0b0a70a3b82a18c974bd1bc5f1dff863405dd61 Binary files /dev/null and b/browser/themes/osx/menuPanel-customize.png differ diff --git a/browser/themes/osx/menuPanel-customize@2x.png b/browser/themes/osx/menuPanel-customize@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..aba481aeb49b48bfc317bdeaeb00ea4048869533 Binary files /dev/null and b/browser/themes/osx/menuPanel-customize@2x.png differ diff --git a/browser/themes/osx/menuPanel-exit.png b/browser/themes/osx/menuPanel-exit.png new file mode 100644 index 0000000000000000000000000000000000000000..e230b9c1bc704b75416a472f9a1fe53faf3c7d70 Binary files /dev/null and b/browser/themes/osx/menuPanel-exit.png differ diff --git a/browser/themes/osx/menuPanel-exit@2x.png b/browser/themes/osx/menuPanel-exit@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..81c901bee74a1042ff4227b96215a911523b477e Binary files /dev/null and b/browser/themes/osx/menuPanel-exit@2x.png differ diff --git a/browser/themes/osx/menuPanel-help.png b/browser/themes/osx/menuPanel-help.png new file mode 100644 index 0000000000000000000000000000000000000000..1f6fecc54ad049dd127de9b37a99546942497c46 Binary files /dev/null and b/browser/themes/osx/menuPanel-help.png differ diff --git a/browser/themes/osx/menuPanel-help@2x.png b/browser/themes/osx/menuPanel-help@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4e745644dbea34c8d8e65690a65121f1b7f58b12 Binary files /dev/null and b/browser/themes/osx/menuPanel-help@2x.png differ diff --git a/browser/themes/osx/menuPanel-small.png b/browser/themes/osx/menuPanel-small.png new file mode 100644 index 0000000000000000000000000000000000000000..ecd3b7f08aa58358ae1f8b44c124582c1bea3ecd Binary files /dev/null and b/browser/themes/osx/menuPanel-small.png differ diff --git a/browser/themes/osx/menuPanel-small@2x.png b/browser/themes/osx/menuPanel-small@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e41e6f499df1ae2b5cb02ec5c42eaa9042211ce0 Binary files /dev/null and b/browser/themes/osx/menuPanel-small@2x.png differ diff --git a/browser/themes/osx/menuPanel.png b/browser/themes/osx/menuPanel.png new file mode 100644 index 0000000000000000000000000000000000000000..4af2c8e2dac31ac9f369ebad5551b6577eda97c9 Binary files /dev/null and b/browser/themes/osx/menuPanel.png differ diff --git a/browser/themes/osx/menuPanel@2x.png b/browser/themes/osx/menuPanel@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..764048a29bdec15883be9191585ed89f8bcb1684 Binary files /dev/null and b/browser/themes/osx/menuPanel@2x.png differ diff --git a/browser/themes/osx/newtab/newTab.css b/browser/themes/osx/newtab/newTab.css index cefab8a42fc36f672069213f9b922a346841130d..0786cfe630d66df6536bea546e690dca836595d3 100644 --- a/browser/themes/osx/newtab/newTab.css +++ b/browser/themes/osx/newtab/newTab.css @@ -51,19 +51,9 @@ #newtab-undo-close-button { padding: 0; border: none; - list-style-image: url("chrome://global/skin/icons/close.png"); - -moz-image-region: rect(0, 16px, 16px, 0); -moz-user-focus: normal; } -#newtab-undo-close-button:hover { - -moz-image-region: rect(0, 32px, 16px, 16px); -} - -#newtab-undo-close-button:hover:active { - -moz-image-region: rect(0, 48px, 16px, 32px); -} - #newtab-undo-close-button > .toolbarbutton-text { display: none; } diff --git a/browser/themes/osx/shared.inc b/browser/themes/osx/shared.inc index 2e8a8f269f46273068957c24c535d52c6c430817..cf095a5fce58dfd8a24493ebfaaf348084e47143 100644 --- a/browser/themes/osx/shared.inc +++ b/browser/themes/osx/shared.inc @@ -1,6 +1,12 @@ %include ../../../toolkit/themes/osx/global/shared.inc %include ../shared/browser.inc +%filter substitution + +%define fgTabTexture linear-gradient(transparent, transparent 2px, hsla(0,0%,100%,0.6) 2px, hsla(0,0%,100%,0.6) 3px, hsl(0,0%,99%) 3px, hsl(0,0%,93%)) +%define toolbarColorLWT rgba(253,253,253,0.45) +%define fgTabTextureLWT linear-gradient(transparent, transparent 2px, rgba(254,254,254,0.72) 2px, @toolbarColorLWT@) +%define fgTabBackgroundColor transparent %define hudButton -moz-appearance: none; color: #434343; border-radius: 4px; border: 1px solid #b5b5b5; background: linear-gradient(#fff, #f2f2f2); box-shadow: inset 0 1px rgba(255,255,255,.8), inset 0 0 1px rgba(255,255, 255,.25), 0 1px rgba(255,255,255,.3); background-clip: padding-box; background-origin: padding-box; padding: 2px 6px; %define hudButtonPressed box-shadow: inset 0 1px 4px -3px #000, 0 1px rgba(255,255,255,.3); %define hudButtonFocused box-shadow: 0 0 1px -moz-mac-focusring inset, 0 0 4px 1px -moz-mac-focusring, 0 0 2px 1px -moz-mac-focusring; diff --git a/browser/themes/osx/social/share-button-active.png b/browser/themes/osx/social/share-button-active.png deleted file mode 100644 index 7df438db014c265c35da304c4a846f5e34c46e4b..0000000000000000000000000000000000000000 Binary files a/browser/themes/osx/social/share-button-active.png and /dev/null differ diff --git a/browser/themes/osx/social/share-button-active@2x.png b/browser/themes/osx/social/share-button-active@2x.png deleted file mode 100644 index 6872dff7b7c4801a39cb9b48b4f352b034271dc0..0000000000000000000000000000000000000000 Binary files a/browser/themes/osx/social/share-button-active@2x.png and /dev/null differ diff --git a/browser/themes/osx/social/share-button.png b/browser/themes/osx/social/share-button.png deleted file mode 100644 index c5298c143eaaa74773f5066766f923ef076a74ca..0000000000000000000000000000000000000000 Binary files a/browser/themes/osx/social/share-button.png and /dev/null differ diff --git a/browser/themes/osx/social/share-button@2x.png b/browser/themes/osx/social/share-button@2x.png deleted file mode 100644 index 4545a276dc59f0833b20a8cbb521569b757117fc..0000000000000000000000000000000000000000 Binary files a/browser/themes/osx/social/share-button@2x.png and /dev/null differ diff --git a/browser/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-inverted.png b/browser/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-inverted.png new file mode 100644 index 0000000000000000000000000000000000000000..295b4ad74e62c9d7fb816500a62a1d1e6295f42d Binary files /dev/null and b/browser/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-inverted.png differ diff --git a/browser/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-inverted@2x.png b/browser/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-inverted@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..23889d7cc5f7cdfa78e750e93a41b2caf9daac46 Binary files /dev/null and b/browser/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-inverted@2x.png differ diff --git a/browser/themes/osx/tabbrowser/newtab-inverted.png b/browser/themes/osx/tabbrowser/newtab-inverted.png new file mode 100644 index 0000000000000000000000000000000000000000..2d29c2cbea688fdf44ba7d1617bd9edd8a04a4c4 Binary files /dev/null and b/browser/themes/osx/tabbrowser/newtab-inverted.png differ diff --git a/browser/themes/osx/tabbrowser/newtab-inverted@2x.png b/browser/themes/osx/tabbrowser/newtab-inverted@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..6feba0e83eaad385ae512fc611187c10dec6e9d4 Binary files /dev/null and b/browser/themes/osx/tabbrowser/newtab-inverted@2x.png differ diff --git a/browser/themes/osx/tabbrowser/tab-active-middle.png b/browser/themes/osx/tabbrowser/tab-active-middle.png new file mode 100644 index 0000000000000000000000000000000000000000..c3e5e18ba3ceddcf098a5b98a5f40c784a7e3d52 Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-active-middle.png differ diff --git a/browser/themes/osx/tabbrowser/tab-active-middle@2x.png b/browser/themes/osx/tabbrowser/tab-active-middle@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..6cdc4472e71aeb715582a8eeb03bd471e61514e2 Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-active-middle@2x.png differ diff --git a/browser/themes/osx/tabbrowser/tab-arrow-left-inverted.png b/browser/themes/osx/tabbrowser/tab-arrow-left-inverted.png new file mode 100644 index 0000000000000000000000000000000000000000..b0826024d787c0d6fad3b0672216e88d4a8e1089 Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-arrow-left-inverted.png differ diff --git a/browser/themes/osx/tabbrowser/tab-arrow-left-inverted@2x.png b/browser/themes/osx/tabbrowser/tab-arrow-left-inverted@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4ca8ec0baedeb9c40240ad2cf8c9f19bf6cb870b Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-arrow-left-inverted@2x.png differ diff --git a/browser/themes/osx/tabbrowser/tab-arrow-right-inverted.png b/browser/themes/osx/tabbrowser/tab-arrow-right-inverted.png new file mode 100644 index 0000000000000000000000000000000000000000..0cd8f37a6fb7dbb22ef7062a01d194348cf4e216 Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-arrow-right-inverted.png differ diff --git a/browser/themes/osx/tabbrowser/tab-arrow-right-inverted@2x.png b/browser/themes/osx/tabbrowser/tab-arrow-right-inverted@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e4ab8cbaa24cb96c0117ba55655c2fb41f6f13b6 Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-arrow-right-inverted@2x.png differ diff --git a/browser/themes/osx/tabbrowser/tab-background-end.png b/browser/themes/osx/tabbrowser/tab-background-end.png new file mode 100644 index 0000000000000000000000000000000000000000..2e515a39efeaafc71c8ee00bc29baa7ca952ce0f Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-background-end.png differ diff --git a/browser/themes/osx/tabbrowser/tab-background-end@2x.png b/browser/themes/osx/tabbrowser/tab-background-end@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..18dba96930805a30ca1af7dd5a30dea29b9e1063 Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-background-end@2x.png differ diff --git a/browser/themes/osx/tabbrowser/tab-background-middle.png b/browser/themes/osx/tabbrowser/tab-background-middle.png new file mode 100644 index 0000000000000000000000000000000000000000..addb64b13f422a34d6b87e4e75488f9fa2e35ba3 Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-background-middle.png differ diff --git a/browser/themes/osx/tabbrowser/tab-background-middle@2x.png b/browser/themes/osx/tabbrowser/tab-background-middle@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..41eba94af8863a032df6dd6a170a511fe06c1cf0 Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-background-middle@2x.png differ diff --git a/browser/themes/osx/tabbrowser/tab-background-start.png b/browser/themes/osx/tabbrowser/tab-background-start.png new file mode 100644 index 0000000000000000000000000000000000000000..243bf0099ffe7760843fc75b98d1029d9c9efbef Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-background-start.png differ diff --git a/browser/themes/osx/tabbrowser/tab-background-start@2x.png b/browser/themes/osx/tabbrowser/tab-background-start@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..86403921de9c7a9543879e3a4a2963e3d472e26b Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-background-start@2x.png differ diff --git a/browser/themes/osx/tabbrowser/tab-bottom-hover-active.png b/browser/themes/osx/tabbrowser/tab-bottom-hover-active.png deleted file mode 100644 index a5fdaba4bb0f223984253e0839b70b9f81f0e7f2..0000000000000000000000000000000000000000 Binary files a/browser/themes/osx/tabbrowser/tab-bottom-hover-active.png and /dev/null differ diff --git a/browser/themes/osx/tabbrowser/tab-bottom-normal-active.png b/browser/themes/osx/tabbrowser/tab-bottom-normal-active.png deleted file mode 100644 index 1a0dceea376d576199d3c6d4bcf8ac974104c4c3..0000000000000000000000000000000000000000 Binary files a/browser/themes/osx/tabbrowser/tab-bottom-normal-active.png and /dev/null differ diff --git a/browser/themes/osx/tabbrowser/tab-bottom-selected-active.png b/browser/themes/osx/tabbrowser/tab-bottom-selected-active.png deleted file mode 100644 index 0596cb28dd471f83629de71d56cfd8b348e4d9c1..0000000000000000000000000000000000000000 Binary files a/browser/themes/osx/tabbrowser/tab-bottom-selected-active.png and /dev/null differ diff --git a/browser/themes/osx/tabbrowser/tab-separator.png b/browser/themes/osx/tabbrowser/tab-separator.png new file mode 100644 index 0000000000000000000000000000000000000000..b643bfc6f67da9c4934f05510b5cbd296e901bcd Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-separator.png differ diff --git a/browser/themes/osx/tabbrowser/tab-separator@2x.png b/browser/themes/osx/tabbrowser/tab-separator@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..11cfca4c149871587aec2e18b71fd6ef3d49823a Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-separator@2x.png differ diff --git a/browser/themes/osx/tabbrowser/tab-stroke-end.png b/browser/themes/osx/tabbrowser/tab-stroke-end.png new file mode 100755 index 0000000000000000000000000000000000000000..099978580391777f4fdd196fc9aa160ebf4123a7 Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-stroke-end.png differ diff --git a/browser/themes/osx/tabbrowser/tab-stroke-end@2x.png b/browser/themes/osx/tabbrowser/tab-stroke-end@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d321ca579016cf5fe8b0d4be6bbb42e3d2216fa1 Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-stroke-end@2x.png differ diff --git a/browser/themes/osx/tabbrowser/tab-stroke-start.png b/browser/themes/osx/tabbrowser/tab-stroke-start.png new file mode 100755 index 0000000000000000000000000000000000000000..e5a7b5ee9aecb73410b5cacdd4951b2520b54bca Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-stroke-start.png differ diff --git a/browser/themes/osx/tabbrowser/tab-stroke-start@2x.png b/browser/themes/osx/tabbrowser/tab-stroke-start@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..64449115cc9ffbcccacffbb3219467fd81086f0d Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-stroke-start@2x.png differ diff --git a/browser/themes/osx/tabbrowser/tab-top-hover-active.png b/browser/themes/osx/tabbrowser/tab-top-hover-active.png deleted file mode 100644 index f41b253d0bce22c49f06bba7bdf1934813ff3562..0000000000000000000000000000000000000000 Binary files a/browser/themes/osx/tabbrowser/tab-top-hover-active.png and /dev/null differ diff --git a/browser/themes/osx/tabbrowser/tab-top-hover-active@2x.png b/browser/themes/osx/tabbrowser/tab-top-hover-active@2x.png deleted file mode 100644 index a8215a283d57a01334bd53c4a864ad373cfc4cd8..0000000000000000000000000000000000000000 Binary files a/browser/themes/osx/tabbrowser/tab-top-hover-active@2x.png and /dev/null differ diff --git a/browser/themes/osx/tabbrowser/tab-top-normal-active.png b/browser/themes/osx/tabbrowser/tab-top-normal-active.png deleted file mode 100644 index 5987a2fe32d7e26d7b0ae3f80625e69ae9b7d45f..0000000000000000000000000000000000000000 Binary files a/browser/themes/osx/tabbrowser/tab-top-normal-active.png and /dev/null differ diff --git a/browser/themes/osx/tabbrowser/tab-top-normal-active@2x.png b/browser/themes/osx/tabbrowser/tab-top-normal-active@2x.png deleted file mode 100644 index 658b291d3940b0a53d321f54ff86e2ade53cf82f..0000000000000000000000000000000000000000 Binary files a/browser/themes/osx/tabbrowser/tab-top-normal-active@2x.png and /dev/null differ diff --git a/browser/themes/osx/tabbrowser/tab-top-selected-active.png b/browser/themes/osx/tabbrowser/tab-top-selected-active.png deleted file mode 100644 index 930e76588fed21ab53cd454f1e7f0d82989b814b..0000000000000000000000000000000000000000 Binary files a/browser/themes/osx/tabbrowser/tab-top-selected-active.png and /dev/null differ diff --git a/browser/themes/osx/tabbrowser/tab-top-selected-active@2x.png b/browser/themes/osx/tabbrowser/tab-top-selected-active@2x.png deleted file mode 100644 index 7de41e77b273e66b7578c11c96efbe054b1655fc..0000000000000000000000000000000000000000 Binary files a/browser/themes/osx/tabbrowser/tab-top-selected-active@2x.png and /dev/null differ diff --git a/browser/themes/shared/browser.inc b/browser/themes/shared/browser.inc index 794b6d5c130f508b2a45f9f31b87ffe362d7f495..429ae613c86eb42b0a3be9881e7fea8edd6e0e57 100644 --- a/browser/themes/shared/browser.inc +++ b/browser/themes/shared/browser.inc @@ -1,3 +1,4 @@ %filter substitution -%define primaryToolbarButtons #back-button, #forward-button, #reload-button, #stop-button, #home-button, #print-button, #downloads-button, #history-button, #bookmarks-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #cut-button, #copy-button, #paste-button, #fullscreen-button, #zoom-out-button, #zoom-in-button, #sync-button, #feed-button, #alltabs-button, #tabview-button, #webrtc-status-button +%define primaryToolbarButtons #back-button, #forward-button, #home-button, #print-button, #downloads-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #cut-button, #copy-button, #paste-button, #fullscreen-button, #zoom-out-button, #zoom-reset-button, #zoom-in-button, #sync-button, #feed-button, #tabview-button, #webrtc-status-button, #social-share-button, #open-file-button, #find-button, #developer-button, #preferences-button, #privatebrowsing-button, #save-page-button, #add-ons-button, #history-panelmenu, #nav-bar-overflow-button, #PanelUI-menu-button, #characterencoding-button +%define inAnyPanel :-moz-any(:not([cui-areatype="toolbar"]),.overflowedItem) diff --git a/browser/themes/shared/customizableui/customizeMode.inc.css b/browser/themes/shared/customizableui/customizeMode.inc.css new file mode 100644 index 0000000000000000000000000000000000000000..5c05f5176e779cc437c99e6184ff079dc738ebeb --- /dev/null +++ b/browser/themes/shared/customizableui/customizeMode.inc.css @@ -0,0 +1,201 @@ +/* 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/. */ + +/* Customization mode */ + +#tab-view-deck { + transition-property: padding; + transition-duration: 150ms; + transition-timing-function: ease-out; +} + +#tab-view-deck[fastcustomizeanimation] { + transition-duration: 1ms; + transition-timing-function: linear; +} + +#nav-bar[customize-entered] > #nav-bar-customization-target { + margin: 1px 3px; +} + +#nav-bar[customize-entered] > #nav-bar-customization-target, +#PanelUI-contents > .panel-customization-placeholder { + outline: 1px dashed transparent; +} + +#main-window[customizing-movingItem] #nav-bar-customization-target, +#main-window[customizing-movingItem] .panel-customization-placeholder { + outline-color: #bbb; +} + +#PanelUI-contents > .panel-customization-placeholder { + cursor: auto; + outline-offset: -5px; +} + +#PanelUI-contents > .panel-customization-placeholder > .panel-customization-placeholder-child { + list-style-image: none; +} + +#customization-panelHolder { + overflow-y: hidden; +} + +#customization-panelWrapper, +#customization-panelWrapper > .panel-arrowcontent { + -moz-box-flex: 1; +} + +#customization-panelHolder > #PanelUI-mainView { + display: flex; + flex-direction: column; + /* Hack alert - by manually setting the preferred height to 0, we convince + #PanelUI-mainView to shrink when the window gets smaller in customization + mode. Not sure why that is - might have to do with our intermingling of + XUL flex, and CSS3 Flexbox. */ + height: 0; +} + +#customization-panelHolder > #PanelUI-mainView > #PanelUI-contents-scroller { + display: flex; + flex: auto; + flex-direction: column; +} + +#main-window[customize-entered] .customization-target { + min-width: 100px; + padding-left: 10px; + padding-right: 10px; +} + +#customization-container { + background-color: rgb(247,247,247); +} + +#customization-palette-container { + padding: 25px; +} + +#customization-header { + font-size: 1.5em; + line-height: 1.5em; + color: rgb(64,100,128); + font-weight: lighter; + margin-bottom: 1em; +} + +#customization-panel-container { + padding: 15px 25px 25px; + background-image: url("chrome://browser/skin/customizableui/customizeMode-separatorHorizontal.png"), + url("chrome://browser/skin/customizableui/customizeMode-separatorVertical.png"), + url("chrome://browser/skin/customizableui/customizeMode-gridTexture.png"), + url("chrome://browser/skin/customizableui/background-noise-toolbar.png"), + linear-gradient(to bottom, #3e86ce, #3878ba); + background-position: center top, left center, left top, left top, left top; + background-repeat: no-repeat, no-repeat, repeat, repeat, no-repeat; + background-size: auto 12px, 12px 100%, auto, auto, auto; + background-attachment: scroll, scroll, fixed, fixed, scroll; + overflow-y: auto; +} + +#customization-panelWrapper > .panel-arrowcontent { + padding: 0 !important; +} + +toolbarpaletteitem { + transition: background-color, border-color, box-shadow, border-width; + transition-duration: 10ms, 10ms, 10ms, 250ms; + transition-timing-function: linear, linear, linear, ease-in-out; +} + +toolbarpaletteitem[mousedown] { + box-shadow: inset 0 0 3px hsl(204,100%,40%); + cursor: -moz-grabbing; + opacity: 0.8; +} + +toolbarpaletteitem > toolbarbutton > .toolbarbutton-icon { + transition: transform 50ms ease-in-out; +} + +toolbarpaletteitem[mousedown] > toolbarbutton > .toolbarbutton-icon { + transform: scale(1.1); +} + +/* Override the toolkit styling for items being dragged over. */ +toolbarpaletteitem[place="toolbar"] { + border-left-width: 0; + border-right-width: 0; + margin-right: 0; + margin-left: 0; +} + +toolbarpaletteitem[dragover] { + border-left-color: transparent; + border-right-color: transparent; +} + +#customization-palette:not([hidden]) { + display: block; + overflow: auto; + min-height: 3em; + margin-bottom: 25px; +} + +toolbarpaletteitem[place="palette"] { + width: 110px; + height: 94px; + overflow: hidden; + display: inline-block; +} + +toolbarpaletteitem[place="palette"][hidden] { + display: none; +} + +#customization-palette > #wrapper-edit-controls, +#customization-palette > #wrapper-zoom-controls { + width: 225px; +} + +#customization-palette .toolbarpaletteitem-box { + -moz-box-pack: center; + -moz-box-flex: 1; + width: 110px; + max-width: 110px; +} + +#wrapper-edit-controls[place="palette"] > .toolbarpaletteitem-box, +#wrapper-zoom-controls[place="palette"] > .toolbarpaletteitem-box { + width: 225px; + max-width: 225px; +} + +#wrapper-edit-controls[place="palette"] > #edit-controls > toolbarbutton, +#wrapper-zoom-controls[place="palette"] > #zoom-controls > toolbarbutton { + margin-left: 0; + margin-right: 0; + max-width: 70px; + min-width: 70px; + max-height: 24px; + height: 24px; + margin-top: 24px; +} + +#wrapper-edit-controls[place="palette"] > #edit-controls > toolbarbutton > .toolbarbutton-text, +#wrapper-zoom-controls[place="palette"] > #zoom-controls > #zoom-reset-button > .toolbarbutton-text { + display: inline; +} + +#wrapper-edit-controls[place="palette"] > #edit-controls > toolbarbutton > .toolbarbutton-icon, +#wrapper-zoom-controls[place="palette"] > #zoom-controls > toolbarbutton > .toolbarbutton-icon { + margin: 0; + -moz-margin-start: 5px; +} + +#customization-palette > toolbarpaletteitem > label { + text-align: center; + margin-left: 0; + margin-right: 0; +} diff --git a/browser/themes/shared/customizableui/panelUIOverlay.inc.css b/browser/themes/shared/customizableui/panelUIOverlay.inc.css new file mode 100644 index 0000000000000000000000000000000000000000..7b04d642c2512fd370cbecb8358db65a3738acb0 --- /dev/null +++ b/browser/themes/shared/customizableui/panelUIOverlay.inc.css @@ -0,0 +1,549 @@ +/* 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/. */ + +%filter substitution +%define menuPanelWidth 21em +%define exitSubviewGutterWidth 38px +%define buttonStateHover :not(:-moz-any([disabled],[checked="true"],[open],:active)):hover +%define buttonStateActive :not([disabled]):-moz-any([open],[checked="true"],:hover:active) + +%include ../browser.inc + +.panel-subviews { + background-image: linear-gradient(to bottom, white 1px, rgba(255, 255, 255, 0) 15px); + background-color: -moz-dialog; + box-shadow: -1px 0px 0px rgba(0, 0, 0, 0.2), -1px 0px 2px rgba(0, 0, 0, 0.1), 1px 0px 0px rgba(255, 255, 255, 0.2) inset; + -moz-margin-start: @exitSubviewGutterWidth@; +} + +.panel-subviews:-moz-locale-dir(rtl) { + box-shadow: 1px 0px 0px rgba(0, 0, 0, 0.2), 1px 0px 2px rgba(0, 0, 0, 0.1), -1px 0px 0px rgba(255, 255, 255, 0.2) inset; +} + +.panel-viewstack[viewtype="main"] > .panel-subviews { + transform: translateX(@menuPanelWidth@); +} + +.panel-viewstack[viewtype="main"] > .panel-subviews:-moz-locale-dir(rtl) { + transform: translateX(-@menuPanelWidth@); +} + +.panel-viewstack:not([viewtype="main"]) > .panel-mainview > #PanelUI-mainView { + -moz-box-flex: 1; +} + +#PanelUI-mainView { + display: flex; + flex-direction: column; +} + +#app-extension-point-end > #PanelUI-menu-button { + padding: 2px 5px; +} +#app-extension-point-end > #PanelUI-menu-button .toolbarbutton-text { + display: none; +} +#app-extension-point-end > #PanelUI-menu-button .toolbarbutton-icon { + margin: 0; +} + +#PanelUI-popup > arrowscrollbox > autorepeatbutton { + display: none; +} +#PanelUI-popup > arrowscrollbox > scrollbox { + overflow: visible; +} + +#PanelUI-popup > .panel-arrowcontainer > .panel-arrowcontent { + overflow: hidden; + padding: 0; + box-shadow: none; +} + +#PanelUI-contents { + padding: .5em 0; +} + +toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"]:not(.panel-wide-item) > .toolbarbutton-text, +#bookmarks-menu-button > toolbarbutton > .toolbarbutton-text, +#PanelUI-contents > toolbarpaletteitem > toolbaritem > toolbarbutton > .toolbarbutton-text, +#PanelUI-contents > toolbaritem > toolbarbutton > .toolbarbutton-text, +#PanelUI-contents > toolbarpaletteitem > toolbarbutton > .toolbarbutton-text, +#PanelUI-contents > toolbarbutton > .toolbarbutton-text { + font-size: 10px; +} + +#wrapper-edit-controls:-moz-any([place="palette"],[place="panel"]) > #edit-controls, +#wrapper-zoom-controls:-moz-any([place="palette"],[place="panel"]) > #zoom-controls { + -moz-margin-start: 0; +} + +#PanelUI-contents, +.panel-mainview:not([panelid="PanelUI-popup"]) { + max-width: @menuPanelWidth@; +} + +panelview:not([mainview]) .toolbarbutton-text, +#customizationui-widget-panel toolbarbutton > .toolbarbutton-text { + text-align: start; + -moz-padding-start: 8px; + display: -moz-box; +} + +#PanelUI-contents { + display: block; + flex: auto; + margin-left: auto; + margin-right: auto; + max-width: @menuPanelWidth@; +} + +#PanelUI-contents-scroller { + overflow-y: auto; + overflow-x: hidden; + width: @menuPanelWidth@; + padding-left: 5px; + padding-right: 5px; + flex: auto; +} + +#edit-controls@inAnyPanel@ > toolbarbutton > .toolbarbutton-icon, +#zoom-controls@inAnyPanel@ > toolbarbutton > .toolbarbutton-icon { + min-width: 0; + min-height: 0; + margin: 0; +} + +toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"]:not(.panel-wide-item), +#PanelUI-contents toolbarbutton, +toolbarpaletteitem[place="panel"] > toolbarbutton, +toolbarpaletteitem[place="palette"] > toolbarbutton, +toolbarpaletteitem[place="panel"] > toolbaritem > toolbarbutton, +toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton, +.panel-customization-placeholder { + -moz-appearance: none; + -moz-box-orient: vertical; + min-width: 7em; + max-width: 7em; + height: 6em; + max-height: 6em; +} + +.panel-customization-placeholder[expand], +.panel-customization-placeholder[contract] { + transition-property: width; + transition-duration: 170ms; + transition-delay: 20ms; + transition-timing-function: ease-in-out; + min-width: 0; + max-width: none; +} + +#edit-controls:not([cui-areatype="toolbar"]) > toolbarbutton, +#zoom-controls:not([cui-areatype="toolbar"]) > toolbarbutton { + -moz-box-orient: horizontal; + min-width: 7em; +} + +#PanelUI-contents > #edit-controls > toolbarbutton, +#PanelUI-contents > #wrapper-edit-controls > #edit-controls > toolbarbutton, +#PanelUI-contents > #zoom-controls > toolbarbutton, +#PanelUI-contents > #wrapper-zoom-controls > #zoom-controls > toolbarbutton { + max-width: none; + max-height: none; + height: auto; +} + +#widget-overflow-list > #edit-controls > toolbarbutton, +#widget-overflow-list > #zoom-controls > toolbarbutton { + -moz-box-orient: horizontal; + -moz-box-align: start; + max-height: none; + height: auto; + padding-left: .5em; + padding-right: .5em; +} + +.panel-wide-item.overflowedItem, +.panel-wide-item[cui-areatype="menu-panel"] { + -moz-box-align: stretch; + padding: .5em 0 .5em; +} + +.panel-combined-button[disabled] > .toolbarbutton-icon { + opacity: .5; +} + +toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"] { + width: 7em; + margin: 0 !important; +} + +toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"]:not(.panel-wide-widget) { + -moz-box-align: center; + -moz-box-pack: center; +} + +toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"] > iframe { + margin: calc(5em / 12) auto; +} + +toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"]:not(.panel-wide-item) > .toolbarbutton-text { + text-align: center; +} + +.panel-customization-placeholder-child > .toolbarbutton-icon, +#bookmarks-menu-button[cui-areatype="menu-panel"] > .toolbarbutton-menubutton-button > .toolbarbutton-icon, +toolbarbutton[cui-areatype="menu-panel"] > .toolbarbutton-icon, +toolbaritem[cui-areatype="menu-panel"] > toolbarbutton > .toolbarbutton-icon, +toolbarpaletteitem[place="palette"] > #bookmarks-menu-button > .toolbarbutton-menubutton-button > .toolbarbutton-icon, +toolbarpaletteitem[place="palette"] > toolbarbutton > .toolbarbutton-icon, +toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton > .toolbarbutton-icon { + min-width: calc(8em / 3); + min-height: calc(8em / 3); + margin: calc(5em / 12); +} + +toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton { + -moz-box-flex: 1; +} + +#edit-controls@inAnyPanel@ > #copy-button, +#zoom-controls@inAnyPanel@ > #zoom-reset-button { + border-left: none; + border-right: none; + border-radius: 0; +} + +#zoom-in-button > .toolbarbutton-text, +#zoom-out-button > .toolbarbutton-text, +#zoom-reset-button > .toolbarbutton-icon { + display: none; +} + +#PanelUI-footer { + display: flex; + background-color: rgba(0, 0, 0, 0.05); + border-top: 1px solid rgba(0,0,0,.1); + padding: 0; + margin: 0; + min-height: 4em; +} + +#PanelUI-help, +#PanelUI-customize, +#PanelUI-quit { + margin: -1px 0 0; + padding: 10px 0; + -moz-appearance: none; + box-shadow: none; + background-image: none; + border: 1px solid transparent; + border-bottom-style: none; + border-radius: 0; + transition: background-color; + -moz-box-orient: vertical; + flex: 1 1 33.33%; +} +:-moz-any(#PanelUI-help, #PanelUI-customize, #PanelUI-quit) > .toolbarbutton-icon { + margin: 0 0 3px; +} + +#PanelUI-customize { + list-style-image: url(chrome://browser/skin/menuPanel-customize.png); +} + +#PanelUI-help { + -moz-border-start-style: none; + list-style-image: url(chrome://browser/skin/menuPanel-help.png); +} + +#PanelUI-quit { + -moz-border-end-style: none; + list-style-image: url(chrome://browser/skin/menuPanel-exit.png); +} + +#PanelUI-customize, +#PanelUI-help, +#PanelUI-quit { + -moz-image-region: rect(0, 16px, 16px, 0); +} + +#PanelUI-customize:hover, +#PanelUI-help:not([disabled]):hover, +#PanelUI-quit:not([disabled]):hover { + -moz-image-region: rect(0, 32px, 16px, 16px); +} + +#PanelUI-customize:hover:active, +#PanelUI-help:not([disabled]):hover:active, +#PanelUI-quit:not([disabled]):hover:active { + -moz-image-region: rect(0, 48px, 16px, 32px); +} + +#PanelUI-help[disabled], +#PanelUI-quit[disabled] { + opacity: 0.4; +} + +#PanelUI-help:not([disabled]):hover, +#PanelUI-customize:hover, +#PanelUI-quit:not([disabled]):hover { + border-color: rgba(8,25,42,0.2); + border-top-color: rgba(8,25,42,0.1); + background-color: rgba(0,0,0,0.1); + box-shadow: none; +} + +#main-window[customize-entered] #PanelUI-customize { + color: white; + background-image: linear-gradient(rgb(41,123,204), rgb(40,133,203)); + box-shadow: inset 0 1px 1px rgba(0,0,0,0.5), 0 2px rgba(255,255,255,0.2); + text-shadow: 0 1px 0 rgba(0,0,0,0.4); +} + +#main-window[customize-entered] #PanelUI-customize:hover, +#main-window[customize-entered] #PanelUI-customize:hover:active { + background-image: linear-gradient(rgb(38,115,191), rgb(38,125,191)); +} + +#customization-palette .toolbarbutton-text { + display: none; +} + +panelview toolbarbutton, +#widget-overflow-list > toolbarbutton, +.customizationmode-button, +#BMB_bookmarksPopup > menu, +#BMB_bookmarksPopup > menuitem { + -moz-appearance: none; + padding: 2px 6px; + background-color: hsla(210,32%,93%,0); + background-clip: padding-box; + border-radius: 2px; + border: 1px solid; + border-color: hsla(210,54%,20%,0) hsla(210,54%,20%,0) hsla(210,54%,20%,0); + box-shadow: 0 1px hsla(0,0%,100%,0) inset, + 0 1px hsla(210,54%,20%,0), + 0 0 2px hsla(210,54%,20%,0); + transition-property: background-color, border-color, box-shadow; + transition-duration: 150ms; +} + +panelview toolbarbutton@buttonStateHover@, +#widget-overflow-list > toolbarbutton@buttonStateHover@, +#edit-controls@inAnyPanel@ > toolbarbutton, +#zoom-controls@inAnyPanel@ > toolbarbutton, +.customizationmode-button, +#BMB_bookmarksPopup > menu@buttonStateHover@, +#BMB_bookmarksPopup > menuitem@buttonStateHover@ { + background-image: -moz-linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1)); + border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.2) hsla(210,54%,20%,.25); + box-shadow: 0 1px hsla(0,0%,100%,.3) inset, + 0 1px hsla(210,54%,20%,.03), + 0 0 2px hsla(210,54%,20%,.1); +} + +panelview toolbarbutton@buttonStateActive@, +.customizationmode-button:not([disabled]):hover:active, +#widget-overflow-list > toolbarbutton@buttonStateActive@, +#BMB_bookmarksPopup > menu@buttonStateActive@, +#BMB_bookmarksPopup > menuitem@buttonStateActive@ { + background-image: -moz-linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1)); + background-color: hsla(210,54%,20%,.15); + border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4); + box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset, + 0 0 1px hsla(210,54%,20%,.2) inset, + 0 1px 0 hsla(210,54%,20%,0), + 0 0 2px hsla(210,54%,20%,0); + text-shadow: none; + transition: none; +} + +#BMB_bookmarksPopup > menu, +#BMB_bookmarksPopup > menuitem { + font: inherit; +} + +#BMB_bookmarksPopup > menu:not([disabled="true"]), +#BMB_bookmarksPopup > menuitem:not([disabled="true"]) { + color: inherit; +} + +#BMB_bookmarksPopup > .panel-arrowcontainer > .panel-arrowcontent > .popup-internal-box > .autorepeatbutton-up, +#BMB_bookmarksPopup > .panel-arrowcontainer > .panel-arrowcontent > .popup-internal-box > .autorepeatbutton-down { + -moz-appearance: none; + margin-top: 0; + margin-bottom: 0; +} + +panelview toolbarseparator, +#BMB_bookmarksPopup > menuseparator { + -moz-appearance: none; + min-height: 0; + border-top: 1px solid ThreeDShadow; + margin: 5px 0; +} + +#PanelUI-historyItems > toolbarbutton { + list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png"); +} + +#PanelUI-recentlyClosedWindows > toolbarbutton > .toolbarbutton-icon, +#PanelUI-recentlyClosedTabs > toolbarbutton > .toolbarbutton-icon, +#PanelUI-historyItems > toolbarbutton > .toolbarbutton-icon { + width: 16px; + height: 16px; +} + +#PanelUI-footer.panel-multiview-anchor, +#PanelUI-footer.panel-multiview-anchor > #PanelUI-help, +toolbarbutton.panel-multiview-anchor { + background-color: Highlight; + background-image: linear-gradient(rgba(255,255,255,0.3), rgba(255,255,255,0)); + background-repeat: repeat-x; + color: HighlightText; +} + +toolbarpaletteitem[place="palette"] > #bookmarks-menu-button > .toolbarbutton-menubutton-dropmarker, +#bookmarks-menu-button[cui-areatype="menu-panel"] > .toolbarbutton-menubutton-dropmarker { + display: none; +} + +#edit-controls@inAnyPanel@ > toolbarbutton, +#zoom-controls@inAnyPanel@ > toolbarbutton { + -moz-box-flex: 1; +} + +#search-container[cui-areatype="menu-panel"] { + width: @menuPanelWidth@; +} + +toolbarpaletteitem[place="palette"] > #search-container { + min-width: 7em; + width: 7em; +} + +#edit-controls@inAnyPanel@ > toolbarbutton, +#zoom-controls@inAnyPanel@ > toolbarbutton { + -moz-appearance: none; +} + +#edit-controls@inAnyPanel@ > toolbarbutton[disabled] > .toolbarbutton-icon, +#zoom-controls@inAnyPanel@ > toolbarbutton[disabled] > .toolbarbutton-icon { + opacity: .25; +} + +#edit-controls.overflowedItem > toolbarbutton > .toolbarbutton-text { + display: none; +} + +#zoom-controls[cui-areatype="toolbar"] > #zoom-reset-button > .toolbarbutton-text { +%ifdef XP_MACOSX + min-width: 6ch; +%else + min-width: 7ch; +%endif +} + +#zoom-controls@inAnyPanel@ > #zoom-reset-button { + list-style-image: none; +} + +#edit-controls@inAnyPanel@ > #paste-button, +#zoom-controls@inAnyPanel@ > #zoom-in-button { + -moz-border-start-width: 1px; + -moz-border-start-style: solid; +} + +#edit-controls@inAnyPanel@ > #cut-button:-moz-locale-dir(ltr), +#edit-controls@inAnyPanel@ > #paste-button:-moz-locale-dir(rtl), +#zoom-controls@inAnyPanel@ > #zoom-out-button:-moz-locale-dir(ltr), +#zoom-controls@inAnyPanel@ > #zoom-in-button:-moz-locale-dir(rtl) { + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; +} + +#edit-controls@inAnyPanel@ > #cut-button:-moz-locale-dir(rtl), +#edit-controls@inAnyPanel@ > #paste-button:-moz-locale-dir(ltr), +#zoom-controls@inAnyPanel@ > #zoom-out-button:-moz-locale-dir(rtl), +#zoom-controls@inAnyPanel@ > #zoom-in-button:-moz-locale-dir(ltr) { + border-top-left-radius: 2px; + border-bottom-left-radius: 2px; +} + +#widget-overflow > .panel-arrowcontainer > .panel-arrowcontent { + padding: 0; +} + +#widget-overflow-scroller { + max-height: 30em; + overflow-y: auto; + overflow-x: hidden; + margin-top: 10px; + margin-bottom: 10px; +} + +#widget-overflow-list { + width: @menuPanelWidth@; + padding-left: 10px; + padding-right: 10px; +} + +#widget-overflow-list > .overflowedItem { + width: 100%; + max-width: @menuPanelWidth@; + min-height: 36px; + background-repeat: no-repeat; + background-position: 0 center; +} + +#widget-overflow-list > toolbarbutton, +#widget-overflow-list > toolbarbutton > toolbarbutton { + -moz-box-align: center; + -moz-box-orient: horizontal; +} + +#widget-overflow-list > toolbarbutton > .toolbarbutton-text, +#widget-overflow-list > #bookmarks-menu-button > toolbarbutton > .toolbarbutton-text { + text-align: start; + -moz-padding-start: .5em; +} + +#widget-overflow-list > #edit-controls, +#widget-overflow-list > #zoom-controls { + min-height: 28px; +} + +#PanelUI-developerItems > toolbarbutton[checked="true"], +#PanelUI-bookmarks > toolbarbutton[checked="true"], +.PanelUI-characterEncodingView-list > toolbarbutton[current] { + -moz-padding-start: 4px; +} + +#PanelUI-developerItems > toolbarbutton[checked="true"] > .toolbarbutton-text, +#PanelUI-bookmarks > toolbarbutton[checked="true"] > .toolbarbutton-text, +.PanelUI-characterEncodingView-list > toolbarbutton[current] > .toolbarbutton-text, +#customizationui-widget-panel .PanelUI-characterEncodingView-list > toolbarbutton[current] > .toolbarbutton-text { + -moz-padding-start: 0px; +} + +#BMB_bookmarksPopup > menuitem[checked="true"]::before, +#PanelUI-bookmarks > toolbarbutton[checked="true"]::before, +#PanelUI-developerItems > toolbarbutton[checked="true"]::before, +.PanelUI-characterEncodingView-list > toolbarbutton[current]::before { + content: "✓"; + display: -moz-box; + width: 12px; +} + +#PanelUI-bookmarks > toolbarbutton[checked="true"]::before, +#PanelUI-developerItems > toolbarbutton[checked="true"]::before, +.PanelUI-characterEncodingView-list > toolbarbutton[current]::before { + -moz-margin-end: -2px; +} + +#BMB_bookmarksPopup > menuitem[checked="true"] > .menu-iconic-left { + display: none; +} diff --git a/browser/themes/shared/menupanel.inc.css b/browser/themes/shared/menupanel.inc.css new file mode 100644 index 0000000000000000000000000000000000000000..1fa2532528b8bc1b487c588948c36a33fb4f60f3 --- /dev/null +++ b/browser/themes/shared/menupanel.inc.css @@ -0,0 +1,140 @@ +/* Menu panel and palette styles */ + +:-moz-any(@primaryToolbarButtons@)[cui-areatype="menu-panel"], +toolbarpaletteitem[place="palette"] > :-moz-any(@primaryToolbarButtons@) { + list-style-image: url(chrome://browser/skin/menuPanel.png); +} + +#home-button[cui-areatype="menu-panel"], +toolbarpaletteitem[place="palette"] > #home-button { + -moz-image-region: rect(0px, 128px, 32px, 96px); +} + +#bookmarks-menu-button[cui-areatype="menu-panel"], +toolbarpaletteitem[place="palette"] > #bookmarks-menu-button { + -moz-image-region: rect(0px, 160px, 32px, 128px); +} + +#bookmarks-menu-button[starred][cui-areatype="menu-panel"] { + -moz-image-region: rect(0px, 192px, 32px, 160px); +} + +#history-panelmenu[cui-areatype="menu-panel"], +toolbarpaletteitem[place="palette"] > #history-panelmenu { + -moz-image-region: rect(0px, 224px, 32px, 192px); +} + +#downloads-button[cui-areatype="menu-panel"], +#downloads-indicator[cui-areatype="menu-panel"], +toolbarpaletteitem[place="palette"] > #downloads-button { + -moz-image-region: rect(0px, 256px, 32px, 224px); +} + +#add-ons-button[cui-areatype="menu-panel"], +toolbarpaletteitem[place="palette"] > #add-ons-button { + -moz-image-region: rect(0px, 288px, 32px, 256px); +} + +#open-file-button[cui-areatype="menu-panel"], +toolbarpaletteitem[place="palette"] > #open-file-button { + -moz-image-region: rect(0px, 320px, 32px, 288px); +} + +#save-page-button[cui-areatype="menu-panel"], +toolbarpaletteitem[place="palette"] > #save-page-button { + -moz-image-region: rect(0px, 352px, 32px, 320px); +} + +#sync-button[cui-areatype="menu-panel"], +toolbarpaletteitem[place="palette"] > #sync-button { + -moz-image-region: rect(0px, 384px, 32px, 352px); +} + +#feed-button[cui-areatype="menu-panel"], +toolbarpaletteitem[place="palette"] > #feed-button { + -moz-image-region: rect(0px, 416px, 32px, 384px); +} + +#social-share-button[cui-areatype="menu-panel"], +toolbarpaletteitem[place="palette"] > #social-share-button { + -moz-image-region: rect(0px, 448px, 32px, 416px); +} + +#characterencoding-button[cui-areatype="menu-panel"], +toolbarpaletteitem[place="palette"] > #characterencoding-button { + -moz-image-region: rect(0px, 480px, 32px, 448px); +} + +#new-window-button[cui-areatype="menu-panel"], +toolbarpaletteitem[place="palette"] > #new-window-button { + -moz-image-region: rect(0px, 512px, 32px, 480px); +} + +#new-tab-button[cui-areatype="menu-panel"], +toolbarpaletteitem[place="palette"] > #new-tab-button { + -moz-image-region: rect(0px, 544px, 32px, 512px); +} + +#privatebrowsing-button[cui-areatype="menu-panel"], +toolbarpaletteitem[place="palette"] > #privatebrowsing-button { + -moz-image-region: rect(0px, 576px, 32px, 544px); +} + +#find-button[cui-areatype="menu-panel"], +toolbarpaletteitem[place="palette"] > #find-button { + -moz-image-region: rect(0px, 640px, 32px, 608px); +} + +#print-button[cui-areatype="menu-panel"], +toolbarpaletteitem[place="palette"] > #print-button { + -moz-image-region: rect(0px, 672px, 32px, 640px); +} + +#fullscreen-button[cui-areatype="menu-panel"], +toolbarpaletteitem[place="palette"] > #fullscreen-button { + -moz-image-region: rect(0px, 704px, 32px, 672px); +} + +#developer-button[cui-areatype="menu-panel"], +toolbarpaletteitem[place="palette"] > #developer-button { + -moz-image-region: rect(0px, 736px, 32px, 704px); +} + +#preferences-button[cui-areatype="menu-panel"], +toolbarpaletteitem[place="palette"] > #preferences-button { + -moz-image-region: rect(0px, 768px, 32px, 736px); +} + +/* Wide panel control icons */ + +#edit-controls@inAnyPanel@ > toolbarbutton, +#zoom-controls@inAnyPanel@ > toolbarbutton, +toolbarpaletteitem[place="palette"] > #edit-controls > toolbarbutton, +toolbarpaletteitem[place="palette"] > #zoom-controls > toolbarbutton { + list-style-image: url(chrome://browser/skin/menuPanel-small.png); +} + +#edit-controls@inAnyPanel@ > #cut-button, +toolbarpaletteitem[place="palette"] > #edit-controls > #cut-button { + -moz-image-region: rect(0px, 32px, 16px, 16px); +} + +#edit-controls@inAnyPanel@ > #copy-button, +toolbarpaletteitem[place="palette"] > #edit-controls > #copy-button { + -moz-image-region: rect(0px, 48px, 16px, 32px); +} + +#edit-controls@inAnyPanel@ > #paste-button, +toolbarpaletteitem[place="palette"] > #edit-controls > #paste-button { + -moz-image-region: rect(0px, 64px, 16px, 48px); +} + +#zoom-controls@inAnyPanel@ > #zoom-out-button, +toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-out-button { + -moz-image-region: rect(0px, 80px, 16px, 64px); +} + +#zoom-controls@inAnyPanel@ > #zoom-in-button, +toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-in-button { + -moz-image-region: rect(0px, 96px, 16px, 80px); +} diff --git a/browser/themes/shared/tab-selected.svg b/browser/themes/shared/tab-selected.svg new file mode 100644 index 0000000000000000000000000000000000000000..4132c4a42460a517bc32b37baf7ede3ebe75717c --- /dev/null +++ b/browser/themes/shared/tab-selected.svg @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<!-- 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/. --> + +<svg version="1.1" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + x="0px" + y="0px" + width="30px" + height="31px" + preserveAspectRatio="none" + xml:space="preserve"> + <defs> + <style><![CDATA[ + +%filter substitution + +%ifdef XP_MACOSX +%include ../osx/shared.inc +%elifdef XP_LINUX +%include ../linux/linuxShared.inc +%else +%include ../windows/windowsShared.inc +%endif + + #tab-background-fill { + background-color: @fgTabBackgroundColor@; + background-image: @fgTabTexture@; + background-repeat: no-repeat; + height: 100%; + width: 100%; + } + +%ifdef WINDOWS_AERO + @media (-moz-windows-default-theme) { + #tab-background-fill { + background-color: @customToolbarColor@; + } + } +%endif + ]]></style> + +%include ../../base/content/tab-shape.inc.svg + </defs> + + <foreignObject class="node" x="0" y="0" width="30" height="31" clip-path="url(#tab-curve-clip-path-@TAB_SIDE@)"> + <body xmlns="http://www.w3.org/1999/xhtml" style="all:unset"> + <div id="tab-background-fill"></div> + </body> + </foreignObject> +</svg> diff --git a/browser/themes/shared/tabs.inc.css b/browser/themes/shared/tabs.inc.css new file mode 100644 index 0000000000000000000000000000000000000000..e793f33c29ea07ad92d95678803877c935152e52 --- /dev/null +++ b/browser/themes/shared/tabs.inc.css @@ -0,0 +1,283 @@ +%if 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/. */ +%endif + +%define tabHeight 31px +%define tabCurveWidth 30px +%define tabCurveHalfWidth 15px + +/* image preloading hack */ +#TabsToolbar::before { + /* Because of bug 853415, we need to ordinal this to the first position: */ + -moz-box-ordinal-group: 0; + content: ''; + display: block; + background-image: + url(chrome://browser/skin/tabbrowser/tab-background-end.png), + url(chrome://browser/skin/tabbrowser/tab-background-middle.png), + url(chrome://browser/skin/tabbrowser/tab-background-start.png); +} + +.tabbrowser-tab, +.tabs-newtab-button { + -moz-appearance: none; + background-color: transparent; + border-radius: 0; + border-width: 0; + margin: 0; + padding: 0; +} + +.tabbrowser-tab { + -moz-box-align: stretch; +} + +.tabbrowser-tab[remote] { + text-decoration: underline; +} + +/* The selected tab should appear above adjacent tabs, .tabs-newtab-button and the highlight of #nav-bar */ +.tabbrowser-tab[selected=true] { + position: relative; + z-index: 2; +} + +.tab-background-middle { + -moz-box-flex: 1; + background-clip: padding-box; + border-left: @tabCurveHalfWidth@ solid transparent; + border-right: @tabCurveHalfWidth@ solid transparent; + margin: 0 -@tabCurveHalfWidth@; +} + +.tab-content { + -moz-padding-end: 9px; + -moz-padding-start: 9px; +} + +.tab-throbber, +.tab-icon-image, +.tab-close-button { + margin-top: 1px; +} + +.tab-throbber, +.tab-icon-image { + height: 16px; + width: 16px; +} + +.tab-icon-image { + list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png"); +} + +.tab-throbber { + list-style-image: url("chrome://browser/skin/tabbrowser/connecting.png"); +} + +.tab-throbber[progress] { + list-style-image: url("chrome://browser/skin/tabbrowser/loading.png"); +} + +.tab-throbber:not([pinned]), +.tab-icon-image:not([pinned]) { + -moz-margin-end: 6px; +} + +.tab-label { + -moz-margin-end: 0; + -moz-margin-start: 0; +} + +.tab-close-button { + -moz-margin-start: 4px; + -moz-margin-end: -2px; + padding: 0; +} + +.tab-background, +.tabs-newtab-button { + /* overlap the tab curves */ + -moz-margin-end: -@tabCurveHalfWidth@; + -moz-margin-start: -@tabCurveHalfWidth@; +} + +.tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox { + -moz-padding-end: @tabCurveHalfWidth@; + -moz-padding-start: @tabCurveHalfWidth@; +} + +.tab-background-start[selected=true]::after, +.tab-background-start[selected=true]::before, +.tab-background-start, +.tab-background-end, +.tab-background-end[selected=true]::after, +.tab-background-end[selected=true]::before { + min-height: @tabHeight@; + width: @tabCurveWidth@; +} + +.tabbrowser-tab:-moz-lwtheme { + color: inherit; +} + +/* Selected tab */ + +/* + Tab background pseudo-elements which are positioned above .tab-background-start/end: + - ::before - provides the fill of the tab curve and is clipped to the tab shape. This is where + pointer events go for the curve. + - ::after - provides the border/stroke of the tab curve and is overlayed above ::before. Pointer + events go through to ::before to get the proper shape. + */ + + +.tab-background-start[selected=true]::after, +.tab-background-end[selected=true]::after { + /* position ::after on top of its parent */ + -moz-margin-start: -@tabCurveWidth@; + background-size: 100% 100%; + content: ""; + display: -moz-box; + position: relative; +} + +.tab-background-start[selected=true]::before, +.tab-background-end[selected=true]::before { + /* all ::before pseudo elements */ + content: ""; + display: -moz-box; +} + +.tab-background-start[selected=true]:-moz-locale-dir(ltr):not(:-moz-lwtheme)::before, +.tab-background-end[selected=true]:-moz-locale-dir(rtl):not(:-moz-lwtheme)::before { + background-image: url(chrome://browser/skin/tabbrowser/tab-selected-start.svg); + background-size: 100% 100%; +} + +.tab-background-end[selected=true]:-moz-locale-dir(ltr):not(:-moz-lwtheme)::before, +.tab-background-start[selected=true]:-moz-locale-dir(rtl):not(:-moz-lwtheme)::before { + background-image: url(chrome://browser/skin/tabbrowser/tab-selected-end.svg); + background-size: 100% 100%; +} + +/* For lightweight themes, clip the header image on start, middle, and end. */ +.tab-background-start[selected=true]:-moz-locale-dir(ltr):-moz-lwtheme::before, +.tab-background-end[selected=true]:-moz-locale-dir(rtl):-moz-lwtheme::before { + clip-path: url(chrome://browser/content/browser.xul#tab-curve-clip-path-start); +} + +.tab-background-end[selected=true]:-moz-locale-dir(ltr):-moz-lwtheme::before, +.tab-background-start[selected=true]:-moz-locale-dir(rtl):-moz-lwtheme::before { + clip-path: url(chrome://browser/content/browser.xul#tab-curve-clip-path-end); +} + +.tab-background-start[selected=true]:-moz-locale-dir(ltr)::after, +.tab-background-end[selected=true]:-moz-locale-dir(rtl)::after { + background-image: url(chrome://browser/skin/tabbrowser/tab-stroke-start.png); +} + +.tab-background-end[selected=true]:-moz-locale-dir(ltr)::after, +.tab-background-start[selected=true]:-moz-locale-dir(rtl)::after { + background-image: url(chrome://browser/skin/tabbrowser/tab-stroke-end.png); +} + +.tab-background-middle[selected=true] { + background-clip: padding-box, padding-box, content-box; + background-color: @fgTabBackgroundColor@; + background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png), + @fgTabTexture@, + none; + background-repeat: repeat-x; + background-size: auto 100%; + /* The padding-top combined with background-clip: content-box (the bottom-most) ensure the + background-color doesn't extend above the top border. */ + padding-top: 2px; +} + +/* Selected tab lightweight theme styles. + See browser-lightweightTheme.css for information about run-time changes to LWT styles. */ +.tab-background-middle[selected=true]:-moz-lwtheme { + background-color: transparent; + background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png), + @fgTabTextureLWT@;/*, + lwtHeader;*/ + /* Don't stretch the LWT header images */ + background-size: auto 100%, auto 100%, auto auto; +} + +/* These LWT styles are normally overridden by browser-lightweightTheme.css */ +.tab-background-start[selected=true]:-moz-lwtheme::before, +.tab-background-end[selected=true]:-moz-lwtheme::before { + background-image: @fgTabTextureLWT@; +} + +.tab-background-start[selected=true]:-moz-lwtheme::before, +.tab-background-end[selected=true]:-moz-lwtheme::before, +.tab-background-middle[selected=true]:-moz-lwtheme { + background-color: transparent; +} + +/* End selected tab */ + +/* new tab button border and gradient on hover */ +.tabbrowser-tab:hover > .tab-stack > .tab-background:not([selected=true]), +.tabs-newtab-button:hover { + background-image: url(chrome://browser/skin/tabbrowser/tab-background-start.png), + url(chrome://browser/skin/tabbrowser/tab-background-middle.png), + url(chrome://browser/skin/tabbrowser/tab-background-end.png); + background-position: left bottom, @tabCurveWidth@ bottom, right bottom; + background-repeat: no-repeat; + background-size: @tabCurveWidth@ 100%, calc(100% - (2 * @tabCurveWidth@)) 100%, @tabCurveWidth@ 100%; +} + +/* Tab pointer-events */ +.tabbrowser-tab { + pointer-events: none; +} + +.tab-background-middle, +.tabs-newtab-button, +.tab-close-button { + pointer-events: auto; +} + +/* Pinned tabs */ + +/* Pinned tab separators need position: absolute when positioned (during overflow). */ +#tabbrowser-tabs[positionpinnedtabs] > .tabbrowser-tab[pinned]::before { + height: 100%; + position: absolute; +} + +.tabbrowser-tab[pinned][titlechanged]:not([selected="true"]) > .tab-stack > .tab-content { + background-image: radial-gradient(farthest-corner at center bottom, rgb(255,255,255) 3%, rgba(186,221,251,0.75) 20%, rgba(127,179,255,0.25) 40%, rgba(127,179,255,0) 70%); + background-position: center bottom 1px; + background-repeat: no-repeat; + background-size: 85% 100%; +} + +/* Background tab separators (3px wide). + Also show separators beside the selected tab when dragging it. */ +#tabbrowser-tabs[movingtab] > .tabbrowser-tab[beforeselected]:not([last-visible-tab])::after, +.tabbrowser-tab:not([selected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before, +#tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([selected]):not([beforehovered]):not(:hover)::after { + -moz-margin-start: -1.5px; + -moz-margin-end: -1.5px; + background-image: url(chrome://browser/skin/tabbrowser/tab-separator.png); + background-position: left bottom; + background-repeat: no-repeat; + background-size: 3px 100%; + content: ""; + display: -moz-box; + margin-bottom: 1px; + width: 3px; +} + +/* New tab button */ + +.tabs-newtab-button { + width: 66px; +} diff --git a/browser/themes/shared/toolbarbuttons.inc.css b/browser/themes/shared/toolbarbuttons.inc.css new file mode 100644 index 0000000000000000000000000000000000000000..293899ef635e02db9058930249f736bfffa99702 --- /dev/null +++ b/browser/themes/shared/toolbarbuttons.inc.css @@ -0,0 +1,139 @@ +:-moz-any(@primaryToolbarButtons@), +#bookmarks-menu-button > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { + list-style-image: url("chrome://browser/skin/Toolbar.png"); +} + +:-moz-any(@primaryToolbarButtons@):-moz-lwtheme-brighttext, +#bookmarks-menu-button:-moz-lwtheme-brighttext > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { + list-style-image: url(chrome://browser/skin/Toolbar-inverted.png); +} + +#back-button { + -moz-image-region: rect(0, 36px, 18px, 18px); +} + +#forward-button { + -moz-image-region: rect(0, 72px, 18px, 54px); +} + +#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon, +#forward-button:-moz-locale-dir(rtl) { + transform: scaleX(-1); +} + +#home-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 126px, 18px, 108px); +} + +#bookmarks-menu-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 144px, 18px, 126px); +} + +#bookmarks-menu-button[cui-areatype="toolbar"][starred] { + -moz-image-region: rect(0, 162px, 18px, 144px); +} + +#bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { + -moz-image-region: rect(0, 630px, 18px, 612px); +} + +#history-panelmenu[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 180px, 18px, 162px); +} + +#downloads-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 198px, 18px, 180px); +} + +#add-ons-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 216px, 18px, 198px); +} + +#open-file-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 234px, 18px, 216px); +} + +#save-page-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 252px, 18px, 234px); +} + +#sync-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 270px, 18px, 252px); +} + +#feed-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 288px, 18px, 270px); +} + +#social-share-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0px, 306px, 18px, 288px); +} + +#characterencoding-button[cui-areatype="toolbar"]{ + -moz-image-region: rect(0, 324px, 18px, 306px); +} + +#new-window-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 342px, 18px, 324px); +} + +#new-tab-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 360px, 18px, 342px); +} + +#privatebrowsing-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 378px, 18px, 360px); +} + +#find-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 396px, 18px, 378px); +} + +#print-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 414px, 18px, 396px); +} + +#fullscreen-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 432px, 18px, 414px); +} + +#developer-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 450px, 18px, 432px); +} + +#preferences-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 468px, 18px, 450px); +} + +#PanelUI-menu-button { + -moz-image-region: rect(0, 486px, 18px, 468px); +} + +#edit-controls:not(@inAnyPanel@) > #cut-button { + -moz-image-region: rect(0, 504px, 18px, 486px); +} + +#edit-controls:not(@inAnyPanel@) > #copy-button { + -moz-image-region: rect(0, 522px, 18px, 504px); +} + +#edit-controls:not(@inAnyPanel@) > #paste-button { + -moz-image-region: rect(0, 540px, 18px, 522px); +} + +#zoom-controls:not(@inAnyPanel@) > #zoom-out-button { + -moz-image-region: rect(0, 558px, 18px, 540px); +} + +#zoom-controls:not(@inAnyPanel@) > #zoom-in-button { + -moz-image-region: rect(0, 576px, 18px, 558px); +} + +#webrtc-status-button:not(@inAnyPanel@) { + -moz-image-region: rect(0, 594px, 18px, 576px); +} + +#nav-bar-overflow-button { + -moz-image-region: rect(0, 612px, 18px, 594px); +} + diff --git a/browser/themes/windows/Makefile.in b/browser/themes/windows/Makefile.in index 173ca68435c6cf993204e3cca62ac579ab2537ba..93893379dd7f52714ac3ebf5f3e5cb883ad8c273 100644 --- a/browser/themes/windows/Makefile.in +++ b/browser/themes/windows/Makefile.in @@ -5,3 +5,32 @@ ICON_FILES := icon.png ICON_DEST = $(FINAL_TARGET)/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd} INSTALL_TARGETS += ICON + +# By default, the pre-processor used for jar.mn will use "%" as a marker for ".css" files and "#" +# otherwise. This falls apart when a file using one marker needs to include a file with the other +# marker since the pre-processor instructions in the included file will not be processed. The +# following SVG files need to include a file which uses "%" as the marker so we invoke the pre- +# processor ourselves here with the marker specified. The resulting SVG files will get packaged by +# the processing of the jar file in this directory. +tab-selected-svg: $(srcdir)/../shared/tab-selected.svg + $(call py_action,preprocessor, \ + --marker % -D TAB_SIDE=start \ + $(ACDEFINES) \ + $(srcdir)/../shared/tab-selected.svg -o tab-selected-start.svg) + $(call py_action,preprocessor, \ + --marker % -D TAB_SIDE=end \ + $(ACDEFINES) \ + $(srcdir)/../shared/tab-selected.svg -o tab-selected-end.svg) +# Same as above for aero. + $(call py_action,preprocessor, \ + --marker % -D TAB_SIDE=start -D WINDOWS_AERO \ + $(ACDEFINES) \ + $(srcdir)/../shared/tab-selected.svg -o tab-selected-start-aero.svg) + $(call py_action,preprocessor, \ + --marker % -D TAB_SIDE=end -D WINDOWS_AERO \ + $(ACDEFINES) \ + $(srcdir)/../shared/tab-selected.svg -o tab-selected-end-aero.svg) + +.PHONY: tab-selected-svg + +export:: tab-selected-svg diff --git a/browser/themes/windows/Toolbar-aero.png b/browser/themes/windows/Toolbar-aero.png new file mode 100644 index 0000000000000000000000000000000000000000..14a90c27b49b0f8cf90766357e5c2582b62ef230 Binary files /dev/null and b/browser/themes/windows/Toolbar-aero.png differ diff --git a/browser/themes/windows/Toolbar-inverted-aero.png b/browser/themes/windows/Toolbar-inverted-aero.png new file mode 100644 index 0000000000000000000000000000000000000000..b42fd7475dbe89ff00dfcf875c45f76c839fab05 Binary files /dev/null and b/browser/themes/windows/Toolbar-inverted-aero.png differ diff --git a/browser/themes/windows/Toolbar-inverted.png b/browser/themes/windows/Toolbar-inverted.png index 2c3253fe80f94776c9a8320252eac24ffff46c9d..b42fd7475dbe89ff00dfcf875c45f76c839fab05 100644 Binary files a/browser/themes/windows/Toolbar-inverted.png and b/browser/themes/windows/Toolbar-inverted.png differ diff --git a/browser/themes/windows/Toolbar-lunaSilver.png b/browser/themes/windows/Toolbar-lunaSilver.png new file mode 100644 index 0000000000000000000000000000000000000000..668f8c108f74fc128fbadb4bdb27daa73fda3767 Binary files /dev/null and b/browser/themes/windows/Toolbar-lunaSilver.png differ diff --git a/browser/themes/windows/Toolbar.png b/browser/themes/windows/Toolbar.png index b84f6ddadf1a04005a46db5f396e5d29977d24a9..687cc1b3dad4197e98b3f39a8d75878c954b13f9 100644 Binary files a/browser/themes/windows/Toolbar.png and b/browser/themes/windows/Toolbar.png differ diff --git a/browser/themes/windows/appmenu-dropmarker.png b/browser/themes/windows/appmenu-dropmarker.png deleted file mode 100644 index 27deaff72225a4c66865190405b071d728899d9c..0000000000000000000000000000000000000000 Binary files a/browser/themes/windows/appmenu-dropmarker.png and /dev/null differ diff --git a/browser/themes/windows/appmenu-icons.png b/browser/themes/windows/appmenu-icons.png deleted file mode 100644 index 78f36581631f5a7ad49eac9fae3f029e914c7c49..0000000000000000000000000000000000000000 Binary files a/browser/themes/windows/appmenu-icons.png and /dev/null differ diff --git a/browser/themes/windows/browser-aero.css b/browser/themes/windows/browser-aero.css index c7e65fb97d131d48b6cc7c58cd536003fd754560..cecfd870e53170dc751621940a7e549dc9cbee10 100644 --- a/browser/themes/windows/browser-aero.css +++ b/browser/themes/windows/browser-aero.css @@ -6,38 +6,16 @@ %include browser.css %undef WINDOWS_AERO -%define customToolbarColor hsl(210,75%,92%) %define glassActiveBorderColor rgb(37, 44, 51) %define glassInactiveBorderColor rgb(102, 102, 102) %include downloads/indicator-aero.css @media not all and (-moz-windows-classic) { - #main-window[sizemode="normal"] > #titlebar > #titlebar-content > #appmenu-button-container { + #main-window[sizemode="normal"] > #tab-view-deck > #browser-panel > #navigator-toolbox > #toolbar-menubar { margin-top: 1px; } - #appmenu-button { - border-width: 2px; - -moz-border-left-colors: @appMenuButtonBorderColor@; - -moz-border-bottom-colors: @appMenuButtonBorderColor@; - -moz-border-right-colors: @appMenuButtonBorderColor@; - margin-bottom: 1px; /* compensate white outer border */ - box-shadow: 0 1px 0 rgba(255,255,255,.25) inset, - 0 0 2px 1px rgba(255,255,255,.25) inset; - } - - #main-window[privatebrowsingmode=temporary] #appmenu-button { - -moz-border-left-colors: rgba(255,255,255,.5) rgba(43,8,65,.9); - -moz-border-bottom-colors: rgba(255,255,255,.5) rgba(43,8,65,.9); - -moz-border-right-colors: rgba(255,255,255,.5) rgba(43,8,65,.9); - } - - #appmenu-popup { - margin-top: -1px; - -moz-margin-start: 1px; - } - .panel-promo-message { font-style: italic; } @@ -50,45 +28,26 @@ background-color: @customToolbarColor@; } - .tabbrowser-tab:not(:-moz-lwtheme), - .tabs-newtab-button:not(:-moz-lwtheme) { - background-image: @toolbarShadowOnTab@, @bgTabTexture@, - linear-gradient(@customToolbarColor@, @customToolbarColor@); - } - - .tabbrowser-tab:not(:-moz-lwtheme):hover, - .tabs-newtab-button:not(:-moz-lwtheme):hover { - background-image: @toolbarShadowOnTab@, @bgTabTextureHover@, - linear-gradient(@customToolbarColor@, @customToolbarColor@); - } - - .tabbrowser-tab[selected="true"]:not(:-moz-lwtheme) { - background-image: linear-gradient(#fff, @toolbarHighlight@ 50%), - linear-gradient(@customToolbarColor@, @customToolbarColor@); - } - - #main-window[tabsontop=false]:not([disablechrome]) .tabbrowser-tab[selected=true]:not(:-moz-lwtheme) { - background-image: @toolbarShadowOnTab@, - linear-gradient(#fff, @toolbarHighlight@ 50%), - linear-gradient(@customToolbarColor@, @customToolbarColor@); + .tab-background-middle[selected=true]:not(:-moz-lwtheme) { + background-color: @customToolbarColor@; } #navigator-toolbox:not(:-moz-lwtheme)::after { background-color: #aabccf; } - #navigator-toolbox[tabsontop=true] #urlbar:not(:-moz-lwtheme), - #navigator-toolbox[tabsontop=true] .searchbar-textbox:not(:-moz-lwtheme) { + #urlbar:not(:-moz-lwtheme), + .searchbar-textbox:not(:-moz-lwtheme) { border-color: hsla(210,54%,20%,.25) hsla(210,54%,20%,.27) hsla(210,54%,20%,.3); } - #navigator-toolbox[tabsontop=true] #urlbar:not(:-moz-lwtheme):not([focused]):hover, - #navigator-toolbox[tabsontop=true] .searchbar-textbox:not(:-moz-lwtheme):not([focused]):hover { + #urlbar:not(:-moz-lwtheme):not([focused]):hover, + .searchbar-textbox:not(:-moz-lwtheme):not([focused]):hover { border-color: hsla(210,54%,20%,.35) hsla(210,54%,20%,.37) hsla(210,54%,20%,.4); } - #navigator-toolbox[tabsontop=true] #urlbar:not(:-moz-lwtheme)[focused], - #navigator-toolbox[tabsontop=true] .searchbar-textbox:not(:-moz-lwtheme)[focused] { + #urlbar:not(:-moz-lwtheme)[focused], + .searchbar-textbox:not(:-moz-lwtheme)[focused] { border-color: hsla(206,100%,60%,.65) hsla(206,100%,55%,.65) hsla(206,100%,50%,.65); } @@ -152,10 +111,6 @@ -moz-appearance: -moz-win-exclude-glass; } - #main-window[chromemargin^="0,"][sizemode=normal] #navigator-toolbox { - margin-top: -7px; - } - /* Artificially draw window borders that are covered by lwtheme, see bug 591930. */ #main-window[sizemode="normal"] > #titlebar > #titlebar-content:-moz-lwtheme { border-top: 2px solid; @@ -166,27 +121,12 @@ -moz-border-top-colors: @glassInactiveBorderColor@ rgba(255,255,255,.6); } - #main-window[sizemode="normal"] > #titlebar > #titlebar-content > #appmenu-button-container:-moz-lwtheme { - margin-top: -1px; - } - #main-window[sizemode="normal"] #titlebar-buttonbox:-moz-lwtheme { margin-top: -2px; } - #appmenu-button { - margin-bottom: -1px; /* compensate white outer border */ - } - - #main-window[sizemode=fullscreen]:not(:-moz-lwtheme) { - -moz-appearance: none; - background-color: #556; - } - #toolbar-menubar:not(:-moz-lwtheme), - #TabsToolbar[tabsontop=true]:not(:-moz-lwtheme), - #nav-bar[tabsontop=false]:not(:-moz-lwtheme), - #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child:not(:-moz-lwtheme) { + #TabsToolbar:not(:-moz-lwtheme) { background-color: transparent !important; color: black; text-shadow: 0 0 .5em white, 0 0 .5em white, 0 1px 0 rgba(255,255,255,.4); @@ -194,33 +134,13 @@ border-right-style: none !important; } - :-moz-any(#toolbar-menubar, #nav-bar[tabsontop=false]) :-moz-any(@primaryToolbarButtons@):not(:-moz-any(#alltabs-button,#tabview-button,#sync-button[status])) > .toolbarbutton-icon:not(:-moz-lwtheme), - :-moz-any(#toolbar-menubar, #nav-bar[tabsontop=false]) :-moz-any(@primaryToolbarButtons@) > toolbarbutton > .toolbarbutton-icon:not(:-moz-lwtheme), - #TabsToolbar[tabsontop=true] :-moz-any(@primaryToolbarButtons@):not(:-moz-any(#alltabs-button,#tabview-button,#new-tab-button,#sync-button[status])) > .toolbarbutton-icon:not(:-moz-lwtheme), - #TabsToolbar[tabsontop=true] :-moz-any(@primaryToolbarButtons@) > toolbarbutton > .toolbarbutton-icon:not(:-moz-lwtheme), - #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child :-moz-any(@primaryToolbarButtons@):not(:-moz-any(#alltabs-button,#tabview-button,#new-tab-button,#sync-button[status])) > .toolbarbutton-icon:not(:-moz-lwtheme), - #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child :-moz-any(@primaryToolbarButtons@) > toolbarbutton > .toolbarbutton-icon:not(:-moz-lwtheme) { - list-style-image: url("chrome://browser/skin/Toolbar-inverted.png"); - } - - :-moz-any(#toolbar-menubar, #TabsToolbar[tabsontop=true], #nav-bar[tabsontop=false]) .toolbarbutton-1 > .toolbarbutton-menu-dropmarker:not(:-moz-lwtheme), - :-moz-any(#toolbar-menubar, #TabsToolbar[tabsontop=true], #nav-bar[tabsontop=false]) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:not(:-moz-lwtheme), - #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child .toolbarbutton-1 > .toolbarbutton-menu-dropmarker:not(:-moz-lwtheme), - #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:not(:-moz-lwtheme) { - list-style-image: url("chrome://browser/skin/toolbarbutton-dropdown-arrow-inverted.png"); - } - /* Vertical toolbar border */ #main-window[sizemode=normal] #navigator-toolbox::after, - #main-window[sizemode=normal] #navigator-toolbox[tabsontop=true] > toolbar:not(#toolbar-menubar):not(#TabsToolbar), - #main-window[sizemode=normal] #navigator-toolbox[tabsontop=false] > toolbar:not(#toolbar-menubar):not(#nav-bar) { + #main-window[sizemode=normal] #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) { border-left: 1px solid @toolbarShadowColor@; border-right: 1px solid @toolbarShadowColor@; background-clip: padding-box; } - #main-window[sizemode=normal] #navigator-toolbox > toolbar:-moz-lwtheme { - border-color: transparent !important; - } #main-window[sizemode=normal] #browser-border-start, #main-window[sizemode=normal] #browser-border-end { display: -moz-box; @@ -233,65 +153,36 @@ background-clip: padding-box; } - #main-window[sizemode=normal][tabsontop=false] #PersonalToolbar:not(:-moz-lwtheme) { - border-top-left-radius: 2.5px; - border-top-right-radius: 2.5px; + /* Toolbar shadow behind tabs */ + #nav-bar { + border-top: 1px solid @toolbarShadowColor@ !important; + background-clip: padding-box; } - /* Toolbar shadow behind tabs */ /* This code is only needed for restored windows (i.e. sizemode=normal) because of the border radius on the toolbar below the tab bar. */ - #main-window[sizemode=normal] #nav-bar[tabsontop=true]:not(:-moz-lwtheme), - #main-window[sizemode=normal] #nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + toolbar:not(:-moz-lwtheme), - #main-window[sizemode=normal] #nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + #customToolbars + #PersonalToolbar:not(:-moz-lwtheme), - #main-window[sizemode=normal][disablechrome] #navigator-toolbox[tabsontop=true]:not(:-moz-lwtheme)::after { + #main-window[sizemode=normal] #nav-bar { border-top: 1px solid @toolbarShadowColor@; border-top-left-radius: 2.5px; border-top-right-radius: 2.5px; background-clip: padding-box; } - #main-window[sizemode=normal] #TabsToolbar[tabsontop=true]:not(:-moz-lwtheme) { - margin-bottom: -1px; - background-image: none !important; - } - #main-window[sizemode=normal] #tabbrowser-tabs[tabsontop=true] > .tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox > .scrollbox-innerbox:not(:-moz-lwtheme) { - position: relative; - } - #navigator-toolbox[tabsontop=false] > #PersonalToolbar { - margin-top: 3px; - } - #navigator-toolbox[tabsontop=false] > #PersonalToolbar:not(:-moz-lwtheme) { - margin-top: 2px; - border-top: 1px solid @toolbarShadowColor@; - background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0)); - } - - #main-window[sizemode=normal] #TabsToolbar[tabsontop=true] { - padding-left: 4px; - padding-right: 4px; + /* Cover the top border of the adjacent toolbar */ + #TabsToolbar { + margin-bottom: -1px; } - #main-window[sizemode=normal] #TabsToolbar[tabsontop=false] { - padding-left: 2px; - padding-right: 2px; - } - - /* Rounded corners for when chrome is disabled */ - #main-window[sizemode=normal][disablechrome] #navigator-toolbox[tabsontop=true]:not(:-moz-lwtheme)::after { - visibility: visible; - background-color: @customToolbarColor@; - background-image: linear-gradient(@toolbarHighlight@, @toolbarHighlight@); - height: 4px; + #main-window[sizemode=normal] #TabsToolbar { + padding-left: 1px; + padding-right: 1px; } /* Make the window draggable by glassed toolbars (bug 555081) */ #toolbar-menubar:not([autohide="true"]), - #TabsToolbar[tabsontop="true"], - #nav-bar[tabsontop=false], - #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"] + #TabsToolbar[tabsontop="false"]:last-child, - #navigator-toolbox > toolbar:not(#toolbar-menubar):-moz-lwtheme { - -moz-binding: url("chrome://global/content/bindings/toolbar.xml#toolbar-drag"); + #TabsToolbar, + #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#addon-bar):-moz-lwtheme { + -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-drag"); } #appcontent:not(:-moz-lwtheme) { @@ -303,29 +194,6 @@ border-radius: 4px; } - #navigator-toolbox[tabsontop=false] #urlbar:not(:-moz-lwtheme), - #navigator-toolbox[tabsontop=false] .searchbar-textbox:not(:-moz-lwtheme) { - background-color: rgba(255,255,255,.725); - @navbarTextboxCustomBorder@ - color: black; - } - - #navigator-toolbox[tabsontop=false] html|*.urlbar-input:not(:-moz-lwtheme)::-moz-placeholder, - #navigator-toolbox[tabsontop=false] .searchbar-textbox > .autocomplete-textbox-container > .textbox-input-box > html|*.textbox-input:not(:-moz-lwtheme)::-moz-placeholder { - opacity: 1.0; - color: #777; - } - - #navigator-toolbox[tabsontop=false] #urlbar:not(:-moz-lwtheme):hover, - #navigator-toolbox[tabsontop=false] .searchbar-textbox:not(:-moz-lwtheme):hover { - background-color: rgba(255,255,255,.898); - } - - #navigator-toolbox[tabsontop=false] #urlbar:not(:-moz-lwtheme)[focused], - #navigator-toolbox[tabsontop=false] .searchbar-textbox:not(:-moz-lwtheme)[focused] { - background-color: white; - } - .tabbrowser-tab:not(:-moz-lwtheme) { text-shadow: none; } @@ -347,6 +215,57 @@ } } +@media (-moz-windows-glass) { + #main-window[sizemode=fullscreen]:not(:-moz-lwtheme) { + -moz-appearance: none; + background-color: #556; + } + + /* Use inverted icons for glassed toolbars */ + #TabsToolbar > toolbarpaletteitem > #bookmarks-menu-button > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:not(:-moz-lwtheme), + #TabsToolbar > #bookmarks-menu-button > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:not(:-moz-lwtheme), + #toolbar-menubar > toolbarpaletteitem > #bookmarks-menu-button > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:not(:-moz-lwtheme), + #toolbar-menubar > #bookmarks-menu-button > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:not(:-moz-lwtheme), + #toolbar-menubar > toolbarpaletteitem > :-moz-any(@primaryToolbarButtons@):not(:-moz-lwtheme), + #toolbar-menubar > :-moz-any(@primaryToolbarButtons@):not(:-moz-lwtheme), + #TabsToolbar > toolbarpaletteitem > :-moz-any(@primaryToolbarButtons@):not(:-moz-lwtheme), + #TabsToolbar > :-moz-any(@primaryToolbarButtons@):not(:-moz-lwtheme) { + list-style-image: url("chrome://browser/skin/Toolbar-inverted.png"); + } + + /* Glass Fog */ + + #TabsToolbar:not(:-moz-lwtheme) { + background-image: none; + position: relative; + } + + #TabsToolbar:not(:-moz-lwtheme)::before { + box-shadow: 0 0 30px 30px rgba(174,189,204,0.85); + content: ""; + display: -moz-box; + height: 0; + margin: 0 60px; /* (30px + 30px) from box-shadow */ + position: absolute; + pointer-events: none; + top: 50%; + width: -moz-available; + z-index: -1; + } + + /* Need to constrain the glass fog to avoid overlapping layers, see bug 886281. */ + #main-window:not([customizing]) #navigator-toolbox:not(:-moz-lwtheme) { + overflow-y: hidden; + } + + #main-window[sizemode=normal] .tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox > .scrollbox-innerbox:not(:-moz-lwtheme) { + position: relative; + } + + /* End Glass Fog */ +} + + @media not all and (-moz-windows-compositor) { @media (-moz-windows-default-theme) { #main-window { @@ -357,14 +276,26 @@ } #toolbar-menubar:not([autohide=true]):not(:-moz-lwtheme), - #TabsToolbar[tabsontop=true]:not(:-moz-lwtheme), - #navigator-toolbox[tabsontop=false] > toolbar:not(#toolbar-menubar):not(:-moz-lwtheme) { - -moz-binding: url("chrome://global/content/bindings/toolbar.xml#toolbar-drag"); + #TabsToolbar:not(:-moz-lwtheme) { + -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-drag"); background-color: transparent; } #toolbar-menubar[autohide=true] { background-color: transparent !important; } + + /* Render a window top border for lwthemes: */ + #main-window[tabsintitlebar][sizemode="normal"] #titlebar-content:-moz-lwtheme { + background-image: linear-gradient(to bottom, + @glassActiveBorderColor@ 0, @glassActiveBorderColor@ 1px, + rgba(255,255,255,.6) 1px, rgba(255,255,255,.6) 2px, transparent 2px); + } + + #main-window[tabsintitlebar][sizemode="normal"] #titlebar-content:-moz-lwtheme:-moz-window-inactive { + background-image: linear-gradient(to bottom, + @glassInactiveBorderColor@ 0, @glassInactiveBorderColor@ 1px, + rgba(255,255,255,.6) 1px, rgba(255,255,255,.6) 2px, transparent 2px); + } } #print-preview-toolbar:not(:-moz-lwtheme) { @@ -400,72 +331,3 @@ #close-button:-moz-locale-dir(rtl) { transform: scaleX(-1); } - -/* ::::: splitmenu highlight style that imitates Windows 7 start menu ::::: */ -@media (-moz-windows-default-theme) { - .splitmenu-menuitem, - .splitmenu-menu { - -moz-appearance: none; - padding-top: 2px; - padding-bottom: 2px; - border: 1px solid transparent; - } - .splitmenu-menuitem { - -moz-margin-end: 0; - } - .splitmenu-menu { - -moz-margin-start: -1px; - } - .splitmenu-menuitem:-moz-locale-dir(ltr), - .splitmenu-menu:-moz-locale-dir(rtl) { - border-top-left-radius: 3px; - border-bottom-left-radius: 3px; - } - .splitmenu-menu:-moz-locale-dir(ltr), - .splitmenu-menuitem:-moz-locale-dir(rtl) { - border-top-right-radius: 3px; - border-bottom-right-radius: 3px; - } - - .splitmenu-menuitem > .menu-text { - -moz-margin-start: 1px !important; - -moz-margin-end: 3px !important; - } - .splitmenu-menu > .menu-right { - -moz-margin-end: -3px; - } - - .splitmenu-menuitem[iconic], - .splitmenu-menu[iconic] { - padding-bottom: 1px; - } - .splitmenu-menuitem[iconic] > .menu-iconic-left { - margin-top: -3px; - margin-bottom: -2px; - -moz-margin-start: -1px; - } - .splitmenu-menuitem[iconic] > .menu-iconic-text { - -moz-margin-start: 2px !important; - -moz-margin-end: 3px !important; - } - .splitmenu-menu[iconic] > .menu-right { - margin-top: -1px; - } - - .splitmenu-menuitem[_moz-menuactive], - .splitmenu-menu[_moz-menuactive] { - background-color: transparent; - background-image: linear-gradient(#fafbfd, #ebf3fd); - border-color: #aeccf1; - } - - .splitmenu-menuitem[disabled][_moz-menuactive], - .splitmenu-menu[disabled][_moz-menuactive] { - background-image: linear-gradient(#f8f9f9, #eaeaea); - border-color: #d8d7d7; - } - - .splitmenu-menu[_moz-menuactive]:not(:hover):not([open]) { - background-image: none; - } -} diff --git a/browser/themes/windows/browser-lightweightTheme.css b/browser/themes/windows/browser-lightweightTheme.css new file mode 100644 index 0000000000000000000000000000000000000000..292d0dc7874331da9323b5b220a1e48b08f63d6d --- /dev/null +++ b/browser/themes/windows/browser-lightweightTheme.css @@ -0,0 +1,29 @@ +/* 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/. */ + +%include windowsShared.inc +%filter substitution + +/* + * LightweightThemeListener will append the current lightweight theme's header + * image to the background-image for each of the following rulesets. + */ + +/* Lightweight theme on tabs */ +#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start[selected=true]:-moz-lwtheme::before, +#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end[selected=true]:-moz-lwtheme::before { + background-attachment: scroll, fixed; + background-color: transparent; + background-image: @fgTabTextureLWT@;/*, lwtHeader;*/ + background-position: 0 0, right top; +} + +#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme { + background-attachment: scroll, scroll, fixed; + background-color: transparent; + background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png), + @fgTabTextureLWT@;/*, + lwtHeader;*/ + background-position: 0 0, 0 0, right top; +} diff --git a/browser/themes/windows/browser.css b/browser/themes/windows/browser.css index 4ef1877fe85a3af6dcb5cfe717cbe13508f1ee27..347db3a73b9ab26ed9e2a13dcfe55a523c08d090 100644 --- a/browser/themes/windows/browser.css +++ b/browser/themes/windows/browser.css @@ -8,29 +8,14 @@ @namespace html url("http://www.w3.org/1999/xhtml"); %include ../shared/browser.inc +%include windowsShared.inc %filter substitution -%define toolbarHighlight rgba(255,255,255,.5) -%define selectedTabHighlight rgba(255,255,255,.7) -%define toolbarShadowColor rgba(10%,10%,10%,.4) -%define toolbarShadowOnTab linear-gradient(to top, rgba(10%,10%,10%,.4) 1px, transparent 1px) -%define bgTabTexture linear-gradient(transparent, hsla(0,0%,45%,.1) 1px, hsla(0,0%,32%,.2) 80%, hsla(0,0%,0%,.2)) -%define bgTabTextureHover linear-gradient(hsla(0,0%,100%,.3) 1px, hsla(0,0%,75%,.2) 80%, hsla(0,0%,60%,.2)) +%define toolbarShadowColor hsla(209,67%,12%,0.35) %define navbarTextboxCustomBorder border-color: rgba(0,0,0,.32); -%define navbarLargeIcons #navigator-toolbox[iconsize=large][mode=icons] > #nav-bar %define forwardTransitionLength 150ms -%define conditionalForwardWithUrlbar window:not([chromehidden~=toolbar]) #navigator-toolbox[iconsize=large][mode=icons] > :-moz-any(#nav-bar[currentset*="unified-back-forward-button,urlbar-container"],#nav-bar:not([currentset])) > #unified-back-forward-button +%define conditionalForwardWithUrlbar window:not([chromehidden~="toolbar"]) #urlbar-container %define conditionalForwardWithUrlbarWidth 27 -%ifdef MOZ_OFFICIAL_BRANDING -%define appMenuButtonBorderColor rgba(255,255,255,.5) rgba(83,42,6,.9) -%else -%if MOZ_UPDATE_CHANNEL == aurora -%define appMenuButtonBorderColor hsla(0,0%,100%,.5) hsla(214,89%,21%,.9) -%else -%define appMenuButtonBorderColor hsla(0,0%,100%,.5) hsla(210,59%,13%,.9) -%endif -%endif - #menubar-items { -moz-box-orient: vertical; /* for flex hack */ } @@ -39,6 +24,31 @@ -moz-box-flex: 1; /* make menu items expand to fill toolbar height */ } +/* We want a 4px gap between the TabsToolbar and the toolbar-menubar when the + toolbar-menu is displayed, and a 16px gap when it is not. 1px is taken care + of by the (light) outer shadow of the tab, the remaining 3/15 are these margins. */ +#toolbar-menubar:not([autohide="true"]) ~ #TabsToolbar, +#toolbar-menubar[autohide="true"]:not([inactive]) ~ #TabsToolbar { + margin-top: 3px; +} + +#main-window[tabsintitlebar][sizemode="normal"][chromehidden~="menubar"] #toolbar-menubar ~ #TabsToolbar, +#main-window[tabsintitlebar][sizemode="normal"] #toolbar-menubar[autohide="true"][inactive] ~ #TabsToolbar { + margin-top: 15px; +} + +#toolbar-menubar:not([autohide="true"]) { + -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-drag"); +} + +#main-window[tabsintitlebar] #main-menubar > menu:not(:-moz-lwtheme) { + color: CaptionText; +} + +#main-window[tabsintitlebar] #main-menubar > menu:not(:-moz-lwtheme):-moz-window-inactive { + color: InactiveCaptionText; +} + #navigator-toolbox { -moz-appearance: none; background-color: transparent; @@ -52,10 +62,6 @@ height: 1px; background-color: ThreeDShadow; } -#navigator-toolbox[tabsontop=false]::after, -#main-window[disablechrome] #navigator-toolbox::after { - visibility: collapse; -} #navigator-toolbox > toolbar:not(:-moz-lwtheme) { -moz-appearance: none; @@ -66,20 +72,26 @@ %ifdef WINDOWS_AERO @media not all and (-moz-windows-compositor) { %endif - #main-window[tabsintitlebar]:not([inFullscreen]) #toolbar-menubar[inactive] ~ #TabsToolbar:not(:-moz-lwtheme) { - background: linear-gradient(to top, @toolbarShadowColor@ 1px, transparent 1px), - linear-gradient(rgba(50%,50%,50%,0), ActiveCaption 85%); + #toolbar-menubar { + background-color: transparent !important; + } + + #main-window[tabsintitlebar]:not([inFullscreen]) #TabsToolbar:not(:-moz-lwtheme) { color: CaptionText; } - #main-window[tabsintitlebar]:not([inFullscreen]) #toolbar-menubar[inactive] ~ #TabsToolbar:not(:-moz-lwtheme):-moz-window-inactive { - background: linear-gradient(to top, @toolbarShadowColor@ 1px, transparent 1px), - linear-gradient(rgba(50%,50%,50%,0), InactiveCaption 85%); + + #main-window[tabsintitlebar]:not([inFullscreen]) #TabsToolbar:not(:-moz-lwtheme):-moz-window-inactive { color: InactiveCaptionText; } + #TabsToolbar:-moz-lwtheme { + background: linear-gradient(to top, @toolbarShadowColor@ 2px, transparent 2px); + } + #main-window[tabsintitlebar] #titlebar:-moz-lwtheme { visibility: hidden; } + #main-window[tabsintitlebar] #titlebar-content:-moz-lwtheme { -moz-binding: url("chrome://global/content/bindings/general.xml#windowdragbox"); visibility: visible; @@ -88,449 +100,118 @@ } %endif -#nav-bar[tabsontop=true], -#nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + toolbar, -#nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + #customToolbars + #PersonalToolbar { - background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0)); -} - -#personal-bookmarks { - min-height: 24px; -} - -#print-preview-toolbar:not(:-moz-lwtheme) { - -moz-appearance: toolbox; -} - -#browser-bottombox:not(:-moz-lwtheme) { - background-color: -moz-dialog; -} - -/* ::::: app menu button ::::: */ - -#appmenu-button { - -moz-appearance: none; - background-clip: padding-box; - border-radius: 0 0 4px 4px; - border: 1px solid; - border-top: none; - color: white; - text-shadow: 0 0 1px rgba(0,0,0,.7), - 0 1px 1.5px rgba(0,0,0,.5); - font-weight: bold; - padding: 0 1.5em .05em; - margin: 0 0 2px; -} - +/** + * In the classic themes, the titlebar has a horizontal gradient, which is + * problematic for reading the text of background tabs when they're in the + * titlebar. We side-step this issue by layering our own gradient underneath + * the tabs. + */ @media (-moz-windows-classic) { - #appmenu-button { - margin-bottom: 1px; - } -} - -%ifndef WINDOWS_AERO -@media (-moz-windows-default-theme) { - #main-window[sizemode="normal"] #appmenu-button { - margin-bottom: 5px; - } -} -%endif - -#appmenu-button:hover:active, -#appmenu-button[open] { - border-radius: 0; -} - -%ifdef MOZ_OFFICIAL_BRANDING -#appmenu-button { - background-image: linear-gradient(rgb(247,182,82), rgb(215,98,10) 95%); - border-color: rgba(83,42,6,.9); - box-shadow: 0 1px 0 rgba(255,255,255,.25) inset, - 0 0 0 1px rgba(255,255,255,.25) inset; -} -#appmenu-button:hover:not(:active):not([open]) { - background-image: radial-gradient(farthest-side at bottom, rgba(252,240,89,.5) 10%, rgba(252,240,89,0) 70%), - radial-gradient(farthest-side at bottom, rgb(236,133,0), rgba(255,229,172,0)), - linear-gradient(rgb(246,170,69), rgb(209,74,0) 95%); - border-color: rgba(83,42,6,.9); - box-shadow: 0 1px 0 rgba(255,255,255,.1) inset, - 0 0 2px 1px rgba(250,234,169,.7) inset, - 0 -1px 0 rgba(250,234,169,.5) inset; -} -#appmenu-button:hover:active, -#appmenu-button[open] { - background-image: linear-gradient(rgb(246,170,69), rgb(209,74,0) 95%); - box-shadow: 0 2px 3px rgba(0,0,0,.4) inset, - 0 1px 1px rgba(0,0,0,.2) inset; -} -%else -%if MOZ_UPDATE_CHANNEL == aurora -#appmenu-button { - background-image: linear-gradient(hsl(208,99%,37%), hsl(214,90%,23%) 95%); - border-color: hsla(214,89%,21%,.9); - box-shadow: 0 1px 0 hsla(205,100%,72%,.2) inset, - 0 0 2px 1px hsla(205,100%,72%,.25) inset; -} -#appmenu-button:hover:not(:active):not([open]) { - background-image: radial-gradient(farthest-side at bottom, hsla(202,100%,85%,.5) 10%, hsla(202,100%,85%,0) 70%), - radial-gradient(farthest-side at bottom, hsla(205,100%,72%,.7), hsla(205,100%,72%,0)), - linear-gradient(hsl(208,98%,34%), hsl(213,87%,20%) 95%); - border-color: hsla(214,89%,21%,.9); - box-shadow: 0 1px 0 hsla(205,100%,72%,.15) inset, - 0 0 2px 1px hsla(205,100%,72%,.5) inset, - 0 -1px 0 hsla(205,100%,72%,.2) inset; -} -#appmenu-button:hover:active, -#appmenu-button[open] { - background-image: linear-gradient(hsl(208,95%,30%), hsl(214,85%,17%) 95%); - box-shadow: 0 2px 3px rgba(0,0,0,.4) inset, - 0 1px 1px rgba(0,0,0,.2) inset; -} -%else -#appmenu-button { - background-image: linear-gradient(hsl(211,33%,32%), hsl(209,53%,10%) 95%); - border-color: hsla(210,59%,13%,.9); - box-shadow: 0 1px 0 hsla(210,48%,90%,.15) inset, - 0 0 2px 1px hsla(211,65%,85%,.15) inset; -} -#appmenu-button:hover:not(:active):not([open]) { - background-image: radial-gradient(farthest-side at bottom, hsla(210,48%,90%,.5) 10%, hsla(210,48%,90%,0) 70%), - radial-gradient(farthest-side at bottom, hsla(211,70%,83%,.5), hsla(211,70%,83%,0)), - linear-gradient(hsl(211,33%,32%), hsl(209,53%,10%) 95%); - border-color: hsla(210,59%,13%,.9); - box-shadow: 0 1px 0 hsla(210,48%,90%,.15) inset, - 0 0 2px 1px hsla(210,48%,90%,.4) inset, - 0 -1px 0 hsla(210,48%,90%,.2) inset; -} -#appmenu-button:hover:active, -#appmenu-button[open] { - background-image: linear-gradient(hsl(211,33%,26%), hsl(209,53%,6%) 95%); - box-shadow: 0 2px 3px rgba(0,0,0,.4) inset, - 0 1px 1px rgba(0,0,0,.2) inset; -} -%endif -%endif - -#main-window[privatebrowsingmode=temporary] #appmenu-button { - background-image: linear-gradient(rgb(153,38,211), rgb(105,19,163) 95%); - border-color: rgba(43,8,65,.9); -} - -#main-window[privatebrowsingmode=temporary] #appmenu-button:hover:not(:active):not([open]) { - background-image: radial-gradient(farthest-side at bottom, rgba(240,193,255,.5) 10%, rgba(240,193,255,0) 70%), - radial-gradient(farthest-side at bottom, rgb(192,81,247), rgba(236,172,255,0)), - linear-gradient(rgb(144,20,207), rgb(95,0,158) 95%); - border-color: rgba(43,8,65,.9); - box-shadow: 0 1px 0 rgba(255,255,255,.1) inset, - 0 0 2px 1px rgba(240,193,255,.7) inset, - 0 -1px 0 rgba(240,193,255,.5) inset; -} - -#main-window[privatebrowsingmode=temporary] #appmenu-button:hover:active, -#main-window[privatebrowsingmode=temporary] #appmenu-button[open] { - background-image: linear-gradient(rgb(144,20,207), rgb(95,0,158) 95%); -} - -#appmenu-button > .button-box { - border-style: none; - padding: 0; -} - -#appmenu-button > .button-box > .button-menu-dropmarker { - list-style-image: url(appmenu-dropmarker.png); - width: auto; - height: auto; - padding: 0; - margin: 0; - -moz-margin-start: .5em; -} - -.splitmenu-menuitem { - -moz-margin-end: 1px; -%ifdef WINDOWS_AERO - -moz-padding-end: 0.5em; -%endif -} - -.splitmenu-menu { - -moz-box-pack: end; -} - -.appmenu-edit-button { - -moz-appearance: none; - border: 1px solid transparent; - padding: 2px; - background: transparent; - border-radius: 3px; -} - -.appmenu-edit-button[disabled="true"] { - opacity: .3; -} - -#appmenuPrimaryPane { - -moz-border-end: 1px solid ThreeDShadow; -} - -@media (-moz-windows-default-theme) { - #appmenu-popup { - -moz-appearance: none; - background: white; - border: 1px solid ThreeDShadow; - } - #appmenuPrimaryPane { - background-color: rgba(255,255,255,0.5); - padding: 2px; - -moz-border-end: none; - } - #appmenuSecondaryPane { - background-color: #f1f5fb; - box-shadow: 1px 0 2px rgb(204,214,234) inset; - -moz-padding-start: 3px; - -moz-padding-end: 2px; - padding-top: 2px; - padding-bottom: 2px; - font-family: "Segoe UI Semibold", "Segoe UI", sans-serif; - } - #appmenuSecondaryPane:-moz-locale-dir(rtl) { - box-shadow: -1px 0 2px rgb(204,214,234) inset; + #main-window[tabsintitlebar]:not([inFullscreen]) #TabsToolbar:not(:-moz-lwtheme) { + background: linear-gradient(to top, @toolbarShadowColor@ 2px, transparent 2px), + linear-gradient(rgba(50%,50%,50%,0), ActiveCaption 85%); } -%ifdef WINDOWS_AERO - #appmenuPrimaryPane menupopup { - -moz-appearance: none; - background-image: linear-gradient(to right, white 26px, ThreeDLightShadow 26px, - ThreeDLightShadow 27px, ThreeDHighlight 27px, - ThreeDHighlight 28px, white 28px); - border: 3px solid; - -moz-border-top-colors: ThreeDShadow white; - -moz-border-bottom-colors: ThreeDShadow white; - -moz-border-left-colors: ThreeDShadow white; - -moz-border-right-colors: ThreeDShadow white; - } -%endif - - #appmenuSecondaryPane menupopup { - -moz-appearance: none; -%ifdef WINDOWS_AERO - background-image: linear-gradient(to right, #f1f5fb 26px, ThreeDLightShadow 26px, - ThreeDLightShadow 27px, ThreeDHighlight 27px, - ThreeDHighlight 28px, #f1f5fb 28px); - border: 3px solid; - -moz-border-top-colors: ThreeDShadow #f1f5fb; - -moz-border-bottom-colors: ThreeDShadow #f1f5fb; - -moz-border-left-colors: ThreeDShadow #f1f5fb; - -moz-border-right-colors: ThreeDShadow #f1f5fb; -%else - background-color: #f1f5fb; - border: 1px solid ThreeDShadow; - padding: 2px; -%endif + #main-window[tabsintitlebar]:not([inFullscreen]) #TabsToolbar:not(:-moz-lwtheme):-moz-window-inactive { + background: linear-gradient(to top, @toolbarShadowColor@ 2px, transparent 2px), + linear-gradient(rgba(50%,50%,50%,0), InactiveCaption 85%); } -%ifdef WINDOWS_AERO - #appmenuPrimaryPane menupopup:-moz-locale-dir(rtl) { - background-image: linear-gradient(to left, white 26px, ThreeDLightShadow 26px, - ThreeDLightShadow 27px, ThreeDHighlight 27px, - ThreeDHighlight 28px, white 28px); - } - #appmenuSecondaryPane menupopup:-moz-locale-dir(rtl) { - background-image: linear-gradient(to left, #f1f5fb 26px, ThreeDLightShadow 26px, - ThreeDLightShadow 27px, ThreeDHighlight 27px, - ThreeDHighlight 28px, #f1f5fb 28px); + #main-window[tabsintitlebar][sizemode="normal"] #titlebar-content:-moz-lwtheme { + /* Render a window top border: */ + background-image: linear-gradient(to bottom, + ThreeDLightShadow 0, ThreeDLightShadow 1px, + ThreeDHighlight 1px, ThreeDHighlight 2px, + ActiveBorder 2px, ActiveBorder 4px, transparent 4px); } +} - /* Hi-DPI overrides of the menu backgrounds, to adjust where the gutter line falls */ - @media (min-resolution: 1.25dppx) { - #appmenuPrimaryPane menupopup { - background-image: linear-gradient(to right, white 22.4px, ThreeDLightShadow 22.4px, - ThreeDLightShadow 23.2px, ThreeDHighlight 23.2px, - ThreeDHighlight 24px, white 24px); - } - #appmenuSecondaryPane menupopup { - background-image: linear-gradient(to right, #f1f5fb 22.4px, ThreeDLightShadow 22.4px, - ThreeDLightShadow 23.2px, ThreeDHighlight 23.2px, - ThreeDHighlight 24px, #f1f5fb 24px); - } - #appmenuPrimaryPane menupopup:-moz-locale-dir(rtl) { - background-image: linear-gradient(to left, white 22.4px, ThreeDLightShadow 22.4px, - ThreeDLightShadow 23.2px, ThreeDHighlight 23.2px, - ThreeDHighlight 24px, white 24px); - } - #appmenuSecondaryPane menupopup:-moz-locale-dir(rtl) { - background-image: linear-gradient(to left, #f1f5fb 22.4px, ThreeDLightShadow 22.4px, - ThreeDLightShadow 23.2px, ThreeDHighlight 23.2px, - ThreeDHighlight 24px, #f1f5fb 24px); - } +/* Render a window top border for lwthemes on WinXP modern themes: */ +@media (-moz-windows-theme: luna-blue) { + #main-window[tabsintitlebar][sizemode="normal"] #titlebar-content:-moz-lwtheme { + background-image: linear-gradient(to bottom, + rgb(8, 49, 216) 0, rgb(8, 49, 216) 1px, + rgb(15, 77, 227) 1px, rgb(15, 77, 227) 2px, + rgb(22, 106, 238) 2px, rgb(22, 106, 238) 3px, + rgb(8, 85, 221) 3px, rgb(8, 85, 221) 4px, + transparent 4px); } - @media (min-resolution: 1.5dppx) { - #appmenuPrimaryPane menupopup { - background-image: linear-gradient(to right, white 20.6667px, ThreeDLightShadow 20.6667px, - ThreeDLightShadow 21.3333px, ThreeDHighlight 21.3333px, - ThreeDHighlight 22px, white 22px); - } - #appmenuSecondaryPane menupopup { - background-image: linear-gradient(to right, #f1f5fb 20.6667px, ThreeDLightShadow 20.6667px, - ThreeDLightShadow 21.3333px, ThreeDHighlight 21.3333px, - ThreeDHighlight 22px, #f1f5fb 22px); - } - #appmenuPrimaryPane menupopup:-moz-locale-dir(rtl) { - background-image: linear-gradient(to left, white 20.6667px, ThreeDLightShadow 20.6667px, - ThreeDLightShadow 21.3333px, ThreeDHighlight 21.3333px, - ThreeDHighlight 22px, white 22px); - } - #appmenuSecondaryPane menupopup:-moz-locale-dir(rtl) { - background-image: linear-gradient(to left, #f1f5fb 20.6667px, ThreeDLightShadow 20.6667px, - ThreeDLightShadow 21.3333px, ThreeDHighlight 21.3333px, - ThreeDHighlight 22px, #f1f5fb 22px); - } + #main-window[tabsintitlebar][sizemode="normal"] #titlebar-content:-moz-lwtheme:-moz-window-inactive { + background-image: linear-gradient(to bottom, + rgb(91, 104, 205) 0, rgb(91, 104, 205) 1px, + rgb(116, 128, 220) 1px, rgb(116, 128, 220) 2px, + rgb(117, 140, 221) 2px, rgb(117, 140, 221) 4px, + transparent 4px); } +} - @media (min-resolution: 2dppx) { - #appmenuPrimaryPane menupopup { - background-image: linear-gradient(to right, white 19.5px, ThreeDLightShadow 19.5px, - ThreeDLightShadow 20px, ThreeDHighlight 20px, - ThreeDHighlight 20.5px, white 20.5px); - } - #appmenuSecondaryPane menupopup { - background-image: linear-gradient(to right, #f1f5fb 19.5px, ThreeDLightShadow 19.5px, - ThreeDLightShadow 20px, ThreeDHighlight 20px, - ThreeDHighlight 20.5px, #f1f5fb 20.5px); - } - #appmenuPrimaryPane menupopup:-moz-locale-dir(rtl) { - background-image: linear-gradient(to left, white 19.5px, ThreeDLightShadow 19.5px, - ThreeDLightShadow 20px, ThreeDHighlight 20px, - ThreeDHighlight 20.5px, white 20.5px); - } - #appmenuSecondaryPane menupopup:-moz-locale-dir(rtl) { - background-image: linear-gradient(to left, #f1f5fb 19.5px, ThreeDLightShadow 19.5px, - ThreeDLightShadow 20px, ThreeDHighlight 20px, - ThreeDHighlight 20.5px, #f1f5fb 20.5px); - } +@media (-moz-windows-theme: luna-silver) { + #main-window[tabsintitlebar][sizemode="normal"] #titlebar-content:-moz-lwtheme { + background-image: linear-gradient(to bottom, + rgb(102,102,126) 0, rgb(102,102,126) 1px, + rgb(168,167,191) 1px, rgb(168,167,191) 2px, + white 2px, white 3px, + rgb(188,188,207) 3px, rgb(188,188,207) 4px, + transparent 4px); } -%endif - .appmenu-menuseparator { - -moz-appearance: none; - margin-top: 3px; - margin-bottom: 3px; -%ifdef WINDOWS_AERO - -moz-margin-start: 30px; -%else - -moz-margin-start: calc(1.45em + 4px); -%endif - padding: 0; - border-top: 1px solid #d6e5f5; - border-bottom: none; + #main-window[tabsintitlebar][sizemode="normal"] #titlebar-content:-moz-lwtheme:-moz-window-inactive { + background-image: linear-gradient(to bottom, + rgb(186,186,197) 0, rgb(186,186,197) 1px, + rgb(236,238,245) 1px, rgb(236,238,245) 2px, + white 2px, white 3px, + rgb(215,215,227) 3px, rgb(215,215,227) 4px, + transparent 4px); } +} -%ifdef WINDOWS_AERO - @media (min-resolution: 1.25dppx) { - .appmenu-menuseparator { - -moz-margin-start: 25px; - } +@media (-moz-windows-theme: luna-olive) { + #main-window[tabsintitlebar][sizemode="normal"] #titlebar-content:-moz-lwtheme { + background-image: linear-gradient(to bottom, + rgb(139,161,105) 0, rgb(139,161,105) 1px, + rgb(171, 189, 133) 1px, rgb(171, 189, 133) 2px, + rgb(164,178,127) 2px, rgb(164,178,127) 3px, + transparent 3px); } - @media (min-resolution: 1.5dppx) { - .appmenu-menuseparator { - -moz-margin-start: 24px; - } - } - @media (min-resolution: 2dppx) { - .appmenu-menuseparator { - -moz-margin-start: 22px; - } - } -%endif - .appmenu-edit-button:not([disabled]):hover { - border: 1px solid #b8d6fb; - box-shadow: inset 0 0 1px white; - background: linear-gradient(#fafbfd, #ebf3fd); - transition: .2s ease-in; + #main-window[tabsintitlebar][sizemode="normal"] #titlebar-content:-moz-lwtheme:-moz-window-inactive { + background-image: linear-gradient(to bottom, + rgb(207, 214, 188) 0, rgb(207, 214, 188) 1px, + rgb(224, 226, 200) 1px, rgb(224, 226, 200) 2px, + rgb(214, 216, 190) 2px, rgb(214, 216, 190) 3px, + transparent 3px); } } -#appmenuSecondaryPane-spacer { - min-height: 1em; -} - -#appmenu-editmenu { - -moz-box-pack: end; -} - -#appmenu_print, -#appmenu_print_popup, -.appmenu-edit-button, -#appmenu-editmenu-cut, -#appmenu-editmenu-copy, -#appmenu-editmenu-paste, -#appmenu-quit { - list-style-image: url("appmenu-icons.png"); -} - -#appmenu-cut, -#appmenu-editmenu-cut { - -moz-image-region: rect(0 16px 16px 0); -} - -#appmenu-copy, -#appmenu-editmenu-copy { - -moz-image-region: rect(0 32px 16px 16px); -} - -#appmenu-paste, -#appmenu-editmenu-paste { - -moz-image-region: rect(0 48px 16px 32px); -} - -#appmenu_print, -#appmenu_print_popup { - -moz-image-region: rect(0 64px 16px 48px); -} - -#appmenu-quit { - -moz-image-region: rect(0 80px 16px 64px); -} - -#appmenu-edit-label { - -moz-appearance: none; - background: transparent; - font-style: italic; -} - -#appmenu_bookmarks { - list-style-image: url("chrome://browser/skin/places/bookmark.png"); - -moz-image-region: rect(0px 48px 16px 32px); +#nav-bar { + background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0)); + box-shadow: 0 1px 0 @toolbarHighlight@ inset; + margin-top: -1px; /* Move up 1px into the TabsToolbar */ + /* Position the toolbar above the bottom of background tabs */ + position: relative; + z-index: 1; } -#appmenu_privateBrowsing, -#appmenu_newPrivateWindow { - list-style-image: url("chrome://browser/skin/Privacy-16.png"); +#personal-bookmarks { + min-height: 24px; } -@media (min-resolution: 1.25dppx) { - #appmenu_privateBrowsing, - #appmenu_newPrivateWindow { - list-style-image: url("chrome://browser/skin/Privacy-32.png"); - } +#print-preview-toolbar:not(:-moz-lwtheme) { + -moz-appearance: toolbox; } -#appmenu_addons { - list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric-16.png"); +#browser-bottombox:not(:-moz-lwtheme) { + background-color: -moz-dialog; } -@media (min-resolution: 1.25dppx) { - #appmenu_addons { - list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric.png"); +%ifndef WINDOWS_AERO +@media (-moz-windows-default-theme) { + #main-window[tabsintitlebar][sizemode="normal"] #toolbar-menubar { + margin-top: 4px; } } - -#BMB_bookmarkThisPage, -#appmenu_bookmarkThisPage { - list-style-image: url("chrome://browser/skin/places/bookmark.png"); - -moz-image-region: rect(0 16px 16px 0); -} +%endif /* ::::: titlebar ::::: */ @@ -543,21 +224,19 @@ } @media (-moz-windows-classic) { - #main-window[sizemode="normal"] > #titlebar > #titlebar-content > #appmenu-button-container { + #main-window[tabsintitlebar][sizemode="normal"] > #tab-view-deck > #browser-panel > #navigator-toolbox > #toolbar-menubar { margin-top: 4px; } } +/* The button box must appear on top of the navigator-toolbox in order for + * click and hover mouse events to work properly for the button in the restored + * window state. Otherwise, elements in the navigator-toolbox, like the menubar, + * can swallow those events. It will also place the buttons above the fog on + * themes with Aero Glass. + */ #titlebar-buttonbox { - -moz-appearance: -moz-window-button-box; -} - -#main-window[sizemode="maximized"] #titlebar-buttonbox { - -moz-appearance: -moz-window-button-box-maximized; -} - -.titlebar-placeholder[type="appmenu-button"] { - margin-left: 4px; + z-index: 1; } .titlebar-placeholder[type="caption-buttons"] { @@ -594,7 +273,8 @@ /* ::::: bookmark buttons ::::: */ -toolbarbutton.bookmark-item { +toolbarbutton.bookmark-item, +#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder { margin: 0; padding: 2px 3px; } @@ -607,13 +287,15 @@ toolbarbutton.bookmark-item[open="true"] { -moz-padding-end: 2px; } -.bookmark-item:not(#bookmarks-menu-button) > .toolbarbutton-icon { +.bookmark-item > .toolbarbutton-icon, +#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-icon { width: 16px; height: 16px; } -/* Prevent [mode="icons"] from hiding the label */ -.bookmark-item > .toolbarbutton-text { +/* Force the display of the label for bookmarks */ +.bookmark-item > .toolbarbutton-text, +#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-text { display: -moz-box !important; } @@ -621,12 +303,7 @@ toolbarbutton.bookmark-item[open="true"] { display: none; } -#wrapper-personal-bookmarks[place="palette"] > .toolbarpaletteitem-box { - background: url("chrome://browser/skin/places/bookmarksToolbar.png") no-repeat center; -} - -.bookmarks-toolbar-customize { - max-width: 15em !important; +#bookmarks-toolbar-placeholder { list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png") !important; } @@ -713,19 +390,23 @@ menuitem.bookmark-item { /* ::::: primary toolbar buttons ::::: */ -.toolbarbutton-1 { - list-style-image: url("chrome://browser/skin/Toolbar.png"); -} +%include ../shared/toolbarbuttons.inc.css +%include ../shared/menupanel.inc.css -.toolbarbutton-1:-moz-lwtheme-brighttext { - list-style-image: url("chrome://browser/skin/Toolbar-inverted.png"); +%ifndef WINDOWS_AERO +@media (-moz-windows-theme: luna-silver) { + :-moz-any(@primaryToolbarButtons@), + #bookmarks-menu-button.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { + list-style-image: url("chrome://browser/skin/Toolbar-lunaSilver.png"); + } } +%endif -.toolbarbutton-1[disabled=true] > .toolbarbutton-icon, -.toolbarbutton-1[disabled=true] > .toolbarbutton-menu-dropmarker, -.toolbarbutton-1[disabled=true] > .toolbarbutton-menubutton-dropmarker, -.toolbarbutton-1[disabled=true] > .toolbarbutton-menubutton-button > .toolbarbutton-icon, -.toolbarbutton-1 > .toolbarbutton-menubutton-button[disabled] > .toolbarbutton-icon { +#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-icon, +#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-menu-dropmarker, +#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-menubutton-dropmarker, +#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-menubutton-button > .toolbarbutton-icon, +#main-window:not([customizing]) .toolbarbutton-1 > .toolbarbutton-menubutton-button[disabled] > .toolbarbutton-icon { opacity: .4; } @@ -744,57 +425,44 @@ menuitem.bookmark-item { -moz-margin-end: 0; } -toolbar[mode=full] .toolbarbutton-1:not([type=menu-button]) { - -moz-box-orient: vertical; -} - -toolbar[mode=full] .toolbarbutton-1, -toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button { - min-width: 57px; -} - -#nav-bar { - /* force iconsize="small" on this toolbar */ - counter-reset: smallicons; -} - -@navbarLargeIcons@ .toolbarbutton-1, -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button { +#nav-bar .toolbarbutton-1, +#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button { -moz-appearance: none; border: none; padding: 0; background: none; } -@navbarLargeIcons@ .toolbarbutton-1:not([type=menu-button]), -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button, -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker { - padding: 5px 2px; +#nav-bar .toolbarbutton-1:not([type=menu-button]), +#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button, +#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker { + padding: 8px 2px; -moz-box-pack: center; } -@navbarLargeIcons@ .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button):not(#social-provider-button) { +#nav-bar .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button):not(#social-provider-button):not(#PanelUI-menu-button) { padding-left: 5px; padding-right: 5px; } -@navbarLargeIcons@ .toolbarbutton-1 > menupopup { +#nav-bar .toolbarbutton-1 > menupopup { margin-top: -3px; } -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button { +#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button { -moz-padding-end: 0; } -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker { +#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker { -moz-padding-start: 0; -moz-box-align: center; } -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-icon, -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-badge-container, -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon, -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { +#nav-bar .toolbarbutton-1 > .toolbarbutton-icon, +#nav-bar .toolbarbutton-1 > .toolbarbutton-text, +#nav-bar .toolbarbutton-1 > .toolbarbutton-badge-container, +#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon, +#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { padding: 2px 6px; background: hsla(210,32%,93%,0) padding-box; border-radius: 2px; @@ -807,41 +475,41 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button { transition-duration: 150ms; } -@navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon, -@navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-container, -@navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-menubutton-button > .toolbarbutton-icon { +#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon, +#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-container, +#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-menubutton-button > .toolbarbutton-icon { padding: 3px 7px; } -@navbarLargeIcons@ .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button):not(#social-provider-button) > .toolbarbutton-icon, -@navbarLargeIcons@ .toolbarbutton-1[type=menu] > .toolbarbutton-text /* hack for add-ons that forcefully display the label */ { +#nav-bar .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button):not(#social-provider-button):not(#PanelUI-menu-button) > .toolbarbutton-icon, +#nav-bar .toolbarbutton-1[type=menu] > .toolbarbutton-text /* hack for add-ons that forcefully display the label */ { -moz-padding-end: 17px; } -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menu-dropmarker { +#nav-bar .toolbarbutton-1 > .toolbarbutton-menu-dropmarker { -moz-margin-start: -15px; } -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon { +#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon { -moz-border-end: none; } -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { +#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { padding: 8px 5px 7px; } -@navbarLargeIcons@ #social-toolbar-item { +#nav-bar .toolbaritem-combined-buttons { margin-left: 2px; margin-right: 2px; } -@navbarLargeIcons@ #social-toolbar-item > .toolbarbutton-1 { +#nav-bar .toolbaritem-combined-buttons > .toolbarbutton-1 { padding-left: 0; padding-right: 0; } -@navbarLargeIcons@ .toolbarbutton-1:not(:hover):not(:active):not([open]) > .toolbarbutton-menubutton-dropmarker::before, -@navbarLargeIcons@ #social-toolbar-item > .toolbarbutton-1:not(:hover):not(:active):not([open]) + .toolbarbutton-1:not(:hover):not(:active):not([open])::before { +#nav-bar .toolbarbutton-1:not(:hover):not(:active):not([open]) > .toolbarbutton-menubutton-dropmarker::before, +#nav-bar .toolbaritem-combined-buttons > .toolbarbutton-1:-moz-any(:not(:hover):not([open]),[disabled]) + .toolbarbutton-1:-moz-any(:not(:hover):not([open]),[disabled])::before { content: ""; display: -moz-box; width: 1px; @@ -855,22 +523,23 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button { box-shadow: 0 0 0 1px hsla(0,0%,100%,.2); } -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon:-moz-locale-dir(ltr), -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-locale-dir(rtl) { +#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon:-moz-locale-dir(ltr), +#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-locale-dir(rtl) { border-top-right-radius: 0; border-bottom-right-radius: 0; } -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon:-moz-locale-dir(rtl), -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-locale-dir(ltr) { +#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon:-moz-locale-dir(rtl), +#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-locale-dir(ltr) { border-top-left-radius: 0; border-bottom-left-radius: 0; } -@navbarLargeIcons@ .toolbarbutton-1:not([disabled]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-button > .toolbarbutton-icon, -@navbarLargeIcons@ .toolbarbutton-1:not([disabled]):hover > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon, -@navbarLargeIcons@ .toolbarbutton-1:not([disabled]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-icon, -@navbarLargeIcons@ .toolbarbutton-1:not([disabled]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-badge-container, +#nav-bar .toolbarbutton-1:not([disabled]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-button > .toolbarbutton-icon, +#nav-bar .toolbarbutton-1:not([disabled]):hover > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon, +#nav-bar .toolbarbutton-1:not([disabled]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-icon, +#nav-bar .toolbarbutton-1:not([disabled]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-text, +#nav-bar .toolbarbutton-1:not([disabled]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-badge-container, @conditionalForwardWithUrlbar@ > .toolbarbutton-1:-moz-any([disabled],:not([open]):not([disabled]):not(:active)) > .toolbarbutton-icon { background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1)); border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.2) hsla(210,54%,20%,.25); @@ -879,8 +548,8 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button { 0 0 2px hsla(210,54%,20%,.1); } -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):not([open]):not(:active):hover > .toolbarbutton-icon, -@navbarLargeIcons@ .toolbarbutton-1:not([buttonover]):not([open]):not(:active):hover > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon, +#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):not([open]):not(:active):hover > .toolbarbutton-icon, +#nav-bar .toolbarbutton-1:not([buttonover]):not([open]):not(:active):hover > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon, @conditionalForwardWithUrlbar@ > #forward-button:not([open]):not(:active):not([disabled]):hover > .toolbarbutton-icon { border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4); background-color: hsla(210,48%,96%,.75); @@ -888,10 +557,11 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button { 0 0 2px hsla(210,54%,20%,.1); } -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):hover:active > .toolbarbutton-icon, -@navbarLargeIcons@ .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon, -@navbarLargeIcons@ .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon, -@navbarLargeIcons@ .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container { +#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):hover:active > .toolbarbutton-icon, +#nav-bar .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon, +#nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon, +#nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-text, +#nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container { background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1)); background-color: hsla(210,54%,20%,.15); border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4); @@ -904,17 +574,17 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button { transition: none; } -@navbarLargeIcons@ .toolbarbutton-1:-moz-any(:hover,[open]) > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon { +#nav-bar .toolbarbutton-1:-moz-any(:hover,[open]) > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon { -moz-border-start-color: hsla(210,54%,20%,.35); } -@navbarLargeIcons@ .toolbarbutton-1[checked]:not(:active):hover > .toolbarbutton-icon { +#nav-bar .toolbarbutton-1[checked]:not(:active):hover > .toolbarbutton-icon { background-color: rgba(90%,90%,90%,.4); transition: background-color .4s; } -:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1, -:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button, +#TabsToolbar .toolbarbutton-1, +#TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button, .tabbrowser-arrowscrollbox > .scrollbutton-up, .tabbrowser-arrowscrollbox > .scrollbutton-down { -moz-appearance: none; @@ -935,53 +605,24 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button { background-repeat: no-repeat; } -#addon-bar .toolbarbutton-1:not([disabled]):hover, -#addon-bar .toolbarbutton-1[open], -#addon-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):hover { - background-image: linear-gradient(to top, transparent, rgba(0,0,0,.15)), - linear-gradient(to top, transparent, rgba(0,0,0,.15) 30%), - linear-gradient(to top, transparent, rgba(0,0,0,.15) 30%); - background-position: left, left, right; - background-size: auto, 1px 100%, 1px 100%; - background-repeat: no-repeat; -} - /* unified back/forward button */ -#back-button { - -moz-image-region: rect(0, 18px, 18px, 0); -} - #forward-button { - -moz-image-region: rect(0, 36px, 18px, 18px); -} - -#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon, -#forward-button:-moz-locale-dir(rtl), -#forward-button:-moz-locale-dir(rtl) > .toolbarbutton-text { - transform: scaleX(-1); -} - -@conditionalForwardWithUrlbar@ { - -moz-box-align: center; + padding: 0 !important; } -@conditionalForwardWithUrlbar@ > #forward-button { - padding: 0; +#forward-button > menupopup { + margin-top: 1px !important; } -@conditionalForwardWithUrlbar@ > #forward-button > menupopup { - margin-top: 1px; -} - -@conditionalForwardWithUrlbar@ > #forward-button > .toolbarbutton-icon { +#forward-button > .toolbarbutton-icon { /*mask: url(keyhole-forward-mask.svg#mask); XXX: this regresses twinopen */ - clip-path: url(chrome://browser/content/browser.xul#windows-keyhole-forward-clip-path); - -moz-margin-start: -6px !important; - border-left-style: none; - border-radius: 0; - padding-left: 7px; - padding-right: 3px; + clip-path: url(chrome://browser/content/browser.xul#windows-keyhole-forward-clip-path) !important; + margin-left: -6px !important; + border-left-style: none !important; + border-radius: 0 !important; + padding-left: 7px !important; + padding-right: 3px !important; } @conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button { @@ -992,60 +633,58 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button { opacity: 0; } -@conditionalForwardWithUrlbar@ > #back-button { - -moz-image-region: rect(18px, 20px, 38px, 0); - padding-top: 3px; - padding-bottom: 3px; - -moz-padding-start: 5px; - -moz-padding-end: 0; - position: relative; - z-index: 1; - border-radius: 0 10000px 10000px 0; +#back-button { + padding-top: 3px !important; + padding-bottom: 3px !important; + -moz-padding-start: 5px !important; + -moz-padding-end: 0 !important; + position: relative !important; + z-index: 1 !important; + border-radius: 0 10000px 10000px 0 !important; } -@conditionalForwardWithUrlbar@ > #back-button:-moz-locale-dir(rtl) { - border-radius: 10000px 0 0 10000px; +#back-button:-moz-locale-dir(rtl) { + border-radius: 10000px 0 0 10000px !important; } -@conditionalForwardWithUrlbar@ > #back-button > menupopup { - margin-top: -1px; +#back-button > menupopup { + margin-top: -1px !important; } -@conditionalForwardWithUrlbar@ > #back-button > .toolbarbutton-icon { - border-radius: 10000px; - padding: 5px; - border: none; - background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1)); +#back-button > .toolbarbutton-icon { + border-radius: 10000px !important; + padding: 5px !important; + border: none !important; + background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1)) !important; box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset, 0 0 0 1px hsla(0,0%,100%,.3) inset, 0 0 0 1px hsla(210,54%,20%,.25), - 0 1px 0 hsla(210,54%,20%,.35); - transition-property: background-color, box-shadow; - transition-duration: 250ms; + 0 1px 0 hsla(210,54%,20%,.35) !important; + transition-property: background-color, box-shadow !important; } -@conditionalForwardWithUrlbar@ > #back-button:not([disabled="true"]):not([open="true"]):not(:active):hover > .toolbarbutton-icon { - background-color: hsla(210,48%,96%,.75); +#back-button:not([disabled="true"]):not([open="true"]):not(:active):hover > .toolbarbutton-icon { + background-color: hsla(210,48%,96%,.75) !important; box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset, 0 0 0 1px hsla(0,0%,100%,.3) inset, 0 0 0 1px hsla(210,54%,20%,.3), 0 1px 0 hsla(210,54%,20%,.4), - 0 0 4px hsla(210,54%,20%,.2); + 0 0 4px hsla(210,54%,20%,.2) !important; } -@conditionalForwardWithUrlbar@ > #back-button:not([disabled="true"]):hover:active > .toolbarbutton-icon, -@conditionalForwardWithUrlbar@ > #back-button[open="true"] > .toolbarbutton-icon { - background-color: hsla(210,54%,20%,.15); +#back-button:not([disabled="true"]):hover:active > .toolbarbutton-icon, +#back-button[open="true"] > .toolbarbutton-icon { + background-color: hsla(210,54%,20%,.15) !important; box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset, 0 0 1px hsla(210,54%,20%,.2) inset, 0 0 0 1px hsla(210,54%,20%,.4), - 0 1px 0 hsla(210,54%,20%,.2); + 0 1px 0 hsla(210,54%,20%,.2) !important; transition: none; } -@conditionalForwardWithUrlbar@ > #back-button[disabled] > .toolbarbutton-icon { +#main-window:not([customizing]) #back-button[disabled] > .toolbarbutton-icon { box-shadow: 0 0 0 1px hsla(210,54%,20%,.55), - 0 1px 0 hsla(210,54%,20%,.65); + 0 1px 0 hsla(210,54%,20%,.65) !important; transition: none; } @@ -1059,97 +698,18 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button { list-style-image: url("chrome://browser/skin/menu-forward.png") !important; } -#stop-button { - -moz-image-region: rect(0, 54px, 18px, 36px); -} - -#reload-button { - -moz-image-region: rect(0, 72px, 18px, 54px); -} - #home-button.bookmark-item { list-style-image: url("chrome://browser/skin/Toolbar.png"); } #home-button.bookmark-item:-moz-lwtheme-brighttext { list-style-image: url("chrome://browser/skin/Toolbar-inverted.png"); } -#home-button { - -moz-image-region: rect(0, 90px, 18px, 72px); -} - -#downloads-button { - -moz-image-region: rect(0, 108px, 18px, 90px); -} - -#history-button { - -moz-image-region: rect(0, 126px, 18px, 108px); -} - -#bookmarks-button, -#bookmarks-menu-button { - -moz-image-region: rect(0, 144px, 18px, 126px); -} - -#bookmarks-menu-button.bookmark-item { - list-style-image: url("chrome://browser/skin/Toolbar.png"); -} - -#bookmarks-menu-button.bookmark-item:-moz-lwtheme-brighttext { - list-style-image: url("chrome://browser/skin/Toolbar-inverted.png"); -} - -#print-button { - -moz-image-region: rect(0, 162px, 18px, 144px); -} - -#new-tab-button { - -moz-image-region: rect(0, 180px, 18px, 162px); -} - -#new-window-button { - -moz-image-region: rect(0, 198px, 18px, 180px); -} - -#cut-button { - -moz-image-region: rect(0, 216px, 18px, 198px); -} - -#copy-button { - -moz-image-region: rect(0, 234px, 18px, 216px); -} - -#paste-button { - -moz-image-region: rect(0, 252px, 18px, 234px); -} - -#fullscreen-button { - -moz-image-region: rect(0, 270px, 18px, 252px); -} - -#zoom-out-button { - -moz-image-region: rect(0, 288px, 18px, 270px); -} -#zoom-in-button { - -moz-image-region: rect(0, 306px, 18px, 288px); -} - -#sync-button { - -moz-image-region: rect(0, 324px, 18px, 306px); -} #sync-button[status="active"] { list-style-image: url("chrome://browser/skin/sync-throbber.png"); -moz-image-region: rect(0, 18px, 18px, 0); } -#feed-button { - -moz-image-region: rect(0, 342px, 18px, 324px); -} - -#webrtc-status-button { - -moz-image-region: rect(0, 360px, 18px, 342px); -} - /* tabview button & menu item */ #tabview-button, @@ -1157,10 +717,6 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button { list-style-image: url(chrome://browser/skin/tabview/tabview.png); } -%ifdef WINDOWS_AERO -:-moz-any(#TabsToolbar, #nav-bar[tabsontop=false], #toolbar-menubar) > #tabview-button:-moz-system-metric(windows-compositor):not(:-moz-lwtheme), -:-moz-any(#TabsToolbar, #nav-bar[tabsontop=false], #toolbar-menubar) > toolbarpaletteitem > #tabview-button:-moz-system-metric(windows-compositor):not(:-moz-lwtheme), -%endif #tabview-button:-moz-lwtheme-brighttext { list-style-image: url(chrome://browser/skin/tabview/tabview-inverted.png); } @@ -1280,53 +836,53 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button { color: black; } -@conditionalForwardWithUrlbar@ + #urlbar-container { +@conditionalForwardWithUrlbar@ > #urlbar-wrapper { padding-left: @conditionalForwardWithUrlbarWidth@px; -moz-margin-start: -@conditionalForwardWithUrlbarWidth@px; position: relative; pointer-events: none; } -@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar { +@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar { -moz-border-start: none; margin-left: 0; pointer-events: all; } -@conditionalForwardWithUrlbar@:not([switchingtabs]) + #urlbar-container > #urlbar { +@conditionalForwardWithUrlbar@:not([switchingtabs]) > #urlbar-wrapper > #urlbar { transition: margin-left @forwardTransitionLength@ ease-out; } -@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(ltr) { +@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(ltr) { border-top-left-radius: 0; border-bottom-left-radius: 0; } -@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(rtl) { +@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) { border-top-right-radius: 0; border-bottom-right-radius: 0; } -@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container { +@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper { clip-path: url("chrome://browser/content/browser.xul#windows-urlbar-back-button-clip-path"); } -@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar { +@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar { margin-left: -@conditionalForwardWithUrlbarWidth@px; } -@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) + #urlbar-container > #urlbar { +@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar { /* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */ transition-delay: 100s; } -@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar { +@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar { /* when not hovered anymore, trigger a new transition to hide the forward button immediately */ margin-left: -@conditionalForwardWithUrlbarWidth@.01px; } -@conditionalForwardWithUrlbar@ + #urlbar-container:-moz-locale-dir(rtl), -@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(rtl) { +@conditionalForwardWithUrlbar@ > #urlbar-wrapper:-moz-locale-dir(rtl), +@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) { /* let windows-urlbar-back-button-mask clip the urlbar's right side for RTL */ transform: scaleX(-1); } @@ -1343,8 +899,7 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder, } #urlbar-container { - -moz-box-orient: horizontal; - -moz-box-align: stretch; + -moz-box-align: center; } .urlbar-textbox-container { @@ -1385,7 +940,7 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder, background: transparent; } -#urlbar-search-splitter + #urlbar-container > #urlbar , +#urlbar-search-splitter + #urlbar-container > #urlbar-wrapper > #urlbar, #urlbar-search-splitter + #search-container > #searchbar > .searchbar-textbox { -moz-margin-start: 0; } @@ -1424,31 +979,31 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder, border-radius: 0; } -@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar > #identity-box { +@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar > #identity-box { border-radius: 0; } -@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) { +@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) { padding-left: 5px; transition: padding-left; } -@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) { +@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) { padding-right: 5px; transition: padding-right; } -@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box { +@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box { /* forward button hiding is delayed when hovered */ transition-delay: 100s; } -@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) { +@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) { /* when not hovered anymore, trigger a new non-delayed transition to react to the forward button hiding */ padding-left: 5.01px; } -@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) { +@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) { /* when not hovered anymore, trigger a new non-delayed transition to react to the forward button hiding */ padding-right: 5.01px; } @@ -1507,7 +1062,7 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder, -moz-image-region: rect(0, 16px, 16px, 0); } -@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar > #identity-box > #page-proxy-favicon { +@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar > #identity-box > #page-proxy-favicon { -moz-margin-end: 1px; } @@ -1611,7 +1166,6 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- /* combined go/reload/stop button in location bar */ -#go-button, #urlbar > toolbarbutton { -moz-appearance: none; padding: 0 2px; @@ -1620,10 +1174,6 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- list-style-image: url("chrome://browser/skin/reload-stop-go.png"); } -#go-button { - padding: 0 3px; -} - #urlbar-reload-button { -moz-image-region: rect(0, 14px, 14px, 0); } @@ -1642,24 +1192,20 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- transform: scaleX(-1); } -#go-button, #urlbar-go-button { -moz-image-region: rect(0, 42px, 14px, 28px); } -#go-button:hover, #urlbar-go-button:hover { background-image: radial-gradient(circle closest-side, hsla(110,70%,50%,.2), hsla(110,70%,50%,0)); -moz-image-region: rect(14px, 42px, 28px, 28px); } -#go-button:hover:active, #urlbar-go-button:hover:active { background-image: radial-gradient(circle closest-side, hsla(110,70%,50%,.1), hsla(110,70%,50%,0)); -moz-image-region: rect(28px, 42px, 42px, 28px); } -#go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon, #urlbar-go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon { transform: scaleX(-1); } @@ -1703,11 +1249,6 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- height: 150px; } -#social-share-button { - list-style-image: url(chrome://browser/skin/social/share-button.png); - -moz-image-region: rect(0, 16px, 16px, 0); -} - .social-share-toolbar { border-right: 1px solid #e2e5e8; background: linear-gradient(to bottom, #ffffff, #f5f7fa); @@ -1807,25 +1348,36 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- -moz-image-region: rect(0, 16px, 16px, 0); } -/* star button */ +/* bookmarks menu-button */ -#star-button { +#bookmarks-menu-button.bookmark-item { list-style-image: url("chrome://browser/skin/places/bookmark.png"); -moz-image-region: rect(0px 16px 16px 0px); } -#star-button:hover { - background-image: radial-gradient(circle closest-side, hsla(45,100%,73%,.3), hsla(45,100%,73%,0)); - -moz-image-region: rect(0px 32px 16px 16px); +#bookmarks-menu-button.bookmark-item[starred] { + -moz-image-region: rect(0px 48px 16px 32px); } -#star-button:hover:active { - background-image: radial-gradient(circle closest-side, hsla(45,100%,73%,.1), hsla(45,100%,73%,0)); - -moz-image-region: rect(0px 48px 16px 32px); +#bookmarks-menu-button.bookmark-item > .toolbarbutton-menubutton-button > .toolbarbutton-icon { + -moz-margin-start: 5px; +} + +#bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { + padding-top: 2px; + padding-bottom: 2px; +} + +#BMB_bookmarksPopup[side="top"], +#BMB_bookmarksPopup[side="bottom"] { + margin-left: -20px; + margin-right: -20px; } -#star-button[starred] { - list-style-image: url("chrome://browser/skin/places/editBookmark.png"); +#BMB_bookmarksPopup[side="left"], +#BMB_bookmarksPopup[side="right"] { + margin-top: -20px; + margin-bottom: -20px; } /* bookmarking panel */ @@ -1880,21 +1432,11 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- .panel-promo-closebutton { -moz-appearance: none; - list-style-image: url("chrome://global/skin/icons/close.png"); - -moz-image-region: rect(0, 16px, 16px, 0); border: none; -moz-margin-end: -10px; margin-top: -5px; } -.panel-promo-closebutton:hover { - -moz-image-region: rect(0, 32px, 16px, 16px); -} - -.panel-promo-closebutton:hover:active { - -moz-image-region: rect(0, 48px, 16px, 32px); -} - .panel-promo-closebutton > .toolbarbutton-text { padding: 0; margin: 0; @@ -1916,23 +1458,6 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- text-shadow: none; } -/* ::::: throbber ::::: */ - -#navigator-throbber { - width: 16px; - min-height: 16px; - margin: 0 3px; -} - -#navigator-throbber[busy="true"] { - list-style-image: url("chrome://global/skin/icons/loading_16.png"); -} - -#navigator-throbber, -#wrapper-navigator-throbber > #navigator-throbber { - list-style-image: url("chrome://global/skin/icons/notloading_16.png"); -} - /* Tabstrip */ #TabsToolbar { @@ -1940,9 +1465,12 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- padding: 0; } -#TabsToolbar:not(:-moz-lwtheme), -#TabsToolbar[tabsontop=false] { - background-image: linear-gradient(to top, @toolbarShadowColor@ 1px, rgba(0,0,0,.05) 1px, transparent 50%); +#TabsToolbar:not(:-moz-lwtheme) { + background-image: linear-gradient(to top, @toolbarShadowColor@ 2px, rgba(0,0,0,.05) 2px, transparent 50%); +} + +#main-window[tabsintitlebar] #TabsToolbar { + background-color: transparent; } %ifndef WINDOWS_AERO @@ -1954,151 +1482,66 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- } %endif -.tabbrowser-tab, -.tabs-newtab-button { - -moz-appearance: none; - background: @toolbarShadowOnTab@, @bgTabTexture@, - linear-gradient(-moz-dialog, -moz-dialog); - background-origin: border-box; - background-position: 1px 2px; - background-size: calc(100% - 2px) calc(100% - 2px); - background-repeat: no-repeat; - margin: 0; - padding: 2px 0 4px; - border-width: 4px 3px 0; - border-style: solid; - border-image: url(tabbrowser/tab.png) 4 3 0 fill repeat stretch; - border-radius: 0; -} - -.tabbrowser-tab[remote] { - text-decoration: underline; -} - -.tabbrowser-tab:hover, -.tabs-newtab-button:hover { - background-image: @toolbarShadowOnTab@, @bgTabTextureHover@, - linear-gradient(-moz-dialog, -moz-dialog); -} +%include ../shared/tabs.inc.css %ifndef WINDOWS_AERO +/* Use lighter colors of buttons and text in the titlebar on luna-blue */ @media (-moz-windows-theme: luna-blue) { - .tabbrowser-tab, - .tabs-newtab-button { - background-image: @toolbarShadowOnTab@, - linear-gradient(hsla(51,34%,89%,.9), hsla(51,15%,79%,.9) 1px, hsla(51,9%,68%,.9)); + #main-window[tabsintitlebar]:not([inFullscreen]) .tabbrowser-arrowscrollbox > .scrollbutton-up, + #main-window[tabsintitlebar]:not([inFullscreen]) .tabbrowser-arrowscrollbox > .scrollbutton-down { + list-style-image: url(chrome://browser/skin/tabbrowser/tab-arrow-left-inverted.png); } - .tabbrowser-tab:hover, - .tabs-newtab-button:hover { - background-image: @toolbarShadowOnTab@, - linear-gradient(hsla(51,34%,100%,.9), hsla(51,15%,94%,.9) 1px, hsla(51,9%,83%,.9)); + #main-window[tabsintitlebar]:not([inFullscreen]) .tabs-newtab-button, + #main-window[tabsintitlebar]:not([inFullscreen]) #TabsToolbar > #new-tab-button, + #main-window[tabsintitlebar]:not([inFullscreen]) #TabsToolbar > toolbarpaletteitem > #new-tab-button { + list-style-image: url(chrome://browser/skin/tabbrowser/newtab-inverted.png); } -} -%endif - -.tabbrowser-tab[selected="true"] { - background-image: linear-gradient(@selectedTabHighlight@, @toolbarHighlight@ 50%), - linear-gradient(-moz-dialog, -moz-dialog); -} - -#main-window[tabsontop=false]:not([disablechrome]) .tabbrowser-tab[selected=true]:not(:-moz-lwtheme) { - background-image: @toolbarShadowOnTab@, - linear-gradient(@selectedTabHighlight@, @toolbarHighlight@ 50%), - linear-gradient(-moz-dialog, -moz-dialog); -} -.tabbrowser-tab:-moz-lwtheme { - color: inherit; -} - -.tabbrowser-tab[selected="true"]:-moz-lwtheme { - background-image: linear-gradient(@selectedTabHighlight@, @toolbarHighlight@ 50%); -} - -.tabbrowser-tab:-moz-lwtheme-brighttext:not([selected="true"]), -.tabs-newtab-button:-moz-lwtheme-brighttext { - background-image: linear-gradient(hsla(0,0%,40%,.6), hsla(0,0%,30%,.6) 80%); -} - -.tabbrowser-tab:-moz-lwtheme-brighttext:not([selected="true"]):hover, -.tabs-newtab-button:-moz-lwtheme-brighttext:hover { - background-image: linear-gradient(hsla(0,0%,60%,.6), hsla(0,0%,45%,.6) 80%); -} - -.tabbrowser-tab:-moz-lwtheme-darktext:not([selected="true"]), -.tabs-newtab-button:-moz-lwtheme-darktext { - background-image: linear-gradient(hsla(0,0%,60%,.5), hsla(0,0%,45%,.5) 80%); -} - -.tabbrowser-tab:-moz-lwtheme-darktext:not([selected="true"]):hover, -.tabs-newtab-button:-moz-lwtheme-darktext:hover { - background-image: linear-gradient(hsla(0,0%,80%,.5), hsla(0,0%,60%,.5) 80%); -} + #main-window[tabsintitlebar]:not([inFullscreen]) #alltabs-button { + list-style-image: url("chrome://browser/skin/toolbarbutton-dropdown-arrow-inverted.png"); + } -.tabbrowser-tab[pinned][titlechanged]:not([selected="true"]) { - background-image: radial-gradient(circle farthest-corner at 50% 3px, rgba(255,255,255,1) 3%, rgba(186,221,251,.75) 40%, rgba(127,179,255,.5) 80%, rgba(127,179,255,.25)); -} -.tabbrowser-tab[pinned][titlechanged]:not([selected="true"]):hover { - background-image: linear-gradient(hsla(0,0%,100%,.4), hsla(0,0%,75%,.4) 80%), - radial-gradient(circle farthest-corner at 50% 3px, rgba(255,255,255,1) 3%, rgba(186,221,251,.75) 40%, rgba(127,179,255,.5) 80%, rgba(127,179,255,.25)); -} + #main-window[tabsintitlebar]:not([inFullscreen]) #TabsToolbar > #tabview-button { + list-style-image: url(chrome://browser/skin/tabview/tabview-inverted.png); + } -.tab-throbber, -.tab-icon-image { - width: 16px; - height: 16px; - list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png"); - -moz-margin-start: 2px; - -moz-margin-end: 3px; -} + #main-window[tabsintitlebar]:not([inFullscreen]) .tab-close-button:not(:-moz-any(:hover,:-moz-lwtheme,[selected="true"])) { + -moz-image-region: rect(0, 64px, 16px, 48px); + } -.tab-throbber { - list-style-image: url("chrome://browser/skin/tabbrowser/connecting.png"); + #tabbrowser-tabs[movingtab] > .tabbrowser-tab[beforeselected]:not([last-visible-tab])::after, + .tabbrowser-tab:not([selected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before, + #tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([selected]):not([beforehovered]):not(:hover)::after { + background-image: url("chrome://browser/skin/tabbrowser/tab-separator-luna-blue.png"); + } } +%endif -.tab-throbber[progress] { - list-style-image: url("chrome://browser/skin/tabbrowser/loading.png"); +.tab-close-button:not(:hover):not([selected="true"]):-moz-lwtheme-brighttext { + -moz-image-region: rect(0, 64px, 16px, 48px) !important; } -.tab-throbber[pinned], -.tab-icon-image[pinned] { - -moz-margin-start: 5px; - -moz-margin-end: 5px; +#main-window[tabsintitlebar]:not([inFullscreen]) .tabbrowser-tab:not([selected]):not(:-moz-lwtheme) { + color: CaptionText; } /* tabbrowser-tab focus ring */ -.tabbrowser-tab:focus > .tab-stack { +.tabbrowser-tab:focus > .tab-stack > .tab-content > .tab-label { outline: 1px dotted; } /* Tab DnD indicator */ .tab-drop-indicator { list-style-image: url(chrome://browser/skin/tabbrowser/tabDragIndicator.png); - margin-bottom: -11px; + margin-bottom: -9px; + z-index: 3; } /* Tab close button */ .tab-close-button { -moz-appearance: none; - -moz-image-region: rect(0, 64px, 16px, 48px); border: none; - padding: 0px; - list-style-image: url("chrome://global/skin/icons/close.png"); -} - -.tab-close-button:hover, -.tab-close-button:hover[selected="true"] { - -moz-image-region: rect(0, 32px, 16px, 16px); -} - -.tab-close-button:hover:active, -.tab-close-button:hover:active[selected="true"] { - -moz-image-region: rect(0, 48px, 16px, 32px); -} - -.tab-close-button[selected="true"] { - -moz-image-region: rect(0, 16px, 16px, 0); } /* Tab scrollbox arrow, tabstrip new tab and all-tabs buttons */ @@ -2112,10 +1555,6 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- background-origin: border-box; } -%ifdef WINDOWS_AERO -.tabbrowser-arrowscrollbox > .scrollbutton-up:-moz-system-metric(windows-compositor):not(:-moz-lwtheme), -.tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-system-metric(windows-compositor):not(:-moz-lwtheme), -%endif .tabbrowser-arrowscrollbox > .scrollbutton-up:-moz-lwtheme-brighttext, .tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-lwtheme-brighttext { list-style-image: url(chrome://browser/skin/tabbrowser/tab-arrow-left-inverted.png); @@ -2159,20 +1598,12 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- -moz-image-region: auto; } -%ifdef WINDOWS_AERO -#TabsToolbar > #new-tab-button:-moz-system-metric(windows-compositor):not(:-moz-lwtheme), -#TabsToolbar > toolbarpaletteitem > #new-tab-button:-moz-system-metric(windows-compositor):not(:-moz-lwtheme), -%endif .tabs-newtab-button:-moz-lwtheme-brighttext, #TabsToolbar > #new-tab-button:-moz-lwtheme-brighttext, #TabsToolbar > toolbarpaletteitem > #new-tab-button:-moz-lwtheme-brighttext { list-style-image: url(chrome://browser/skin/tabbrowser/newtab-inverted.png); } -.tabs-newtab-button { - width: 28px; -} - #TabsToolbar > #new-tab-button { width: 26px; } @@ -2181,10 +1612,6 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- list-style-image: url("chrome://browser/skin/toolbarbutton-dropdown-arrow.png"); } -%ifdef WINDOWS_AERO -:-moz-any(#TabsToolbar, #nav-bar[tabsontop=false], #toolbar-menubar) > #alltabs-button:-moz-system-metric(windows-compositor):not(:-moz-lwtheme), -:-moz-any(#TabsToolbar, #nav-bar[tabsontop=false], #toolbar-menubar) > toolbarpaletteitem > #alltabs-button:-moz-system-metric(windows-compositor):not(:-moz-lwtheme), -%endif #alltabs-button:-moz-lwtheme-brighttext { list-style-image: url("chrome://browser/skin/toolbarbutton-dropdown-arrow-inverted.png"); } @@ -2218,8 +1645,6 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- /* Tabstrip close button */ .tabs-closebutton { -moz-appearance: none; - list-style-image: url("chrome://global/skin/icons/close.png"); - -moz-image-region: rect(0, 16px, 16px, 0); padding: 4px 2px; margin: 0px; border: none; @@ -2231,14 +1656,6 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- -moz-padding-start: 2px !important; } -.tabs-closebutton:hover { - -moz-image-region: rect(0, 32px, 16px, 16px); -} - -.tabs-closebutton:hover:active { - -moz-image-region: rect(0, 48px, 16px, 32px); -} - toolbarbutton.chevron { list-style-image: url("chrome://global/skin/toolbar/chevron.gif") !important; } @@ -2256,10 +1673,6 @@ toolbarbutton.chevron > .toolbarbutton-icon { margin: 0; } -toolbar[mode="text"] toolbarbutton.chevron > .toolbarbutton-icon { - display: -moz-box; /* display chevron icon in text mode */ -} - #sidebar-throbber[loading="true"] { list-style-image: url("chrome://global/skin/icons/loading_16.png"); -moz-margin-end: 4px; @@ -2508,7 +1921,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] { -moz-margin-end: -8px; } -@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box { +@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box { padding-left: 5px; } @@ -2635,8 +2048,6 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] { } /* Bookmarks roots menu-items */ -#appmenu_subscribeToPage:not([disabled]), -#appmenu_subscribeToPageMenu, #subscribeToPageMenuitem:not([disabled]), #subscribeToPageMenupopup, #BMB_subscribeToPageMenuitem:not([disabled]), @@ -2645,14 +2056,14 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] { } #bookmarksToolbarFolderMenu, -#appmenu_bookmarksToolbar, -#BMB_bookmarksToolbar { +#BMB_bookmarksToolbar, +#panelMenu_bookmarksToolbar { list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png"); -moz-image-region: auto; } -#appmenu_unsortedBookmarks, -#BMB_unsortedBookmarks { +#BMB_unsortedBookmarks, +#panelMenu_unsortedBookmarks { list-style-image: url("chrome://browser/skin/places/unsortedBookmarks.png"); -moz-image-region: auto; } @@ -2721,54 +2132,6 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] { margin-top: .5em; } -/* Add-on bar */ - -#addon-bar { - -moz-appearance: none; - min-height: 20px; - border-top-style: none; - border-bottom-style: none; - padding-top: 1px; - background-image: linear-gradient(rgba(0,0,0,.15) 1px, rgba(255,255,255,.15) 1px); - background-size: 100% 2px; - background-repeat: no-repeat; -} - -#status-bar { - -moz-appearance: none; - background-color: transparent; - border: none; - min-height: 0; -} - -#addon-bar[customizing] > #status-bar { - opacity: .5; - background-image: repeating-linear-gradient(135deg, - rgba(255,255,255,.3), rgba(255,255,255,.3) 5px, - rgba(0,0,0,.3) 5px, rgba(0,0,0,.3) 10px); -} - -#status-bar > statusbarpanel { - border-width: 0; - -moz-appearance: none; -} - -#addonbar-closebutton { - border: none; - padding: 0 5px; - list-style-image: url("chrome://global/skin/icons/close.png"); - -moz-appearance: none; - -moz-image-region: rect(0, 16px, 16px, 0); -} - -#addonbar-closebutton:hover { - -moz-image-region: rect(0, 32px, 16px, 16px); -} - -#addonbar-closebutton:hover:active { - -moz-image-region: rect(0, 48px, 16px, 32px); -} - /* Status panel */ .statuspanel-label { @@ -2860,7 +2223,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] { position: relative; } -@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-badge-container { +#nav-bar .toolbarbutton-1 > .toolbarbutton-badge-container { padding: 2px 5px; } @@ -2892,7 +2255,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] { right: 0; } -@navbarLargeIcons@ *|* > .toolbarbutton-badge[badge]:not([badge=""])::after { +#nav-bar .toolbarbutton-badge[badge]:not([badge=""])::after { top: 1px; right: 1px; } @@ -2902,7 +2265,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] { right: auto; } -@navbarLargeIcons@ *|* > .toolbarbutton-badge[badge]:not([badge=""]):-moz-locale-dir(rtl)::after { +#nav-bar .toolbarbutton-badge[badge]:not([badge=""]):-moz-locale-dir(rtl)::after { left: 1px; right: auto; } @@ -3017,20 +2380,32 @@ chatbox { border-top-right-radius: 2.5px; } -#main-window[privatebrowsingmode=temporary] #toolbar-menubar { - background-image: url("chrome://browser/skin/privatebrowsing-dark.png"); - background-position: top right; - background-repeat: no-repeat; +/* Customization mode */ + +%include ../shared/customizableui/customizeMode.inc.css + +#main-window[customizing] { + background-image: url("chrome://browser/skin/customizableui/customizeMode-gridTexture.png"); + background-attachment: fixed; } -#main-window[privatebrowsingmode=temporary] #toolbar-menubar:-moz-locale-dir(rtl) { - background-position: top left; +#main-window:-moz-any([customize-entering],[customize-entered]) #tab-view-deck { + padding: 0 2em 2em; } -#main-window[privatebrowsingmode=temporary] #appmenu-button > .button-box > .box-inherit > .button-icon { - list-style-image: url("chrome://browser/skin/privatebrowsing-light.png"); - width: 20px; - height: 16px; +#customization-container { + border-left: 1px solid @toolbarShadowColor@; + border-right: 1px solid @toolbarShadowColor@; + background-clip: padding-box; +} + +/* End customization mode */ + +#main-window[privatebrowsingmode=temporary] #TabsToolbar::after { + content: ""; + display: -moz-box; + width: 40px; + background: url("chrome://browser/skin/privatebrowsing-indicator.png") no-repeat center center; } %include ../shared/UITour.inc.css diff --git a/browser/themes/windows/customizableui/background-noise-toolbar.png b/browser/themes/windows/customizableui/background-noise-toolbar.png new file mode 100644 index 0000000000000000000000000000000000000000..d09ba9dafb5ede66e92ce577ecaa6f9575dba104 Binary files /dev/null and b/browser/themes/windows/customizableui/background-noise-toolbar.png differ diff --git a/browser/themes/windows/customizableui/customizeMode-gridTexture.png b/browser/themes/windows/customizableui/customizeMode-gridTexture.png new file mode 100644 index 0000000000000000000000000000000000000000..a7c2775cfc799da31a505b249f5a59b89c148a58 Binary files /dev/null and b/browser/themes/windows/customizableui/customizeMode-gridTexture.png differ diff --git a/browser/themes/windows/customizableui/customizeMode-separatorHorizontal.png b/browser/themes/windows/customizableui/customizeMode-separatorHorizontal.png new file mode 100644 index 0000000000000000000000000000000000000000..5e17cb4db08e310e6c3a9e14c5bd722772dfb639 Binary files /dev/null and b/browser/themes/windows/customizableui/customizeMode-separatorHorizontal.png differ diff --git a/browser/themes/windows/customizableui/customizeMode-separatorVertical.png b/browser/themes/windows/customizableui/customizeMode-separatorVertical.png new file mode 100644 index 0000000000000000000000000000000000000000..dc4caee812878f246c87d71093768eb36c5656fc Binary files /dev/null and b/browser/themes/windows/customizableui/customizeMode-separatorVertical.png differ diff --git a/browser/themes/windows/customizableui/panelUIOverlay.css b/browser/themes/windows/customizableui/panelUIOverlay.css new file mode 100644 index 0000000000000000000000000000000000000000..d66a8e0aa1360f4cbe6237c52ca197165b571559 --- /dev/null +++ b/browser/themes/windows/customizableui/panelUIOverlay.css @@ -0,0 +1,30 @@ +/* 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/. */ + +%include ../../shared/customizableui/panelUIOverlay.inc.css + +#PanelUI-contents #zoom-out-btn { + padding-left: 12px; + padding-right: 12px; +} + +#PanelUI-contents #zoom-in-btn { + padding-left: 12px; + padding-right: 12px; +} + +#BMB_bookmarksPopup > menu, +#BMB_bookmarksPopup > menuitem { + padding-top: 1px; + padding-bottom: 1px; +} + +#BMB_bookmarksPopup > menu > .menu-text, +#BMB_bookmarksPopup > menuitem > .menu-text, +#BMB_bookmarksPopup > menu > .menu-iconic-text, +#BMB_bookmarksPopup > menuitem > .menu-iconic-text, +#BMB_bookmarksPopup > menuseparator { + padding-top: 0; + padding-bottom: 0; +} diff --git a/browser/themes/windows/downloads/indicator-aero.css b/browser/themes/windows/downloads/indicator-aero.css index bcb72c8ae4a32182b519e21d5890b86905ecbd54..1c466e1dbf0be954fdacdbae9df4290711b3a7a0 100644 --- a/browser/themes/windows/downloads/indicator-aero.css +++ b/browser/themes/windows/downloads/indicator-aero.css @@ -6,30 +6,20 @@ /* The following rules are for the downloads indicator when in its normal, non-downloading, non-paused state (ie, it's just showing the downloads button icon). */ - #toolbar-menubar #downloads-button:not([attention]) > #downloads-indicator-anchor > #downloads-indicator-icon:not(:-moz-lwtheme), - #TabsToolbar[tabsontop=true] #downloads-button:not([attention]) > #downloads-indicator-anchor > #downloads-indicator-icon:not(:-moz-lwtheme), - #navigator-toolbox[tabsontop=false] > #nav-bar #downloads-button:not([attention]) > #downloads-indicator-anchor > #downloads-indicator-icon:not(:-moz-lwtheme), - #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child #downloads-button:not([attention]) > #downloads-indicator-anchor > #downloads-indicator-icon:not(:-moz-lwtheme), + :-moz-any(#toolbar-menubar, #TabsToolbar) #downloads-button:not([attention]) > #downloads-indicator-anchor > #downloads-indicator-icon:not(:-moz-lwtheme), /* The following rules are for the downloads indicator when in its paused or undetermined progress state. We use :not([counter]) as a shortcut for :-moz-any([progress], [paused]). */ - /* This is the case where the downloads indicator has been moved next to the menubar */ + /* This is the case where the downloads indicator has been moved next to the menubar as well as + the case where the downloads indicator is in the tabstrip toolbar. */ #toolbar-menubar #downloads-button:not([counter]) > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter, - /* This is the case where the downloads indicator is in the tabstrip toolbar with tabs on top. */ - #TabsToolbar[tabsontop=true] #downloads-button:not(:-moz-lwtheme):not([counter]) > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter, - /* This is the case where the downloads indicator is anywhere in the nav-bar with tabs on bottom. */ - #navigator-toolbox[tabsontop=false] > #nav-bar #downloads-button:not(:-moz-lwtheme):not([counter]) > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter, - /* This is the case where the downloads indicator is in the tabstrip when the tabstrip is the last item in the toolbox (and is therefore over glass) */ - #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child #downloads-button:not(:-moz-lwtheme):not([counter]) > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter { - background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"), 0, 108, 18, 90); + #TabsToolbar #downloads-button:not(:-moz-lwtheme):not([counter]) > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter { + background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"), 0, 198, 18, 180); } - #toolbar-menubar #downloads-indicator-counter:not(:-moz-lwtheme), - #TabsToolbar[tabsontop=true] #downloads-indicator-counter:not(:-moz-lwtheme), - #navigator-toolbox[tabsontop=false] > #nav-bar #downloads-indicator-counter:not(:-moz-lwtheme), - #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child #downloads-indicator-counter:not(:-moz-lwtheme) { + :-moz-any(#toolbar-menubar, #TabsToolbar) #downloads-indicator-counter:not(:-moz-lwtheme) { color: white; text-shadow: 0 0 1px rgba(0,0,0,.7), 0 1px 1.5px rgba(0,0,0,.5); diff --git a/browser/themes/windows/downloads/indicator.css b/browser/themes/windows/downloads/indicator.css index b989a0e90cdb25085d773a9bf84d48b3a172b074..90b22d45ae5b019ce9e745df23d0eb39f7c73f86 100644 --- a/browser/themes/windows/downloads/indicator.css +++ b/browser/themes/windows/downloads/indicator.css @@ -21,14 +21,14 @@ #downloads-indicator-icon { background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"), - 0, 108, 18, 90) center no-repeat; + 0, 198, 18, 180) center no-repeat; min-width: 18px; min-height: 18px; } #downloads-indicator-icon:-moz-lwtheme-brighttext { background: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"), - 0, 108, 18, 90) center no-repeat; + 0, 198, 18, 180) center no-repeat; } #downloads-button[attention] > #downloads-indicator-anchor > #downloads-indicator-icon { @@ -40,10 +40,15 @@ #downloads-button:not([counter]) > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter { background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"), - 0, 108, 18, 90) center no-repeat; + 0, 198, 18, 180) center no-repeat; background-size: 12px; } +#downloads-button:not([counter]) > #downloads-indicator-anchor > +#downloads-button-progress-area > #downloads-indicator-counter:-moz-lwtheme-brighttext { + background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"), 0, 198, 18, 180); +} + #downloads-button:not([counter])[attention] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter { background-image: url("chrome://browser/skin/downloads/download-glow.png"); } @@ -153,8 +158,3 @@ #downloads-button[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-remainder { background-image: linear-gradient(#4b5000, #515700); } - -toolbar[mode="full"] > #downloads-button[indicator] > .toolbarbutton-text { - margin: 0; - text-align: center; -} diff --git a/browser/themes/windows/jar.mn b/browser/themes/windows/jar.mn index c3db1b6a4473be9661a5de1a2098550a3ab0e280..1df89b3b33310524e7f80884a9ad131e73120b17 100644 --- a/browser/themes/windows/jar.mn +++ b/browser/themes/windows/jar.mn @@ -22,10 +22,13 @@ browser.jar: #endif skin/classic/browser/aboutTabCrashed.css skin/classic/browser/actionicon-tab.png - skin/classic/browser/appmenu-icons.png - skin/classic/browser/appmenu-dropmarker.png * skin/classic/browser/browser.css +* skin/classic/browser/browser-lightweightTheme.css skin/classic/browser/click-to-play-warning-stripes.png + skin/classic/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png) + skin/classic/browser/customizableui/customizeMode-gridTexture.png (customizableui/customizeMode-gridTexture.png) + skin/classic/browser/customizableui/customizeMode-separatorHorizontal.png (customizableui/customizeMode-separatorHorizontal.png) + skin/classic/browser/customizableui/customizeMode-separatorVertical.png (customizableui/customizeMode-separatorVertical.png) * skin/classic/browser/engineManager.css skin/classic/browser/fullscreen-darknoise.png skin/classic/browser/Geolocation-16.png @@ -42,6 +45,11 @@ browser.jar: skin/classic/browser/livemark-folder.png skin/classic/browser/menu-back.png skin/classic/browser/menu-forward.png + skin/classic/browser/menuPanel.png + skin/classic/browser/menuPanel-customize.png + skin/classic/browser/menuPanel-exit.png + skin/classic/browser/menuPanel-help.png + skin/classic/browser/menuPanel-small.png skin/classic/browser/mixed-content-blocked-16.png skin/classic/browser/mixed-content-blocked-64.png skin/classic/browser/monitor.png @@ -58,8 +66,7 @@ browser.jar: skin/classic/browser/Privacy-16.png skin/classic/browser/Privacy-32.png skin/classic/browser/Privacy-48.png - skin/classic/browser/privatebrowsing-light.png - skin/classic/browser/privatebrowsing-dark.png + skin/classic/browser/privatebrowsing-indicator.png skin/classic/browser/reload-stop-go.png skin/classic/browser/searchbar.css skin/classic/browser/searchbar-dropdown-arrow.png @@ -68,6 +75,7 @@ browser.jar: skin/classic/browser/slowStartup-16.png skin/classic/browser/Toolbar.png skin/classic/browser/Toolbar-inverted.png + skin/classic/browser/Toolbar-lunaSilver.png skin/classic/browser/toolbarbutton-dropdown-arrow.png skin/classic/browser/toolbarbutton-dropdown-arrow-inverted.png skin/classic/browser/urlbar-arrow.png @@ -79,6 +87,7 @@ browser.jar: skin/classic/browser/webRTC-shareDevice-16.png skin/classic/browser/webRTC-shareDevice-64.png skin/classic/browser/webRTC-sharingDevice-16.png +* skin/classic/browser/customizableui/panelUIOverlay.css (customizableui/panelUIOverlay.css) * skin/classic/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay.css) skin/classic/browser/downloads/buttons.png (downloads/buttons.png) skin/classic/browser/downloads/contentAreaDownloadsView.css (downloads/contentAreaDownloadsView.css) @@ -99,7 +108,6 @@ browser.jar: skin/classic/browser/newtab/controls.png (newtab/controls.png) skin/classic/browser/places/places.css (places/places.css) * skin/classic/browser/places/organizer.css (places/organizer.css) - skin/classic/browser/places/editBookmark.png (places/editBookmark.png) skin/classic/browser/places/bookmark.png (places/bookmark.png) skin/classic/browser/places/query.png (places/query.png) skin/classic/browser/places/bookmarksMenu.png (places/bookmarksMenu.png) @@ -130,18 +138,30 @@ browser.jar: skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css) skin/classic/browser/social/services-16.png (social/services-16.png) skin/classic/browser/social/services-64.png (social/services-64.png) - skin/classic/browser/social/share-button.png (social/share-button.png) - skin/classic/browser/social/share-button-active.png (social/share-button-active.png) skin/classic/browser/social/chat-icons.png (social/chat-icons.png) skin/classic/browser/tabbrowser/newtab.png (tabbrowser/newtab.png) skin/classic/browser/tabbrowser/newtab-inverted.png (tabbrowser/newtab-inverted.png) skin/classic/browser/tabbrowser/connecting.png (tabbrowser/connecting.png) skin/classic/browser/tabbrowser/loading.png (tabbrowser/loading.png) skin/classic/browser/tabbrowser/tab.png (tabbrowser/tab.png) + skin/classic/browser/tabbrowser/tab-active-middle.png (tabbrowser/tab-active-middle.png) skin/classic/browser/tabbrowser/tab-arrow-left.png (tabbrowser/tab-arrow-left.png) skin/classic/browser/tabbrowser/tab-arrow-left-inverted.png (tabbrowser/tab-arrow-left-inverted.png) + skin/classic/browser/tabbrowser/tab-background-start.png (tabbrowser/tab-background-start.png) + skin/classic/browser/tabbrowser/tab-background-middle.png (tabbrowser/tab-background-middle.png) + skin/classic/browser/tabbrowser/tab-background-end.png (tabbrowser/tab-background-end.png) skin/classic/browser/tabbrowser/tab-overflow-border.png (tabbrowser/tab-overflow-border.png) + +# NOTE: The following two files (tab-selected-end.svg, tab-selected-start.svg) get pre-processed in +# Makefile.in with a non-default marker of "%" and the result of that gets packaged. + skin/classic/browser/tabbrowser/tab-selected-end.svg (tab-selected-end.svg) + skin/classic/browser/tabbrowser/tab-selected-start.svg (tab-selected-start.svg) + + skin/classic/browser/tabbrowser/tab-stroke-end.png (tabbrowser/tab-stroke-end.png) + skin/classic/browser/tabbrowser/tab-stroke-start.png (tabbrowser/tab-stroke-start.png) skin/classic/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png) + skin/classic/browser/tabbrowser/tab-separator-luna-blue.png (tabbrowser/tab-separator-luna-blue.png) + skin/classic/browser/tabbrowser/tab-separator.png (tabbrowser/tab-separator.png) skin/classic/browser/tabview/close.png (tabview/close.png) skin/classic/browser/tabview/edit-light.png (tabview/edit-light.png) skin/classic/browser/tabview/grain.png (tabview/grain.png) @@ -300,10 +320,13 @@ browser.jar: #endif skin/classic/aero/browser/aboutTabCrashed.css skin/classic/aero/browser/actionicon-tab.png - skin/classic/aero/browser/appmenu-dropmarker.png - skin/classic/aero/browser/appmenu-icons.png * skin/classic/aero/browser/browser.css (browser-aero.css) +* skin/classic/aero/browser/browser-lightweightTheme.css skin/classic/aero/browser/click-to-play-warning-stripes.png + skin/classic/aero/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png) + skin/classic/aero/browser/customizableui/customizeMode-gridTexture.png (customizableui/customizeMode-gridTexture.png) + skin/classic/aero/browser/customizableui/customizeMode-separatorHorizontal.png (customizableui/customizeMode-separatorHorizontal.png) + skin/classic/aero/browser/customizableui/customizeMode-separatorVertical.png (customizableui/customizeMode-separatorVertical.png) * skin/classic/aero/browser/engineManager.css skin/classic/aero/browser/fullscreen-darknoise.png skin/classic/aero/browser/Geolocation-16.png @@ -320,6 +343,11 @@ browser.jar: skin/classic/aero/browser/livemark-folder.png (livemark-folder-aero.png) skin/classic/aero/browser/menu-back.png (menu-back-aero.png) skin/classic/aero/browser/menu-forward.png (menu-forward-aero.png) + skin/classic/aero/browser/menuPanel.png (menuPanel-aero.png) + skin/classic/aero/browser/menuPanel-customize.png + skin/classic/aero/browser/menuPanel-exit.png + skin/classic/aero/browser/menuPanel-help.png + skin/classic/aero/browser/menuPanel-small.png (menuPanel-small-aero.png) skin/classic/aero/browser/mixed-content-blocked-16.png skin/classic/aero/browser/mixed-content-blocked-64.png skin/classic/aero/browser/monitor.png @@ -336,16 +364,15 @@ browser.jar: skin/classic/aero/browser/Privacy-16.png (Privacy-16-aero.png) skin/classic/aero/browser/Privacy-32.png (Privacy-32-aero.png) skin/classic/aero/browser/Privacy-48.png (Privacy-48-aero.png) - skin/classic/aero/browser/privatebrowsing-light.png - skin/classic/aero/browser/privatebrowsing-dark.png + skin/classic/aero/browser/privatebrowsing-indicator.png skin/classic/aero/browser/reload-stop-go.png skin/classic/aero/browser/searchbar.css skin/classic/aero/browser/searchbar-dropdown-arrow.png (searchbar-dropdown-arrow-aero.png) skin/classic/aero/browser/Secure24.png (Secure24-aero.png) skin/classic/aero/browser/setDesktopBackground.css skin/classic/aero/browser/slowStartup-16.png - skin/classic/aero/browser/Toolbar.png - skin/classic/aero/browser/Toolbar-inverted.png + skin/classic/aero/browser/Toolbar.png (Toolbar-aero.png) + skin/classic/aero/browser/Toolbar-inverted.png (Toolbar-inverted-aero.png) skin/classic/aero/browser/toolbarbutton-dropdown-arrow.png skin/classic/aero/browser/toolbarbutton-dropdown-arrow-inverted.png skin/classic/aero/browser/urlbar-arrow.png @@ -357,6 +384,7 @@ browser.jar: skin/classic/aero/browser/webRTC-shareDevice-16.png skin/classic/aero/browser/webRTC-shareDevice-64.png skin/classic/aero/browser/webRTC-sharingDevice-16.png +* skin/classic/aero/browser/customizableui/panelUIOverlay.css (customizableui/panelUIOverlay.css) * skin/classic/aero/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay-aero.css) skin/classic/aero/browser/downloads/buttons.png (downloads/buttons-aero.png) skin/classic/aero/browser/downloads/contentAreaDownloadsView.css (downloads/contentAreaDownloadsView.css) @@ -378,7 +406,6 @@ browser.jar: * skin/classic/aero/browser/places/places.css (places/places-aero.css) * skin/classic/aero/browser/places/organizer.css (places/organizer-aero.css) skin/classic/aero/browser/places/bookmark.png (places/bookmark.png) - skin/classic/aero/browser/places/editBookmark.png (places/editBookmark.png) skin/classic/aero/browser/places/query.png (places/query-aero.png) skin/classic/aero/browser/places/bookmarksMenu.png (places/bookmarksMenu-aero.png) skin/classic/aero/browser/places/bookmarksToolbar.png (places/bookmarksToolbar-aero.png) @@ -408,18 +435,29 @@ browser.jar: skin/classic/aero/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css) skin/classic/aero/browser/social/services-16.png (social/services-16.png) skin/classic/aero/browser/social/services-64.png (social/services-64.png) - skin/classic/aero/browser/social/share-button.png (social/share-button.png) - skin/classic/aero/browser/social/share-button-active.png (social/share-button-active.png) skin/classic/aero/browser/social/chat-icons.png (social/chat-icons.png) skin/classic/aero/browser/tabbrowser/newtab.png (tabbrowser/newtab.png) skin/classic/aero/browser/tabbrowser/newtab-inverted.png (tabbrowser/newtab-inverted.png) skin/classic/aero/browser/tabbrowser/connecting.png (tabbrowser/connecting.png) skin/classic/aero/browser/tabbrowser/loading.png (tabbrowser/loading.png) skin/classic/aero/browser/tabbrowser/tab.png (tabbrowser/tab.png) + skin/classic/aero/browser/tabbrowser/tab-active-middle.png (tabbrowser/tab-active-middle.png) skin/classic/aero/browser/tabbrowser/tab-arrow-left.png (tabbrowser/tab-arrow-left.png) skin/classic/aero/browser/tabbrowser/tab-arrow-left-inverted.png (tabbrowser/tab-arrow-left-inverted.png) + skin/classic/aero/browser/tabbrowser/tab-background-start.png (tabbrowser/tab-background-start.png) + skin/classic/aero/browser/tabbrowser/tab-background-middle.png (tabbrowser/tab-background-middle.png) + skin/classic/aero/browser/tabbrowser/tab-background-end.png (tabbrowser/tab-background-end.png) skin/classic/aero/browser/tabbrowser/tab-overflow-border.png (tabbrowser/tab-overflow-border.png) + +# NOTE: The following two files (tab-selected-end.svg, tab-selected-start.svg) get pre-processed in +# Makefile.in with a non-default marker of "%" and the result of that gets packaged. + skin/classic/aero/browser/tabbrowser/tab-selected-end.svg (tab-selected-end-aero.svg) + skin/classic/aero/browser/tabbrowser/tab-selected-start.svg (tab-selected-start-aero.svg) + + skin/classic/aero/browser/tabbrowser/tab-stroke-end.png (tabbrowser/tab-stroke-end.png) + skin/classic/aero/browser/tabbrowser/tab-stroke-start.png (tabbrowser/tab-stroke-start.png) skin/classic/aero/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png) + skin/classic/aero/browser/tabbrowser/tab-separator.png (tabbrowser/tab-separator-aero.png) skin/classic/aero/browser/tabview/close.png (tabview/close.png) skin/classic/aero/browser/tabview/edit-light.png (tabview/edit-light.png) skin/classic/aero/browser/tabview/grain.png (tabview/grain.png) diff --git a/browser/themes/windows/menuPanel-aero.png b/browser/themes/windows/menuPanel-aero.png new file mode 100644 index 0000000000000000000000000000000000000000..59061ec0aaa38b85dddacb4c31f257c4ad43ecf5 Binary files /dev/null and b/browser/themes/windows/menuPanel-aero.png differ diff --git a/browser/themes/windows/menuPanel-customize.png b/browser/themes/windows/menuPanel-customize.png new file mode 100644 index 0000000000000000000000000000000000000000..e0b0a70a3b82a18c974bd1bc5f1dff863405dd61 Binary files /dev/null and b/browser/themes/windows/menuPanel-customize.png differ diff --git a/browser/themes/windows/menuPanel-exit.png b/browser/themes/windows/menuPanel-exit.png new file mode 100644 index 0000000000000000000000000000000000000000..6359d7262a286a34074f6f245636ad15a95993b5 Binary files /dev/null and b/browser/themes/windows/menuPanel-exit.png differ diff --git a/browser/themes/windows/menuPanel-help.png b/browser/themes/windows/menuPanel-help.png new file mode 100644 index 0000000000000000000000000000000000000000..4d23717748de84d681bfabd3c326420931a90e84 Binary files /dev/null and b/browser/themes/windows/menuPanel-help.png differ diff --git a/browser/themes/windows/menuPanel-small-aero.png b/browser/themes/windows/menuPanel-small-aero.png new file mode 100644 index 0000000000000000000000000000000000000000..4cd3e52b13d26ae5c4d85cb3ed3c00cd6c70f2ab Binary files /dev/null and b/browser/themes/windows/menuPanel-small-aero.png differ diff --git a/browser/themes/windows/menuPanel-small.png b/browser/themes/windows/menuPanel-small.png new file mode 100644 index 0000000000000000000000000000000000000000..a9fe97171b8328cf9646aabb320c6c9097a5b448 Binary files /dev/null and b/browser/themes/windows/menuPanel-small.png differ diff --git a/browser/themes/windows/menuPanel.png b/browser/themes/windows/menuPanel.png new file mode 100644 index 0000000000000000000000000000000000000000..31d8d282579eea1379dcb5d918159b5fe43587d6 Binary files /dev/null and b/browser/themes/windows/menuPanel.png differ diff --git a/browser/themes/windows/newtab/newTab.css b/browser/themes/windows/newtab/newTab.css index 024bccfd9d2d2498d544c5387dd59065fdc22af8..69258a39642749b60fe117d6ca6abfdf5e0ecddf 100644 --- a/browser/themes/windows/newtab/newTab.css +++ b/browser/themes/windows/newtab/newTab.css @@ -57,19 +57,9 @@ -moz-appearance: none; padding: 0; border: none; - list-style-image: url("chrome://global/skin/icons/close.png"); - -moz-image-region: rect(0, 16px, 16px, 0); -moz-user-focus: normal; } -#newtab-undo-close-button:hover { - -moz-image-region: rect(0, 32px, 16px, 16px); -} - -#newtab-undo-close-button:hover:active { - -moz-image-region: rect(0, 48px, 16px, 32px); -} - #newtab-undo-close-button > .toolbarbutton-text { display: none; } diff --git a/browser/themes/windows/places/editBookmark.png b/browser/themes/windows/places/editBookmark.png deleted file mode 100644 index fbca0523df169b6892d2b5050035152fb6b92606..0000000000000000000000000000000000000000 Binary files a/browser/themes/windows/places/editBookmark.png and /dev/null differ diff --git a/browser/themes/windows/places/organizer-aero.css b/browser/themes/windows/places/organizer-aero.css index 645aff64b4b3827563e3901bb4f6e2f31a502ce5..502573a463a1bd42006b01f3419059f7c4e38d0a 100644 --- a/browser/themes/windows/places/organizer-aero.css +++ b/browser/themes/windows/places/organizer-aero.css @@ -2,11 +2,12 @@ * 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/. */ +%define WINDOWS_AERO +%include ../windowsShared.inc %include organizer.css +%undef WINDOWS_AERO %filter substitution -%define toolbarHighlight rgba(255,255,255,.5) -%define customToolbarColor hsl(210,75%,92%) #placesView { border-top: none; diff --git a/browser/themes/windows/places/organizer.css b/browser/themes/windows/places/organizer.css index 4ccdc1b5c00d0cacf368102c2b8364703c1201c1..ae20999296c3fac29f7cd334999df980ae6c1cf7 100644 --- a/browser/themes/windows/places/organizer.css +++ b/browser/themes/windows/places/organizer.css @@ -18,11 +18,11 @@ } #back-button { - -moz-image-region: rect(0, 18px, 18px, 0); + -moz-image-region: rect(0, 54px, 18px, 36px); } #forward-button { - -moz-image-region: rect(0, 36px, 18px, 18px); + -moz-image-region: rect(0, 72px, 18px, 54px); } #back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon, diff --git a/browser/themes/windows/privatebrowsing-dark.png b/browser/themes/windows/privatebrowsing-indicator.png similarity index 100% rename from browser/themes/windows/privatebrowsing-dark.png rename to browser/themes/windows/privatebrowsing-indicator.png diff --git a/browser/themes/windows/privatebrowsing-light.png b/browser/themes/windows/privatebrowsing-light.png deleted file mode 100644 index c12f50779858230c939f5f96582437fd60e82610..0000000000000000000000000000000000000000 Binary files a/browser/themes/windows/privatebrowsing-light.png and /dev/null differ diff --git a/browser/themes/windows/social/share-button-active.png b/browser/themes/windows/social/share-button-active.png deleted file mode 100644 index e819a740bf2e8a837d5f09e2e3c84b159acd508f..0000000000000000000000000000000000000000 Binary files a/browser/themes/windows/social/share-button-active.png and /dev/null differ diff --git a/browser/themes/windows/social/share-button.png b/browser/themes/windows/social/share-button.png deleted file mode 100644 index 931874dc36ca2057d91682fd6d69af3e42356ed1..0000000000000000000000000000000000000000 Binary files a/browser/themes/windows/social/share-button.png and /dev/null differ diff --git a/browser/themes/windows/tabbrowser/tab-active-middle.png b/browser/themes/windows/tabbrowser/tab-active-middle.png new file mode 100644 index 0000000000000000000000000000000000000000..be90ec0a12bf4efc43674e34c6d6c928f6bca98d Binary files /dev/null and b/browser/themes/windows/tabbrowser/tab-active-middle.png differ diff --git a/browser/themes/windows/tabbrowser/tab-background-end.png b/browser/themes/windows/tabbrowser/tab-background-end.png new file mode 100644 index 0000000000000000000000000000000000000000..d78b44c0ef10d9509ce234203b6a96c69ad25bda Binary files /dev/null and b/browser/themes/windows/tabbrowser/tab-background-end.png differ diff --git a/browser/themes/windows/tabbrowser/tab-background-middle.png b/browser/themes/windows/tabbrowser/tab-background-middle.png new file mode 100644 index 0000000000000000000000000000000000000000..86a4ab4d0acac486d3ea84b15467bce39b44df86 Binary files /dev/null and b/browser/themes/windows/tabbrowser/tab-background-middle.png differ diff --git a/browser/themes/windows/tabbrowser/tab-background-start.png b/browser/themes/windows/tabbrowser/tab-background-start.png new file mode 100644 index 0000000000000000000000000000000000000000..7898b2b225a0ae9f9a6df197e2d0cceb13dd3f7d Binary files /dev/null and b/browser/themes/windows/tabbrowser/tab-background-start.png differ diff --git a/browser/themes/windows/tabbrowser/tab-separator-aero.png b/browser/themes/windows/tabbrowser/tab-separator-aero.png new file mode 100644 index 0000000000000000000000000000000000000000..af4403a500a0e320d1fac2c4d7b9196c9f8973eb Binary files /dev/null and b/browser/themes/windows/tabbrowser/tab-separator-aero.png differ diff --git a/browser/themes/windows/tabbrowser/tab-separator-luna-blue.png b/browser/themes/windows/tabbrowser/tab-separator-luna-blue.png new file mode 100644 index 0000000000000000000000000000000000000000..2f8cae3b3251af8c85416c09ec2b7d3b094594e2 Binary files /dev/null and b/browser/themes/windows/tabbrowser/tab-separator-luna-blue.png differ diff --git a/browser/themes/windows/tabbrowser/tab-separator.png b/browser/themes/windows/tabbrowser/tab-separator.png new file mode 100644 index 0000000000000000000000000000000000000000..c76c615fc18c37261e76ab39db98b18e19c67013 Binary files /dev/null and b/browser/themes/windows/tabbrowser/tab-separator.png differ diff --git a/browser/themes/windows/tabbrowser/tab-stroke-end.png b/browser/themes/windows/tabbrowser/tab-stroke-end.png new file mode 100644 index 0000000000000000000000000000000000000000..763f43195a6424856df5d181c8954ab1d47dc08b Binary files /dev/null and b/browser/themes/windows/tabbrowser/tab-stroke-end.png differ diff --git a/browser/themes/windows/tabbrowser/tab-stroke-start.png b/browser/themes/windows/tabbrowser/tab-stroke-start.png new file mode 100644 index 0000000000000000000000000000000000000000..91f533dfcce43df0f3baa7526f8a6be240564f6b Binary files /dev/null and b/browser/themes/windows/tabbrowser/tab-stroke-start.png differ diff --git a/browser/themes/windows/windowsShared.inc b/browser/themes/windows/windowsShared.inc new file mode 100644 index 0000000000000000000000000000000000000000..d614535a0ee985285b774f9eaea3c37f7840056f --- /dev/null +++ b/browser/themes/windows/windowsShared.inc @@ -0,0 +1,13 @@ +/* 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/. */ + +%filter substitution + +%define toolbarHighlight rgba(253,253,253,0.45) +%define fgTabTexture linear-gradient(transparent, transparent 2px, rgba(254,254,254,0.72) 2px, rgba(254,254,254,0.72) 2px, rgba(250,250,250,0.88) 3px, rgba(250,250,250,0.88) 3px, rgba(254,254,254,0.72) 4px, rgba(254,254,254,0.72) 4px, @toolbarHighlight@) +%define fgTabBackgroundColor -moz-dialog +%define fgTabTextureLWT @fgTabTexture@ + +% Aero-only defines +%define customToolbarColor hsl(210,75%,92%) diff --git a/gfx/src/nsThemeConstants.h b/gfx/src/nsThemeConstants.h index 8e11e8af20631e6bfc9e96cbd6dc2bc99f9d4218..d1003c5ad2d46829d91c58eaffda249dcca1d556 100644 --- a/gfx/src/nsThemeConstants.h +++ b/gfx/src/nsThemeConstants.h @@ -249,8 +249,9 @@ #define NS_THEME_WIN_MEDIA_TOOLBOX 222 #define NS_THEME_WIN_BROWSER_TAB_BAR_TOOLBOX 223 -// Unified toolbar on the Mac +// Unified toolbar and titlebar elements on the Mac #define NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR 224 +#define NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON 226 // Vista glass #define NS_THEME_WIN_BORDERLESS_GLASS 229 diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index d8c934cabebfead1460434bec0ed4d9d713bfd56..636a371517739273bd9e8d0ed356a43f05d1fb8d 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -2196,14 +2196,20 @@ nsDisplayThemedBackground::nsDisplayThemedBackground(nsDisplayListBuilder* aBuil const nsStyleDisplay* disp = mFrame->StyleDisplay(); mAppearance = disp->mAppearance; mFrame->IsThemed(disp, &mThemeTransparency); + // Perform necessary RegisterThemeGeometry - if (mAppearance == NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR || - mAppearance == NS_THEME_TOOLBAR || - mAppearance == NS_THEME_WINDOW_TITLEBAR) { - RegisterThemeGeometry(aBuilder, aFrame); - } else if (mAppearance == NS_THEME_WIN_BORDERLESS_GLASS || - mAppearance == NS_THEME_WIN_GLASS) { - aBuilder->SetGlassDisplayItem(this); + switch (disp->mAppearance) { + case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR: + case NS_THEME_TOOLBAR: + case NS_THEME_WINDOW_TITLEBAR: + case NS_THEME_WINDOW_BUTTON_BOX: + case NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON: + RegisterThemeGeometry(aBuilder, aFrame); + break; + case NS_THEME_WIN_BORDERLESS_GLASS: + case NS_THEME_WIN_GLASS: + aBuilder->SetGlassDisplayItem(this); + break; } mBounds = GetBoundsInternal(); diff --git a/layout/style/nsCSSKeywordList.h b/layout/style/nsCSSKeywordList.h index 03ec0e796a6533adee483440a86a1f02d9d2933c..62b8bdb502c76adb914483ac2c6dbede37732c11 100644 --- a/layout/style/nsCSSKeywordList.h +++ b/layout/style/nsCSSKeywordList.h @@ -105,6 +105,7 @@ CSS_KEY(-moz-list, _moz_list) CSS_KEY(-moz-mac-chrome-active, _moz_mac_chrome_active) CSS_KEY(-moz-mac-chrome-inactive, _moz_mac_chrome_inactive) CSS_KEY(-moz-mac-focusring, _moz_mac_focusring) +CSS_KEY(-moz-mac-fullscreen-button, _moz_mac_fullscreen_button) CSS_KEY(-moz-mac-menuselect, _moz_mac_menuselect) CSS_KEY(-moz-mac-menushadow, _moz_mac_menushadow) CSS_KEY(-moz-mac-menutextdisable, _moz_mac_menutextdisable) diff --git a/layout/style/nsCSSProps.cpp b/layout/style/nsCSSProps.cpp index 40e5ed6e69d7af1f1e5753f86f5ae4a07735624e..0d2bd43d609e217cce2a9e5e030204f126b38efb 100644 --- a/layout/style/nsCSSProps.cpp +++ b/layout/style/nsCSSProps.cpp @@ -611,6 +611,7 @@ const int32_t nsCSSProps::kAppearanceKTable[] = { eCSSKeyword__moz_win_glass, NS_THEME_WIN_GLASS, eCSSKeyword__moz_win_borderless_glass, NS_THEME_WIN_BORDERLESS_GLASS, eCSSKeyword__moz_mac_unified_toolbar, NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR, + eCSSKeyword__moz_mac_fullscreen_button, NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON, eCSSKeyword__moz_window_titlebar, NS_THEME_WINDOW_TITLEBAR, eCSSKeyword__moz_window_titlebar_maximized, NS_THEME_WINDOW_TITLEBAR_MAXIMIZED, eCSSKeyword__moz_window_frame_left, NS_THEME_WINDOW_FRAME_LEFT, diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index 6d8516161fd0a2e9165027c51445c017d57c3cb4..a410fdde3a6574feefdfbc7a5a9c30024317c072 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -3981,6 +3981,8 @@ pref("ui.panel.default_level_parent", true); pref("mousewheel.system_scroll_override_on_root_content.enabled", false); +pref("ui.key.menuAccessKeyFocuses", true); + # XP_UNIX #endif #endif diff --git a/toolkit/components/alerts/resources/content/alert.xul b/toolkit/components/alerts/resources/content/alert.xul index 7538be0afbdeb4153d3f3fa63d78fab280947453..6850aa50a2715125eac560e11bf786431491c9d8 100644 --- a/toolkit/components/alerts/resources/content/alert.xul +++ b/toolkit/components/alerts/resources/content/alert.xul @@ -36,7 +36,7 @@ </box> <vbox class="alertCloseBox"> - <toolbarbutton class="alertCloseButton" + <toolbarbutton class="alertCloseButton close-icon" tooltiptext="&closeAlert.tooltip;" onclick="event.stopPropagation();" oncommand="close();"/> diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index b5f3a84db0f02a3ebecc4ec9474bd70159565cc3..0d89d6761170ad709b1caf1f39a753a211cb8e66 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -2714,12 +2714,12 @@ "n_buckets": 20, "description": "Firefox: Time in ms spent on switching tabs in response to a tab click" }, - "FX_APP_MENU_OPEN_MS": { + "FX_IDENTITY_POPUP_OPEN_MS": { "kind": "exponential", "high": "1000", "n_buckets": 10, "extended_statistics_ok": true, - "description": "Firefox: Time taken by the app-menu opening in milliseconds" + "description": "Firefox: Time taken by the identity popup to open in milliseconds" }, "FX_BOOKMARKS_TOOLBAR_INIT_MS": { "kind": "exponential", diff --git a/toolkit/content/widgets/findbar.xml b/toolkit/content/widgets/findbar.xml index 750caff8eca7c536a1aea833d8ea7d8e037724f4..649716d1550f2216a111c5c571353d60ce8e210d 100644 --- a/toolkit/content/widgets/findbar.xml +++ b/toolkit/content/widgets/findbar.xml @@ -194,7 +194,7 @@ <xul:label anonid="match-case-status" class="findbar-find-fast"/> </xul:hbox> <xul:toolbarbutton anonid="find-closebutton" - class="findbar-closebutton" + class="findbar-closebutton close-icon" tooltiptext="&findCloseButton.tooltip;" oncommand="close();"/> </content> diff --git a/toolkit/content/widgets/notification.xml b/toolkit/content/widgets/notification.xml index 55511cc64b05b6970d9e638b1de50fffa50b1cd9..1256e55d732fc7885155dd3d37f910a534bb3928 100644 --- a/toolkit/content/widgets/notification.xml +++ b/toolkit/content/widgets/notification.xml @@ -370,7 +370,7 @@ <children/> </xul:hbox> <xul:toolbarbutton ondblclick="event.stopPropagation();" - class="messageCloseButton tabbable" + class="messageCloseButton close-icon tabbable" xbl:inherits="hidden=hideclose" tooltiptext="&closeNotification.tooltip;" oncommand="document.getBindingParent(this).close();"/> @@ -466,7 +466,7 @@ <xul:menupopup anonid="menupopup" xbl:inherits="oncommand=menucommand"> <children/> - <xul:menuitem class="menuitem-iconic popup-notification-closeitem" + <xul:menuitem class="menuitem-iconic popup-notification-closeitem close-icon" label="&closeNotificationItem.label;" xbl:inherits="oncommand=closeitemcommand"/> </xul:menupopup> @@ -475,7 +475,7 @@ </xul:vbox> <xul:vbox pack="start"> <xul:toolbarbutton anonid="closebutton" - class="messageCloseButton popup-notification-closebutton tabbable" + class="messageCloseButton close-icon popup-notification-closebutton tabbable" xbl:inherits="oncommand=closebuttoncommand" tooltiptext="&closeNotification.tooltip;"/> </xul:vbox> diff --git a/toolkit/content/widgets/scrollbox.xml b/toolkit/content/widgets/scrollbox.xml index ea5f90cc0bba0e5039356b5ba166e769f2f14960..8f2acb41600359991ef1148b31d5501277685a65 100644 --- a/toolkit/content/widgets/scrollbox.xml +++ b/toolkit/content/widgets/scrollbox.xml @@ -222,6 +222,12 @@ bottom: scrollPaddingRect.bottom - parseFloat(style.paddingBottom) }; + // Provide an entry point for derived bindings to adjust these values. + if (this._adjustElementStartAndEnd) { + [elementStart, elementEnd] = + this._adjustElementStartAndEnd(element, elementStart, elementEnd); + } + if (elementStart <= (vertical ? scrollContentRect.top : scrollContentRect.left)) { elementStart = vertical ? scrollPaddingRect.top : scrollPaddingRect.left; } diff --git a/toolkit/content/widgets/toolbar.xml b/toolkit/content/widgets/toolbar.xml index 935cb0e7bf90daa8756c5545fb81d9c0c402afcc..17158c2c9f553742cf97d0c6fbde8415faaeb68b 100644 --- a/toolkit/content/widgets/toolbar.xml +++ b/toolkit/content/widgets/toolbar.xml @@ -404,6 +404,9 @@ <constructor> this._setInactive(); </constructor> + <destructor> + this._setActive(); + </destructor> <field name="_inactiveTimeout">null</field> diff --git a/toolkit/content/widgets/toolbarbutton.xml b/toolkit/content/widgets/toolbarbutton.xml index 857461c43675e8915933ff620b74fd22342862a9..e11c29d1b6dff747aa0a34ef0baf3aba54cbc407 100644 --- a/toolkit/content/widgets/toolbarbutton.xml +++ b/toolkit/content/widgets/toolbarbutton.xml @@ -60,7 +60,7 @@ <xul:toolbarbutton class="box-inherit toolbarbutton-menubutton-button" anonid="button" flex="1" allowevents="true" xbl:inherits="disabled,crop,image,label,accesskey,command, - align,dir,pack,orient"/> + align,dir,pack,orient,tooltiptext=buttontooltiptext"/> <xul:dropmarker type="menu-button" class="toolbarbutton-menubutton-dropmarker" xbl:inherits="align,dir,pack,orient,disabled,label,open"/> </content> @@ -72,5 +72,15 @@ <xul:image class="toolbarbutton-icon" xbl:inherits="src=image"/> </content> </binding> + + <binding id="toolbarbutton-wrapping-label" + extends="chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton"> + <content> + <children includes="observes|template|menupopup|panel|tooltip"/> + <xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,label"/> + <xul:label class="toolbarbutton-text toolbarbutton-label" flex="1" + xbl:inherits="xbl:text=label,accesskey"/> + </content> + </binding> </bindings> diff --git a/toolkit/content/xul.css b/toolkit/content/xul.css index 6201a7c06060e29e648a963558a0a29f27174992..53674ab828151e6cd813949affddc32c7ae1d03d 100644 --- a/toolkit/content/xul.css +++ b/toolkit/content/xul.css @@ -157,6 +157,10 @@ toolbarbutton[type="menu-button"] { -moz-binding: url("chrome://global/content/bindings/toolbarbutton.xml#menu-button"); } +toolbarbutton[type="wrap"] { + -moz-binding: url("chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton-wrapping-label"); +} + toolbar[mode="icons"] .toolbarbutton-text, toolbar[mode="text"] .toolbarbutton-icon { display: none; @@ -690,7 +694,7 @@ label.text-link, label[onclick] { -moz-user-focus: normal; } -label[control], label.radio-label, label.checkbox-label { +label[control], label.radio-label, label.checkbox-label, label.toolbarbutton-label { -moz-binding: url("chrome://global/content/bindings/text.xml#label-control"); } diff --git a/toolkit/modules/LightweightThemeConsumer.jsm b/toolkit/modules/LightweightThemeConsumer.jsm index c10313efa65dc4136f3a9502b0e7a016e8fcbd88..0e3f8fbd59406c15940fe399ba8dc3955aa7f960 100644 --- a/toolkit/modules/LightweightThemeConsumer.jsm +++ b/toolkit/modules/LightweightThemeConsumer.jsm @@ -41,6 +41,23 @@ LightweightThemeConsumer.prototype = { _lastData: null, _lastScreenWidth: null, _lastScreenHeight: null, + _enabled: true, +#ifdef XP_MACOSX + _chromemarginDefault: undefined, +#endif + + enable: function() { + this._enabled = true; + this._update(this._lastData); + }, + + disable: function() { + // Dance to keep the data, but reset the applied styles: + let lastData = this._lastData + this._update(null); + this._enabled = false; + this._lastData = lastData; + }, observe: function (aSubject, aTopic, aData) { if (aTopic != "lightweight-theme-styling-update") @@ -80,6 +97,8 @@ LightweightThemeConsumer.prototype = { this._lastData = aData; aData = LightweightThemeImageOptimizer.optimize(aData, this._win.screen); } + if (!this._enabled) + return; var root = this._doc.documentElement; var active = !!aData.headerURL; @@ -110,10 +129,21 @@ LightweightThemeConsumer.prototype = { } #ifdef XP_MACOSX - if (active) - root.setAttribute("drawintitlebar", "true"); - else - root.removeAttribute("drawintitlebar"); + // Sample whether or not we draw in the titlebar by default the first time we update. + // If the root has no chromemargin attribute, getAttribute will return null, and + // we'll remove the attribute when the lw-theme is deactivated. + if (this._chromemarginDefault === undefined) + this._chromemarginDefault = root.getAttribute("chromemargin"); + + if (active) { + root.setAttribute("chromemargin", "0,-1,-1,-1"); + } + else { + if (this._chromemarginDefault) + root.setAttribute("chromemargin", this._chromemarginDefault); + else + root.removeAttribute("chromemargin"); + } #endif } } diff --git a/toolkit/themes/linux/global/icons/notloading_16.png b/toolkit/themes/linux/global/icons/notloading_16.png deleted file mode 100644 index 04dab30ed37c3adc05e20068ccf5bf0f46dbf803..0000000000000000000000000000000000000000 Binary files a/toolkit/themes/linux/global/icons/notloading_16.png and /dev/null differ diff --git a/toolkit/themes/linux/global/inContentUI.css b/toolkit/themes/linux/global/inContentUI.css index 98a430ee7adcb40ceadc22460f177465d15bcc3c..784ed4dd6bdd687bafa0a8e8cf9fbb3a90a9504c 100644 --- a/toolkit/themes/linux/global/inContentUI.css +++ b/toolkit/themes/linux/global/inContentUI.css @@ -9,14 +9,13 @@ @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); @namespace html url("http://www.w3.org/1999/xhtml"); - /* Page background */ *|*:root { -moz-appearance: none; padding: 18px; background-color: Window; - background-image: linear-gradient(rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0) 160px), - linear-gradient(-moz-dialog, Window 160px); + background-image: /* Texture */ + url("chrome://global/skin/inContentUI/background-texture.png"); color: WindowText; } diff --git a/toolkit/themes/linux/global/jar.mn b/toolkit/themes/linux/global/jar.mn index 5bd2732e6691eed8f73186ad3b43c0b9e79ded13..3332135d9bf5f74ec6deb9b2ec81ecb2e514a98f 100644 --- a/toolkit/themes/linux/global/jar.mn +++ b/toolkit/themes/linux/global/jar.mn @@ -45,7 +45,6 @@ toolkit.jar: + skin/classic/global/icons/blacklist_large.png (icons/blacklist_large.png) + skin/classic/global/icons/find.png (icons/find.png) + skin/classic/global/icons/loading_16.png (icons/loading_16.png) -+ skin/classic/global/icons/notloading_16.png (icons/notloading_16.png) + skin/classic/global/icons/panelarrow-horizontal.svg (icons/panelarrow-horizontal.svg) + skin/classic/global/icons/panelarrow-vertical.svg (icons/panelarrow-vertical.svg) + skin/classic/global/icons/resizer.png (icons/resizer.png) diff --git a/toolkit/themes/osx/global/alerts/alert.css b/toolkit/themes/osx/global/alerts/alert.css index e19d881e77fde264e92c77bbad4137bc2eb15d37..8e30e1885306b52c9b3fdedf3360d809d0d920d2 100644 --- a/toolkit/themes/osx/global/alerts/alert.css +++ b/toolkit/themes/osx/global/alerts/alert.css @@ -92,20 +92,9 @@ label { -moz-appearance: none; padding: 0; margin: 2px; - list-style-image: url("chrome://global/skin/icons/close.png"); border: none; - -moz-image-region: rect(0, 16px, 16px, 0); } .alertCloseButton > .toolbarbutton-text { display: none; } - -.alertCloseButton:hover { - -moz-image-region: rect(0, 32px, 16px, 16px); -} - -.alertCloseButton:hover:active { - -moz-image-region: rect(0, 48px, 16px, 32px); -} - diff --git a/toolkit/themes/osx/global/findBar.css b/toolkit/themes/osx/global/findBar.css index 7acc18786665c11916908604a84921382a6addcd..89041af18a4d9e0073ef15263994fde752327f60 100644 --- a/toolkit/themes/osx/global/findBar.css +++ b/toolkit/themes/osx/global/findBar.css @@ -52,35 +52,12 @@ label.findbar-find-fast:-moz-lwtheme, -moz-margin-start: 4px; -moz-padding-start: 0; -moz-padding-end: 8px; - list-style-image: url("chrome://global/skin/icons/close.png"); border: none; - -moz-image-region: rect(0, 16px, 16px, 0); /* make sure the closebutton is displayed as the first element in the bar: */ -moz-box-ordinal-group: 0; } -.findbar-closebutton:hover { - -moz-image-region: rect(0, 32px, 16px, 16px); -} - -.findbar-closebutton:hover:active { - -moz-image-region: rect(0, 48px, 16px, 32px); -} - @media (min-resolution: 2dppx) { - .findbar-closebutton { - list-style-image: url("chrome://global/skin/icons/close@2x.png"); - -moz-image-region: rect(0, 32px, 32px, 0); - } - - .findbar-closebutton:hover { - -moz-image-region: rect(0, 64px, 32px, 32px); - } - - .findbar-closebutton:hover:active { - -moz-image-region: rect(0, 96px, 32px, 64px); - } - .findbar-closebutton > .toolbarbutton-icon { width: 16px; } diff --git a/toolkit/themes/osx/global/global.css b/toolkit/themes/osx/global/global.css index 30f89de3821ed815339fe17da198bdb188c15459..3812de95c7790242be322043f115feccbd25fd62 100644 --- a/toolkit/themes/osx/global/global.css +++ b/toolkit/themes/osx/global/global.css @@ -335,3 +335,33 @@ notification > button > .button-box > .button-text { .popup-internal-box > autorepeatbutton[disabled="true"] { visibility: collapse; } + +/* :::::: Close button icons ::::: */ + +.close-icon { + list-style-image: url("chrome://global/skin/icons/close.png"); + -moz-image-region: rect(0, 16px, 16px, 0); +} + +.close-icon:hover { + -moz-image-region: rect(0, 32px, 16px, 16px); +} + +.close-icon:hover:active { + -moz-image-region: rect(0, 48px, 16px, 32px); +} + +@media (min-resolution: 2dppx) { + .close-icon { + list-style-image: url("chrome://global/skin/icons/close@2x.png"); + -moz-image-region: rect(0, 32px, 32px, 0); + } + + .close-icon:hover { + -moz-image-region: rect(0, 64px, 32px, 32px); + } + + .close-icon:hover:active { + -moz-image-region: rect(0, 96px, 32px, 64px); + } +} diff --git a/toolkit/themes/osx/global/icons/close.png b/toolkit/themes/osx/global/icons/close.png index 9d5b280f258346cfcc848d37380478c57307f965..d58f23bac1f29a8efc2047633e9edeacc59ed25b 100644 Binary files a/toolkit/themes/osx/global/icons/close.png and b/toolkit/themes/osx/global/icons/close.png differ diff --git a/toolkit/themes/osx/global/icons/notloading_16.png b/toolkit/themes/osx/global/icons/notloading_16.png deleted file mode 100644 index ece0ee18a1cffa9bccdd9eae5146b48df48819c4..0000000000000000000000000000000000000000 Binary files a/toolkit/themes/osx/global/icons/notloading_16.png and /dev/null differ diff --git a/toolkit/themes/osx/global/jar.mn b/toolkit/themes/osx/global/jar.mn index a83da864a69ed6e97a4ae09e4469607042b5b3d4..190224dddfbe5d64849637972f809ae1afb08826 100644 --- a/toolkit/themes/osx/global/jar.mn +++ b/toolkit/themes/osx/global/jar.mn @@ -112,7 +112,6 @@ toolkit.jar: skin/classic/global/icons/information-large.png (icons/information-large.png) skin/classic/global/icons/loading_16.png (icons/loading_16.png) skin/classic/global/icons/menulist-dropmarker.png (icons/menulist-dropmarker.png) - skin/classic/global/icons/notloading_16.png (icons/notloading_16.png) skin/classic/global/icons/notfound.png (icons/notfound.png) skin/classic/global/icons/panebutton-active.png (icons/panebutton-active.png) skin/classic/global/icons/panebutton-inactive.png (icons/panebutton-inactive.png) diff --git a/toolkit/themes/osx/global/notification.css b/toolkit/themes/osx/global/notification.css index 3557ed97adcdb1d808e9a0718da8d61880611a08..ee507becbbf17eb96df1d5f218c698182f6453ae 100644 --- a/toolkit/themes/osx/global/notification.css +++ b/toolkit/themes/osx/global/notification.css @@ -65,23 +65,13 @@ notification[type="critical"] { -moz-appearance: none; padding: 0; margin: 0 2px; - list-style-image: url("chrome://global/skin/icons/close.png"); border: none; - -moz-image-region: rect(0, 16px, 16px, 0); } .messageCloseButton > .toolbarbutton-text { display: none; } -.messageCloseButton:hover { - -moz-image-region: rect(0, 32px, 16px, 16px); -} - -.messageCloseButton:hover:active { - -moz-image-region: rect(0, 48px, 16px, 32px); -} - .messageCloseButton:-moz-focusring > .toolbarbutton-icon { border-radius: 10000px; box-shadow: 0 0 2px 1px -moz-mac-focusring, @@ -89,19 +79,6 @@ notification[type="critical"] { } @media (min-resolution: 2dppx) { - .messageCloseButton { - list-style-image: url("chrome://global/skin/icons/close@2x.png"); - -moz-image-region: rect(0, 32px, 32px, 0); - } - - .messageCloseButton:hover { - -moz-image-region: rect(0, 64px, 32px, 32px); - } - - .messageCloseButton:hover:active { - -moz-image-region: rect(0, 96px, 32px, 64px); - } - .messageCloseButton > .toolbarbutton-icon { width: 16px; } diff --git a/toolkit/themes/osx/global/toolbarbutton.css b/toolkit/themes/osx/global/toolbarbutton.css index a369527145ad79e16cc2cade75863176e0286771..ae73d8efa98361b0afe04cde24d86e2d3f3e7702 100644 --- a/toolkit/themes/osx/global/toolbarbutton.css +++ b/toolkit/themes/osx/global/toolbarbutton.css @@ -34,16 +34,6 @@ toolbarbutton[disabled="true"][open="true"] { color: -moz-mac-disabledtoolbartext !important; } -/* ..... checked state ..... */ - -toolbarbutton[checked="true"] { - background-color: #DDDDDD; - background-image: none; - border-right: 1px solid #b9b9b9; - border-left: 1px solid #b9b9b9; - color: ButtonText !important; -} - /* ::::: toolbarbutton menu ::::: */ .toolbarbutton-menu-dropmarker { diff --git a/toolkit/themes/windows/global/alerts/alert.css b/toolkit/themes/windows/global/alerts/alert.css index 8271681240323f0a985254782e748319f9795b60..06f36038f7aa9526e67059f96f1df03eba0ec2b6 100644 --- a/toolkit/themes/windows/global/alerts/alert.css +++ b/toolkit/themes/windows/global/alerts/alert.css @@ -78,9 +78,7 @@ label { } .alertCloseButton { - list-style-image: url("chrome://global/skin/icons/close.png"); -moz-appearance: none; - -moz-image-region: rect(0, 16px, 16px, 0); padding: 4px 2px; border: none !important; } @@ -88,12 +86,3 @@ label { .alertCloseButton > .toolbarbutton-text { display: none; } - -.alertCloseButton:hover { - -moz-image-region: rect(0, 32px, 16px, 16px); -} - -.alertCloseButton:hover:active { - -moz-image-region: rect(0, 48px, 16px, 32px); -} - diff --git a/toolkit/themes/windows/global/findBar.css b/toolkit/themes/windows/global/findBar.css index 86de66ed0d612162b41455d90765dd714acb3e8c..d59dca39522754beebfee6e63c9779229f3f1dc4 100644 --- a/toolkit/themes/windows/global/findBar.css +++ b/toolkit/themes/windows/global/findBar.css @@ -35,18 +35,9 @@ findbar[hidden] { -moz-padding-start: 0; -moz-padding-end: 8px; border: none; - list-style-image: url("chrome://global/skin/icons/close.png"); -moz-appearance: none; - -moz-image-region: rect(0, 16px, 16px, 0); } -.findbar-closebutton:hover { - -moz-image-region: rect(0, 32px, 16px, 16px); -} - -.findbar-closebutton:hover:active { - -moz-image-region: rect(0, 48px, 16px, 32px); -} /* Search field */ diff --git a/toolkit/themes/windows/global/global.css b/toolkit/themes/windows/global/global.css index b23f7a5c65dfe09fa1cd4006448f78d2d35fef00..8c551d0fe77ebd74d72fb26743bd298ae44b5d7d 100644 --- a/toolkit/themes/windows/global/global.css +++ b/toolkit/themes/windows/global/global.css @@ -321,3 +321,38 @@ label[disabled="true"]:-moz-system-metric(windows-classic) { background-position: left bottom; %endif } + +/* :::::: Close button icons ::::: */ + +.close-icon { + list-style-image: url("chrome://global/skin/icons/close.png"); + -moz-image-region: rect(0, 16px, 16px, 0); +} + +.close-icon:hover { + -moz-image-region: rect(0, 32px, 16px, 16px); +} + +.close-icon:hover:active { + -moz-image-region: rect(0, 48px, 16px, 32px); +} + +%ifdef XP_WIN +@media (-moz-windows-theme: luna-blue) { + .close-icon { + list-style-image: url("chrome://global/skin/icons/close-lunaBlue.png"); + } +} + +@media (-moz-windows-theme: luna-olive) { + .close-icon { + list-style-image: url("chrome://global/skin/icons/close-lunaOlive.png"); + } +} + +@media (-moz-windows-theme: luna-silver) { + .close-icon { + list-style-image: url("chrome://global/skin/icons/close-lunaSilver.png"); + } +} +%endif diff --git a/toolkit/themes/windows/global/icons/close-lunaBlue.png b/toolkit/themes/windows/global/icons/close-lunaBlue.png new file mode 100644 index 0000000000000000000000000000000000000000..b657c47e44f9e2b6c75dfc7c7f59a181977e760f Binary files /dev/null and b/toolkit/themes/windows/global/icons/close-lunaBlue.png differ diff --git a/toolkit/themes/windows/global/icons/close-lunaOlive.png b/toolkit/themes/windows/global/icons/close-lunaOlive.png new file mode 100644 index 0000000000000000000000000000000000000000..b071b141b5db14b87eafcbd7d5f5cac19ae82a68 Binary files /dev/null and b/toolkit/themes/windows/global/icons/close-lunaOlive.png differ diff --git a/toolkit/themes/windows/global/icons/close-lunaSilver.png b/toolkit/themes/windows/global/icons/close-lunaSilver.png new file mode 100644 index 0000000000000000000000000000000000000000..36cbda9ab129b3905b2d0f7ac9bca924107b54a9 Binary files /dev/null and b/toolkit/themes/windows/global/icons/close-lunaSilver.png differ diff --git a/toolkit/themes/windows/global/icons/close-win8.png b/toolkit/themes/windows/global/icons/close-win8.png new file mode 100644 index 0000000000000000000000000000000000000000..803e148b73b19b591bc8cb46289592f453fb1e50 Binary files /dev/null and b/toolkit/themes/windows/global/icons/close-win8.png differ diff --git a/toolkit/themes/windows/global/icons/close.png b/toolkit/themes/windows/global/icons/close.png index e559a7003923cba3b85c4e659de29abbac4408da..ae989fd8b86625273be592b626efa84164b764ed 100644 Binary files a/toolkit/themes/windows/global/icons/close.png and b/toolkit/themes/windows/global/icons/close.png differ diff --git a/toolkit/themes/windows/global/icons/notloading_16.png b/toolkit/themes/windows/global/icons/notloading_16.png deleted file mode 100644 index f8366ded5146007efaf63a49d9097e706e0af42e..0000000000000000000000000000000000000000 Binary files a/toolkit/themes/windows/global/icons/notloading_16.png and /dev/null differ diff --git a/toolkit/themes/windows/global/inContentUI.css b/toolkit/themes/windows/global/inContentUI.css index 94b959815bf7d420341e75cb80b1088931692bdd..61a663df18c7138f23dd1bccf9920ee4fd79684a 100644 --- a/toolkit/themes/windows/global/inContentUI.css +++ b/toolkit/themes/windows/global/inContentUI.css @@ -16,9 +16,7 @@ background-repeat: repeat; color: -moz-dialogText; background-color: -moz-dialog; - background-image: /* Fade-out texture at the top, and blend with browser tab */ - linear-gradient(rgba(255,255,255,0.5), rgba(255,255,255,0) 30%), - /* Texture */ + background-image: /* Texture */ url("chrome://global/skin/inContentUI/background-texture.png"); } @@ -31,9 +29,7 @@ html|html { *|*:root { color: #000; background-color: #CCD9EA; - background-image: /* Fade-out texture at the top */ - linear-gradient(rgb(237,245,252), rgba(237,245,252,0) 156px), - /* Texture */ + background-image: /* Texture */ url("chrome://global/skin/inContentUI/background-texture.png"); } } @@ -42,9 +38,7 @@ html|html { *|*:root { color: #000; /* Blame shorlander for this monstrosity. */ - background-image: /* Fade-out texture and light beams at the top */ - linear-gradient(rgb(237,245,252) 3px, rgba(237,245,252,0) 156px), - /* Side gradients */ + background-image: /* Side gradients */ linear-gradient(to right, rgba(255,255,255,0.2), rgba(255,255,255,0) 40%, rgba(255,255,255,0) 60%, rgba(255,255,255,0.2)), diff --git a/toolkit/themes/windows/global/jar.mn b/toolkit/themes/windows/global/jar.mn index be2369e3cc9963ebb9f6ecbab80b7073d5e4e34c..6cddc68efd405fe26a4101e4b6ee8394ae5262c5 100644 --- a/toolkit/themes/windows/global/jar.mn +++ b/toolkit/themes/windows/global/jar.mn @@ -103,6 +103,9 @@ toolkit.jar: skin/classic/global/icons/blacklist_large.png (icons/blacklist_large.png) skin/classic/global/icons/Close.gif (icons/Close.gif) skin/classic/global/icons/close.png (icons/close.png) + skin/classic/global/icons/close-lunaBlue.png (icons/close-lunaBlue.png) + skin/classic/global/icons/close-lunaOlive.png (icons/close-lunaOlive.png) + skin/classic/global/icons/close-lunaSilver.png (icons/close-lunaSilver.png) skin/classic/global/icons/collapse.png (icons/collapse.png) skin/classic/global/icons/Error.png (icons/Error.png) skin/classic/global/icons/error-16.png (icons/error-16.png) @@ -119,7 +122,6 @@ toolkit.jar: skin/classic/global/icons/information-48.png (icons/information-48.png) skin/classic/global/icons/information-64.png (icons/information-64.png) skin/classic/global/icons/loading_16.png (icons/loading_16.png) - skin/classic/global/icons/notloading_16.png (icons/notloading_16.png) skin/classic/global/icons/Minimize.gif (icons/Minimize.gif) skin/classic/global/icons/Print-preview.png (icons/Print-preview.png) skin/classic/global/icons/Portrait.png (icons/Portrait.png) @@ -301,7 +303,6 @@ toolkit.jar: skin/classic/aero/global/icons/information-48.png (icons/information-48-aero.png) skin/classic/aero/global/icons/information-64.png (icons/information-64-aero.png) skin/classic/aero/global/icons/loading_16.png (icons/loading_16.png) - skin/classic/aero/global/icons/notloading_16.png (icons/notloading_16.png) skin/classic/aero/global/icons/Minimize.gif (icons/Minimize.gif) skin/classic/aero/global/icons/Print-preview.png (icons/Print-preview-aero.png) skin/classic/aero/global/icons/Portrait.png (icons/Portrait-aero.png) diff --git a/toolkit/themes/windows/global/notification.css b/toolkit/themes/windows/global/notification.css index 0481d09196056112b12c7ad1df1b137da032b7d8..70534dfaaf8b28f38926c3f7d63d68215ffa95d0 100644 --- a/toolkit/themes/windows/global/notification.css +++ b/toolkit/themes/windows/global/notification.css @@ -42,21 +42,11 @@ notification[type="critical"] { } .messageCloseButton { - list-style-image: url("chrome://global/skin/icons/close.png"); -moz-appearance: none; - -moz-image-region: rect(0, 16px, 16px, 0); padding: 4px 2px; border: none !important; } -.messageCloseButton:hover { - -moz-image-region: rect(0, 32px, 16px, 16px); -} - -.messageCloseButton:hover:active { - -moz-image-region: rect(0, 48px, 16px, 32px); -} - .messageCloseButton > .toolbarbutton-icon { -moz-margin-end: 5px; } @@ -172,8 +162,3 @@ XXX: apply styles to all themes until bug 509642 is fixed -moz-margin-end: -14px; margin-top: -10px; } - -.popup-notification-closeitem { - list-style-image: url("chrome://global/skin/icons/close.png"); - -moz-image-region: rect(0, 16px, 16px, 0); -} diff --git a/widget/cocoa/nsChildView.h b/widget/cocoa/nsChildView.h index 8ca8855a5205adc06cc0fb8b57c88d7fd4ff603d..ced4bc1b0b526adfb1317d1c3438e17526949e0a 100644 --- a/widget/cocoa/nsChildView.h +++ b/widget/cocoa/nsChildView.h @@ -109,18 +109,6 @@ class GLManager; @interface NSView (Undocumented) -// Draws the title string of a window. -// Present on NSThemeFrame since at least 10.6. -// _drawTitleBar is somewhat complex, and has changed over the years -// since OS X 10.6. But in that time it's never done anything that -// would break when called outside of -[NSView drawRect:] (which we -// sometimes do), or whose output can't be redirected to a -// CGContextRef object (which we also sometimes do). This is likely -// to remain true for the indefinite future. However we should -// check _drawTitleBar in each new major version of OS X. For more -// information see bug 877767. -- (void)_drawTitleBar:(NSRect)aRect; - // Returns an NSRect that is the bounding box for all an NSView's dirty // rectangles (ones that need to be redrawn). The full list of dirty // rectangles can be obtained by calling -[NSView _dirtyRegion] and then @@ -130,6 +118,14 @@ class GLManager; // outside a call to -[NSView drawRect:]. - (NSRect)_dirtyRect; +// Undocumented method of one or more of NSFrameView's subclasses. Called +// when one or more of the titlebar buttons needs to be repositioned, to +// disappear, or to reappear (say if the window's style changes). If +// 'redisplay' is true, the entire titlebar (the window's top 22 pixels) is +// marked as needing redisplay. This method has been present in the same +// format since at least OS X 10.5. +- (void)_tileTitlebarAndRedisplay:(BOOL)redisplay; + @end // Support for pixel scroll deltas, not part of NSEvent.h diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm index 0616332a90b606db46eb23414a4ad4dc3a272fad..f81bfbb17437124afad5f739db21fd475223543d 100644 --- a/widget/cocoa/nsChildView.mm +++ b/widget/cocoa/nsChildView.mm @@ -168,7 +168,6 @@ uint32_t nsChildView::sLastInputEventCount = 0; - (void)clearCorners; // Overlay drawing functions for traditional CGContext drawing -- (void)drawTitleString; - (void)drawTitlebarHighlight; - (void)maskTopCornersInContext:(CGContextRef)aContext; @@ -2219,11 +2218,6 @@ nsChildView::UpdateTitlebarImageBuffer() NSGraphicsContext* context = [NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:[frameView isFlipped]]; [NSGraphicsContext setCurrentContext:context]; - // Draw the title string. - if ([frameView respondsToSelector:@selector(_drawTitleBar:)]) { - [frameView _drawTitleBar:[frameView bounds]]; - } - // Draw the titlebar controls into the titlebar image. for (id view in [window titlebarControls]) { NSRect viewFrame = [view frame]; @@ -2388,6 +2382,19 @@ FindUnifiedToolbarBottom(const nsTArray<nsIWidget::ThemeGeometry>& aThemeGeometr } return unifiedToolbarBottom; } + +static nsIntRect +FindFirstRectOfType(const nsTArray<nsIWidget::ThemeGeometry>& aThemeGeometries, + uint8_t aWidgetType) +{ + for (uint32_t i = 0; i < aThemeGeometries.Length(); ++i) { + const nsIWidget::ThemeGeometry& g = aThemeGeometries[i]; + if (g.mWidgetType == aWidgetType) { + return g.mRect; + } + } + return nsIntRect(); +} void nsChildView::UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) @@ -2395,6 +2402,7 @@ nsChildView::UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometri if (![mView window] || ![[mView window] isKindOfClass:[ToolbarWindow class]]) return; + // Update unified toolbar height. int32_t windowWidth = mBounds.width; int32_t titlebarBottom = FindTitlebarBottom(aThemeGeometries, windowWidth); int32_t unifiedToolbarBottom = @@ -2406,6 +2414,12 @@ nsChildView::UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometri int32_t contentOffset = drawsContentsIntoWindowFrame ? titlebarHeight : 0; int32_t devUnifiedHeight = titlebarHeight + unifiedToolbarBottom - contentOffset; [win setUnifiedToolbarHeight:DevPixelsToCocoaPoints(devUnifiedHeight)]; + + // Update titlebar control offsets. + nsIntRect windowButtonRect = FindFirstRectOfType(aThemeGeometries, NS_THEME_WINDOW_BUTTON_BOX); + [win placeWindowButtons:[mView convertRect:DevPixelsToCocoaPoints(windowButtonRect) toView:nil]]; + nsIntRect fullScreenButtonRect = FindFirstRectOfType(aThemeGeometries, NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON); + [win placeFullScreenButton:[mView convertRect:DevPixelsToCocoaPoints(fullScreenButtonRect) toView:nil]]; } TemporaryRef<gfx::DrawTarget> @@ -3458,7 +3472,6 @@ NSEvent* gLastDragMouseDownEvent = nil; } if ([self isCoveringTitlebar]) { - [self drawTitleString]; [self drawTitlebarHighlight]; [self maskTopCornersInContext:aContext]; } @@ -3626,26 +3639,6 @@ NSEvent* gLastDragMouseDownEvent = nil; CGContextRestoreGState(aContext); } -- (void)drawTitleString -{ - NSView* frameView = [[[self window] contentView] superview]; - if (![frameView respondsToSelector:@selector(_drawTitleBar:)]) { - return; - } - - NSGraphicsContext* oldContext = [NSGraphicsContext currentContext]; - CGContextRef ctx = (CGContextRef)[oldContext graphicsPort]; - CGContextSaveGState(ctx); - if ([oldContext isFlipped] != [frameView isFlipped]) { - CGContextTranslateCTM(ctx, 0, [self bounds].size.height); - CGContextScaleCTM(ctx, 1, -1); - } - [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:[frameView isFlipped]]]; - [frameView _drawTitleBar:[frameView bounds]]; - CGContextRestoreGState(ctx); - [NSGraphicsContext setCurrentContext:oldContext]; -} - - (void)drawTitlebarHighlight { DrawTitlebarHighlight([self bounds].size, [self cornerRadius], diff --git a/widget/cocoa/nsCocoaWindow.h b/widget/cocoa/nsCocoaWindow.h index 7cc310b40e79dc2410a2ed645d3dc01132c48a56..63f0ff27d2397794c44af8152d403d4426058c81 100644 --- a/widget/cocoa/nsCocoaWindow.h +++ b/widget/cocoa/nsCocoaWindow.h @@ -125,6 +125,11 @@ typedef struct _nsCocoaWindowList { - (NSRect)contentRectForFrameRect:(NSRect)windowFrame styleMask:(NSUInteger)windowStyle; - (NSRect)frameRectForContentRect:(NSRect)windowContentRect styleMask:(NSUInteger)windowStyle; +// Present since at least OS X 10.5. The OS calls this method on NSWindow +// (and its subclasses) to find out which NSFrameView subclass to instantiate +// to create its "frame view". ++ (Class)frameViewClassForStyleMask:(NSUInteger)styleMask; + @end @interface PopupWindow : BaseWindow @@ -192,6 +197,8 @@ typedef struct _nsCocoaWindowList { CGFloat mUnifiedToolbarHeight; NSColor *mBackgroundColor; NSView *mTitlebarView; // strong + NSRect mWindowButtonsRect; + NSRect mFullScreenButtonRect; } // Pass nil here to get the default appearance. - (void)setTitlebarColor:(NSColor*)aColor forActiveWindow:(BOOL)aActive; @@ -202,6 +209,10 @@ typedef struct _nsCocoaWindowList { - (void)setTitlebarNeedsDisplayInRect:(NSRect)aRect sync:(BOOL)aSync; - (void)setTitlebarNeedsDisplayInRect:(NSRect)aRect; - (void)setDrawsContentsIntoWindowFrame:(BOOL)aState; +- (void)placeWindowButtons:(NSRect)aRect; +- (void)placeFullScreenButton:(NSRect)aRect; +- (NSPoint)windowButtonsPositionWithDefaultPosition:(NSPoint)aDefaultPosition; +- (NSPoint)fullScreenButtonPositionWithDefaultPosition:(NSPoint)aDefaultPosition; @end class nsCocoaWindow : public nsBaseWidget, public nsPIWidgetCocoa @@ -282,6 +293,7 @@ public: virtual void SetShowsToolbarButton(bool aShow); virtual void SetShowsFullScreenButton(bool aShow); virtual void SetWindowAnimationType(WindowAnimationType aType); + NS_IMETHOD SetNonClientMargins(nsIntMargin &margins); NS_IMETHOD SetWindowTitlebarColor(nscolor aColor, bool aActive); virtual void SetDrawsInTitlebar(bool aState); virtual nsresult SynthesizeNativeMouseEvent(nsIntPoint aPoint, diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm index c19affe6af4809b468861dfb5f771686ebc974da..5175e669e0f507b362433b441c83b60c11c3ab75 100644 --- a/widget/cocoa/nsCocoaWindow.mm +++ b/widget/cocoa/nsCocoaWindow.mm @@ -1992,6 +1992,15 @@ void nsCocoaWindow::SetWindowAnimationType(nsIWidget::WindowAnimationType aType) mAnimationType = aType; } +NS_IMETHODIMP nsCocoaWindow::SetNonClientMargins(nsIntMargin &margins) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + SetDrawsInTitlebar(margins.top == 0); + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} + NS_IMETHODIMP nsCocoaWindow::SetWindowTitlebarColor(nscolor aColor, bool aActive) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; @@ -2518,14 +2527,95 @@ GetDPI(NSWindow* aWindow) return dpi * backingScale; } +@interface NSView(FrameViewMethodSwizzling) +- (NSPoint)FrameView__closeButtonOrigin; +- (NSPoint)FrameView__fullScreenButtonOrigin; +@end + +@implementation NSView(FrameViewMethodSwizzling) + +- (NSPoint)FrameView__closeButtonOrigin +{ + NSPoint defaultPosition = [self FrameView__closeButtonOrigin]; + if ([[self window] isKindOfClass:[ToolbarWindow class]]) { + return [(ToolbarWindow*)[self window] windowButtonsPositionWithDefaultPosition:defaultPosition]; + } + return defaultPosition; +} + +- (NSPoint)FrameView__fullScreenButtonOrigin +{ + NSPoint defaultPosition = [self FrameView__fullScreenButtonOrigin]; + if ([[self window] isKindOfClass:[ToolbarWindow class]]) { + return [(ToolbarWindow*)[self window] fullScreenButtonPositionWithDefaultPosition:defaultPosition]; + } + return defaultPosition; +} + +@end + +static NSMutableSet *gSwizzledFrameViewClasses = nil; + @interface BaseWindow(Private) - (void)removeTrackingArea; - (void)cursorUpdated:(NSEvent*)aEvent; - (void)updateContentViewSize; +- (void)reflowTitlebarElements; @end @implementation BaseWindow +// The frame of a window is implemented using undocumented NSView subclasses. +// We offset the window buttons by overriding the methods _closeButtonOrigin +// and _fullScreenButtonOrigin on these frame view classes. The class which is +// used for a window is determined in the window's frameViewClassForStyleMask: +// method, so this is where we make sure that we have swizzled the method on +// all encountered classes. ++ (Class)frameViewClassForStyleMask:(NSUInteger)styleMask +{ + Class frameViewClass = [super frameViewClassForStyleMask:styleMask]; + + if (!gSwizzledFrameViewClasses) { + gSwizzledFrameViewClasses = [[NSMutableSet setWithCapacity:3] retain]; + if (!gSwizzledFrameViewClasses) { + return frameViewClass; + } + } + + static IMP our_closeButtonOrigin = + class_getMethodImplementation([NSView class], + @selector(FrameView__closeButtonOrigin)); + static IMP our_fullScreenButtonOrigin = + class_getMethodImplementation([NSView class], + @selector(FrameView__fullScreenButtonOrigin)); + + if (![gSwizzledFrameViewClasses containsObject:frameViewClass]) { + // Either of these methods might be implemented in both a subclass of + // NSFrameView and one of its own subclasses. Which means that if we + // aren't careful we might end up swizzling the same method twice. + // Since method swizzling involves swapping pointers, this would break + // things. + IMP _closeButtonOrigin = + class_getMethodImplementation(frameViewClass, + @selector(_closeButtonOrigin)); + if (_closeButtonOrigin && _closeButtonOrigin != our_closeButtonOrigin) { + nsToolkit::SwizzleMethods(frameViewClass, @selector(_closeButtonOrigin), + @selector(FrameView__closeButtonOrigin)); + } + IMP _fullScreenButtonOrigin = + class_getMethodImplementation(frameViewClass, + @selector(_fullScreenButtonOrigin)); + if (_fullScreenButtonOrigin && + _fullScreenButtonOrigin != our_fullScreenButtonOrigin) { + nsToolkit::SwizzleMethods(frameViewClass, @selector(_fullScreenButtonOrigin), + @selector(FrameView__fullScreenButtonOrigin)); + } + [gSwizzledFrameViewClasses addObject:frameViewClass]; + } + + return frameViewClass; +} + - (id)initWithContentRect:(NSRect)aContentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)aBufferingType defer:(BOOL)aFlag { mDrawsIntoWindowFrame = NO; @@ -2606,8 +2696,12 @@ static const NSString* kStateShowsToolbarButton = @"showsToolbarButton"; - (void)setDrawsContentsIntoWindowFrame:(BOOL)aState { + bool changed = (aState != mDrawsIntoWindowFrame); mDrawsIntoWindowFrame = aState; - [self updateContentViewSize]; + if (changed) { + [self updateContentViewSize]; + [self reflowTitlebarElements]; + } } - (BOOL)drawsContentsIntoWindowFrame @@ -2722,6 +2816,15 @@ static const NSString* kStateShowsToolbarButton = @"showsToolbarButton"; [[self contentView] setFrameSize:rect.size]; } +// Possibly move the titlebar buttons. +- (void)reflowTitlebarElements +{ + NSView *frameView = [[self contentView] superview]; + if ([frameView respondsToSelector:@selector(_tileTitlebarAndRedisplay:)]) { + [frameView _tileTitlebarAndRedisplay:NO]; + } +} + // Override methods that translate between content rect and frame rect. - (NSRect)contentRectForFrameRect:(NSRect)aRect { @@ -2922,6 +3025,8 @@ static const NSString* kStateShowsToolbarButton = @"showsToolbarButton"; mBackgroundColor = [[NSColor whiteColor] retain]; mUnifiedToolbarHeight = 22.0f; + mWindowButtonsRect = NSZeroRect; + mFullScreenButtonRect = NSZeroRect; // setBottomCornerRounded: is a private API call, so we check to make sure // we respond to it just in case. @@ -3056,6 +3161,40 @@ static const NSString* kStateShowsToolbarButton = @"showsToolbarButton"; } } +- (void)placeWindowButtons:(NSRect)aRect +{ + if (!NSEqualRects(mWindowButtonsRect, aRect)) { + mWindowButtonsRect = aRect; + [self reflowTitlebarElements]; + } +} + +- (NSPoint)windowButtonsPositionWithDefaultPosition:(NSPoint)aDefaultPosition +{ + if ([self drawsContentsIntoWindowFrame] && !NSIsEmptyRect(mWindowButtonsRect)) { + return NSMakePoint(std::max(mWindowButtonsRect.origin.x, aDefaultPosition.x), + std::min(mWindowButtonsRect.origin.y, aDefaultPosition.y)); + } + return aDefaultPosition; +} + +- (void)placeFullScreenButton:(NSRect)aRect +{ + if (!NSEqualRects(mFullScreenButtonRect, aRect)) { + mFullScreenButtonRect = aRect; + [self reflowTitlebarElements]; + } +} + +- (NSPoint)fullScreenButtonPositionWithDefaultPosition:(NSPoint)aDefaultPosition; +{ + if ([self drawsContentsIntoWindowFrame] && !NSIsEmptyRect(mFullScreenButtonRect)) { + return NSMakePoint(std::min(mFullScreenButtonRect.origin.x, aDefaultPosition.x), + std::min(mFullScreenButtonRect.origin.y, aDefaultPosition.y)); + } + return aDefaultPosition; +} + // Returning YES here makes the setShowsToolbarButton method work even though // the window doesn't contain an NSToolbar. - (BOOL)_hasToolbar diff --git a/widget/cocoa/nsNativeThemeCocoa.mm b/widget/cocoa/nsNativeThemeCocoa.mm index 76deab83a6e10ad3392f38f3c863982718b864f2..d250bbd4382c5f9ac5a55c2f6a304892c29da67f 100644 --- a/widget/cocoa/nsNativeThemeCocoa.mm +++ b/widget/cocoa/nsNativeThemeCocoa.mm @@ -361,6 +361,33 @@ static NSWindow* NativeWindowForFrame(nsIFrame* aFrame, return (NSWindow*)topLevelWidget->GetNativeData(NS_NATIVE_WINDOW); } +static NSSize +WindowButtonsSize(nsIFrame* aFrame) +{ + NSWindow* window = NativeWindowForFrame(aFrame); + if (!window) { + // Return fallback values. + if (!nsCocoaFeatures::OnLionOrLater()) + return NSMakeSize(57, 16); + return NSMakeSize(54, 16); + } + + NSRect buttonBox = NSZeroRect; + NSButton* closeButton = [window standardWindowButton:NSWindowCloseButton]; + if (closeButton) { + buttonBox = NSUnionRect(buttonBox, [closeButton frame]); + } + NSButton* minimizeButton = [window standardWindowButton:NSWindowMiniaturizeButton]; + if (minimizeButton) { + buttonBox = NSUnionRect(buttonBox, [minimizeButton frame]); + } + NSButton* zoomButton = [window standardWindowButton:NSWindowZoomButton]; + if (zoomButton) { + buttonBox = NSUnionRect(buttonBox, [zoomButton frame]); + } + return buttonBox.size; +} + static BOOL FrameIsInActiveWindow(nsIFrame* aFrame) { nsIWidget* topLevelWidget = NULL; @@ -2748,7 +2775,24 @@ nsNativeThemeCocoa::GetMinimumWidgetSize(nsRenderingContext* aContext, aResult->SizeTo(0, (2 + 2) /* top */ + 9 + (1 + 1) /* bottom */); break; } - + + case NS_THEME_WINDOW_BUTTON_BOX: { + NSSize size = WindowButtonsSize(aFrame); + aResult->SizeTo(size.width, size.height); + *aIsOverridable = false; + break; + } + + case NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON: { + if ([NativeWindowForFrame(aFrame) respondsToSelector:@selector(toggleFullScreen:)]) { + // This value is hardcoded because it's needed before we can measure the + // position and size of the fullscreen button. + aResult->SizeTo(16, 17); + } + *aIsOverridable = false; + break; + } + case NS_THEME_PROGRESSBAR: { SInt32 barHeight = 0; @@ -3039,10 +3083,12 @@ nsNativeThemeCocoa::ThemeSupportsWidget(nsPresContext* aPresContext, nsIFrame* a case NS_THEME_DIALOG: case NS_THEME_WINDOW: + case NS_THEME_WINDOW_BUTTON_BOX: case NS_THEME_WINDOW_TITLEBAR: case NS_THEME_MENUPOPUP: case NS_THEME_MENUITEM: case NS_THEME_MENUSEPARATOR: + case NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON: case NS_THEME_TOOLTIP: case NS_THEME_CHECKBOX: