mirror of
https://github.com/roytam1/basilisk55.git
synced 2026-05-26 15:02:46 +00:00
1443 lines
45 KiB
XML
1443 lines
45 KiB
XML
<?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/. -->
|
|
|
|
<!DOCTYPE bindings [
|
|
<!ENTITY % datetimeboxDTD SYSTEM "chrome://global/locale/datetimebox.dtd">
|
|
%datetimeboxDTD;
|
|
]>
|
|
|
|
<!--
|
|
TODO
|
|
Bug 1446342:
|
|
Input type="date" not working if the other form elements has name="document"
|
|
|
|
Any alternative solution:
|
|
document === window.document
|
|
document === this.ownerDocument
|
|
-->
|
|
|
|
<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="date-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[
|
|
/* eslint-disable no-multi-spaces */
|
|
this.mYearPlaceHolder = ]]>"&date.year.placeholder;"<![CDATA[;
|
|
this.mMonthPlaceHolder = ]]>"&date.month.placeholder;"<![CDATA[;
|
|
this.mDayPlaceHolder = ]]>"&date.day.placeholder;"<![CDATA[;
|
|
this.mSeparatorText = "/";
|
|
/* eslint-enable no-multi-spaces */
|
|
|
|
this.mMinMonth = 1;
|
|
this.mMaxMonth = 12;
|
|
this.mMinDay = 1;
|
|
this.mMaxDay = 31;
|
|
this.mMinYear = 1;
|
|
// Maximum year limited by ECMAScript date object range, year <= 275760.
|
|
this.mMaxYear = 275760;
|
|
this.mMonthDayLength = 2;
|
|
this.mYearLength = 4;
|
|
this.mMonthPageUpDownInterval = 3;
|
|
this.mDayPageUpDownInterval = 7;
|
|
this.mYearPageUpDownInterval = 10;
|
|
|
|
// Default to en-US, month-day-year order.
|
|
this.mMonthField =
|
|
window.document.getAnonymousElementByAttribute(this, "anonid", "input-one");
|
|
this.mDayField =
|
|
window.document.getAnonymousElementByAttribute(this, "anonid", "input-two");
|
|
this.mYearField =
|
|
window.document.getAnonymousElementByAttribute(this, "anonid", "input-three");
|
|
this.mYearField.size = this.mYearLength;
|
|
this.mYearField.maxLength = this.mMaxYear.toString().length;
|
|
|
|
this.mMonthField.placeholder = this.mMonthPlaceHolder;
|
|
this.mDayField.placeholder = this.mDayPlaceHolder;
|
|
this.mYearField.placeholder = this.mYearPlaceHolder;
|
|
|
|
this.mMonthField.setAttribute("min", this.mMinMonth);
|
|
this.mMonthField.setAttribute("max", this.mMaxMonth);
|
|
this.mMonthField.setAttribute("pginterval",
|
|
this.mMonthPageUpDownInterval);
|
|
this.mDayField.setAttribute("min", this.mMinDay);
|
|
this.mDayField.setAttribute("max", this.mMaxDay);
|
|
this.mDayField.setAttribute("pginterval", this.mDayPageUpDownInterval);
|
|
this.mYearField.setAttribute("min", this.mMinYear);
|
|
this.mYearField.setAttribute("max", this.mMaxYear);
|
|
this.mYearField.setAttribute("pginterval",
|
|
this.mYearPageUpDownInterval);
|
|
|
|
this.mDaySeparator =
|
|
window.document.getAnonymousElementByAttribute(this, "anonid", "sep-first");
|
|
this.mDaySeparator.textContent = this.mSeparatorText;
|
|
this.mYearSeparator =
|
|
window.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");
|
|
|
|
if (this.isDisabled() || this.isReadonly()) {
|
|
return;
|
|
}
|
|
|
|
if (this.mMonthField && !this.mMonthField.disabled &&
|
|
!this.mMonthField.readOnly) {
|
|
this.mMonthField.value = "";
|
|
this.mMonthField.setAttribute("typeBuffer", "");
|
|
}
|
|
|
|
if (this.mDayField && !this.mDayField.disabled &&
|
|
!this.mDayField.readOnly) {
|
|
this.mDayField.value = "";
|
|
this.mDayField.setAttribute("typeBuffer", "");
|
|
}
|
|
|
|
if (this.mYearField && !this.mYearField.disabled &&
|
|
!this.mYearField.readOnly) {
|
|
this.mYearField.value = "";
|
|
this.mYearField.setAttribute("typeBuffer", "");
|
|
}
|
|
|
|
if (!aFromInputElement && this.mInputElement.value) {
|
|
this.mInputElement.setUserInput("");
|
|
}
|
|
|
|
this.updateResetButtonVisibility();
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<method name="setFieldsFromInputValue">
|
|
<body>
|
|
<![CDATA[
|
|
let value = this.mInputElement.value;
|
|
if (!value) {
|
|
this.clearInputFields(true);
|
|
return;
|
|
}
|
|
|
|
this.log("setFieldsFromInputValue: " + value);
|
|
let [year, month, day] = value.split("-");
|
|
|
|
this.setFieldValue(this.mYearField, year);
|
|
this.setFieldValue(this.mMonthField, month);
|
|
this.setFieldValue(this.mDayField, day);
|
|
|
|
this.notifyPicker();
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<method name="getDaysInMonth">
|
|
<parameter name="aMonth"/>
|
|
<parameter name="aYear"/>
|
|
<body>
|
|
<![CDATA[
|
|
// Javascript's month is 0-based, so this means last day of the
|
|
// previous month.
|
|
return new Date(aYear, aMonth, 0).getDate();
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<method name="isFieldInvalid">
|
|
<parameter name="aField"/>
|
|
<body>
|
|
<![CDATA[
|
|
if (this.isEmpty(aField.value)) {
|
|
return true;
|
|
}
|
|
|
|
let min = Number(aField.getAttribute("min"));
|
|
let max = Number(aField.getAttribute("max"));
|
|
|
|
if (Number(aField.value) < min || Number(aField.value) > max) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<method name="setInputValueFromFields">
|
|
<body>
|
|
<![CDATA[
|
|
if (!this.isAnyValueAvailable(false) && this.mInputElement.value) {
|
|
// Values in the input box was cleared, clear the input element's
|
|
// value if not empty.
|
|
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;
|
|
}
|
|
|
|
let year = this.mYearField.value;
|
|
let month = this.mMonthField.value;
|
|
let day = this.mDayField.value;
|
|
|
|
if (day > this.getDaysInMonth(month, year)) {
|
|
// Don't set invalid date, otherwise input element's value will be
|
|
// set to empty.
|
|
return;
|
|
}
|
|
|
|
let date = [year, month, day].join("-");
|
|
|
|
if (date == this.mInputElement.value) {
|
|
return;
|
|
}
|
|
|
|
this.log("setInputValueFromFields: " + date);
|
|
this.mInputElement.setUserInput(date);
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<method name="setFieldsFromPicker">
|
|
<parameter name="aValue"/>
|
|
<body>
|
|
<![CDATA[
|
|
let year = aValue.year;
|
|
let month = aValue.month;
|
|
let day = aValue.day;
|
|
|
|
if (!this.isEmpty(year)) {
|
|
this.setFieldValue(this.mYearField, year);
|
|
}
|
|
|
|
if (!this.isEmpty(month)) {
|
|
this.setFieldValue(this.mMonthField, month);
|
|
}
|
|
|
|
if (!this.isEmpty(day)) {
|
|
this.setFieldValue(this.mDayField, day);
|
|
}
|
|
|
|
// Update input element's .value if needed.
|
|
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 (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="incrementFieldValue">
|
|
<parameter name="aTargetField"/>
|
|
<parameter name="aTimes"/>
|
|
<body>
|
|
<![CDATA[
|
|
let value;
|
|
|
|
// Use current date if field is empty.
|
|
if (this.isEmpty(aTargetField.value)) {
|
|
let now = new Date();
|
|
|
|
if (aTargetField == this.mYearField) {
|
|
value = now.getFullYear();
|
|
} else if (aTargetField == this.mMonthField) {
|
|
value = now.getMonth() + 1;
|
|
} else if (aTargetField == this.mDayField) {
|
|
value = now.getDate();
|
|
} else {
|
|
this.log("Field not supported in incrementFieldValue.");
|
|
return;
|
|
}
|
|
} else {
|
|
value = Number(aTargetField.value);
|
|
}
|
|
|
|
let min = Number(aTargetField.getAttribute("min"));
|
|
let max = Number(aTargetField.getAttribute("max"));
|
|
|
|
value += Number(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;
|
|
|
|
// Home/End key does nothing on year field.
|
|
if (targetField == this.mYearField && (key == "Home" ||
|
|
key == "End")) {
|
|
return;
|
|
}
|
|
|
|
switch (key) {
|
|
case "ArrowUp":
|
|
this.incrementFieldValue(targetField, 1);
|
|
break;
|
|
case "ArrowDown":
|
|
this.incrementFieldValue(targetField, -1);
|
|
break;
|
|
case "PageUp": {
|
|
let interval = targetField.getAttribute("pginterval");
|
|
this.incrementFieldValue(targetField, interval);
|
|
break;
|
|
}
|
|
case "PageDown": {
|
|
let interval = targetField.getAttribute("pginterval");
|
|
this.incrementFieldValue(targetField, 0 - interval);
|
|
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="getCurrentValue">
|
|
<body>
|
|
<![CDATA[
|
|
let year;
|
|
if (!this.isEmpty(this.mYearField.value)) {
|
|
year = Number(this.mYearField.value);
|
|
}
|
|
|
|
let month;
|
|
if (!this.isEmpty(this.mMonthField.value)) {
|
|
month = Number(this.mMonthField.value);
|
|
}
|
|
|
|
let day;
|
|
if (!this.isEmpty(this.mDayField.value)) {
|
|
day = Number(this.mDayField.value);
|
|
}
|
|
|
|
let date = { year, month, day };
|
|
|
|
this.log("getCurrentValue: " + JSON.stringify(date));
|
|
return date;
|
|
]]>
|
|
</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 (aValue.length == aField.maxLength) {
|
|
let min = Number(aField.getAttribute("min"));
|
|
let max = Number(aField.getAttribute("max"));
|
|
|
|
if (aValue < min) {
|
|
value = min;
|
|
} else if (aValue > max) {
|
|
value = max;
|
|
}
|
|
}
|
|
|
|
if (aField == this.mMonthField ||
|
|
aField == this.mDayField) {
|
|
// prepend zero
|
|
if (value < 10) {
|
|
value = "0" + value;
|
|
}
|
|
} else {
|
|
// prepend zeroes
|
|
if (value < 10) {
|
|
value = "000" + value;
|
|
} else if (value < 100) {
|
|
value = "00" + value;
|
|
} else if (value < 1000) {
|
|
value = "0" + value;
|
|
}
|
|
|
|
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="isAnyValueAvailable">
|
|
<parameter name="aForPicker"/>
|
|
<body>
|
|
<![CDATA[
|
|
return !this.isEmpty(this.mMonthField.value) ||
|
|
!this.isEmpty(this.mDayField.value) ||
|
|
!this.isEmpty(this.mYearField.value);
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
</implementation>
|
|
</binding>
|
|
|
|
<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 =
|
|
window.document.getAnonymousElementByAttribute(this, "anonid", "input-one");
|
|
this.mHourField.setAttribute("typeBuffer", "");
|
|
this.mMinuteField =
|
|
window.document.getAnonymousElementByAttribute(this, "anonid", "input-two");
|
|
this.mMinuteField.setAttribute("typeBuffer", "");
|
|
this.mDayPeriodField =
|
|
window.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 =
|
|
window.document.getAnonymousElementByAttribute(this, "anonid", "sep-first");
|
|
this.mMinuteSeparator.textContent = this.mSeparatorText;
|
|
this.mSpaceSeparator =
|
|
window.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();
|
|
}
|
|
this.updateResetButtonVisibility();
|
|
]]>
|
|
</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.isAnyValueAvailable(false) && this.mInputElement.value) {
|
|
// Values in the input box was cleared, clear the input element's
|
|
// value if not empty.
|
|
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().
|
|
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;
|
|
}
|
|
|
|
if (time == this.mInputElement.value) {
|
|
return;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
// Update input element's .value if needed.
|
|
this.setInputValueFromFields();
|
|
]]>
|
|
</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.value) {
|
|
this.mInputElement.setUserInput("");
|
|
}
|
|
|
|
this.updateResetButtonVisibility();
|
|
]]>
|
|
</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.updateResetButtonVisibility();
|
|
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();
|
|
}
|
|
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);
|
|
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;
|
|
this.updateResetButtonVisibility();
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<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.
|
|
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;
|
|
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 class="datetime-input-edit-wrapper"
|
|
anonid="edit-wrapper">
|
|
<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" 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 =
|
|
window.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
|
|
});
|
|
// This is to open the picker when input element is clicked (this
|
|
// includes padding area).
|
|
this.mInputElement.addEventListener("click", this,
|
|
{ mozSystemGroup: true });
|
|
]]>
|
|
</constructor>
|
|
|
|
<destructor>
|
|
<![CDATA[
|
|
this.EVENTS.forEach((eventName) => {
|
|
this.removeEventListener(eventName, this, { mozSystemGroup: true });
|
|
});
|
|
this.removeEventListener("keypress", this, {
|
|
capture: true,
|
|
mozSystemGroup: true
|
|
});
|
|
this.mInputElement.removeEventListener("click", this,
|
|
{ mozSystemGroup: true });
|
|
|
|
this.mInputElement = null;
|
|
]]>
|
|
</destructor>
|
|
|
|
<property name="EVENTS" readonly="true">
|
|
<getter>
|
|
<![CDATA[
|
|
return ["focus", "blur", "copy", "cut", "paste", "mousedown"];
|
|
]]>
|
|
</getter>
|
|
</property>
|
|
|
|
<method name="log">
|
|
<parameter name="aMsg"/>
|
|
<body>
|
|
<![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");
|
|
window.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="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.isAnyValueAvailable(true)) {
|
|
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.onBlur(aEvent);
|
|
break;
|
|
}
|
|
case "mousedown": {
|
|
if (aEvent.originalTarget == this.mResetButton) {
|
|
aEvent.preventDefault();
|
|
}
|
|
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="onBlur">
|
|
<parameter name="aEvent"/>
|
|
<body>
|
|
<![CDATA[
|
|
this.log("onBlur originalTarget: " + aEvent.originalTarget +
|
|
" target: " + aEvent.target);
|
|
|
|
let target = aEvent.originalTarget;
|
|
target.setAttribute("typeBuffer", "");
|
|
this.setInputValueFromFields();
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<method name="onKeyPress">
|
|
<parameter name="aEvent"/>
|
|
<body>
|
|
<![CDATA[
|
|
this.log("onKeyPress key: " + aEvent.key);
|
|
|
|
switch (aEvent.key) {
|
|
// Close picker on Enter, Escape or Space key.
|
|
case "Enter":
|
|
case "Escape":
|
|
case " ": {
|
|
if (this.mIsPickerOpen) {
|
|
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;
|
|
}
|
|
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 +
|
|
" target: " + aEvent.target);
|
|
|
|
if (aEvent.defaultPrevented || this.isDisabled() || this.isReadonly()) {
|
|
return;
|
|
}
|
|
|
|
if (aEvent.originalTarget == this.mResetButton) {
|
|
this.clearInputFields(false);
|
|
} else if (!this.mIsPickerOpen) {
|
|
this.mInputElement.openDateTimePicker(this.getCurrentValue());
|
|
}
|
|
]]>
|
|
</body>
|
|
</method>
|
|
</implementation>
|
|
</binding>
|
|
|
|
</bindings>
|