Bug 1427950 - Change rich-select to default to an indeterminate state when no options are selected. r=jaws
This avoids the magic of the select automatically making the first option selected without the application state having a good way to know about this.
MozReview-Commit-ID: 1OEsjh2KW1h
--- a/toolkit/components/payments/res/components/rich-option.js
+++ b/toolkit/components/payments/res/components/rich-option.js
@@ -15,26 +15,24 @@ class RichOption extends ObservedPropert
static get observedAttributes() {
return [
"selected",
"value",
];
}
connectedCallback() {
+ this.classList.add("rich-option");
this.render();
- let richSelect = this.closest("rich-select");
- if (richSelect && richSelect.render) {
- richSelect.render();
- }
-
this.addEventListener("click", this);
this.addEventListener("keydown", this);
}
+ render() {}
+
handleEvent(event) {
switch (event.type) {
case "click": {
this.onClick(event);
break;
}
case "keydown": {
this.onKeyDown(event);
@@ -64,8 +62,10 @@ class RichOption extends ObservedPropert
static _createElement(fragment, className) {
let element = document.createElement("span");
element.classList.add(className);
fragment.appendChild(element);
return element;
}
}
+
+customElements.define("rich-option", RichOption);
--- a/toolkit/components/payments/res/components/rich-select.js
+++ b/toolkit/components/payments/res/components/rich-select.js
@@ -22,29 +22,37 @@ class RichSelect extends ObservedPropert
}
constructor() {
super();
this.addEventListener("blur", this);
this.addEventListener("click", this);
this.addEventListener("keydown", this);
+
+ this._mutationObserver = new MutationObserver((mutations) => {
+ for (let mutation of mutations) {
+ for (let addedNode of mutation.addedNodes) {
+ if (addedNode.nodeType != Node.ELEMENT_NODE ||
+ !addedNode.matches(".rich-option:not(.rich-select-selected-clone)")) {
+ continue;
+ }
+ // Move the added rich option to the popup.
+ this.popupBox.appendChild(addedNode);
+ }
+ }
+ });
+ this._mutationObserver.observe(this, {
+ childList: true,
+ });
}
connectedCallback() {
this.setAttribute("tabindex", "0");
this.render();
-
- this._mutationObserver = new MutationObserver(() => {
- this.render();
- });
- this._mutationObserver.observe(this, {
- childList: true,
- subtree: true,
- });
}
get popupBox() {
return this.querySelector(":scope > .rich-select-popup-box");
}
get selectedOption() {
return this.popupBox.querySelector(":scope > [selected]");
@@ -147,46 +155,42 @@ class RichSelect extends ObservedPropert
render() {
let popupBox = this.popupBox;
if (!popupBox) {
popupBox = document.createElement("div");
popupBox.classList.add("rich-select-popup-box");
this.appendChild(popupBox);
}
- /* eslint-disable max-len */
- let options =
- this.querySelectorAll(":scope > :not(.rich-select-popup-box):not(.rich-select-selected-clone)");
- /* eslint-enable max-len */
+ let options = this.querySelectorAll(":scope > .rich-option:not(.rich-select-selected-clone)");
for (let option of options) {
popupBox.appendChild(option);
}
let selectedChild;
for (let child of popupBox.children) {
if (child.selected) {
selectedChild = child;
break;
}
}
- if (!selectedChild && popupBox.children.length) {
- selectedChild = popupBox.children[0];
- selectedChild.selected = true;
- }
let selectedClone = this.querySelector(":scope > .rich-select-selected-clone");
if (!this._optionsAreEquivalent(selectedClone, selectedChild)) {
if (selectedClone) {
selectedClone.remove();
}
if (selectedChild) {
selectedClone = selectedChild.cloneNode(false);
selectedClone.removeAttribute("id");
selectedClone.removeAttribute("selected");
- selectedClone.classList.add("rich-select-selected-clone");
- selectedClone = this.appendChild(selectedClone);
+ } else {
+ selectedClone = document.createElement("rich-option");
+ selectedClone.textContent = "(None selected)";
}
+ selectedClone.classList.add("rich-select-selected-clone");
+ selectedClone = this.appendChild(selectedClone);
}
}
}
customElements.define("rich-select", RichSelect);