summaryrefslogtreecommitdiffstats
path: root/comm/mail/components/unifiedtoolbar/content/unified-toolbar-customization-pane.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/components/unifiedtoolbar/content/unified-toolbar-customization-pane.mjs')
-rw-r--r--comm/mail/components/unifiedtoolbar/content/unified-toolbar-customization-pane.mjs264
1 files changed, 264 insertions, 0 deletions
diff --git a/comm/mail/components/unifiedtoolbar/content/unified-toolbar-customization-pane.mjs b/comm/mail/components/unifiedtoolbar/content/unified-toolbar-customization-pane.mjs
new file mode 100644
index 0000000000..a43b7c6005
--- /dev/null
+++ b/comm/mail/components/unifiedtoolbar/content/unified-toolbar-customization-pane.mjs
@@ -0,0 +1,264 @@
+/* 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/. */
+
+import "./search-bar.mjs"; // eslint-disable-line import/no-unassigned-import
+import "./customization-palette.mjs"; // eslint-disable-line import/no-unassigned-import
+import "./customization-target.mjs"; // eslint-disable-line import/no-unassigned-import
+import {
+ BUTTON_STYLE_MAP,
+ BUTTON_STYLE_PREF,
+} from "resource:///modules/ButtonStyle.mjs";
+
+const { getDefaultItemIdsForSpace } = ChromeUtils.importESModule(
+ "resource:///modules/CustomizableItems.sys.mjs"
+);
+
+/**
+ * Template ID: unifiedToolbarCustomizationPaneTemplate
+ * Attributes:
+ * - space: Identifier of the space this pane is for. Changes are not observed.
+ * - current-items: Currently used items in this space.
+ * - builtin-space: Boolean indicating if the space is a built in space (true) or an
+ * extension provided space (false).
+ */
+class UnifiedToolbarCustomizationPane extends HTMLElement {
+ /**
+ * Reference to the customization target for the main toolbar area.
+ *
+ * @type {CustomizationTarget?}
+ */
+ #toolbarTarget = null;
+
+ /**
+ * Reference to the title of the space specific palette.
+ *
+ * @type {?HTMLHeadingElement}
+ */
+ #spaceSpecificTitle = null;
+
+ /**
+ * Reference to the palette for items only available in the current space.
+ *
+ * @type {?CustomizationPalette}
+ */
+ #spaceSpecificPalette = null;
+
+ /**
+ * Reference to the palette for items available in all spaces.
+ *
+ * @type {?CustomizationPalette}
+ */
+ #genericPalette = null;
+
+ /**
+ * List of the item IDs that are in the toolbar by default in this area.
+ *
+ * @type {string[]}
+ */
+ #defaultItemIds = [];
+
+ /**
+ * The search bar used to filter the items in the palettes.
+ *
+ * @type {?SearchBar}
+ */
+ #searchBar = null;
+
+ connectedCallback() {
+ if (this.shadowRoot) {
+ document.l10n.connectRoot(this.shadowRoot);
+ return;
+ }
+ this.setAttribute("role", "tabpanel");
+ const shadowRoot = this.attachShadow({ mode: "open" });
+ document.l10n.connectRoot(shadowRoot);
+
+ const space = this.getAttribute("space");
+
+ const template = document
+ .getElementById("unifiedToolbarCustomizationPaneTemplate")
+ .content.cloneNode(true);
+ const styles = document.createElement("link");
+ styles.setAttribute("rel", "stylesheet");
+ styles.setAttribute(
+ "href",
+ "chrome://messenger/skin/shared/unifiedToolbarCustomizationPane.css"
+ );
+
+ this.#toolbarTarget = template.querySelector(".toolbar-target");
+ this.#toolbarTarget.setAttribute("space", space);
+
+ this.#spaceSpecificTitle = template.querySelector(".space-specific-title");
+ document.l10n.setAttributes(
+ this.#spaceSpecificTitle,
+ this.hasAttribute("builtin-space")
+ ? `customize-palette-${space}-specific-title`
+ : "customize-palette-extension-specific-title"
+ );
+ this.#spaceSpecificTitle.id = `${space}PaletteTitle`;
+ this.#spaceSpecificPalette = template.querySelector(
+ ".space-specific-palette"
+ );
+ this.#spaceSpecificPalette.id = `${space}Palette`;
+ this.#spaceSpecificPalette.setAttribute(
+ "aria-labelledby",
+ this.#spaceSpecificTitle.id
+ );
+ this.#spaceSpecificPalette.setAttribute("space", space);
+ const genericTitle = template.querySelector(".generic-palette-title");
+ genericTitle.id = `${space}GenericPaletteTitle`;
+ this.#genericPalette = template.querySelector(".generic-palette");
+ this.#genericPalette.id = `${space}GenericPalette`;
+ this.#genericPalette.setAttribute("aria-labelledby", genericTitle.id);
+
+ this.#searchBar = template.querySelector("search-bar");
+ this.#searchBar.addEventListener("search", this.#handleSearch);
+ this.#searchBar.addEventListener("autocomplete", this.#handleFilter);
+
+ this.initialize();
+
+ shadowRoot.append(styles, template);
+
+ this.addEventListener("dragover", this.#handleDragover);
+ }
+
+ disconnectedCallback() {
+ document.l10n.disconnectRoot(this.shadowRoot);
+ }
+
+ #handleFilter = event => {
+ this.#spaceSpecificPalette.filterItems(event.detail);
+ this.#genericPalette.filterItems(event.detail);
+ };
+
+ #handleSearch = event => {
+ // Don't clear the search bar.
+ event.preventDefault();
+ };
+
+ /**
+ * Default handler to indicate nothing can be dropped in the customization,
+ * except for the dragging and dropping in the palettes and targets.
+ *
+ * @param {DragEvent} event - Drag over event.
+ */
+ #handleDragover = event => {
+ event.dataTransfer.dropEffect = "none";
+ event.preventDefault();
+ };
+
+ /**
+ * Initialize the contents of this element from the state. The relevant state
+ * for this element are the items currently in the toolbar for this space.
+ *
+ * @param {boolean} [deep = false] - If true calls initialize on all the
+ * targets and palettes.
+ */
+ initialize(deep = false) {
+ const space = this.getAttribute("space");
+ this.#defaultItemIds = getDefaultItemIdsForSpace(space);
+ const currentItems = this.hasAttribute("current-items")
+ ? this.getAttribute("current-items")
+ : this.#defaultItemIds.join(",");
+ this.#toolbarTarget.setAttribute("current-items", currentItems);
+ this.#spaceSpecificPalette.setAttribute("items-in-use", currentItems);
+ this.#genericPalette.setAttribute("items-in-use", currentItems);
+
+ if (deep) {
+ this.#searchBar.reset();
+ this.#toolbarTarget.initialize();
+ this.#spaceSpecificPalette.initialize();
+ this.#genericPalette.initialize();
+ this.#spaceSpecificTitle.hidden = this.#spaceSpecificPalette.isEmpty;
+ this.#spaceSpecificPalette.hidden = this.#spaceSpecificPalette.isEmpty;
+ }
+
+ this.updateButtonStyle(
+ BUTTON_STYLE_MAP[Services.prefs.getIntPref(BUTTON_STYLE_PREF, 0)]
+ );
+ }
+
+ /**
+ * Reset the items in the targets to the defaults.
+ */
+ reset() {
+ this.#toolbarTarget.setItems(this.#defaultItemIds);
+ this.#spaceSpecificPalette.setItems(this.#defaultItemIds);
+ this.#genericPalette.setItems(this.#defaultItemIds);
+ }
+
+ /**
+ * Add an item to the default target in this space. Can only add items that
+ * are available in all spaces.
+ *
+ * @param {string} itemId - Item ID of the item to add to the default target.
+ */
+ addItem(itemId) {
+ this.#genericPalette.addItemById(itemId);
+ }
+
+ /**
+ * Remove an item from all targets in this space.
+ *
+ * @param {string} itemId - Item ID of the item to remove from this pane's
+ * targets.
+ */
+ removeItem(itemId) {
+ this.#toolbarTarget.removeItemById(itemId);
+ }
+
+ /**
+ * Check if an item is currently in a target in this pane.
+ *
+ * @param {string} itemId - Item ID of the item to check for.
+ * @returns {boolean} If the item is currently used in this pane.
+ */
+ hasItem(itemId) {
+ return Boolean(this.#toolbarTarget.hasItem(itemId));
+ }
+
+ /**
+ * If the customization state of this space matches its default state.
+ *
+ * @type {boolean}
+ */
+ get matchesDefaultState() {
+ const itemsInToolbar = this.#toolbarTarget.itemIds;
+ return itemsInToolbar.join(",") === this.#defaultItemIds.join(",");
+ }
+
+ /**
+ * If the customization state of this space matches the currently saved
+ * configuration.
+ *
+ * @type {boolean}
+ */
+ get hasChanges() {
+ return this.#toolbarTarget.hasChanges;
+ }
+
+ /**
+ * Current customization state for this space.
+ *
+ * @type {string[]}
+ */
+ get itemIds() {
+ return this.#toolbarTarget.itemIds;
+ }
+
+ /**
+ * Update the class of the toolbar preview to reflect the selected button
+ * style.
+ *
+ * @param {string} value - The class to apply.
+ */
+ updateButtonStyle(value) {
+ this.#toolbarTarget.classList.remove(...BUTTON_STYLE_MAP);
+ this.#toolbarTarget.classList.add(value);
+ }
+}
+customElements.define(
+ "unified-toolbar-customization-pane",
+ UnifiedToolbarCustomizationPane
+);