diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /comm/calendar/base/content/widgets/calendar-modebox.js | |
parent | Initial commit. (diff) | |
download | thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'comm/calendar/base/content/widgets/calendar-modebox.js')
-rw-r--r-- | comm/calendar/base/content/widgets/calendar-modebox.js | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/comm/calendar/base/content/widgets/calendar-modebox.js b/comm/calendar/base/content/widgets/calendar-modebox.js new file mode 100644 index 0000000000..417c790e34 --- /dev/null +++ b/comm/calendar/base/content/widgets/calendar-modebox.js @@ -0,0 +1,244 @@ +/* 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"; + +/* globals MozXULElement */ + +// Wrap in a block to prevent leaking to window scope. +{ + /** + * A calendar-modebox directly extends to a xul:box element with extra functionality. Like a + * xul:hbox it has a horizontal orientation. It is designed to be displayed only: + * 1) in given application modes (e.g "task" mode, "calendar" mode) and + * 2) only in relation to the "checked" attribute of a control (e.g. a command or checkbox). + * + * - The attribute "mode" denotes a comma-separated list of all modes that the modebox should + * not be collapsed in, e.g. `mode="calendar,task"`. + * - The attribute "current" denotes the current viewing mode. + * - The attribute "refcontrol" points to a control, either a "command", "checkbox" or other + * elements that support a "checked" attribute, that is often used to denote whether a + * modebox should be displayed or not. If "refcontrol" is set to the id of a command you + * can there set the oncommand attribute like: + * `oncommand='document.getElementById('my-mode-pane').togglePane(event)`. + * In case it is a checkbox element or derived checkbox element this is done automatically + * by listening to the event "CheckboxChange". So if the current application mode is one of + * the modes listed in the "mode" attribute it is additionally verified whether the element + * denoted by "refcontrol" is checked or not. + * - The attribute "collapsedinmodes" is a comma-separated list of the modes the modebox + * should be collapsed in (e.g. "mail,calendar"). For example, if the user collapses a + * modebox when in a given mode, that mode would be added to "collapsedinmodes". This + * attribute is made persistent across restarts. + * + * @augments {MozXULElement} + */ + class CalendarModebox extends MozXULElement { + static get observedAttributes() { + return ["current"]; + } + + connectedCallback() { + if (this.delayConnectedCallback()) { + return; + } + + this.mRefControl = null; + + if (this.hasAttribute("refcontrol")) { + this.mRefControl = document.getElementById(this.getAttribute("refcontrol")); + if (this.mRefControl && this.mRefControl.localName == "checkbox") { + this.mRefControl.addEventListener("CheckboxStateChange", this, true); + } + } + } + + attributeChangedCallback(name, oldValue, newValue) { + if (name == "current" && oldValue != newValue) { + let display = this.isVisibleInMode(newValue); + this.setVisible(display, false, true); + } + } + + get currentMode() { + return this.getAttribute("current"); + } + + /** + * The event handler for various events relevant to CalendarModebox. + * + * @param {Event} event - The event. + */ + handleEvent(event) { + if (event.type == "CheckboxStateChange") { + this.onCheckboxStateChange(event); + } + } + + /** + * A "mode attribute" contains comma-separated lists of values, for example: + * `modewidths="200,200,200"`. Each of these values corresponds to one of the modes in + * the "mode" attribute: `mode="mail,calendar,task"`. This function sets a new value for + * a given mode in a given "mode attribute". + * + * @param {string} attributeName - A "mode attribute" in which to set a new value. + * @param {string} value - A new value to set. + * @param {string} [mode=this.currentMode] - Set the value for this mode. + */ + setModeAttribute(attributeName, value, mode = this.currentMode) { + if (!this.hasAttribute(attributeName)) { + return; + } + let attributeValues = this.getAttribute(attributeName).split(","); + let modes = this.getAttribute("mode").split(","); + attributeValues[modes.indexOf(mode)] = value; + this.setAttribute(attributeName, attributeValues.join(",")); + } + + /** + * A "mode attribute" contains comma-separated lists of values, for example: + * `modewidths="200,200,200"`. Each of these values corresponds to one of the modes in + * the "mode" attribute: `mode="mail,calendar,task"`. This function returns the value + * for a given mode in a given "mode attribute". + * + * @param {string} attributeName - A "mode attribute" to get a value from. + * @param {string} [mode=this.currentMode] - Get the value for this mode. + * @returns {string} The value found in the mode attribute or an empty string. + */ + getModeAttribute(attributeName, mode = this.currentMode) { + if (!this.hasAttribute(attributeName)) { + return ""; + } + let attributeValues = this.getAttribute(attributeName).split(","); + let modes = this.getAttribute("mode").split(","); + return attributeValues[modes.indexOf(mode)]; + } + + /** + * Sets the visibility (collapsed state) of this modebox and (optionally) updates the + * `collapsedinmode` attribute and (optionally) notifies the `refcontrol`. + * + * @param {boolean} visible - Whether the modebox should become visible or not. + * @param {boolean} [toPushModeCollapsedAttribute=true] - Whether to push the current mode + * to `collapsedinmodes` attribute. + * @param {boolean} [toNotifyRefControl=true] - Whether to notify the `refcontrol`. + */ + setVisible(visible, toPushModeCollapsedAttribute = true, toNotifyRefControl = true) { + let pushModeCollapsedAttribute = toPushModeCollapsedAttribute === true; + let notifyRefControl = toNotifyRefControl === true; + + let collapsedModes = []; + let modeIndex = -1; + let collapsedInMode = false; + + if (this.hasAttribute("collapsedinmodes")) { + collapsedModes = this.getAttribute("collapsedinmodes").split(","); + modeIndex = collapsedModes.indexOf(this.currentMode); + collapsedInMode = modeIndex > -1; + } + + let display = visible; + if (display && !pushModeCollapsedAttribute) { + display = !collapsedInMode; + } + + this.collapsed = !display || !this.isVisibleInMode(); + + if (pushModeCollapsedAttribute) { + if (!display) { + if (modeIndex == -1) { + collapsedModes.push(this.currentMode); + if (this.getAttribute("collapsedinmodes") == ",") { + collapsedModes.splice(0, 2); + } + } + } else if (modeIndex > -1) { + collapsedModes.splice(modeIndex, 1); + if (collapsedModes.join(",") == "") { + collapsedModes[0] = ","; + } + } + this.setAttribute("collapsedinmodes", collapsedModes.join(",")); + + Services.xulStore.persist(this, "collapsedinmodes"); + } + + if (notifyRefControl && this.hasAttribute("refcontrol")) { + let command = document.getElementById(this.getAttribute("refcontrol")); + if (command) { + command.setAttribute("checked", display); + command.disabled = !this.isVisibleInMode(); + } + } + } + + /** + * Return whether this modebox is visible for a given mode, according to both its + * `mode` and `collapsedinmodes` attributes. + * + * @param {string} [mode=this.currentMode] - Is the modebox visible for this mode? + * @returns {boolean} Whether this modebox is visible for the given mode. + */ + isVisible(mode = this.currentMode) { + if (!this.isVisibleInMode(mode)) { + return false; + } + let collapsedModes = this.getAttribute("collapsedinmodes").split(","); + return !collapsedModes.includes(mode); + } + + /** + * Returns whether this modebox is visible for a given mode, according to its + * `mode` attribute. + * + * @param {string} [mode=this.currentMode] - Is the modebox visible for this mode? + * @returns {boolean} Whether this modebox is visible for the given mode. + */ + isVisibleInMode(mode = this.currentMode) { + return this.hasAttribute("mode") ? this.getAttribute("mode").split(",").includes(mode) : true; + } + + /** + * Used to toggle the checked state of a command connected to this modebox, and set the + * visibility of this modebox accordingly. + * + * @param {Event} event - An event with a command (with a checked attribute) as its target. + */ + togglePane(event) { + let command = event.target; + let newValue = command.getAttribute("checked") == "true" ? "false" : "true"; + command.setAttribute("checked", newValue); + this.setVisible(newValue == "true", true, true); + } + + /** + * Handles a change in a checkbox state, by making this modebox visible or not. + * + * @param {Event} event - An event with a target that has a `checked` attribute. + */ + onCheckboxStateChange(event) { + let newValue = event.target.checked; + this.setVisible(newValue, true, true); + } + } + + customElements.define("calendar-modebox", CalendarModebox); + + /** + * A `calendar-modebox` but with a vertical orientation like a `vbox`. (Different Custom + * Elements cannot be defined using the same class, thus we need this subclass.) + * + * @augments {CalendarModebox} + */ + class CalendarModevbox extends CalendarModebox { + connectedCallback() { + if (this.delayConnectedCallback()) { + return; + } + super.connectedCallback(); + this.setAttribute("orient", "vertical"); + } + } + + customElements.define("calendar-modevbox", CalendarModevbox); +} |