Bug 1446101 - Part 2: Convert the all tabs panel to photon styles r=dao
MozReview-Commit-ID: 3VzqnG6X5rw
This commit is contained in:
51
browser/base/content/browser-allTabsMenu.inc.xul
Normal file
51
browser/base/content/browser-allTabsMenu.inc.xul
Normal file
@@ -0,0 +1,51 @@
|
||||
<!-- 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="allTabsMenu"
|
||||
class="cui-widget-panel"
|
||||
role="group"
|
||||
type="arrow"
|
||||
hidden="true"
|
||||
flip="slide"
|
||||
position="bottomcenter topright"
|
||||
noautofocus="true">
|
||||
<panelmultiview mainViewId="allTabsMenu-allTabsView" disablekeynav="true">
|
||||
<panelview id="allTabsMenu-allTabsView" class="PanelUI-subView">
|
||||
<vbox class="panel-subview-body">
|
||||
<toolbarbutton id="allTabsUndoCloseButton"
|
||||
class="undo-close-tab subviewbutton subviewbutton-iconic"
|
||||
label="&undoCloseTab.label;"
|
||||
key="key_undoCloseTab"
|
||||
command="History:UndoCloseTab"/>
|
||||
<toolbarseparator/>
|
||||
<toolbarbutton class="container-tabs-button subviewbutton subviewbutton-nav"
|
||||
closemenu="none"
|
||||
oncommand="PanelUI.showSubView('allTabsMenu-containerTabsView', this);"
|
||||
label="&newUserContext.label;"/>
|
||||
<toolbarseparator class="container-tabs-separator"/>
|
||||
<toolbarbutton id="allTabsMenu-hiddenTabsButton"
|
||||
class="hidden-tabs-button subviewbutton subviewbutton-nav"
|
||||
closemenu="none"
|
||||
oncommand="PanelUI.showSubView('allTabsMenu-hiddenTabsView', this);"
|
||||
label="&hiddenTabs.label;" />
|
||||
<toolbarseparator class="hidden-tabs-separator"/>
|
||||
<vbox id="allTabsMenu-allTabsViewTabs" class="panel-subview-body"/>
|
||||
</vbox>
|
||||
</panelview>
|
||||
|
||||
<panelview id="allTabsMenu-hiddenTabsView" class="PanelUI-subView">
|
||||
<vbox class="panel-subview-body"/>
|
||||
</panelview>
|
||||
|
||||
<panelview id="allTabsMenu-containerTabsView" class="PanelUI-subView">
|
||||
<vbox class="panel-subview-body">
|
||||
<toolbarseparator class="container-tabs-submenu-separator"/>
|
||||
<toolbarbutton class="subviewbutton"
|
||||
label="&manageUserContext.label;"
|
||||
accesskey="&manageUserContext.accesskey;"
|
||||
command="Browser:OpenAboutContainers"/>
|
||||
</vbox>
|
||||
</panelview>
|
||||
</panelmultiview>
|
||||
</panel>
|
||||
144
browser/base/content/browser-allTabsMenu.js
Normal file
144
browser/base/content/browser-allTabsMenu.js
Normal file
@@ -0,0 +1,144 @@
|
||||
/* 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-allTabsViewTabs",
|
||||
containerTabsView: "allTabsMenu-containerTabsView",
|
||||
hiddenTabsButton: "allTabsMenu-hiddenTabsButton",
|
||||
hiddenTabsView: "allTabsMenu-hiddenTabsView",
|
||||
},
|
||||
_initialized: false,
|
||||
|
||||
initElements() {
|
||||
for (let [name, id] of Object.entries(this.kElements)) {
|
||||
this[name] = document.getElementById(id);
|
||||
}
|
||||
},
|
||||
|
||||
init() {
|
||||
if (this._initialized) return;
|
||||
|
||||
this.initElements();
|
||||
|
||||
let hiddenTabsMenuButton = this.allTabsView.querySelector(".hidden-tabs-button");
|
||||
let hiddenTabsSeparator = this.allTabsView.querySelector(".hidden-tabs-separator");
|
||||
this.hiddenAudioTabsPopup = new TabsPanel({
|
||||
view: this.allTabsView,
|
||||
insertBefore: hiddenTabsSeparator,
|
||||
filterFn: (tab) => tab.hidden && tab.soundPlaying,
|
||||
});
|
||||
this.allTabsPanel = new TabsPanel({
|
||||
view: this.allTabsView,
|
||||
containerNode: this.allTabsViewTabs,
|
||||
filterFn: (tab) => !tab.pinned && !tab.hidden,
|
||||
onPopulate() {
|
||||
// Set the visible tab status.
|
||||
let tabContainer = gBrowser.tabContainer;
|
||||
// We don't want menu item decoration unless there is overflow.
|
||||
if (tabContainer.getAttribute("overflow") != "true") {
|
||||
return;
|
||||
}
|
||||
|
||||
let windowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
let arrowScrollboxRect = windowUtils.getBoundsWithoutFlushing(tabContainer.arrowScrollbox);
|
||||
for (let row of this.rows) {
|
||||
let curTabRect = windowUtils.getBoundsWithoutFlushing(row.tab);
|
||||
if (curTabRect.left >= arrowScrollboxRect.left &&
|
||||
curTabRect.right <= arrowScrollboxRect.right) {
|
||||
row.setAttribute("tabIsVisible", "true");
|
||||
} else {
|
||||
row.removeAttribute("tabIsVisible");
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
let containerTabsButton = this.allTabsView.querySelector(".container-tabs-button");
|
||||
let containerTabsSeparator = this.allTabsView.querySelector(".container-tabs-separator");
|
||||
this.allTabsView.addEventListener("ViewShowing", (e) => {
|
||||
PanelUI._ensureShortcutsShown(this.allTabsView);
|
||||
e.target.querySelector(".undo-close-tab").disabled =
|
||||
SessionStore.getClosedTabCount(window) == 0;
|
||||
|
||||
let containersEnabled = Services.prefs.getBoolPref("privacy.userContext.enabled")
|
||||
&& !PrivateBrowsingUtils.isWindowPrivate(window);
|
||||
containerTabsButton.hidden = !containersEnabled;
|
||||
containerTabsSeparator.hidden = !containersEnabled;
|
||||
|
||||
let hasHiddenTabs = gBrowser.visibleTabs.length < gBrowser.tabs.length;
|
||||
hiddenTabsMenuButton.hidden = !hasHiddenTabs;
|
||||
hiddenTabsSeparator.hidden = !hasHiddenTabs;
|
||||
});
|
||||
|
||||
this.allTabsView.addEventListener("ViewShown", (e) => {
|
||||
let selectedRow = this.allTabsView.querySelector(".all-tabs-item[selected]");
|
||||
selectedRow.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.createElement("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.setAttribute("data-identity-color", identity.color);
|
||||
menuitem.setAttribute("data-identity-icon", identity.icon);
|
||||
|
||||
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;
|
||||
},
|
||||
|
||||
showAllTabsPanel() {
|
||||
this.init();
|
||||
PanelUI.showSubView(this.kElements.allTabsView, this.allTabsButton);
|
||||
},
|
||||
|
||||
hideAllTabsPanel() {
|
||||
this.init();
|
||||
PanelMultiView.hidePopup(this.allTabsView.closest("panel"));
|
||||
},
|
||||
|
||||
showHiddenTabsPanel() {
|
||||
this.init();
|
||||
this.allTabsView.addEventListener("ViewShown", (e) => {
|
||||
PanelUI.showSubView(this.kElements.hiddenTabsView, this.hiddenTabsButton);
|
||||
}, {once: true});
|
||||
this.showAllTabsPanel();
|
||||
},
|
||||
};
|
||||
@@ -56,7 +56,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
SiteDataManager: "resource:///modules/SiteDataManager.jsm",
|
||||
SitePermissions: "resource:///modules/SitePermissions.jsm",
|
||||
TabCrashHandler: "resource:///modules/ContentCrashHandlers.jsm",
|
||||
TabsPopup: "resource:///modules/TabsPopup.jsm",
|
||||
TabsPopup: "resource:///modules/TabsList.jsm",
|
||||
TelemetryStopwatch: "resource://gre/modules/TelemetryStopwatch.jsm",
|
||||
Translation: "resource:///modules/translation/Translation.jsm",
|
||||
UITour: "resource:///modules/UITour.jsm",
|
||||
@@ -84,6 +84,8 @@ XPCOMUtils.defineLazyScriptGetter(this, "PanelUI",
|
||||
"chrome://browser/content/customizableui/panelUI.js");
|
||||
XPCOMUtils.defineLazyScriptGetter(this, "gViewSourceUtils",
|
||||
"chrome://global/content/viewSourceUtils.js");
|
||||
XPCOMUtils.defineLazyScriptGetter(this, "gTabsPanel",
|
||||
"chrome://browser/content/browser-allTabsMenu.js");
|
||||
XPCOMUtils.defineLazyScriptGetter(this, ["LightWeightThemeWebInstaller",
|
||||
"gExtensionsNotifications",
|
||||
"gXPInstallObserver"],
|
||||
@@ -1747,6 +1749,11 @@ var gBrowserInit = {
|
||||
gSync.init();
|
||||
});
|
||||
|
||||
scheduleIdleTask(() => {
|
||||
// Initialize the all tabs menu
|
||||
gTabsPanel.init();
|
||||
});
|
||||
|
||||
scheduleIdleTask(() => {
|
||||
CombinedStopReload.startAnimationPrefMonitoring();
|
||||
});
|
||||
|
||||
@@ -528,6 +528,7 @@
|
||||
#include ../../components/customizableui/content/panelUI.inc.xul
|
||||
#include ../../components/controlcenter/content/panel.inc.xul
|
||||
#include ../../components/downloads/content/downloadsPanel.inc.xul
|
||||
#include browser-allTabsMenu.inc.xul
|
||||
|
||||
<hbox id="downloads-animation-container" mousethrough="always">
|
||||
<vbox id="downloads-notification-anchor" hidden="true">
|
||||
@@ -679,29 +680,10 @@
|
||||
|
||||
<toolbarbutton id="alltabs-button"
|
||||
class="toolbarbutton-1 chromeclass-toolbar-additional tabs-alltabs-button badged-button"
|
||||
type="menu"
|
||||
oncommand="gTabsPanel.showAllTabsPanel();"
|
||||
label="&listAllTabs.label;"
|
||||
tooltiptext="&listAllTabs.label;"
|
||||
removable="false">
|
||||
<menupopup id="alltabs-popup"
|
||||
position="after_end">
|
||||
<menuitem id="alltabs_undoCloseTab"
|
||||
key="key_undoCloseTab"
|
||||
label="&undoCloseTab.label;"
|
||||
observes="History:UndoCloseTab"/>
|
||||
<menuseparator id="alltabs-popup-separator-1"/>
|
||||
<menu id="alltabs_containersTab"
|
||||
label="&newUserContext.label;">
|
||||
<menupopup id="alltabs_containersMenuTab" />
|
||||
</menu>
|
||||
<menuseparator id="alltabs-popup-separator-2"/>
|
||||
<menu id="alltabs_hiddenTabs"
|
||||
label="&hiddenTabs.label;">
|
||||
<menupopup id="alltabs_hiddenTabsMenu"/>
|
||||
</menu>
|
||||
<menuseparator id="alltabs-popup-separator-3"/>
|
||||
</menupopup>
|
||||
</toolbarbutton>
|
||||
removable="false"/>
|
||||
|
||||
<hbox class="titlebar-placeholder" type="post-tabs"
|
||||
ordinal="1000"
|
||||
|
||||
@@ -158,6 +158,9 @@ with Files("macWindow.inc.xul"):
|
||||
with Files("tabbrowser*"):
|
||||
BUG_COMPONENT = ("Firefox", "Tabbed Browser")
|
||||
|
||||
with Files("browser-allTabsMenu.js"):
|
||||
BUG_COMPONENT = ("Firefox", "Tabbed Browser")
|
||||
|
||||
with Files("webext-panels*"):
|
||||
BUG_COMPONENT = ("WebExtensions", "Frontend")
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ browser.jar:
|
||||
content/browser/browser.js (content/browser.js)
|
||||
* content/browser/browser.xul (content/browser.xul)
|
||||
content/browser/browser-addons.js (content/browser-addons.js)
|
||||
content/browser/browser-allTabsMenu.js (content/browser-allTabsMenu.js)
|
||||
content/browser/browser-captivePortal.js (content/browser-captivePortal.js)
|
||||
content/browser/browser-ctrlTab.js (content/browser-ctrlTab.js)
|
||||
content/browser/browser-customization.js (content/browser-customization.js)
|
||||
|
||||
@@ -843,12 +843,12 @@ const PanelUI = {
|
||||
},
|
||||
|
||||
_addedShortcuts: false,
|
||||
_ensureShortcutsShown() {
|
||||
if (this._addedShortcuts) {
|
||||
_ensureShortcutsShown(view = this.mainView) {
|
||||
if (view.hasAttribute("added-shortcuts")) {
|
||||
return;
|
||||
}
|
||||
this._addedShortcuts = true;
|
||||
for (let button of this.mainView.querySelectorAll("toolbarbutton[key]")) {
|
||||
view.setAttribute("added-shortcuts", "true");
|
||||
for (let button of view.querySelectorAll("toolbarbutton[key]")) {
|
||||
let keyId = button.getAttribute("key");
|
||||
let key = document.getElementById(keyId);
|
||||
if (!key) {
|
||||
|
||||
@@ -259,7 +259,6 @@ async function doTestForAllTabsFavicon(aTestPage, aExpectedCookies, aIsThirdPart
|
||||
|
||||
// Set the 'overflow' attribute to make allTabs button available.
|
||||
let tabBrowser = document.getElementById("tabbrowser-tabs");
|
||||
let allTabsBtn = document.getElementById("alltabs-button");
|
||||
tabBrowser.setAttribute("overflow", true);
|
||||
|
||||
// Start to observe the event of that the favicon has been fully loaded.
|
||||
@@ -280,14 +279,15 @@ async function doTestForAllTabsFavicon(aTestPage, aExpectedCookies, aIsThirdPart
|
||||
firstPageURI, true);
|
||||
|
||||
// Make the popup of allTabs showing up and trigger the loading of the favicon.
|
||||
let allTabsPopupShownPromise = BrowserTestUtils.waitForEvent(allTabsBtn, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(allTabsBtn, {});
|
||||
let allTabsView = document.getElementById("allTabsMenu-allTabsView");
|
||||
let allTabsPopupShownPromise = BrowserTestUtils.waitForEvent(allTabsView, "ViewShown");
|
||||
gTabsPanel.showAllTabsPanel();
|
||||
await promiseObserveFavicon;
|
||||
await allTabsPopupShownPromise;
|
||||
|
||||
// Close the popup of allTabs and wait until it's done.
|
||||
let allTabsPopupHiddenPromise = BrowserTestUtils.waitForEvent(allTabsBtn, "popuphidden");
|
||||
EventUtils.synthesizeMouseAtCenter(allTabsBtn, {});
|
||||
let allTabsPopupHiddenPromise = BrowserTestUtils.waitForEvent(allTabsView.panelMultiView, "PanelMultiViewHidden");
|
||||
gTabsPanel.hideAllTabsPanel();
|
||||
await allTabsPopupHiddenPromise;
|
||||
|
||||
// Close the tab.
|
||||
@@ -313,14 +313,14 @@ async function doTestForAllTabsFavicon(aTestPage, aExpectedCookies, aIsThirdPart
|
||||
secondPageURI, true);
|
||||
|
||||
// Make the popup of allTabs showing up again.
|
||||
allTabsPopupShownPromise = BrowserTestUtils.waitForEvent(allTabsBtn, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(allTabsBtn, {});
|
||||
allTabsPopupShownPromise = BrowserTestUtils.waitForEvent(allTabsView, "ViewShown");
|
||||
gTabsPanel.showAllTabsPanel();
|
||||
await promiseObserveFavicon;
|
||||
await allTabsPopupShownPromise;
|
||||
|
||||
// Close the popup of allTabs and wait until it's done.
|
||||
allTabsPopupHiddenPromise = BrowserTestUtils.waitForEvent(allTabsBtn, "popuphidden");
|
||||
EventUtils.synthesizeMouseAtCenter(allTabsBtn, {});
|
||||
allTabsPopupHiddenPromise = BrowserTestUtils.waitForEvent(allTabsView.panelMultiView, "PanelMultiViewHidden");
|
||||
gTabsPanel.hideAllTabsPanel();
|
||||
await allTabsPopupHiddenPromise;
|
||||
|
||||
// Close the tab.
|
||||
|
||||
@@ -215,7 +215,6 @@ async function doTestForAllTabsFavicon(aTestPage, aFaviconHost, aFaviconURL) {
|
||||
|
||||
// Set the 'overflow' attribute to make allTabs button available.
|
||||
let tabBrowser = document.getElementById("tabbrowser-tabs");
|
||||
let allTabsBtn = document.getElementById("alltabs-button");
|
||||
tabBrowser.setAttribute("overflow", true);
|
||||
|
||||
// Create the observer object for observing request channels of the personal
|
||||
@@ -239,14 +238,15 @@ async function doTestForAllTabsFavicon(aTestPage, aFaviconHost, aFaviconURL) {
|
||||
Services.obs.addObserver(observer, "http-on-modify-request");
|
||||
|
||||
// Make the popup of allTabs showing up and trigger the loading of the favicon.
|
||||
let allTabsPopupShownPromise = BrowserTestUtils.waitForEvent(allTabsBtn, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(allTabsBtn, {});
|
||||
let allTabsView = document.getElementById("allTabsMenu-allTabsView");
|
||||
let allTabsPopupShownPromise = BrowserTestUtils.waitForEvent(allTabsView, "ViewShown");
|
||||
gTabsPanel.showAllTabsPanel();
|
||||
await observer.promise;
|
||||
await allTabsPopupShownPromise;
|
||||
|
||||
// Close the popup of allTabs and wait until it's done.
|
||||
let allTabsPopupHiddenPromise = BrowserTestUtils.waitForEvent(allTabsBtn, "popuphidden");
|
||||
EventUtils.synthesizeMouseAtCenter(allTabsBtn, {});
|
||||
let allTabsPopupHiddenPromise = BrowserTestUtils.waitForEvent(allTabsView.panelMultiView, "PanelMultiViewHidden");
|
||||
gTabsPanel.hideAllTabsPanel();
|
||||
await allTabsPopupHiddenPromise;
|
||||
|
||||
// Remove the observer for not receiving the favicon requests for opening a tab
|
||||
@@ -274,14 +274,14 @@ async function doTestForAllTabsFavicon(aTestPage, aFaviconHost, aFaviconURL) {
|
||||
Services.obs.addObserver(observer, "http-on-modify-request");
|
||||
|
||||
// Make the popup of allTabs showing up again.
|
||||
allTabsPopupShownPromise = BrowserTestUtils.waitForEvent(allTabsBtn, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(allTabsBtn, {});
|
||||
allTabsPopupShownPromise = BrowserTestUtils.waitForEvent(allTabsView, "ViewShown");
|
||||
gTabsPanel.showAllTabsPanel();
|
||||
await observer.promise;
|
||||
await allTabsPopupShownPromise;
|
||||
|
||||
// Close the popup of allTabs and wait until it's done.
|
||||
allTabsPopupHiddenPromise = BrowserTestUtils.waitForEvent(allTabsBtn, "popuphidden");
|
||||
EventUtils.synthesizeMouseAtCenter(allTabsBtn, {});
|
||||
allTabsPopupHiddenPromise = BrowserTestUtils.waitForEvent(allTabsView.panelMultiView, "PanelMultiViewHidden");
|
||||
gTabsPanel.hideAllTabsPanel();
|
||||
await allTabsPopupHiddenPromise;
|
||||
|
||||
Services.obs.removeObserver(observer, "http-on-modify-request");
|
||||
|
||||
@@ -308,6 +308,8 @@ These should match what Safari and other Apple applications use on OS X Lion. --
|
||||
<!ENTITY fileMenu.accesskey "F">
|
||||
<!ENTITY newUserContext.label "New Container Tab">
|
||||
<!ENTITY newUserContext.accesskey "B">
|
||||
<!ENTITY manageUserContext.label "Manage Containers">
|
||||
<!ENTITY manageUserContext.accesskey "O">
|
||||
<!ENTITY newNavigatorCmd.label "New Window">
|
||||
<!ENTITY newNavigatorCmd.key "N">
|
||||
<!ENTITY newNavigatorCmd.accesskey "N">
|
||||
|
||||
@@ -4,9 +4,22 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["TabsPopup"];
|
||||
ChromeUtils.defineModuleGetter(this, "PanelMultiView",
|
||||
"resource:///modules/PanelMultiView.jsm");
|
||||
|
||||
var EXPORTED_SYMBOLS = ["TabsPanel", "TabsPopup"];
|
||||
const NSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
function setAttributes(element, attrs) {
|
||||
for (let [name, value] of Object.entries(attrs)) {
|
||||
if (value) {
|
||||
element.setAttribute(name, value);
|
||||
} else {
|
||||
element.removeAttribute(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TabsListBase {
|
||||
constructor({className, filterFn, insertBefore, onPopulate, containerNode}) {
|
||||
this.className = className;
|
||||
@@ -130,22 +143,23 @@ class TabsListBase {
|
||||
|
||||
class TabsPopup extends TabsListBase {
|
||||
/*
|
||||
* Handle menuitem rows for tab objects in a menupopup.
|
||||
* Generate toolbarbuttons for tabs that meet some criteria.
|
||||
*
|
||||
* @param {object} opts Options for configuring this instance.
|
||||
* @param {string} opts.className
|
||||
* An optional class name to be added to menuitem elements.
|
||||
* @param {function} opts.filterFn
|
||||
* A function to filter which tabs are added to the popup.
|
||||
* A function to filter which tabs are used.
|
||||
* @param {object} opts.view
|
||||
* A panel view to listen to events on.
|
||||
* @param {object} opts.containerNode
|
||||
* An optional element to append elements to, if ommitted they
|
||||
* will be appended to opts.view.firstChild or before
|
||||
* opts.insertBefore.
|
||||
* @param {object} opts.insertBefore
|
||||
* An optional element to insert the menuitems before in the
|
||||
* popup, if omitted they will be appended to popup.
|
||||
* An optional element to insert the results before, if
|
||||
* omitted they will be appended to opts.containerNode.
|
||||
* @param {function} opts.onPopulate
|
||||
* An optional function that will be called with the
|
||||
* popupshowing event that caused the menu to be populated.
|
||||
* @param {object} opts.popup
|
||||
* A menupopup element to populate and register the show/hide
|
||||
* listeners on.
|
||||
*/
|
||||
constructor({className, filterFn, insertBefore, onPopulate, popup}) {
|
||||
super({className, filterFn, insertBefore, onPopulate, containerNode: popup});
|
||||
@@ -230,3 +244,140 @@ class TabsPopup extends TabsListBase {
|
||||
addEndImage().setAttribute("soundplaying", "true");
|
||||
}
|
||||
}
|
||||
|
||||
const TABS_PANEL_EVENTS = {
|
||||
show: "ViewShowing",
|
||||
hide: "PanelMultiViewHidden",
|
||||
};
|
||||
|
||||
class TabsPanel extends TabsListBase {
|
||||
constructor(opts) {
|
||||
super({
|
||||
...opts,
|
||||
containerNode: opts.containerNode || opts.view.firstChild,
|
||||
onPopulate: (...args) => {
|
||||
this._onPopulate(...args);
|
||||
if (typeof opts.onPopulate == "function") {
|
||||
opts.onPopulate.call(this, ...args);
|
||||
}
|
||||
},
|
||||
});
|
||||
this.view = opts.view;
|
||||
this.view.addEventListener(TABS_PANEL_EVENTS.show, this);
|
||||
this.panelMultiView = null;
|
||||
}
|
||||
|
||||
handleEvent(event) {
|
||||
switch (event.type) {
|
||||
case TABS_PANEL_EVENTS.hide:
|
||||
if (event.target == this.panelMultiView) {
|
||||
this._cleanup();
|
||||
this.panelMultiView = null;
|
||||
}
|
||||
break;
|
||||
case TABS_PANEL_EVENTS.show:
|
||||
if (!this.listenersRegistered && event.target == this.view) {
|
||||
this.panelMultiView = this.view.panelMultiView;
|
||||
this._populate(event);
|
||||
}
|
||||
break;
|
||||
case "command":
|
||||
if (event.target.hasAttribute("toggle-mute")) {
|
||||
event.target.tab.toggleMuteAudio();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
super.handleEvent(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_onPopulate(event) {
|
||||
// The loading throbber can't be set until the toolbarbutton is rendered,
|
||||
// so do that on first populate.
|
||||
for (let row of this.rows) {
|
||||
this._setImageAttributes(row, row.tab);
|
||||
}
|
||||
}
|
||||
|
||||
_selectTab(tab) {
|
||||
super._selectTab(tab);
|
||||
PanelMultiView.hidePopup(this.view.closest("panel"));
|
||||
}
|
||||
|
||||
_setupListeners() {
|
||||
super._setupListeners();
|
||||
this.panelMultiView.addEventListener(TABS_PANEL_EVENTS.hide, this);
|
||||
}
|
||||
|
||||
_cleanupListeners() {
|
||||
super._cleanupListeners();
|
||||
this.panelMultiView.removeEventListener(TABS_PANEL_EVENTS.hide, this);
|
||||
}
|
||||
|
||||
_createRow(tab) {
|
||||
let {doc} = this;
|
||||
let row = doc.createElementNS(NSXUL, "toolbaritem");
|
||||
row.setAttribute("class", "all-tabs-item");
|
||||
|
||||
let button = doc.createElementNS(NSXUL, "toolbarbutton");
|
||||
button.setAttribute("class", "all-tabs-button subviewbutton subviewbutton-iconic");
|
||||
button.setAttribute("flex", "1");
|
||||
button.setAttribute("crop", "right");
|
||||
button.tab = tab;
|
||||
|
||||
row.appendChild(button);
|
||||
|
||||
let secondaryButton = doc.createElementNS(NSXUL, "toolbarbutton");
|
||||
secondaryButton.setAttribute(
|
||||
"class", "all-tabs-secondary-button subviewbutton subviewbutton-iconic");
|
||||
secondaryButton.setAttribute("closemenu", "none");
|
||||
secondaryButton.setAttribute("toggle-mute", "true");
|
||||
secondaryButton.tab = tab;
|
||||
row.appendChild(secondaryButton);
|
||||
|
||||
this._setRowAttributes(row, tab);
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
_setRowAttributes(row, tab) {
|
||||
setAttributes(row, {selected: tab.selected});
|
||||
|
||||
let busy = tab.getAttribute("busy");
|
||||
let button = row.firstChild;
|
||||
setAttributes(button, {
|
||||
busy,
|
||||
label: tab.label,
|
||||
image: !busy && tab.getAttribute("image"),
|
||||
iconloadingprincipal: tab.getAttribute("iconloadingprincipal"),
|
||||
});
|
||||
|
||||
this._setImageAttributes(row, tab);
|
||||
|
||||
let secondaryButton = row.querySelector(".all-tabs-secondary-button");
|
||||
setAttributes(secondaryButton, {
|
||||
muted: tab.muted,
|
||||
soundplaying: tab.soundPlaying,
|
||||
hidden: !(tab.muted || tab.soundPlaying),
|
||||
});
|
||||
}
|
||||
|
||||
_setImageAttributes(row, tab) {
|
||||
let button = row.firstChild;
|
||||
let busy = tab.getAttribute("busy");
|
||||
let image = this.doc.getAnonymousElementByAttribute(
|
||||
button, "class", "toolbarbutton-icon") ||
|
||||
this.doc.getAnonymousElementByAttribute(
|
||||
button, "class", "toolbarbutton-icon tab-throbber-fallback");
|
||||
|
||||
if (image) {
|
||||
setAttributes(image, {busy});
|
||||
if (busy) {
|
||||
image.classList.add("tab-throbber-fallback");
|
||||
} else {
|
||||
image.classList.remove("tab-throbber-fallback");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,7 +103,7 @@ with Files("SiteDataManager.jsm"):
|
||||
with Files("SitePermissions.jsm"):
|
||||
BUG_COMPONENT = ("Firefox", "Site Identity and Permission Panels")
|
||||
|
||||
with Files("TabsPopup.jsm"):
|
||||
with Files("TabsList.jsm"):
|
||||
BUG_COMPONENT = ("Firefox", "Tabbed Browser")
|
||||
|
||||
with Files("ThemeVariableMap.jsm"):
|
||||
@@ -172,7 +172,7 @@ EXTRA_JS_MODULES += [
|
||||
'SchedulePressure.jsm',
|
||||
'SiteDataManager.jsm',
|
||||
'SitePermissions.jsm',
|
||||
'TabsPopup.jsm',
|
||||
'TabsList.jsm',
|
||||
'ThemeVariableMap.jsm',
|
||||
'TransientPrefs.jsm',
|
||||
'webrtcUI.jsm',
|
||||
|
||||
6
browser/themes/shared/icons/undo.svg
Normal file
6
browser/themes/shared/icons/undo.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<!-- 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 xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<path fill="context-fill" d="M16,11 C16,11.5522847 15.5522847,12 15,12 C14.4477153,12 14,11.5522847 14,11 C14,8.23857625 11.7614237,6 9,6 C6.94968096,6 5.18760031,7.23409522 4.41604369,9 L7.0043326,9 C7.55661734,9 8.0043326,9.44771525 8.0043326,10 C8.0043326,10.5522847 7.55661734,11 7.0043326,11 L2,11 C1.44771525,11 1,10.5522847 1,10 L1,5 C1,4.44771525 1.44771525,4 2,4 C2.55228475,4 3,4.44771525 3,5 L3,7.39241339 C4.22489715,5.35958217 6.45367486,4 9,4 C12.8659932,4 16,7.13400675 16,11 Z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 784 B |
@@ -176,6 +176,7 @@
|
||||
skin/classic/browser/stop-to-reload.svg (../shared/icons/stop-to-reload.svg)
|
||||
skin/classic/browser/sync.svg (../shared/icons/sync.svg)
|
||||
skin/classic/browser/tab.svg (../shared/icons/tab.svg)
|
||||
skin/classic/browser/undo.svg (../shared/icons/undo.svg)
|
||||
skin/classic/browser/bookmarks-toolbar.svg (../shared/icons/bookmarks-toolbar.svg)
|
||||
skin/classic/browser/webIDE.svg (../shared/icons/webIDE.svg)
|
||||
skin/classic/browser/window.svg (../shared/icons/window.svg)
|
||||
|
||||
@@ -784,3 +784,63 @@
|
||||
.alltabs-endimage[activemedia-blocked] {
|
||||
list-style-image: url(chrome://browser/skin/tabbrowser/tab-audio-blocked.svg);
|
||||
}
|
||||
|
||||
#appMenu-allTabsView {
|
||||
--blue-40: #45a1ff;
|
||||
max-width: 42em;
|
||||
}
|
||||
|
||||
.all-tabs-item > .all-tabs-secondary-button {
|
||||
padding: 0;
|
||||
padding-inline-start: 6px;
|
||||
opacity: .8;
|
||||
-moz-context-properties: fill;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
.all-tabs-secondary-button:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.all-tabs-item:hover {
|
||||
background-color: var(--arrowpanel-dimmed)
|
||||
}
|
||||
|
||||
.all-tabs-item > .all-tabs-button > .tab-throbber-fallback {
|
||||
display: block;
|
||||
margin-inline-end: 0;
|
||||
}
|
||||
|
||||
.all-tabs-item[selected] {
|
||||
box-shadow: inset 4px 0 var(--blue-40);
|
||||
}
|
||||
|
||||
.all-tabs-item[tabIsVisible] {
|
||||
box-shadow: inset -4px 0 ThreeDShadow;
|
||||
}
|
||||
|
||||
.all-tabs-item[selected][tabIsVisible] {
|
||||
box-shadow: inset -4px 0 ThreeDShadow, inset 4px 0 var(--blue-40);
|
||||
}
|
||||
|
||||
.all-tabs-button,
|
||||
.all-tabs-secondary-button {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.all-tabs-secondary-button > label {
|
||||
display: none;
|
||||
margin: 0 5.5px;
|
||||
}
|
||||
|
||||
.all-tabs-secondary-button[soundplaying] {
|
||||
list-style-image: url(chrome://browser/skin/tabbrowser/tab-audio-playing.svg);
|
||||
}
|
||||
|
||||
.all-tabs-secondary-button[muted] {
|
||||
list-style-image: url(chrome://browser/skin/tabbrowser/tab-audio-muted.svg);
|
||||
}
|
||||
|
||||
.undo-close-tab {
|
||||
list-style-image: url(chrome://browser/skin/undo.svg);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<content>
|
||||
<children includes="observes|template|menupopup|panel|tooltip"/>
|
||||
<xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,label,type,consumeanchor"/>
|
||||
<xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,label,type,consumeanchor,triggeringprincipal=iconloadingprincipal"/>
|
||||
<xul:label class="toolbarbutton-text" crop="right" flex="1"
|
||||
xbl:inherits="value=label,accesskey,crop,dragover-top,wrap"/>
|
||||
<xul:label class="toolbarbutton-multiline-text" flex="1"
|
||||
|
||||
Reference in New Issue
Block a user