Files
sousa-gecko/toolkit/content/widgets/popupnotification.js
T
Kalen Lu 077049f30f Bug 2049712 - Fix credit card update doorhanger displaying dropdown arrow without having additional actions. r=mtigley,hjones
Add `dropmarkerhidden` to `observedAttributes` so callback runs again and the button type tracks the secondary-action count on every show

Differential Revision: https://phabricator.services.mozilla.com/D309429
2026-07-02 01:42:00 +00:00

244 lines
9.2 KiB
JavaScript

/* 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";
// This is loaded into all XUL windows. Wrap in a block to prevent
// leaking to window scope.
{
class MozPopupNotification extends MozXULElement {
static get inheritedAttributes() {
return {
".popup-notification-icon": "popupid,src=icon,class=iconclass,hasicon",
".popup-notification-body": "popupid",
".popup-notification-origin": "value=origin,tooltiptext=origin",
".popup-notification-description": "popupid,id=descriptionid",
".popup-notification-description > span:first-of-type":
"text=label,popupid",
".popup-notification-description > .popup-notification-description-name":
"text=name,popupid",
".popup-notification-description > span:nth-of-type(2)":
"text=endlabel,popupid",
".popup-notification-description > b:last-of-type":
"text=secondname,popupid",
".popup-notification-description > span:last-of-type":
"text=secondendlabel,popupid",
".popup-notification-hint-text": "text=hinttext",
".popup-notification-closebutton": "hidden=closebuttonhidden",
".popup-notification-learnmore-link": "href=learnmoreurl",
".popup-notification-warning": "hidden=warninghidden,text=warninglabel",
".popup-notification-secondary-button":
"label=secondarybuttonlabel,accesskey=secondarybuttonaccesskey,hidden=secondarybuttonhidden",
".popup-notification-more-actions-popup":
"hidden=secondarybuttonhidden",
".popup-notification-primary-button":
"label=buttonlabel,accesskey=buttonaccesskey,disabled=mainactiondisabled",
};
}
static get observedAttributes() {
return [...super.observedAttributes, "dropmarkerhidden"];
}
attributeChangedCallback(name, oldValue, newValue) {
if (!this._hasSlotted) {
return;
}
// If the label and/or accesskey for the primary button is set by
// inherited attributes, its data-l10n-id needs to be unset or
// DOM Localization will overwrite the values.
if (name === "buttonlabel" || name === "buttonaccesskey") {
this.button?.removeAttribute("data-l10n-id");
}
if (name === "dropmarkerhidden" && this.secondaryButton) {
this.secondaryButton.type = newValue !== null ? "default" : "split";
}
super.attributeChangedCallback(name, oldValue, newValue);
}
show() {
this.slotContents();
if (this.checkboxState) {
this.checkbox.checked = this.checkboxState.checked;
this.checkbox.setAttribute("label", this.checkboxState.label);
this.checkbox.hidden = false;
} else {
this.checkbox.hidden = true;
// Reset checked state to avoid wrong using of previous value.
this.checkbox.checked = false;
}
this.hidden = false;
}
static get markup() {
return `
<hbox class="popup-notification-header-container"></hbox>
<hbox align="start" class="popup-notification-body-container">
<image class="popup-notification-icon"/>
<vbox pack="start" class="popup-notification-body">
<a class="popup-notification-origin header" crop="center"></a>
<!-- These need to be on the same line to avoid creating
whitespace between them (whitespace is added in the
localization file, if necessary). -->
<description class="popup-notification-description"><html:span></html:span><html:b class="popup-notification-description-name"></html:b><html:span></html:span><html:b></html:b><html:span></html:span></description>
<description class="popup-notification-hint-text"></description>
<vbox class="popup-notification-bottom-content" align="start">
<label class="popup-notification-learnmore-link" is="text-link" data-l10n-id="popup-notification-learn-more"></label>
<checkbox class="popup-notification-checkbox"/>
<description class="popup-notification-warning"/>
</vbox>
</vbox>
<toolbarbutton class="messageCloseButton close-icon popup-notification-closebutton tabbable" data-l10n-id="close-notification-message"></toolbarbutton>
</hbox>
<hbox class="popup-notification-footer-container"></hbox>
<html:moz-button-group class="panel-footer">
<html:moz-button type="split" class="popup-notification-secondary-button">
</html:moz-button>
<html:moz-button type="primary" class="popup-notification-primary-button" data-l10n-id="popup-notification-default-button2">
</html:moz-button>
</html:moz-button-group>
<menupopup class="popup-notification-more-actions-popup" position="after_end" data-l10n-id="popup-notification-more-actions-button">
</menupopup>
`;
}
slotContents() {
if (this._hasSlotted) {
return;
}
if (
this.hasAttribute("buttoncommand") ||
this.hasAttribute("secondarybuttoncommand") ||
this.hasAttribute("learnmoreclick")
) {
throw new Error(
"The attributes 'buttoncommand', 'secondarybuttoncommand' and 'learnmoreclick' are not supported anymore use `addEventListener` instead"
);
}
this._hasSlotted = true;
MozXULElement.insertFTLIfNeeded("toolkit/global/notification.ftl");
MozXULElement.insertFTLIfNeeded("toolkit/global/popupnotification.ftl");
this.appendChild(this.constructor.fragment);
this.button = this.querySelector(".popup-notification-primary-button");
if (
this.hasAttribute("buttonlabel") ||
this.hasAttribute("buttonaccesskey")
) {
this.button.removeAttribute("data-l10n-id");
}
this.secondaryButton = this.querySelector(
".popup-notification-secondary-button"
);
this.secondaryButton.type = this.hasAttribute("dropmarkerhidden")
? "default"
: "split";
this.checkbox = this.querySelector(".popup-notification-checkbox");
this.closebutton = this.querySelector(".popup-notification-closebutton");
this.menubutton = this.secondaryButton;
this.menupopup = this.querySelector(
".popup-notification-more-actions-popup"
);
let popupnotificationfooter = this.querySelector(
"popupnotificationfooter"
);
if (popupnotificationfooter) {
this.querySelector(".popup-notification-footer-container").append(
popupnotificationfooter
);
}
let popupnotificationheader = this.querySelector(
"popupnotificationheader"
);
if (popupnotificationheader) {
this.querySelector(".popup-notification-header-container").append(
popupnotificationheader
);
}
for (let popupnotificationcontent of this.querySelectorAll(
"popupnotificationcontent"
)) {
this.appendNotificationContent(popupnotificationcontent);
}
this.initializeAttributeInheritance();
let customEventDelegator = (type, event) => {
let customEvent = new CustomEvent(type, {
cancelable: true,
bubbles: true,
});
// Give listeners the chance to prevent the default behavior.
if (this.dispatchEvent(customEvent)) {
PopupNotifications._onButtonEvent(event, type, "button", this);
}
};
this.button.addEventListener(
"click",
event => customEventDelegator("buttoncommand", event),
{ capture: true }
);
this.secondaryButton.addEventListener(
"click",
event => {
if (
this.secondaryButton.chevronButtonEl?.contains(event.originalTarget)
) {
this.menupopup.openPopup(
this.secondaryButton.chevronButtonEl,
"after_end"
);
} else {
customEventDelegator("secondarybuttoncommand", event);
}
},
{ capture: true }
);
this.secondaryButton.addEventListener("keydown", event => {
if (event.key === "ArrowDown") {
event.preventDefault();
this.menupopup.openPopup(
this.secondaryButton.chevronButtonEl,
"after_end"
);
}
});
this.checkbox.addEventListener("command", event => {
PopupNotifications._onCheckboxCommand(event);
});
this.closebutton.addEventListener("command", event => {
PopupNotifications._dismiss(event, true);
});
this.menupopup.addEventListener("popupshown", event => {
PopupNotifications._onButtonEvent(event, "dropmarkerpopupshown");
});
this.menupopup.addEventListener("command", event => {
PopupNotifications._onMenuCommand(event);
});
this.querySelector(".popup-notification-learnmore-link").addEventListener(
"click",
event => customEventDelegator("learnmoreclick", event)
);
}
appendNotificationContent(el) {
this.querySelector(".popup-notification-bottom-content").before(el);
}
}
customElements.define("popupnotification", MozPopupNotification);
}