Bug 1318317 - [DateTimeInput] hide reset button when there is no value. r=mconley
authorJessica Jong <jjong@mozilla.com>
Tue, 24 Jan 2017 17:19:00 +0100
changeset 331002 f17e441ce4d05bb69a98a5088d7d8f0e3b4c8e0c
parent 331001 57bd56bce11aa7612cc6978ad0a1447103c04b54
child 331003 f25c2fd8740b383c1fa5524222c99e2c87518e13
push id31258
push userkwierso@gmail.com
push dateThu, 26 Jan 2017 00:56:03 +0000
treeherdermozilla-central@52a34f9a6cf1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconley
bugs1318317
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1318317 - [DateTimeInput] hide reset button when there is no value. r=mconley
toolkit/content/widgets/datetimebox.xml
--- a/toolkit/content/widgets/datetimebox.xml
+++ b/toolkit/content/widgets/datetimebox.xml
@@ -71,16 +71,17 @@
         this.mDaySeparator.textContent = this.mSeparatorText;
         this.mYearSeparator =
           document.getAnonymousElementByAttribute(this, "anonid", "sep-second");
         this.mYearSeparator.textContent = this.mSeparatorText;
 
         if (this.mInputElement.value) {
           this.setFieldsFromInputValue();
         }
+        this.updateResetButtonVisibility();
       ]]>
       </constructor>
 
       <method name="clearInputFields">
         <parameter name="aFromInputElement"/>
         <body>
         <![CDATA[
           this.log("clearInputFields");
@@ -105,16 +106,18 @@
               !this.mYearField.readOnly) {
             this.mYearField.value = "";
             this.mYearField.setAttribute("typeBuffer", "");
           }
 
           if (!aFromInputElement) {
             this.mInputElement.setUserInput("");
           }
+
+          this.updateResetButtonVisibility();
         ]]>
         </body>
       </method>
 
       <method name="setFieldsFromInputValue">
         <body>
         <![CDATA[
           let value = this.mInputElement.value;
@@ -165,16 +168,21 @@
             return false;
           ]]>
         </body>
       </method>
 
       <method name="setInputValueFromFields">
         <body>
         <![CDATA[
+          if (!this.isAnyValueAvailable(false)) {
+            this.mInputElement.setUserInput("");
+            return;
+          }
+
           if (this.isFieldInvalid(this.mYearField) ||
               this.isFieldInvalid(this.mMonthField) ||
               this.isFieldInvalid(this.mDayField)) {
             // We still need to notify picker in case any of the field has
             // changed. If we can set input element value, then notifyPicker
             // will be called in setFieldsFromInputValue().
             this.notifyPicker();
             return;
@@ -401,21 +409,23 @@
 
             if (value.toString().length > this.mYearLength &&
                 value.toString().length <= this.mMaxYear.toString().length) {
               this.mYearField.size = value.toString().length;
             }
           }
 
           aField.value = value;
+          this.updateResetButtonVisibility();
         ]]>
         </body>
       </method>
 
-      <method name="isValueAvailable">
+      <method name="isAnyValueAvailable">
+        <parameter name="aForPicker"/>
         <body>
         <![CDATA[
           return !this.isEmpty(this.mMonthField.value) ||
                  !this.isEmpty(this.mDayField.value) ||
                  !this.isEmpty(this.mYearField.value);
         ]]>
         </body>
       </method>
@@ -487,16 +497,17 @@
         this.mSecondSeparator = null;
         this.mSecondField = null;
         this.mMillisecSeparator = null;
         this.mMillisecField = null;
 
         if (this.mInputElement.value) {
           this.setFieldsFromInputValue();
         }
+        this.updateResetButtonVisibility();
         ]]>
       </constructor>
 
       <method name="insertSeparator">
         <parameter name="aSeparatorText"/>
         <body>
         <![CDATA[
           let container = this.mHourField.parentNode;
@@ -612,16 +623,21 @@
           this.notifyPicker();
         ]]>
         </body>
       </method>
 
       <method name="setInputValueFromFields">
         <body>
         <![CDATA[
+          if (!this.isAnyValueAvailable(false)) {
+            this.mInputElement.setUserInput("");
+            return;
+          }
+
           if (this.isEmpty(this.mHourField.value) ||
               this.isEmpty(this.mMinuteField.value) ||
               (this.mDayPeriodField && this.isEmpty(this.mDayPeriodField.value)) ||
               (this.mSecondField && this.isEmpty(this.mSecondField.value)) ||
               (this.mMillisecField && this.isEmpty(this.mMillisecField.value))) {
             // We still need to notify picker in case any of the field has
             // changed. If we can set input element value, then notifyPicker
             // will be called in setFieldsFromInputValue().
@@ -719,16 +735,18 @@
           if (this.mDayPeriodField && !this.mDayPeriodField.disabled &&
               !this.mDayPeriodField.readOnly) {
             this.mDayPeriodField.value = "";
           }
 
           if (!aFromInputElement) {
             this.mInputElement.setUserInput("");
           }
+
+          this.updateResetButtonVisibility();
         ]]>
         </body>
       </method>
 
       <method name="incrementFieldValue">
         <parameter name="aTargetField"/>
         <parameter name="aTimes"/>
         <body>
@@ -788,16 +806,17 @@
             if (key == "Home" || key == "End") {
               return;
             }
 
             this.mDayPeriodField.value =
               this.mDayPeriodField.value == this.mAMIndicator ?
                 this.mPMIndicator : this.mAMIndicator;
             this.mDayPeriodField.select();
+            this.updateResetButtonVisibility();
             this.setInputValueFromFields();
             return;
           }
 
           switch (key) {
             case "ArrowUp":
               this.incrementFieldValue(targetField, 1);
               break;
@@ -845,16 +864,17 @@
               targetField == this.mDayPeriodField) {
             if (key == "a" || key == "A") {
               this.mDayPeriodField.value = this.mAMIndicator;
               this.mDayPeriodField.select();
             } else if (key == "p" || key == "P") {
               this.mDayPeriodField.value = this.mPMIndicator;
               this.mDayPeriodField.select();
             }
+            this.updateResetButtonVisibility();
             return;
           }
 
           if (targetField.classList.contains("numeric") && key.match(/[0-9]/)) {
             let buffer = targetField.getAttribute("typeBuffer") || "";
 
             buffer = buffer.concat(key);
             this.setFieldValue(targetField, buffer);
@@ -900,26 +920,40 @@
             if (value < 10) {
               value = "00" + value;
             } else if (value < 100) {
               value = "0" + value;
             }
           }
 
           aField.value = value;
+          this.updateResetButtonVisibility();
         ]]>
         </body>
       </method>
 
-      <method name="isValueAvailable">
+      <method name="isAnyValueAvailable">
+        <parameter name="aForPicker"/>
         <body>
         <![CDATA[
+          let available = !this.isEmpty(this.mHourField.value) ||
+                          !this.isEmpty(this.mMinuteField.value);
+
+          if (available) {
+            return true;
+          }
+
           // Picker only cares about hour:minute.
-          return !this.isEmpty(this.mHourField.value) ||
-                 !this.isEmpty(this.mMinuteField.value);
+          if (aForPicker) {
+            return false;
+          }
+
+          return (this.mDayPeriodField && !this.isEmpty(this.mDayPeriodField.value)) ||
+                 (this.mSecondField && !this.isEmpty(this.mSecondField.value)) ||
+                 (this.mMillisecField && !this.isEmpty(this.mMillisecField.value));
         ]]>
         </body>
       </method>
 
       <method name="getCurrentValue">
         <body>
         <![CDATA[
           let hour;
@@ -975,33 +1009,35 @@
                       xbl:inherits="disabled,readonly,tabindex"/>
           <html:span anonid="sep-second" class="datetime-separator"></html:span>
           <html:input anonid="input-three"
                       class="textbox-input datetime-input numeric"
                       size="2" maxlength="2"
                       xbl:inherits="disabled,readonly,tabindex"/>
         </html:span>
 
-        <html:button class="datetime-reset-button" anoid="reset-button"
-                     tabindex="-1" xbl:inherits="disabled"
-                     onclick="document.getBindingParent(this).clearInputFields(false);"/>
+        <html:button class="datetime-reset-button" anonid="reset-button"
+                     tabindex="-1" xbl:inherits="disabled"/>
       </html:div>
     </content>
 
     <implementation implements="nsIDateTimeInputArea">
       <constructor>
       <![CDATA[
         this.DEBUG = false;
         this.mInputElement = this.parentNode;
 
         this.mMin = this.mInputElement.min;
         this.mMax = this.mInputElement.max;
         this.mStep = this.mInputElement.step;
         this.mIsPickerOpen = false;
 
+        this.mResetButton =
+          document.getAnonymousElementByAttribute(this, "anonid", "reset-button");
+
         this.EVENTS.forEach((eventName) => {
           this.addEventListener(eventName, this, { mozSystemGroup: true });
         });
         // Handle keypress separately since we need to catch it on capturing.
         this.addEventListener("keypress", this, {
           capture: true,
           mozSystemGroup: true
         });
@@ -1036,16 +1072,28 @@
         <![CDATA[
           if (this.DEBUG) {
             dump("[DateTimeBox] " + aMsg + "\n");
           }
         ]]>
         </body>
       </method>
 
+      <method name="updateResetButtonVisibility">
+        <body>
+          <![CDATA[
+            if (this.isAnyValueAvailable(false)) {
+              this.mResetButton.style.visibility = "visible";
+            } else {
+              this.mResetButton.style.visibility = "hidden";
+            }
+          ]]>
+        </body>
+      </method>
+
       <method name="focusInnerTextBox">
         <body>
         <![CDATA[
           this.log("focusInnerTextBox");
           document.getAnonymousElementByAttribute(this, "anonid", "input-one").focus();
         ]]>
         </body>
       </method>
@@ -1159,20 +1207,26 @@
       </method>
 
       <method name="getCurrentValue">
         <body>
           throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
         </body>
       </method>
 
+      <method name="isAnyValueAvailable">
+        <body>
+          throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+        </body>
+      </method>
+
       <method name="notifyPicker">
         <body>
         <![CDATA[
-          if (this.mIsPickerOpen && this.isValueAvailable()) {
+          if (this.mIsPickerOpen && this.isAnyValueAvailable(true)) {
             this.mInputElement.updateDateTimePicker(this.getCurrentValue());
           }
         ]]>
         </body>
       </method>
 
       <method name="isDisabled">
         <body>
@@ -1265,17 +1319,21 @@
             case "Enter":
             case " ": {
               this.mInputElement.closeDateTimePicker();
               aEvent.preventDefault();
               break;
             }
             case "Backspace": {
               let targetField = aEvent.originalTarget;
+              targetField.value = "";
               targetField.setAttribute("typeBuffer", "");
+              this.updateResetButtonVisibility();
+              this.setInputValueFromFields();
+              aEvent.preventDefault();
               break;
             }
             case "ArrowRight":
             case "ArrowLeft": {
               this.advanceToNextField(aEvent.key == "ArrowRight" ? false : true);
               aEvent.preventDefault();
               break;
             }
@@ -1307,22 +1365,24 @@
         <parameter name="aEvent"/>
         <body>
         <![CDATA[
           this.log("onClick originalTarget: " + aEvent.originalTarget);
 
           // XXX: .originalTarget is not expected.
           // When clicking on one of the inner text boxes, the .originalTarget is
           // a HTMLDivElement and when clicking on the reset button, it's a
-          // HTMLButtonElement but it's not equal to our reset-button.
+          // HTMLButtonElement.
           if (aEvent.defaultPrevented || this.isDisabled() || this.isReadonly()) {
             return;
           }
 
-          if (!(aEvent.originalTarget instanceof HTMLButtonElement)) {
+          if (aEvent.originalTarget == this.mResetButton) {
+            this.clearInputFields(false);
+          } else {
             this.mInputElement.openDateTimePicker(this.getCurrentValue());
           }
         ]]>
         </body>
       </method>
     </implementation>
   </binding>