Bug 1427950 - Dispatch a "change" event from <rich-select> when a user changes the selectedness. r=jaws draft
authorMatthew Noorenberghe <mozilla@noorenberghe.ca>
Mon, 29 Jan 2018 18:08:15 -0800
changeset 749037 fb02340c31781c9d16691ff074625d933278f33e
parent 749036 8371def08bafaa962df35fd6d1c55cc50b4bfc9d
child 749038 df382271d36bbed6c474fb39aafe73e4d46e080a
push id97299
push usermozilla@noorenberghe.ca
push dateTue, 30 Jan 2018 21:24:25 +0000
reviewersjaws
bugs1427950
milestone60.0a1
Bug 1427950 - Dispatch a "change" event from <rich-select> when a user changes the selectedness. r=jaws Programmatic changes don't dispatch the event in order to avoid infinite loops. MozReview-Commit-ID: 1GYFaSasAZO
toolkit/components/payments/res/components/rich-option.js
toolkit/components/payments/res/components/rich-select.js
--- a/toolkit/components/payments/res/components/rich-option.js
+++ b/toolkit/components/payments/res/components/rich-option.js
@@ -17,48 +17,14 @@ class RichOption extends ObservedPropert
       "selected",
       "value",
     ];
   }
 
   connectedCallback() {
     this.classList.add("rich-option");
     this.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);
-        break;
-      }
-    }
-  }
-
-  onClick(event) {
-    if (this.closest("rich-select").open &&
-        !this.disabled &&
-        event.button == 0) {
-      for (let option of this.parentNode.children) {
-        option.selected = option == this;
-      }
-    }
-  }
-
-  onKeyDown(event) {
-    if (!this.disabled &&
-        event.which == 13 /* Enter */) {
-      for (let option of this.parentNode.children) {
-        option.selected = option == this;
-      }
-    }
-  }
 }
 
 customElements.define("rich-option", RichOption);
--- a/toolkit/components/payments/res/components/rich-select.js
+++ b/toolkit/components/payments/res/components/rich-select.js
@@ -96,45 +96,62 @@ class RichSelect extends ObservedPropert
 
   onBlur(event) {
     if (event.target == this) {
       this.open = false;
     }
   }
 
   onClick(event) {
-    if (!this.disabled &&
-        event.button == 0) {
-      this.open = !this.open;
+    if (event.button != 0) {
+      return;
     }
+
+    let option = event.target.closest(".rich-option");
+    if (this.open && option && !option.matches(".rich-select-selected-clone") && !option.selected) {
+      this.selectedOption = option;
+      this._dispatchChangeEvent();
+    }
+    this.open = !this.open;
   }
 
   onKeyDown(event) {
     if (event.key == " ") {
       this.open = !this.open;
     } else if (event.key == "ArrowDown") {
       let selectedOption = this.selectedOption;
       let next = selectedOption.nextElementSibling;
       if (next) {
         next.selected = true;
         selectedOption.selected = false;
+        this._dispatchChangeEvent();
       }
     } else if (event.key == "ArrowUp") {
       let selectedOption = this.selectedOption;
       let next = selectedOption.previousElementSibling;
       if (next) {
         next.selected = true;
         selectedOption.selected = false;
+        this._dispatchChangeEvent();
       }
     } else if (event.key == "Enter" ||
                event.key == "Escape") {
       this.open = false;
     }
   }
 
+  /**
+   * Only dispatched upon a user-initiated change.
+   */
+  _dispatchChangeEvent() {
+    let changeEvent = document.createEvent("UIEvent");
+    changeEvent.initEvent("change", true, true);
+    this.dispatchEvent(changeEvent);
+  }
+
   _optionsAreEquivalent(a, b) {
     if (!a || !b) {
       return false;
     }
 
     let aAttrs = a.constructor.observedAttributes;
     let bAttrs = b.constructor.observedAttributes;
     if (aAttrs.length != bAttrs.length) {