summaryrefslogtreecommitdiffstats
path: root/toolkit/content/widgets/datetimebox.xml
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /toolkit/content/widgets/datetimebox.xml
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'toolkit/content/widgets/datetimebox.xml')
-rw-r--r--toolkit/content/widgets/datetimebox.xml807
1 files changed, 807 insertions, 0 deletions
diff --git a/toolkit/content/widgets/datetimebox.xml b/toolkit/content/widgets/datetimebox.xml
new file mode 100644
index 000000000..05591e65a
--- /dev/null
+++ b/toolkit/content/widgets/datetimebox.xml
@@ -0,0 +1,807 @@
+<?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 = "";
+ }
+
+ if (this.mMinuteField && !this.mMinuteField.disabled &&
+ !this.mMinuteField.readOnly) {
+ this.mMinuteField.value = "";
+ }
+
+ if (this.mSecondField && !this.mSecondField.disabled &&
+ !this.mSecondField.readOnly) {
+ this.mSecondField.value = "";
+ }
+
+ if (this.mMillisecField && !this.mMillisecField.disabled &&
+ !this.mMillisecField.readOnly) {
+ this.mMillisecField.value = "";
+ }
+
+ 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;
+ ]]>
+ </constructor>
+
+ <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>
+
+ </implementation>
+
+ <handlers>
+ <handler event="focus">
+ <![CDATA[
+ this.log("focus on: " + event.originalTarget);
+
+ let target = event.originalTarget;
+ if (target.type == "text") {
+ this.mLastFocusedField = target;
+ target.select();
+ }
+ ]]>
+ </handler>
+
+ <handler event="blur">
+ <![CDATA[
+ this.setInputValueFromFields();
+ ]]>
+ </handler>
+
+ <handler event="click">
+ <![CDATA[
+ // 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.
+ this.log("click on: " + event.originalTarget);
+ if (event.defaultPrevented || this.isDisabled() || this.isReadonly()) {
+ return;
+ }
+
+ if (!(event.originalTarget instanceof HTMLButtonElement)) {
+ this.mInputElement.openDateTimePicker(this.getCurrentValue());
+ }
+ ]]>
+ </handler>
+
+ <handler event="keypress" phase="capturing">
+ <![CDATA[
+ let key = event.key;
+ this.log("keypress: " + key);
+
+ if (key == "Backspace" || key == "Tab") {
+ return;
+ }
+
+ if (key == "Enter" || key == " ") {
+ // Close picker on Enter and Space.
+ this.mInputElement.closeDateTimePicker();
+ }
+
+ if (key == "ArrowUp" || key == "ArrowDown" ||
+ key == "PageUp" || key == "PageDown" ||
+ key == "Home" || key == "End") {
+ this.handleKeyboardNav(event);
+ } else if (key == "ArrowRight" || key == "ArrowLeft") {
+ this.advanceToNextField((key == "ArrowRight" ? false : true));
+ } else {
+ this.handleKeypress(event);
+ }
+
+ event.preventDefault();
+ ]]>
+ </handler>
+ </handlers>
+ </binding>
+
+</bindings>