summaryrefslogtreecommitdiffstats
path: root/browser/components/customizableui/CustomizableWidgets.jsm
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/customizableui/CustomizableWidgets.jsm')
-rw-r--r--browser/components/customizableui/CustomizableWidgets.jsm640
1 files changed, 640 insertions, 0 deletions
diff --git a/browser/components/customizableui/CustomizableWidgets.jsm b/browser/components/customizableui/CustomizableWidgets.jsm
new file mode 100644
index 0000000000..0cb23f3a2f
--- /dev/null
+++ b/browser/components/customizableui/CustomizableWidgets.jsm
@@ -0,0 +1,640 @@
+/* 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 { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+const { AppConstants } = ChromeUtils.importESModule(
+ "resource://gre/modules/AppConstants.sys.mjs"
+);
+const { PrivateBrowsingUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/PrivateBrowsingUtils.sys.mjs"
+);
+
+const lazy = {};
+
+ChromeUtils.defineESModuleGetters(lazy, {
+ RecentlyClosedTabsAndWindowsMenuUtils:
+ "resource:///modules/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.sys.mjs",
+ SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
+ ShortcutUtils: "resource://gre/modules/ShortcutUtils.sys.mjs",
+});
+
+XPCOMUtils.defineLazyModuleGetters(lazy, {
+ Sanitizer: "resource:///modules/Sanitizer.jsm",
+});
+
+ChromeUtils.defineModuleGetter(
+ lazy,
+ "PanelMultiView",
+ "resource:///modules/PanelMultiView.jsm"
+);
+
+const kPrefCustomizationDebug = "browser.uiCustomization.debug";
+const kPrefScreenshots = "extensions.screenshots.disabled";
+
+XPCOMUtils.defineLazyGetter(lazy, "log", () => {
+ let { ConsoleAPI } = ChromeUtils.importESModule(
+ "resource://gre/modules/Console.sys.mjs"
+ );
+ let debug = Services.prefs.getBoolPref(kPrefCustomizationDebug, false);
+ let consoleOptions = {
+ maxLogLevel: debug ? "all" : "log",
+ prefix: "CustomizableWidgets",
+ };
+ return new ConsoleAPI(consoleOptions);
+});
+
+XPCOMUtils.defineLazyPreferenceGetter(
+ lazy,
+ "screenshotsDisabled",
+ kPrefScreenshots,
+ false
+);
+
+XPCOMUtils.defineLazyPreferenceGetter(
+ lazy,
+ "SCREENSHOT_BROWSER_COMPONENT",
+ "screenshots.browser.component.enabled",
+ false
+);
+
+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(lazy.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;
+ case "unload":
+ this.onWindowUnload(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;
+
+ lazy.PanelMultiView.getViewNode(
+ document,
+ "appMenuRecentlyClosedTabs"
+ ).disabled = lazy.SessionStore.getClosedTabCount(window) == 0;
+ lazy.PanelMultiView.getViewNode(
+ document,
+ "appMenuRecentlyClosedWindows"
+ ).disabled = lazy.SessionStore.getClosedWindowCount(window) == 0;
+
+ lazy.PanelMultiView.getViewNode(
+ document,
+ "appMenu-restoreSession"
+ ).hidden = !lazy.SessionStore.canRestoreLastSession;
+
+ // 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(
+ query,
+ document.getElementById("appMenu_historyMenu"),
+ panelview
+ );
+ // When either of these sub-subviews show, populate them with recently closed
+ // objects data.
+ lazy.PanelMultiView.getViewNode(
+ document,
+ this.recentlyClosedTabsPanel
+ ).addEventListener("ViewShowing", this);
+ lazy.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);
+ window.addEventListener("unload", this);
+ },
+ onViewHiding(event) {
+ lazy.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;
+ lazy.PanelMultiView.getViewNode(
+ document,
+ this.recentlyClosedTabsPanel
+ ).removeEventListener("ViewShowing", this);
+ lazy.PanelMultiView.getViewNode(
+ document,
+ this.recentlyClosedWindowsPanel
+ ).removeEventListener("ViewShowing", this);
+ }
+ panelMultiView.removeEventListener("PanelMultiViewHidden", this);
+ },
+ onWindowUnload(event) {
+ if (this._panelMenuView) {
+ delete this._panelMenuView;
+ }
+ },
+ onSubViewShowing(event) {
+ let panelview = event.target;
+ let document = event.target.ownerDocument;
+ let window = document.defaultView;
+
+ this._panelMenuView.clearAllContents(panelview);
+
+ let getFragment =
+ panelview.id == this.recentlyClosedTabsPanel
+ ? lazy.RecentlyClosedTabsAndWindowsMenuUtils.getTabsFragment
+ : lazy.RecentlyClosedTabsAndWindowsMenuUtils.getWindowsFragment;
+
+ let fragment = getFragment(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 separator = document.createXULElement("toolbarseparator");
+ 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-button");
+ } else {
+ element.classList.add("subviewbutton-iconic", "bookmark-item");
+ }
+ }
+ panelview.appendChild(body);
+ panelview.appendChild(separator);
+ panelview.appendChild(footer);
+ },
+ },
+ {
+ id: "save-page-button",
+ l10nId: "toolbar-button-save-page",
+ shortcutId: "key_savePage",
+ onCommand(aEvent) {
+ let win = aEvent.target.ownerGlobal;
+ win.saveBrowser(win.gBrowser.selectedBrowser);
+ },
+ },
+ {
+ id: "print-button",
+ l10nId: "navbar-print",
+ shortcutId: "printKb",
+ keepBroadcastAttributesWhenCustomizing: true,
+ onCreated(aNode) {
+ aNode.setAttribute("command", "cmd_printPreviewToggle");
+ },
+ },
+ {
+ 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",
+ l10nId: "toolbar-button-open-file",
+ shortcutId: "openFileKb",
+ 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: "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",
+ l10nId: "repair-text-encoding-button",
+ onCommand(aEvent) {
+ aEvent.view.BrowserForceEncodingDetection();
+ },
+ },
+ {
+ id: "email-link-button",
+ l10nId: "toolbar-button-email-link",
+ onCommand(aEvent) {
+ let win = aEvent.view;
+ win.MailIntegration.sendLinkForBrowser(win.gBrowser.selectedBrowser);
+ },
+ },
+];
+
+if (Services.prefs.getBoolPref("identity.fxaccounts.enabled")) {
+ CustomizableWidgets.push({
+ id: "sync-button",
+ l10nId: "toolbar-button-synced-tabs",
+ type: "view",
+ viewId: "PanelUI-remotetabs",
+ onViewShowing(aEvent) {
+ let panelview = aEvent.target;
+ let doc = panelview.ownerDocument;
+
+ let syncNowBtn = panelview.querySelector(".syncnow-label");
+ let l10nId = syncNowBtn.getAttribute(
+ panelview.ownerGlobal.gSync._isCurrentlySyncing
+ ? "syncing-data-l10n-id"
+ : "sync-now-data-l10n-id"
+ );
+ syncNowBtn.setAttribute("data-l10n-id", l10nId);
+
+ let SyncedTabsPanelList = doc.defaultView.SyncedTabsPanelList;
+ panelview.syncedTabsPanelList = new SyncedTabsPanelList(
+ panelview,
+ lazy.PanelMultiView.getViewNode(doc, "PanelUI-remotetabs-deck"),
+ lazy.PanelMultiView.getViewNode(doc, "PanelUI-remotetabs-tabslist")
+ );
+ },
+ onViewHiding(aEvent) {
+ aEvent.target.syncedTabsPanelList.destroy();
+ aEvent.target.syncedTabsPanelList = null;
+ },
+ });
+}
+
+if (!lazy.screenshotsDisabled) {
+ CustomizableWidgets.push({
+ id: "screenshot-button",
+ shortcutId: "key_screenshot",
+ l10nId: "screenshot-toolbarbutton",
+ onCommand(aEvent) {
+ if (lazy.SCREENSHOT_BROWSER_COMPONENT) {
+ Services.obs.notifyObservers(
+ aEvent.currentTarget.ownerGlobal,
+ "menuitem-screenshot"
+ );
+ } else {
+ Services.obs.notifyObservers(
+ null,
+ "menuitem-screenshot-extension",
+ "toolbar"
+ );
+ }
+ },
+ onCreated(aNode) {
+ aNode.ownerGlobal.MozXULElement.insertFTLIfNeeded(
+ "browser/screenshots.ftl"
+ );
+ Services.obs.addObserver(this, "toggle-screenshot-disable");
+ },
+ observe(subj, topic, data) {
+ let document = subj.document;
+ let button = document.getElementById("screenshot-button");
+
+ if (!button) {
+ return;
+ }
+
+ if (data == "true") {
+ button.setAttribute("disabled", "true");
+ } else {
+ button.removeAttribute("disabled");
+ }
+ },
+ });
+}
+
+let preferencesButton = {
+ id: "preferences-button",
+ l10nId: "toolbar-settings-button",
+ onCommand(aEvent) {
+ let win = aEvent.target.ownerGlobal;
+ win.openPreferences(undefined);
+ },
+};
+if (AppConstants.platform == "macosx") {
+ preferencesButton.shortcutId = "key_preferencesCmdMac";
+}
+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 = lazy.Sanitizer.sanitize(itemsToClear, {
+ ignoreTimespan: false,
+ range: lazy.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",
+ l10nId: "toolbar-button-new-private-window",
+ shortcutId: "key_privatebrowsing",
+ onCommand(e) {
+ let win = e.target.ownerGlobal;
+ win.OpenBrowserWindow({ private: true });
+ },
+ });
+}
+
+// If the pref is set to `true`, we don't register this widget.
+if (!Services.prefs.getBoolPref("extensions.unifiedExtensions.enabled")) {
+ CustomizableWidgets.push({
+ id: "add-ons-button",
+ shortcutId: "key_openAddons",
+ l10nId: "toolbar-addons-themes-button",
+ onCommand(aEvent) {
+ let win = aEvent.target.ownerGlobal;
+ win.BrowserOpenAddonsMgr();
+ },
+ });
+}