diff options
Diffstat (limited to 'browser/base/content/browser-allTabsMenu.js')
-rw-r--r-- | browser/base/content/browser-allTabsMenu.js | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/browser/base/content/browser-allTabsMenu.js b/browser/base/content/browser-allTabsMenu.js new file mode 100644 index 0000000000..324c5d95ab --- /dev/null +++ b/browser/base/content/browser-allTabsMenu.js @@ -0,0 +1,190 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This file is loaded into the browser window scope. +/* eslint-env mozilla/browser-window */ + +ChromeUtils.defineModuleGetter( + this, + "TabsPanel", + "resource:///modules/TabsList.jsm" +); + +var gTabsPanel = { + kElements: { + allTabsButton: "alltabs-button", + allTabsView: "allTabsMenu-allTabsView", + allTabsViewTabs: "allTabsMenu-allTabsView-tabs", + dropIndicator: "allTabsMenu-dropIndicator", + containerTabsView: "allTabsMenu-containerTabsView", + hiddenTabsButton: "allTabsMenu-hiddenTabsButton", + hiddenTabsView: "allTabsMenu-hiddenTabsView", + }, + _initialized: false, + _initializedElements: false, + + initElements() { + if (this._initializedElements) { + return; + } + let template = document.getElementById("allTabsMenu-container"); + template.replaceWith(template.content); + + for (let [name, id] of Object.entries(this.kElements)) { + this[name] = document.getElementById(id); + } + this._initializedElements = true; + }, + + init() { + if (this._initialized) { + return; + } + + this.initElements(); + + this.hiddenAudioTabsPopup = new TabsPanel({ + view: this.allTabsView, + insertBefore: document.getElementById("allTabsMenu-tabsSeparator"), + filterFn: tab => tab.hidden && tab.soundPlaying, + }); + let showPinnedTabs = Services.prefs.getBoolPref( + "browser.tabs.tabmanager.enabled" + ); + this.allTabsPanel = new TabsPanel({ + view: this.allTabsView, + containerNode: this.allTabsViewTabs, + filterFn: tab => + !tab.hidden && (!tab.pinned || (showPinnedTabs && tab.pinned)), + dropIndicator: this.dropIndicator, + }); + + this.allTabsView.addEventListener("ViewShowing", e => { + PanelUI._ensureShortcutsShown(this.allTabsView); + + let containersEnabled = + Services.prefs.getBoolPref("privacy.userContext.enabled") && + !PrivateBrowsingUtils.isWindowPrivate(window); + document.getElementById("allTabsMenu-containerTabsButton").hidden = + !containersEnabled; + + let hasHiddenTabs = gBrowser.visibleTabs.length < gBrowser.tabs.length; + document.getElementById("allTabsMenu-hiddenTabsButton").hidden = + !hasHiddenTabs; + document.getElementById("allTabsMenu-hiddenTabsSeparator").hidden = + !hasHiddenTabs; + }); + + this.allTabsView.addEventListener("ViewShown", e => + this.allTabsView + .querySelector(".all-tabs-item[selected]") + ?.scrollIntoView({ block: "center" }) + ); + + let containerTabsMenuSeparator = + this.containerTabsView.querySelector("toolbarseparator"); + this.containerTabsView.addEventListener("ViewShowing", e => { + let elements = []; + let frag = document.createDocumentFragment(); + + ContextualIdentityService.getPublicIdentities().forEach(identity => { + let menuitem = document.createXULElement("toolbarbutton"); + menuitem.setAttribute("class", "subviewbutton subviewbutton-iconic"); + menuitem.setAttribute( + "label", + ContextualIdentityService.getUserContextLabel(identity.userContextId) + ); + // The styles depend on this. + menuitem.setAttribute("usercontextid", identity.userContextId); + // The command handler depends on this. + menuitem.setAttribute("data-usercontextid", identity.userContextId); + menuitem.classList.add("identity-icon-" + identity.icon); + menuitem.classList.add("identity-color-" + identity.color); + + menuitem.setAttribute("command", "Browser:NewUserContextTab"); + + frag.appendChild(menuitem); + elements.push(menuitem); + }); + + e.target.addEventListener( + "ViewHiding", + () => { + for (let element of elements) { + element.remove(); + } + }, + { once: true } + ); + containerTabsMenuSeparator.parentNode.insertBefore( + frag, + containerTabsMenuSeparator + ); + }); + + this.hiddenTabsPopup = new TabsPanel({ + view: this.hiddenTabsView, + filterFn: tab => tab.hidden, + }); + + this._initialized = true; + }, + + get canOpen() { + this.initElements(); + return isElementVisible(this.allTabsButton); + }, + + showAllTabsPanel(event, entrypoint = "unknown") { + // Note that event may be null. + + // Only space and enter should open the popup, ignore other keypresses: + if (event?.type == "keypress" && event.key != "Enter" && event.key != " ") { + return; + } + this.init(); + if (this.canOpen) { + Services.telemetry.keyedScalarAdd( + "browser.ui.interaction.all_tabs_panel_entrypoint", + entrypoint, + 1 + ); + PanelUI.showSubView( + this.kElements.allTabsView, + this.allTabsButton, + event + ); + } + }, + + hideAllTabsPanel() { + if (this.allTabsView) { + PanelMultiView.hidePopup(this.allTabsView.closest("panel")); + } + }, + + showHiddenTabsPanel(event, entrypoint = "unknown") { + this.init(); + if (!this.canOpen) { + return; + } + this.allTabsView.addEventListener( + "ViewShown", + e => { + PanelUI.showSubView( + this.kElements.hiddenTabsView, + this.hiddenTabsButton + ); + }, + { once: true } + ); + this.showAllTabsPanel(event, entrypoint); + }, + + searchTabs() { + gURLBar.search(UrlbarTokenizer.RESTRICT.OPENPAGE, { + searchModeEntry: "tabmenu", + }); + }, +}; |