diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /browser/components/customizableui/CustomizableWidgets.jsm | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | browser/components/customizableui/CustomizableWidgets.jsm | 941 |
1 files changed, 941 insertions, 0 deletions
diff --git a/browser/components/customizableui/CustomizableWidgets.jsm b/browser/components/customizableui/CustomizableWidgets.jsm new file mode 100644 index 0000000000..f37d1e44e1 --- /dev/null +++ b/browser/components/customizableui/CustomizableWidgets.jsm @@ -0,0 +1,941 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +var EXPORTED_SYMBOLS = ["CustomizableWidgets"]; + +const { CustomizableUI } = ChromeUtils.import( + "resource:///modules/CustomizableUI.jsm" +); +const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const { XPCOMUtils } = ChromeUtils.import( + "resource://gre/modules/XPCOMUtils.jsm" +); +const { AppConstants } = ChromeUtils.import( + "resource://gre/modules/AppConstants.jsm" +); + +XPCOMUtils.defineLazyModuleGetters(this, { + PanelView: "resource:///modules/PanelMultiView.jsm", + RecentlyClosedTabsAndWindowsMenuUtils: + "resource:///modules/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm", + ShortcutUtils: "resource://gre/modules/ShortcutUtils.jsm", + CharsetMenu: "resource://gre/modules/CharsetMenu.jsm", + PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm", + Sanitizer: "resource:///modules/Sanitizer.jsm", + SyncedTabs: "resource://services-sync/SyncedTabs.jsm", +}); + +ChromeUtils.defineModuleGetter( + this, + "PanelMultiView", + "resource:///modules/PanelMultiView.jsm" +); + +const kPrefCustomizationDebug = "browser.uiCustomization.debug"; + +XPCOMUtils.defineLazyGetter(this, "log", () => { + let scope = {}; + ChromeUtils.import("resource://gre/modules/Console.jsm", scope); + let debug = Services.prefs.getBoolPref(kPrefCustomizationDebug, false); + let consoleOptions = { + maxLogLevel: debug ? "all" : "log", + prefix: "CustomizableWidgets", + }; + return new scope.ConsoleAPI(consoleOptions); +}); + +function setAttributes(aNode, aAttrs) { + let doc = aNode.ownerDocument; + for (let [name, value] of Object.entries(aAttrs)) { + if (!value) { + if (aNode.hasAttribute(name)) { + aNode.removeAttribute(name); + } + } else { + if (name == "shortcutId") { + continue; + } + if (name == "label" || name == "tooltiptext") { + let stringId = typeof value == "string" ? value : name; + let additionalArgs = []; + if (aAttrs.shortcutId) { + let shortcut = doc.getElementById(aAttrs.shortcutId); + if (shortcut) { + additionalArgs.push(ShortcutUtils.prettifyShortcut(shortcut)); + } + } + value = CustomizableUI.getLocalizedProperty( + { id: aAttrs.id }, + stringId, + additionalArgs + ); + } + aNode.setAttribute(name, value); + } + } +} + +const CustomizableWidgets = [ + { + id: "history-panelmenu", + type: "view", + viewId: "PanelUI-history", + shortcutId: "key_gotoHistory", + tooltiptext: "history-panelmenu.tooltiptext2", + recentlyClosedTabsPanel: "appMenu-library-recentlyClosedTabs", + recentlyClosedWindowsPanel: "appMenu-library-recentlyClosedWindows", + handleEvent(event) { + switch (event.type) { + case "PanelMultiViewHidden": + this.onPanelMultiViewHidden(event); + break; + case "ViewShowing": + this.onSubViewShowing(event); + break; + default: + throw new Error(`Unsupported event for '${this.id}'`); + } + }, + onViewShowing(event) { + if (this._panelMenuView) { + return; + } + + let panelview = event.target; + let document = panelview.ownerDocument; + let window = document.defaultView; + + // We restrict the amount of results to 42. Not 50, but 42. Why? Because 42. + let query = + "place:queryType=" + + Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY + + "&sort=" + + Ci.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING + + "&maxResults=42&excludeQueries=1"; + + this._panelMenuView = new window.PlacesPanelview( + document.getElementById("appMenu_historyMenu"), + panelview, + query + ); + // When either of these sub-subviews show, populate them with recently closed + // objects data. + PanelMultiView.getViewNode( + document, + this.recentlyClosedTabsPanel + ).addEventListener("ViewShowing", this); + PanelMultiView.getViewNode( + document, + this.recentlyClosedWindowsPanel + ).addEventListener("ViewShowing", this); + // When the popup is hidden (thus the panelmultiview node as well), make + // sure to stop listening to PlacesDatabase updates. + panelview.panelMultiView.addEventListener("PanelMultiViewHidden", this); + }, + onViewHiding(event) { + log.debug("History view is being hidden!"); + }, + onPanelMultiViewHidden(event) { + let panelMultiView = event.target; + let document = panelMultiView.ownerDocument; + if (this._panelMenuView) { + this._panelMenuView.uninit(); + delete this._panelMenuView; + PanelMultiView.getViewNode( + document, + this.recentlyClosedTabsPanel + ).removeEventListener("ViewShowing", this); + PanelMultiView.getViewNode( + document, + this.recentlyClosedWindowsPanel + ).removeEventListener("ViewShowing", this); + } + panelMultiView.removeEventListener("PanelMultiViewHidden", this); + }, + onSubViewShowing(event) { + let panelview = event.target; + let document = event.target.ownerDocument; + let window = document.defaultView; + let viewType = + panelview.id == this.recentlyClosedTabsPanel ? "Tabs" : "Windows"; + + this._panelMenuView.clearAllContents(panelview); + + let utils = RecentlyClosedTabsAndWindowsMenuUtils; + let method = `get${viewType}Fragment`; + let fragment = utils[method](window, "toolbarbutton", true); + let elementCount = fragment.childElementCount; + this._panelMenuView._setEmptyPopupStatus(panelview, !elementCount); + if (!elementCount) { + return; + } + + let body = document.createXULElement("vbox"); + body.className = "panel-subview-body"; + body.appendChild(fragment); + let footer; + while (--elementCount >= 0) { + let element = body.children[elementCount]; + CustomizableUI.addShortcut(element); + element.classList.add("subviewbutton"); + if (element.classList.contains("restoreallitem")) { + footer = element; + element.classList.add("panel-subview-footer"); + } else { + element.classList.add("subviewbutton-iconic", "bookmark-item"); + } + } + panelview.appendChild(body); + panelview.appendChild(footer); + }, + }, + { + id: "save-page-button", + shortcutId: "key_savePage", + tooltiptext: "save-page-button.tooltiptext3", + onCommand(aEvent) { + let win = aEvent.target.ownerGlobal; + win.saveBrowser(win.gBrowser.selectedBrowser); + }, + }, + { + id: "find-button", + shortcutId: "key_find", + tooltiptext: "find-button.tooltiptext3", + onCommand(aEvent) { + let win = aEvent.target.ownerGlobal; + if (win.gLazyFindCommand) { + win.gLazyFindCommand("onFindCommand"); + } + }, + }, + { + id: "open-file-button", + shortcutId: "openFileKb", + tooltiptext: "open-file-button.tooltiptext3", + onCommand(aEvent) { + let win = aEvent.target.ownerGlobal; + win.BrowserOpenFileWindow(); + }, + }, + { + id: "sidebar-button", + tooltiptext: "sidebar-button.tooltiptext2", + onCommand(aEvent) { + let win = aEvent.target.ownerGlobal; + win.SidebarUI.toggle(); + }, + onCreated(aNode) { + // Add an observer so the button is checked while the sidebar is open + let doc = aNode.ownerDocument; + let obChecked = doc.createXULElement("observes"); + obChecked.setAttribute("element", "sidebar-box"); + obChecked.setAttribute("attribute", "checked"); + let obPosition = doc.createXULElement("observes"); + obPosition.setAttribute("element", "sidebar-box"); + obPosition.setAttribute("attribute", "positionend"); + + aNode.appendChild(obChecked); + aNode.appendChild(obPosition); + }, + }, + { + id: "add-ons-button", + shortcutId: "key_openAddons", + tooltiptext: "add-ons-button.tooltiptext3", + onCommand(aEvent) { + let win = aEvent.target.ownerGlobal; + win.BrowserOpenAddonsMgr(); + }, + }, + { + id: "zoom-controls", + type: "custom", + tooltiptext: "zoom-controls.tooltiptext2", + onBuild(aDocument) { + let buttons = [ + { + id: "zoom-out-button", + command: "cmd_fullZoomReduce", + label: true, + closemenu: "none", + tooltiptext: "tooltiptext2", + shortcutId: "key_fullZoomReduce", + class: "toolbarbutton-1 toolbarbutton-combined", + }, + { + id: "zoom-reset-button", + command: "cmd_fullZoomReset", + closemenu: "none", + tooltiptext: "tooltiptext2", + shortcutId: "key_fullZoomReset", + class: "toolbarbutton-1 toolbarbutton-combined", + }, + { + id: "zoom-in-button", + command: "cmd_fullZoomEnlarge", + closemenu: "none", + label: true, + tooltiptext: "tooltiptext2", + shortcutId: "key_fullZoomEnlarge", + class: "toolbarbutton-1 toolbarbutton-combined", + }, + ]; + + let node = aDocument.createXULElement("toolbaritem"); + node.setAttribute("id", "zoom-controls"); + node.setAttribute( + "label", + CustomizableUI.getLocalizedProperty(this, "label") + ); + 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"); + + buttons.forEach(function(aButton, aIndex) { + if (aIndex != 0) { + node.appendChild(aDocument.createXULElement("separator")); + } + let btnNode = aDocument.createXULElement("toolbarbutton"); + setAttributes(btnNode, aButton); + node.appendChild(btnNode); + }); + return node; + }, + }, + { + id: "edit-controls", + type: "custom", + tooltiptext: "edit-controls.tooltiptext2", + onBuild(aDocument) { + let buttons = [ + { + id: "cut-button", + command: "cmd_cut", + label: true, + tooltiptext: "tooltiptext2", + shortcutId: "key_cut", + class: "toolbarbutton-1 toolbarbutton-combined", + }, + { + id: "copy-button", + command: "cmd_copy", + label: true, + tooltiptext: "tooltiptext2", + shortcutId: "key_copy", + class: "toolbarbutton-1 toolbarbutton-combined", + }, + { + id: "paste-button", + command: "cmd_paste", + label: true, + tooltiptext: "tooltiptext2", + shortcutId: "key_paste", + class: "toolbarbutton-1 toolbarbutton-combined", + }, + ]; + + let node = aDocument.createXULElement("toolbaritem"); + node.setAttribute("id", "edit-controls"); + node.setAttribute( + "label", + CustomizableUI.getLocalizedProperty(this, "label") + ); + 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"); + + buttons.forEach(function(aButton, aIndex) { + if (aIndex != 0) { + node.appendChild(aDocument.createXULElement("separator")); + } + let btnNode = aDocument.createXULElement("toolbarbutton"); + setAttributes(btnNode, aButton); + node.appendChild(btnNode); + }); + + let listener = { + onWidgetInstanceRemoved: (aWidgetId, aDoc) => { + if (aWidgetId != this.id || aDoc != aDocument) { + return; + } + CustomizableUI.removeListener(listener); + }, + onWidgetOverflow(aWidgetNode) { + if (aWidgetNode == node) { + node.ownerGlobal.updateEditUIVisibility(); + } + }, + onWidgetUnderflow(aWidgetNode) { + if (aWidgetNode == node) { + node.ownerGlobal.updateEditUIVisibility(); + } + }, + }; + CustomizableUI.addListener(listener); + + return node; + }, + }, + { + id: "characterencoding-button", + label: "characterencoding-button2.label", + type: "view", + viewId: "PanelUI-characterEncodingView", + tooltiptext: "characterencoding-button2.tooltiptext", + maybeDisableMenu(aDocument) { + let window = aDocument.defaultView; + return !( + window.gBrowser && + window.gBrowser.selectedBrowser.mayEnableCharacterEncodingMenu + ); + }, + populateList(aDocument, aContainerId, aSection) { + let containerElem = aDocument.getElementById(aContainerId); + + containerElem.addEventListener("command", this.onCommand); + + let list = this.charsetInfo[aSection]; + + for (let item of list) { + let elem = aDocument.createXULElement("toolbarbutton"); + elem.setAttribute("label", item.label); + elem.setAttribute("type", "checkbox"); + elem.section = aSection; + elem.value = item.value; + elem.setAttribute("class", "subviewbutton"); + containerElem.appendChild(elem); + } + }, + updateCurrentCharset(aDocument) { + let currentCharset = + aDocument.defaultView.gBrowser.selectedBrowser.characterSet; + let { + charsetAutodetected, + } = aDocument.defaultView.gBrowser.selectedBrowser; + currentCharset = CharsetMenu.foldCharset( + currentCharset, + charsetAutodetected + ); + + let pinnedContainer = aDocument.getElementById( + "PanelUI-characterEncodingView-pinned" + ); + let charsetContainer = aDocument.getElementById( + "PanelUI-characterEncodingView-charsets" + ); + let elements = [ + ...pinnedContainer.children, + ...charsetContainer.children, + ]; + + this._updateElements(elements, currentCharset); + }, + _updateElements(aElements, aCurrentItem) { + if (!aElements.length) { + return; + } + let disabled = this.maybeDisableMenu(aElements[0].ownerDocument); + for (let elem of aElements) { + if (disabled) { + elem.setAttribute("disabled", "true"); + } else { + elem.removeAttribute("disabled"); + } + if (elem.value.toLowerCase() == aCurrentItem.toLowerCase()) { + elem.setAttribute("checked", "true"); + } else { + elem.removeAttribute("checked"); + } + } + }, + onViewShowing(aEvent) { + if (!this._inited) { + this.onInit(); + } + let document = aEvent.target.ownerDocument; + + if ( + !document.getElementById("PanelUI-characterEncodingView-pinned") + .firstChild + ) { + this.populateList( + document, + "PanelUI-characterEncodingView-pinned", + "pinnedCharsets" + ); + this.populateList( + document, + "PanelUI-characterEncodingView-charsets", + "otherCharsets" + ); + } + + this.updateCurrentCharset(document); + }, + onCommand(aEvent) { + let node = aEvent.target; + if (!node.hasAttribute || !node.section) { + return; + } + + let window = node.ownerGlobal; + let value = node.value; + + window.BrowserSetForcedCharacterSet(value); + }, + onCreated(aNode) { + let document = aNode.ownerDocument; + + let updateButton = () => { + if (this.maybeDisableMenu(document)) { + aNode.setAttribute("disabled", "true"); + } else { + aNode.removeAttribute("disabled"); + } + }; + + let getPanel = () => { + let { PanelUI } = document.ownerGlobal; + return PanelUI.overflowPanel; + }; + + if ( + CustomizableUI.getAreaType(this.currentArea) == + CustomizableUI.TYPE_MENU_PANEL + ) { + getPanel().addEventListener("popupshowing", updateButton); + } + + let listener = { + onWidgetAdded: (aWidgetId, aArea) => { + if (aWidgetId != this.id) { + return; + } + if ( + CustomizableUI.getAreaType(aArea) == CustomizableUI.TYPE_MENU_PANEL + ) { + getPanel().addEventListener("popupshowing", updateButton); + } + }, + onWidgetRemoved: (aWidgetId, aPrevArea) => { + if (aWidgetId != this.id) { + return; + } + aNode.removeAttribute("disabled"); + if ( + CustomizableUI.getAreaType(aPrevArea) == + CustomizableUI.TYPE_MENU_PANEL + ) { + getPanel().removeEventListener("popupshowing", updateButton); + } + }, + onWidgetInstanceRemoved: (aWidgetId, aDoc) => { + if (aWidgetId != this.id || aDoc != document) { + return; + } + + CustomizableUI.removeListener(listener); + getPanel().removeEventListener("popupshowing", updateButton); + }, + }; + CustomizableUI.addListener(listener); + this.onInit(); + }, + onInit() { + this._inited = true; + if (!this.charsetInfo) { + this.charsetInfo = CharsetMenu.getData(); + } + }, + }, + { + id: "email-link-button", + tooltiptext: "email-link-button.tooltiptext3", + onCommand(aEvent) { + let win = aEvent.view; + win.MailIntegration.sendLinkForBrowser(win.gBrowser.selectedBrowser); + }, + }, +]; + +if (Services.prefs.getBoolPref("identity.fxaccounts.enabled")) { + CustomizableWidgets.push({ + id: "sync-button", + label: "remotetabs-panelmenu.label", + tooltiptext: "remotetabs-panelmenu.tooltiptext2", + type: "view", + viewId: "PanelUI-remotetabs", + deckIndices: { + DECKINDEX_TABS: 0, + DECKINDEX_TABSDISABLED: 1, + DECKINDEX_FETCHING: 2, + DECKINDEX_NOCLIENTS: 3, + }, + TABS_PER_PAGE: 25, + NEXT_PAGE_MIN_TABS: 5, // Minimum number of tabs displayed when we click "Show All" + onViewShowing(aEvent) { + let doc = aEvent.target.ownerDocument; + this._tabsList = doc.getElementById("PanelUI-remotetabs-tabslist"); + Services.obs.addObserver(this, SyncedTabs.TOPIC_TABS_CHANGED); + + let deck = doc.getElementById("PanelUI-remotetabs-deck"); + if (SyncedTabs.isConfiguredToSyncTabs) { + if (SyncedTabs.hasSyncedThisSession) { + deck.selectedIndex = this.deckIndices.DECKINDEX_TABS; + } else { + // Sync hasn't synced tabs yet, so show the "fetching" panel. + deck.selectedIndex = this.deckIndices.DECKINDEX_FETCHING; + } + // force a background sync. + SyncedTabs.syncTabs().catch(ex => { + Cu.reportError(ex); + }); + // show the current list - it will be updated by our observer. + this._showTabs(); + } else { + // not configured to sync tabs, so no point updating the list. + deck.selectedIndex = this.deckIndices.DECKINDEX_TABSDISABLED; + } + }, + onViewHiding() { + Services.obs.removeObserver(this, SyncedTabs.TOPIC_TABS_CHANGED); + this._tabsList = null; + }, + _tabsList: null, + observe(subject, topic, data) { + switch (topic) { + case SyncedTabs.TOPIC_TABS_CHANGED: + this._showTabs(); + break; + default: + break; + } + }, + + _showTabsPromise: Promise.resolve(), + // Update the tab list after any existing in-flight updates are complete. + _showTabs(paginationInfo) { + this._showTabsPromise = this._showTabsPromise.then( + () => { + return this.__showTabs(paginationInfo); + }, + e => { + Cu.reportError(e); + } + ); + }, + // Return a new promise to update the tab list. + __showTabs(paginationInfo) { + if (!this._tabsList) { + // Closed between the previous `this._showTabsPromise` + // resolving and now. + return undefined; + } + let doc = this._tabsList.ownerDocument; + let deck = doc.getElementById("PanelUI-remotetabs-deck"); + return SyncedTabs.getTabClients() + .then(clients => { + // The view may have been hidden while the promise was resolving. + if (!this._tabsList) { + return; + } + if (clients.length === 0 && !SyncedTabs.hasSyncedThisSession) { + // the "fetching tabs" deck is being shown - let's leave it there. + // When that first sync completes we'll be notified and update. + return; + } + + if (clients.length === 0) { + deck.selectedIndex = this.deckIndices.DECKINDEX_NOCLIENTS; + return; + } + + deck.selectedIndex = this.deckIndices.DECKINDEX_TABS; + this._clearTabList(); + SyncedTabs.sortTabClientsByLastUsed(clients); + let fragment = doc.createDocumentFragment(); + + let clientNumber = 0; + for (let client of clients) { + // add a menu separator for all clients other than the first. + if (fragment.lastElementChild) { + let separator = doc.createXULElement("menuseparator"); + fragment.appendChild(separator); + } + // We add the client's elements to a container, and indicate which + // element labels it. + let labelId = `synced-tabs-client-${clientNumber++}`; + let container = doc.createXULElement("vbox"); + container.classList.add("PanelUI-remotetabs-clientcontainer"); + container.setAttribute("role", "group"); + container.setAttribute("aria-labelledby", labelId); + if (paginationInfo && paginationInfo.clientId == client.id) { + this._appendClient( + client, + container, + labelId, + paginationInfo.maxTabs + ); + } else { + this._appendClient(client, container, labelId); + } + fragment.appendChild(container); + } + this._tabsList.appendChild(fragment); + PanelView.forNode( + this._tabsList.closest("panelview") + ).descriptionHeightWorkaround(); + }) + .catch(err => { + Cu.reportError(err); + }) + .then(() => { + // an observer for tests. + Services.obs.notifyObservers( + null, + "synced-tabs-menu:test:tabs-updated" + ); + }); + }, + _clearTabList() { + let list = this._tabsList; + while (list.lastChild) { + list.lastChild.remove(); + } + }, + _showNoClientMessage() { + this._appendMessageLabel("notabslabel"); + }, + _appendMessageLabel(messageAttr, appendTo = null) { + if (!appendTo) { + appendTo = this._tabsList; + } + let message = this._tabsList.getAttribute(messageAttr); + let doc = this._tabsList.ownerDocument; + let messageLabel = doc.createXULElement("label"); + messageLabel.textContent = message; + appendTo.appendChild(messageLabel); + return messageLabel; + }, + _appendClient(client, container, labelId, maxTabs = this.TABS_PER_PAGE) { + let doc = container.ownerDocument; + // Create the element for the remote client. + let clientItem = doc.createXULElement("label"); + clientItem.setAttribute("id", labelId); + clientItem.setAttribute("itemtype", "client"); + let window = doc.defaultView; + clientItem.setAttribute( + "tooltiptext", + window.gSync.formatLastSyncDate(new Date(client.lastModified)) + ); + clientItem.textContent = client.name; + + container.appendChild(clientItem); + + if (!client.tabs.length) { + let label = this._appendMessageLabel("notabsforclientlabel", container); + label.setAttribute("class", "PanelUI-remotetabs-notabsforclient-label"); + } else { + // If this page will display all tabs, show no additional buttons. + // If the next page will display all the remaining tabs, show a "Show All" button + // Otherwise, show a "Shore More" button + let hasNextPage = client.tabs.length > maxTabs; + let nextPageIsLastPage = + hasNextPage && maxTabs + this.TABS_PER_PAGE >= client.tabs.length; + if (nextPageIsLastPage) { + // When the user clicks "Show All", try to have at least NEXT_PAGE_MIN_TABS more tabs + // to display in order to avoid user frustration + maxTabs = Math.min( + client.tabs.length - this.NEXT_PAGE_MIN_TABS, + maxTabs + ); + } + if (hasNextPage) { + client.tabs = client.tabs.slice(0, maxTabs); + } + for (let tab of client.tabs) { + let tabEnt = this._createTabElement(doc, tab); + container.appendChild(tabEnt); + } + if (hasNextPage) { + let showAllEnt = this._createShowMoreElement( + doc, + client.id, + nextPageIsLastPage ? Infinity : maxTabs + this.TABS_PER_PAGE + ); + container.appendChild(showAllEnt); + } + } + }, + _createTabElement(doc, tabInfo) { + let item = doc.createXULElement("toolbarbutton"); + let tooltipText = + (tabInfo.title ? tabInfo.title + "\n" : "") + tabInfo.url; + item.setAttribute("itemtype", "tab"); + item.setAttribute("class", "subviewbutton"); + item.setAttribute("targetURI", tabInfo.url); + item.setAttribute( + "label", + tabInfo.title != "" ? tabInfo.title : tabInfo.url + ); + item.setAttribute("image", tabInfo.icon); + item.setAttribute("tooltiptext", tooltipText); + // We need to use "click" instead of "command" here so openUILink + // respects different buttons (eg, to open in a new tab). + item.addEventListener("click", e => { + doc.defaultView.openUILink(tabInfo.url, e, { + triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal( + {} + ), + }); + if (doc.defaultView.whereToOpenLink(e) != "current") { + e.preventDefault(); + e.stopPropagation(); + } else { + CustomizableUI.hidePanelForNode(item); + } + }); + return item; + }, + _createShowMoreElement(doc, clientId, showCount) { + let labelAttr, tooltipAttr; + if (showCount === Infinity) { + labelAttr = "showAllLabel"; + tooltipAttr = "showAllTooltipText"; + } else { + labelAttr = "showMoreLabel"; + tooltipAttr = "showMoreTooltipText"; + } + let showAllItem = doc.createXULElement("toolbarbutton"); + showAllItem.setAttribute("itemtype", "showmorebutton"); + showAllItem.setAttribute("class", "subviewbutton"); + let label = this._tabsList.getAttribute(labelAttr); + showAllItem.setAttribute("label", label); + let tooltipText = this._tabsList.getAttribute(tooltipAttr); + showAllItem.setAttribute("tooltiptext", tooltipText); + showAllItem.addEventListener("click", e => { + e.preventDefault(); + e.stopPropagation(); + this._showTabs({ clientId, maxTabs: showCount }); + }); + return showAllItem; + }, + }); +} + +let preferencesButton = { + id: "preferences-button", + onCommand(aEvent) { + let win = aEvent.target.ownerGlobal; + win.openPreferences(undefined); + }, +}; +if (AppConstants.platform == "win") { + preferencesButton.label = "preferences-button.labelWin"; + preferencesButton.tooltiptext = "preferences-button.tooltipWin2"; +} else if (AppConstants.platform == "macosx") { + preferencesButton.tooltiptext = "preferences-button.tooltiptext.withshortcut"; + preferencesButton.shortcutId = "key_preferencesCmdMac"; +} else { + preferencesButton.tooltiptext = "preferences-button.tooltiptext2"; +} +CustomizableWidgets.push(preferencesButton); + +if (Services.prefs.getBoolPref("privacy.panicButton.enabled")) { + CustomizableWidgets.push({ + id: "panic-button", + type: "view", + viewId: "PanelUI-panicView", + + forgetButtonCalled(aEvent) { + let doc = aEvent.target.ownerDocument; + let group = doc.getElementById("PanelUI-panic-timeSpan"); + let itemsToClear = [ + "cookies", + "history", + "openWindows", + "formdata", + "sessions", + "cache", + "downloads", + "offlineApps", + ]; + let newWindowPrivateState = PrivateBrowsingUtils.isWindowPrivate( + doc.defaultView + ) + ? "private" + : "non-private"; + let promise = Sanitizer.sanitize(itemsToClear, { + ignoreTimespan: false, + range: Sanitizer.getClearRange(+group.value), + privateStateForNewWindow: newWindowPrivateState, + }); + promise.then(function() { + let otherWindow = Services.wm.getMostRecentWindow("navigator:browser"); + if (otherWindow.closed) { + Cu.reportError("Got a closed window!"); + } + if (otherWindow.PanicButtonNotifier) { + otherWindow.PanicButtonNotifier.notify(); + } else { + otherWindow.PanicButtonNotifierShouldNotify = true; + } + }); + }, + handleEvent(aEvent) { + switch (aEvent.type) { + case "command": + this.forgetButtonCalled(aEvent); + break; + } + }, + onViewShowing(aEvent) { + let win = aEvent.target.ownerGlobal; + let doc = win.document; + let eventBlocker = null; + eventBlocker = doc.l10n.translateElements([aEvent.target]); + + let forgetButton = aEvent.target.querySelector( + "#PanelUI-panic-view-button" + ); + let group = doc.getElementById("PanelUI-panic-timeSpan"); + group.selectedItem = doc.getElementById("PanelUI-panic-5min"); + forgetButton.addEventListener("command", this); + + if (eventBlocker) { + aEvent.detail.addBlocker(eventBlocker); + } + }, + onViewHiding(aEvent) { + let forgetButton = aEvent.target.querySelector( + "#PanelUI-panic-view-button" + ); + forgetButton.removeEventListener("command", this); + }, + }); +} + +if (PrivateBrowsingUtils.enabled) { + CustomizableWidgets.push({ + id: "privatebrowsing-button", + shortcutId: "key_privatebrowsing", + onCommand(e) { + let win = e.target.ownerGlobal; + win.OpenBrowserWindow({ private: true }); + }, + }); +} |