Bug 1383205 - Update transitionend properties of <option> elements on a deferred task. r=jaws draft
authorFelipe Gomes <felipc@gmail.com>
Fri, 28 Jul 2017 11:21:56 -0300
changeset 617502 0ae422735190ffc8a32fae19ab9d9bd11db3ea3b
parent 616915 36f95aeb4c77f7cf3b3366583008cd6e4b6b1dba
child 639825 1a7eb4b45d2640623dd0bb261e29d02f6b22d2a6
push id71061
push userfelipc@gmail.com
push dateFri, 28 Jul 2017 14:22:35 +0000
reviewersjaws
bugs1383205
milestone56.0a1
Bug 1383205 - Update transitionend properties of <option> elements on a deferred task. r=jaws Also, we only care about the properties that we support and that are animatable, as the non-animatable ones do not generate transitionend events MozReview-Commit-ID: 9QEgJnWorTP
browser/base/content/test/forms/browser_selectpopup_colors.js
toolkit/modules/SelectContentHelper.jsm
--- a/browser/base/content/test/forms/browser_selectpopup_colors.js
+++ b/browser/base/content/test/forms/browser_selectpopup_colors.js
@@ -125,25 +125,34 @@ const SELECT_STYLE_OF_OPTION_CHANGES_AFT
   '  <option>{"color": "rgb(255, 0, 0)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
   '  <option selected="true">{"end": "true"}</option>' +
   "</select></body><scr" +
   "ipt>" +
   "  var select = document.getElementById('one');" +
   "  select.addEventListener('focus', () => select.style.color = 'red');" +
   "</script></html>";
 
-const SELECT_STYLE_OF_OPTION_CHANGES_AFTER_TRANSITIONEND =
+const SELECT_COLOR_OF_OPTION_CHANGES_AFTER_TRANSITIONEND =
   "<html><head><style>" +
   "  select { transition: all .1s; }" +
   "  select:focus { background-color: orange; }" +
   "</style></head><body><select id='one'>" +
   '  <option>{"color": "rgb(0, 0, 0)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
   '  <option selected="true">{"end": "true"}</option>' +
   "</select></body></html>";
 
+const SELECT_TEXTSHADOW_OF_OPTION_CHANGES_AFTER_TRANSITIONEND =
+  "<html><head><style>" +
+  "  select { transition: all .1s; }" +
+  "  select:focus { text-shadow: 0 0 0 #303030; }" +
+  "</style></head><body><select id='one'>" +
+  '  <option>{"text-shadow": "none"}</option>' +
+  '  <option selected="true">{"end": "true"}</option>' +
+  "</select></body></html>";
+
 const SELECT_TRANSPARENT_COLOR_WITH_TEXT_SHADOW =
   "<html><head><style>" +
   "  select { color: transparent; text-shadow: 0 0 0 #303030; }" +
   "</style></head><body><select id='one'>" +
   '  <option>{"color": "rgba(0, 0, 0, 0)", "backgroundColor": "rgba(0, 0, 0, 0)", "textShadow": "rgb(48, 48, 48) 0px 0px 0px"}</option>' +
   '  <option selected="true">{"end": "true"}</option>' +
   "</select></body></html>";
 
@@ -401,27 +410,39 @@ add_task(async function test_style_of_op
     waitForComputedStyle: {
       property: "color",
       value: "rgb(255, 0, 0)"
     }
   };
   await testSelectColors(SELECT_STYLE_OF_OPTION_CHANGES_AFTER_FOCUS_EVENT, 2, options);
 });
 
-add_task(async function test_style_of_options_is_dependent_on_transitionend() {
+add_task(async function test_color_of_options_is_dependent_on_transitionend() {
   let options = {
     selectColor: "rgb(0, 0, 0)",
     selectBgColor: "rgb(255, 165, 0)",
     waitForComputedStyle: {
       property: "background-image",
       value: "linear-gradient(rgb(255, 165, 0), rgb(255, 165, 0))"
     }
   };
 
-  await testSelectColors(SELECT_STYLE_OF_OPTION_CHANGES_AFTER_TRANSITIONEND, 2, options);
+  await testSelectColors(SELECT_COLOR_OF_OPTION_CHANGES_AFTER_TRANSITIONEND, 2, options);
+});
+
+add_task(async function test_textshadow_of_options_is_dependent_on_transitionend() {
+  let options = {
+    skipSelectColorTest: true,
+    waitForComputedStyle: {
+      property: "text-shadow",
+      value: "rgb(48, 48, 48) 0px 0px 0px"
+    }
+  };
+
+  await testSelectColors(SELECT_TEXTSHADOW_OF_OPTION_CHANGES_AFTER_TRANSITIONEND, 2, options);
 });
 
 add_task(async function test_transparent_color_with_text_shadow() {
   let options = {
     selectColor: "rgba(0, 0, 0, 0)",
     selectTextShadow: "rgb(48, 48, 48) 0px 0px 0px",
     selectBgColor: "rgb(255, 255, 255)"
   };
--- a/toolkit/modules/SelectContentHelper.jsm
+++ b/toolkit/modules/SelectContentHelper.jsm
@@ -15,16 +15,22 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyServiceGetter(this, "DOMUtils",
                                    "@mozilla.org/inspector/dom-utils;1", "inIDOMUtils");
 XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask",
                                   "resource://gre/modules/DeferredTask.jsm");
 
 const kStateActive = 0x00000001; // NS_EVENT_STATE_ACTIVE
 const kStateHover = 0x00000004; // NS_EVENT_STATE_HOVER
 
+const SUPPORTED_PROPERTIES = [
+  "color",
+  "background-color",
+  "text-shadow",
+];
+
 // A process global state for whether or not content thinks
 // that a <select> dropdown is open or not. This is managed
 // entirely within this module, and is read-only accessible
 // via SelectContentHelper.open.
 var gOpen = false;
 
 this.EXPORTED_SYMBOLS = [
   "SelectContentHelper"
@@ -354,17 +360,19 @@ this.SelectContentHelper.prototype = {
       }
       case "mozhidedropdown":
         if (this.element === event.target) {
           this.global.sendAsyncMessage("Forms:HideDropDown", {});
           this.uninit();
         }
         break;
       case "transitionend":
-        this._update();
+        if (SUPPORTED_PROPERTIES.indexOf(event.propertyName) != -1) {
+          this._updateTimer.arm();
+        }
         break;
     }
   }
 
 }
 
 function getComputedStyles(element) {
   return element.ownerGlobal.getComputedStyle(element);
@@ -385,16 +393,20 @@ function buildOptionListForChildren(node
         tagName == "OPTGROUP" ? child.getAttribute("label")
                               : child.text;
       if (textContent == null) {
         textContent = "";
       }
 
       let cs = getComputedStyles(child);
 
+      // Note: If you add any more CSS properties support here,
+      // please add the property name to the SUPPORTED_PROPERTIES
+      // list so that the menu can be correctly updated when CSS
+      // transitions are used.
       let info = {
         index: child.index,
         tagName,
         textContent,
         disabled: child.disabled,
         display: cs.display,
         // We need to do this for every option element as each one can have
         // an individual style set for direction