toolkit/content/widgets/datetimebox.xml
author Cykesiopka <cykesiopka.bmo@gmail.com>
Fri, 18 Nov 2016 00:49:25 +0800
changeset 368361 01aafb2359c9423afd979ec57c401e5034d285fa
parent 368247 f438bfb22339793b15dc1a63140dbbb85a998e5f
child 371562 5122a14c6fe6215a3f8184adc9ffd5fb6783da81
permissions -rw-r--r--
Bug 1311379 - Stop using Scoped.h NSS types in WebCryptoTask.(cpp|h). r=rbarnes,ttaubert Scoped.h is deprecated. MozReview-Commit-ID: CAcnrB9v3dH

<?xml version="1.0"?>

<!-- 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/. -->

<bindings id="datetimeboxBindings"
   xmlns="http://www.mozilla.org/xbl"
   xmlns:html="http://www.w3.org/1999/xhtml"
   xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
   xmlns:xbl="http://www.mozilla.org/xbl">

  <binding id="time-input"
           extends="chrome://global/content/bindings/datetimebox.xml#datetime-input-base">
    <resources>
      <stylesheet src="chrome://global/content/textbox.css"/>
      <stylesheet src="chrome://global/skin/textbox.css"/>
      <stylesheet src="chrome://global/content/bindings/datetimebox.css"/>
    </resources>

    <implementation>
      <constructor>
      <![CDATA[
        // TODO: Bug 1301312 - localization for input type=time input.
        this.mHour12 = true;
        this.mAMIndicator = "AM";
        this.mPMIndicator = "PM";
        this.mPlaceHolder = "--";
        this.mSeparatorText = ":";
        this.mMillisecSeparatorText = ".";
        this.mMaxLength = 2;
        this.mMillisecMaxLength = 3;
        this.mDefaultStep = 60 * 1000; // in milliseconds

        this.mMinHourInHour12 = 1;
        this.mMaxHourInHour12 = 12;
        this.mMinMinute = 0;
        this.mMaxMinute = 59;
        this.mMinSecond = 0;
        this.mMaxSecond = 59;
        this.mMinMillisecond = 0;
        this.mMaxMillisecond = 999;

        this.mHourPageUpDownInterval = 3;
        this.mMinSecPageUpDownInterval = 10;

        this.mHourField =
          document.getAnonymousElementByAttribute(this, "anonid", "input-one");
        this.mHourField.setAttribute("typeBuffer", "");
        this.mMinuteField =
          document.getAnonymousElementByAttribute(this, "anonid", "input-two");
        this.mMinuteField.setAttribute("typeBuffer", "");
        this.mDayPeriodField =
          document.getAnonymousElementByAttribute(this, "anonid", "input-three");
        this.mDayPeriodField.classList.remove("numeric");

        this.mHourField.placeholder = this.mPlaceHolder;
        this.mMinuteField.placeholder = this.mPlaceHolder;
        this.mDayPeriodField.placeholder = this.mPlaceHolder;

        this.mHourField.setAttribute("min", this.mMinHourInHour12);
        this.mHourField.setAttribute("max", this.mMaxHourInHour12);
        this.mMinuteField.setAttribute("min", this.mMinMinute);
        this.mMinuteField.setAttribute("max", this.mMaxMinute);

        this.mMinuteSeparator =
           document.getAnonymousElementByAttribute(this, "anonid", "sep-first");
        this.mMinuteSeparator.textContent = this.mSeparatorText;
        this.mSpaceSeparator =
          document.getAnonymousElementByAttribute(this, "anonid", "sep-second");
        // space between time and am/pm field
        this.mSpaceSeparator.textContent = " ";

        this.mSecondSeparator = null;
        this.mSecondField = null;
        this.mMillisecSeparator = null;
        this.mMillisecField = null;

        if (this.mInputElement.value) {
          this.setFieldsFromInputValue();
        }
        ]]>
      </constructor>

      <method name="insertSeparator">
        <parameter name="aSeparatorText"/>
        <body>
        <![CDATA[
          let container = this.mHourField.parentNode;
          const HTML_NS = "http://www.w3.org/1999/xhtml";

          let separator = document.createElementNS(HTML_NS, "span");
          separator.textContent = aSeparatorText;
          separator.setAttribute("class", "datetime-separator");
          container.insertBefore(separator, this.mSpaceSeparator);

          return separator;
        ]]>
        </body>
      </method>

      <method name="insertAdditionalField">
        <parameter name="aPlaceHolder"/>
        <parameter name="aMin"/>
        <parameter name="aMax"/>
        <parameter name="aSize"/>
        <parameter name="aMaxLength"/>
        <body>
        <![CDATA[
          let container = this.mHourField.parentNode;
          const HTML_NS = "http://www.w3.org/1999/xhtml";

          let field = document.createElementNS(HTML_NS, "input");
          field.classList.add("textbox-input", "datetime-input", "numeric");
          field.setAttribute("size", aSize);
          field.setAttribute("maxlength", aMaxLength);
          field.setAttribute("min", aMin);
          field.setAttribute("max", aMax);
          field.setAttribute("typeBuffer", "");
          field.disabled = this.mInputElement.disabled;
          field.readOnly = this.mInputElement.readOnly;
          field.tabIndex = this.mInputElement.tabIndex;
          field.placeholder = aPlaceHolder;
          container.insertBefore(field, this.mSpaceSeparator);

          return field;
        ]]>
        </body>
      </method>

      <method name="setFieldsFromInputValue">
        <body>
        <![CDATA[
          let value = this.mInputElement.value;
          if (!value) {
            this.clearInputFields(true);
            return;
          }

          this.log("setFieldsFromInputValue: " + value);
          let [hour, minute, second] = value.split(':');

          this.setFieldValue(this.mHourField, hour);
          this.setFieldValue(this.mMinuteField, minute);
          if (this.mHour12) {
            this.mDayPeriodField.value = (hour >= this.mMaxHourInHour12) ?
              this.mPMIndicator : this.mAMIndicator;
          }

          if (!this.isEmpty(second)) {
            let index = second.indexOf(".");
            let millisecond;
            if (index != -1) {
              millisecond = second.substring(index + 1);
              second = second.substring(0, index);
            }

            if (!this.mSecondField) {
              this.mSecondSeparator = this.insertSeparator(this.mSeparatorText);
              this.mSecondField = this.insertAdditionalField(this.mPlaceHolder,
                this.mMinSecond, this.mMaxSecond, this.mMaxLength,
                this.mMaxLength);
            }
            this.setFieldValue(this.mSecondField, second);

            if (!this.isEmpty(millisecond)) {
              if (!this.mMillisecField) {
                this.mMillisecSeparator = this.insertSeparator(
                  this.mMillisecSeparatorText);
                this.mMillisecField = this.insertAdditionalField(
                  this.mPlaceHolder, this.mMinMillisecond, this.mMaxMillisecond,
                  this.mMillisecMaxLength, this.mMillisecMaxLength);
              }
              this.setFieldValue(this.mMillisecField, millisecond);
            } else if (this.mMillisecField) {
              this.mMillisecField.remove();
              this.mMillisecField = null;

              this.mMillisecSeparator.remove();
              this.mMillisecSeparator = null;
            }
          } else {
            if (this.mSecondField) {
              this.mSecondField.remove();
              this.mSecondField = null;

              this.mSecondSeparator.remove();
              this.mSecondSeparator = null;
            }

            if (this.mMillisecField) {
              this.mMillisecField.remove();
              this.mMillisecField = null;

              this.mMillisecSeparator.remove();
              this.mMillisecSeparator = null;
            }
          }
          this.notifyPicker();
        ]]>
        </body>
      </method>

      <method name="setInputValueFromFields">
        <body>
        <![CDATA[
          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().
            this.notifyPicker();
            return;
          }

          let hour = Number(this.mHourField.value);
          if (this.mHour12) {
            let dayPeriod = this.mDayPeriodField.value;
            if (dayPeriod == this.mPMIndicator &&
                hour < this.mMaxHourInHour12) {
              hour += this.mMaxHourInHour12;
            } else if (dayPeriod == this.mAMIndicator &&
                       hour == this.mMaxHourInHour12) {
              hour = 0;
            }
          }

          hour = (hour < 10) ? ("0" + hour) : hour;

          let time = hour + ":" + this.mMinuteField.value;
          if (this.mSecondField) {
            time += ":" + this.mSecondField.value;
          }

          if (this.mMillisecField) {
            time += "." + this.mMillisecField.value;
          }

          this.log("setInputValueFromFields: " + time);
          this.mInputElement.setUserInput(time);
        ]]>
        </body>
      </method>

      <method name="setFieldsFromPicker">
        <parameter name="aValue"/>
        <body>
        <![CDATA[
          let hour = aValue.hour;
          let minute = aValue.minute;
          this.log("setFieldsFromPicker: " + hour + ":" + minute);

          if (!this.isEmpty(hour)) {
            this.setFieldValue(this.mHourField, hour);
            if (this.mHour12) {
              this.mDayPeriodField.value =
                (hour >= this.mMaxHourInHour12) ? this.mPMIndicator
                                                : this.mAMIndicator;
            }
          }

          if (!this.isEmpty(minute)) {
            this.setFieldValue(this.mMinuteField, minute);
          }
        ]]>
        </body>
       </method>

      <method name="clearInputFields">
        <parameter name="aFromInputElement"/>
        <body>
        <![CDATA[
          this.log("clearInputFields");

          if (this.isDisabled() || this.isReadonly()) {
            return;
          }

          if (this.mHourField && !this.mHourField.disabled &&
              !this.mHourField.readOnly) {
            this.mHourField.value = "";
            this.mHourField.setAttribute("typeBuffer", "");
          }

          if (this.mMinuteField && !this.mMinuteField.disabled &&
              !this.mMinuteField.readOnly) {
            this.mMinuteField.value = "";
            this.mMinuteField.setAttribute("typeBuffer", "");
          }

          if (this.mSecondField && !this.mSecondField.disabled &&
              !this.mSecondField.readOnly) {
            this.mSecondField.value = "";
            this.mSecondField.setAttribute("typeBuffer", "");
          }

          if (this.mMillisecField && !this.mMillisecField.disabled &&
              !this.mMillisecField.readOnly) {
            this.mMillisecField.value = "";
            this.mMillisecField.setAttribute("typeBuffer", "");
          }

          if (this.mDayPeriodField && !this.mDayPeriodField.disabled &&
              !this.mDayPeriodField.readOnly) {
            this.mDayPeriodField.value = "";
          }

          if (!aFromInputElement) {
            this.mInputElement.setUserInput("");
          }
        ]]>
        </body>
      </method>

      <method name="incrementFieldValue">
        <parameter name="aTargetField"/>
        <parameter name="aTimes"/>
        <body>
        <![CDATA[
          let value;

          // Use current time if field is empty.
          if (this.isEmpty(aTargetField.value)) {
            let now = new Date();

            if (aTargetField == this.mHourField) {
              value = now.getHours() % this.mMaxHourInHour12 ||
                this.mMaxHourInHour12;
            } else if (aTargetField == this.mMinuteField) {
              value = now.getMinutes();
            } else if (aTargetField == this.mSecondField) {
              value = now.getSeconds();
            } else if (aTargetField == this.mMillisecField) {
              value = now.getMilliseconds();
            } else {
              this.log("Field not supported in incrementFieldValue.");
              return;
            }
          } else {
            value = Number(aTargetField.value);
          }

          let min = aTargetField.getAttribute("min");
          let max = aTargetField.getAttribute("max");

          value += aTimes;
          if (value > max) {
            value -= (max - min + 1);
          } else if (value < min) {
            value += (max - min + 1);
          }
          this.setFieldValue(aTargetField, value);
          aTargetField.select();
        ]]>
        </body>
      </method>

      <method name="handleKeyboardNav">
        <parameter name="aEvent"/>
        <body>
        <![CDATA[
          if (this.isDisabled() || this.isReadonly()) {
            return;
          }

          let targetField = aEvent.originalTarget;
          let key = aEvent.key;

          if (this.mDayPeriodField &&
              targetField == this.mDayPeriodField) {
            // Home/End key does nothing on AM/PM field.
            if (key == "Home" || key == "End") {
              return;
            }

            this.mDayPeriodField.value =
              this.mDayPeriodField.value == this.mAMIndicator ?
                this.mPMIndicator : this.mAMIndicator;
            this.mDayPeriodField.select();
            this.setInputValueFromFields();
            return;
          }

          switch (key) {
            case "ArrowUp":
              this.incrementFieldValue(targetField, 1);
              break;
            case "ArrowDown":
              this.incrementFieldValue(targetField, -1);
              break;
            case "PageUp":
              this.incrementFieldValue(targetField,
                targetField == this.mHourField ? this.mHourPageUpDownInterval
                                               : this.mMinSecPageUpDownInterval);
              break;
            case "PageDown":
              this.incrementFieldValue(targetField,
                targetField == this.mHourField ? (0 - this.mHourPageUpDownInterval)
                                               : (0 - this.mMinSecPageUpDownInterval));
              break;
            case "Home":
              let min = targetField.getAttribute("min");
              this.setFieldValue(targetField, min);
              targetField.select();
              break;
            case "End":
              let max = targetField.getAttribute("max");
              this.setFieldValue(targetField, max);
              targetField.select();
              break;
          }
          this.setInputValueFromFields();
        ]]>
        </body>
      </method>

      <method name="handleKeypress">
        <parameter name="aEvent"/>
        <body>
        <![CDATA[
          if (this.isDisabled() || this.isReadonly()) {
            return;
          }

          let targetField = aEvent.originalTarget;
          let key = aEvent.key;

          if (this.mDayPeriodField &&
              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();
            }
            return;
          }

          if (targetField.classList.contains("numeric") && key.match(/[0-9]/)) {
            let buffer = targetField.getAttribute("typeBuffer") || "";

            buffer = buffer.concat(key);
            this.setFieldValue(targetField, buffer);
            targetField.select();

            let n = Number(buffer);
            let max = targetField.getAttribute("max");
            if (buffer.length >= targetField.maxLength || n * 10 > max) {
              buffer = "";
              this.advanceToNextField();
            }
            targetField.setAttribute("typeBuffer", buffer);
          }
        ]]>
        </body>
      </method>

      <method name="setFieldValue">
       <parameter name="aField"/>
       <parameter name="aValue"/>
        <body>
        <![CDATA[
          let value = Number(aValue);
          if (isNaN(value)) {
            this.log("NaN on setFieldValue!");
            return;
          }

          if (aField.maxLength == this.mMaxLength) { // For hour, minute and second
            if (aField == this.mHourField && this.mHour12) {
              value = (value > this.mMaxHourInHour12) ?
                value - this.mMaxHourInHour12 : value;
              if (aValue == "00") {
                value = this.mMaxHourInHour12;
              }
            }
            // prepend zero
            if (value < 10) {
              value = "0" + value;
            }
          } else if (aField.maxLength == this.mMillisecMaxLength) {
            // prepend zeroes
            if (value < 10) {
              value = "00" + value;
            } else if (value < 100) {
              value = "0" + value;
            }
          }

          aField.value = value;
        ]]>
        </body>
      </method>

      <method name="isValueAvailable">
        <body>
        <![CDATA[
          // Picker only cares about hour:minute.
          return !this.isEmpty(this.mHourField.value) ||
                 !this.isEmpty(this.mMinuteField.value);
        ]]>
        </body>
      </method>

      <method name="getCurrentValue">
        <body>
        <![CDATA[
          let hour;
          if (!this.isEmpty(this.mHourField.value)) {
            hour = Number(this.mHourField.value);
            if (this.mHour12) {
              let dayPeriod = this.mDayPeriodField.value;
              if (dayPeriod == this.mPMIndicator &&
                  hour < this.mMaxHourInHour12) {
                hour += this.mMaxHourInHour12;
              } else if (dayPeriod == this.mAMIndicator &&
                         hour == this.mMaxHourInHour12) {
                hour = 0;
              }
            }
           }

          let minute;
          if (!this.isEmpty(this.mMinuteField.value)) {
            minute = Number(this.mMinuteField.value);
          }

          // Picker only needs hour/minute.
          let time = { hour, minute };

          this.log("getCurrentValue: " + JSON.stringify(time));
          return time;
        ]]>
        </body>
      </method>
    </implementation>
  </binding>

  <binding id="datetime-input-base">
    <resources>
      <stylesheet src="chrome://global/content/textbox.css"/>
      <stylesheet src="chrome://global/skin/textbox.css"/>
      <stylesheet src="chrome://global/content/bindings/datetimebox.css"/>
    </resources>

    <content>
      <html:div class="datetime-input-box-wrapper"
                xbl:inherits="context,disabled,readonly">
        <html:span>
          <html:input anonid="input-one"
                      class="textbox-input datetime-input numeric"
                      size="2" maxlength="2"
                      xbl:inherits="disabled,readonly,tabindex"/>
          <html:span anonid="sep-first" class="datetime-separator"></html:span>
          <html:input anonid="input-two"
                      class="textbox-input datetime-input numeric"
                      size="2" maxlength="2"
                      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: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.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
        });
      ]]>
      </constructor>

      <destructor>
      <![CDATA[
        this.mInputElement = null;

        this.EVENTS.forEach((eventName) => {
          this.removeEventListener(eventName, this, { mozSystemGroup: true });
        });
        this.removeEventListener("keypress", onKeyPress, {
          capture: true,
          mozSystemGroup: true
        });
      ]]>
      </destructor>

      <property name="EVENTS" readonly="true">
        <getter>
        <![CDATA[
          return ["click", "focus", "blur", "copy", "cut", "paste"];
        ]]>
        </getter>
      </property>

      <method name="log">
        <parameter name="aMsg"/>
        <body>
        <![CDATA[
          if (this.DEBUG) {
            dump("[DateTimeBox] " + aMsg + "\n");
          }
        ]]>
        </body>
      </method>

      <method name="focusInnerTextBox">
        <body>
        <![CDATA[
          this.log("focusInnerTextBox");
          document.getAnonymousElementByAttribute(this, "anonid", "input-one").focus();
        ]]>
        </body>
      </method>

      <method name="blurInnerTextBox">
        <body>
        <![CDATA[
          this.log("blurInnerTextBox");
          if (this.mLastFocusedField) {
            this.mLastFocusedField.blur();
          }
        ]]>
        </body>
      </method>

      <method name="notifyInputElementValueChanged">
        <body>
        <![CDATA[
          this.log("inputElementValueChanged");
          this.setFieldsFromInputValue();
        ]]>
        </body>
      </method>

      <method name="setValueFromPicker">
        <parameter name="aValue"/>
        <body>
        <![CDATA[
          this.setFieldsFromPicker(aValue);
        ]]>
        </body>
      </method>

      <method name="advanceToNextField">
        <parameter name="aReverse"/>
        <body>
        <![CDATA[
          this.log("advanceToNextField");

          let focusedInput = this.mLastFocusedField;
          let next = aReverse ? focusedInput.previousElementSibling
                              : focusedInput.nextElementSibling;
          if (!next && !aReverse) {
            this.setInputValueFromFields();
            return;
          }

          while (next) {
            if (next.type == "text" && !next.disabled) {
              next.focus();
              break;
            }
            next = aReverse ? next.previousElementSibling
                            : next.nextElementSibling;
          }
        ]]>
        </body>
      </method>

      <method name="setPickerState">
        <parameter name="aIsOpen"/>
        <body>
        <![CDATA[
          this.log("picker is now " + (aIsOpen ? "opened" : "closed"));
          this.mIsPickerOpen = aIsOpen;
        ]]>
        </body>
      </method>

      <method name="isEmpty">
        <parameter name="aValue"/>
        <body>
          return (aValue == undefined || 0 === aValue.length);
        </body>
      </method>

      <method name="clearInputFields">
        <body>
          throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
        </body>
      </method>

      <method name="setFieldsFromInputValue">
        <body>
          throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
        </body>
      </method>

      <method name="setInputValueFromFields">
        <body>
          throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
        </body>
      </method>

      <method name="setFieldsFromPicker">
        <body>
          throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
        </body>
      </method>

      <method name="handleKeypress">
        <body>
          throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
        </body>
      </method>

      <method name="handleKeyboardNav">
        <body>
          throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
        </body>
      </method>

      <method name="notifyPicker">
        <body>
        <![CDATA[
          if (this.mIsPickerOpen && this.isValueAvailable()) {
            this.mInputElement.updateDateTimePicker(this.getCurrentValue());
          }
        ]]>
        </body>
      </method>

      <method name="isDisabled">
        <body>
        <![CDATA[
          return this.hasAttribute("disabled");
        ]]>
        </body>
      </method>

      <method name="isReadonly">
        <body>
        <![CDATA[
          return this.hasAttribute("readonly");
        ]]>
        </body>
      </method>

      <method name="handleEvent">
        <parameter name="aEvent"/>
        <body>
        <![CDATA[
          this.log("handleEvent: " + aEvent.type);

          switch (aEvent.type) {
            case "keypress": {
              this.onKeyPress(aEvent);
              break;
            }
            case "click": {
              this.onClick(aEvent);
              break;
            }
            case "focus": {
              this.onFocus(aEvent);
              break;
            }
            case "blur": {
              this.setInputValueFromFields();
              break;
            }
            case "copy":
            case "cut":
            case "paste": {
              aEvent.preventDefault();
              break;
            }
            default:
              break;
          }
        ]]>
        </body>
      </method>

      <method name="onFocus">
        <parameter name="aEvent"/>
        <body>
        <![CDATA[
          this.log("onFocus originalTarget: " + aEvent.originalTarget);

          let target = aEvent.originalTarget;
          if ((target instanceof HTMLInputElement) && target.type == "text") {
            this.mLastFocusedField = target;
            target.select();
          }
        ]]>
        </body>
      </method>

      <method name="onKeyPress">
        <parameter name="aEvent"/>
        <body>
        <![CDATA[
          this.log("onKeyPress key: " + aEvent.key);

          switch (aEvent.key) {
            // Close picker on Enter or Space key.
            case "Enter":
            case " ": {
              this.mInputElement.closeDateTimePicker();
              aEvent.preventDefault();
              break;
            }
            case "Backspace": {
              let targetField = aEvent.originalTarget;
              targetField.setAttribute("typeBuffer", "");
              break;
            }
            case "ArrowRight":
            case "ArrowLeft": {
              this.advanceToNextField(aEvent.key == "ArrowRight" ? false : true);
              aEvent.preventDefault();
              break;
            }
            case "ArrowUp":
            case "ArrowDown":
            case "PageUp":
            case "PageDown":
            case "Home":
            case "End": {
              this.handleKeyboardNav(aEvent);
              aEvent.preventDefault();
              break;
            }
            default: {
              // printable characters
              if (aEvent.keyCode == 0 &&
                  !(aEvent.ctrlKey || aEvent.altKey || aEvent.metaKey)) {
                this.handleKeypress(aEvent);
                aEvent.preventDefault();
              }
              break;
            }
          }
        ]]>
        </body>
      </method>

      <method name="onClick">
        <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.
          if (aEvent.defaultPrevented || this.isDisabled() || this.isReadonly()) {
            return;
          }

          if (!(aEvent.originalTarget instanceof HTMLButtonElement)) {
            this.mInputElement.openDateTimePicker(this.getCurrentValue());
          }
        ]]>
        </body>
      </method>
    </implementation>
  </binding>

</bindings>