--- a/toolkit/content/widgets/datetimebox.xml
+++ b/toolkit/content/widgets/datetimebox.xml
@@ -55,26 +55,26 @@
<method name="buildEditFields">
<body>
<![CDATA[
const HTML_NS = "http://www.w3.org/1999/xhtml";
let root =
document.getAnonymousElementByAttribute(this, "anonid", "edit-wrapper");
+ let yearMaxLength = this.mMaxYear.toString().length
this.mYearField = this.createEditField(this.mYearPlaceHolder,
- this.mYearLength, true, this.mMinYear, this.mMaxYear,
+ true, this.mYearLength, yearMaxLength, this.mMinYear, this.mMaxYear,
this.mYearPageUpDownInterval);
- this.mYearField.maxLength = this.mMaxYear.toString().length;
this.mMonthField = this.createEditField(this.mMonthPlaceHolder,
- this.mMonthDayLength, true, this.mMinMonth, this.mMaxMonth,
- this.mMonthPageUpDownInterval);
+ true, this.mMonthDayLength, this.mMonthDayLength, this.mMinMonth,
+ this.mMaxMonth, this.mMonthPageUpDownInterval);
this.mDayField = this.createEditField(this.mDayPlaceHolder,
- this.mMonthDayLength, true, this.mMinDay, this.mMaxDay,
- this.mDayPageUpDownInterval);
+ true, this.mMonthDayLength, this.mMonthDayLength, this.mMinDay,
+ this.mMaxDay, this.mDayPageUpDownInterval);
let fragment = document.createDocumentFragment();
let formatter = Intl.DateTimeFormat(this.mLocales, {
year: "numeric",
month: "numeric",
day: "numeric"
});
formatter.formatToParts(Date.now()).map(part => {
@@ -122,17 +122,16 @@
if (this.mDayField && !this.mDayField.disabled &&
!this.mDayField.readOnly) {
this.clearFieldValue(this.mDayField);
}
if (this.mYearField && !this.mYearField.disabled &&
!this.mYearField.readOnly) {
this.clearFieldValue(this.mYearField);
- this.mYearField.size = this.mYearLength;
}
if (!aFromInputElement) {
this.mInputElement.setUserInput("");
}
]]>
</body>
</method>
@@ -267,17 +266,18 @@
if (targetField.classList.contains("numeric") && key.match(/[0-9]/)) {
let buffer = targetField.getAttribute("typeBuffer") || "";
buffer = buffer.concat(key);
this.setFieldValue(targetField, buffer);
let n = Number(buffer);
let max = targetField.getAttribute("max");
- if (buffer.length >= targetField.maxLength || n * 10 > max) {
+ let maxLength = targetField.getAttribute("maxlength");
+ if (buffer.length >= maxLength || n * 10 > max) {
buffer = "";
this.advanceToNextField();
}
targetField.setAttribute("typeBuffer", buffer);
}
]]>
</body>
</method>
@@ -387,46 +387,38 @@
}
let value = Number(aValue);
if (isNaN(value)) {
this.log("NaN on setFieldValue!");
return;
}
- if (aValue.length == aField.maxLength) {
+ let maxLength = aField.getAttribute("maxlength");
+ if (aValue.length == maxLength) {
let min = Number(aField.getAttribute("min"));
let max = Number(aField.getAttribute("max"));
if (value < min) {
value = min;
} else if (value > max) {
value = max;
}
}
aField.setAttribute("rawValue", value);
// Display formatted value based on locale.
- let minDigits = (aField == this.mYearField ? this.mYearLength
- : aField.size);
+ let minDigits = aField.getAttribute("mindigits");
let formatted = value.toLocaleString(this.mLocales, {
minimumIntegerDigits: minDigits,
useGrouping: false
});
- if (aField == this.mYearField) {
- this.mYearField.size = formatted.length;
- }
-
- aField.value = formatted;
- if (document.activeElement == this.mInputElement &&
- this.mLastFocusedField && this.mLastFocusedField == aField) {
- aField.select();
- }
+ aField.textContent = formatted;
this.updateResetButtonVisibility();
]]>
</body>
</method>
<method name="isAnyValueAvailable">
<parameter name="aForPicker"/>
<body>
@@ -553,41 +545,39 @@
let options = {
hour: "numeric",
minute: "numeric",
hour12: this.mHour12
};
this.mHourField = this.createEditField(this.mHourPlaceHolder,
- this.mMaxLength, true, this.mMinHour, this.mMaxHour,
- this.mHourPageUpDownInterval);
+ true, this.mMaxLength, this.mMaxLength, this.mMinHour,
+ this.mMaxHour, this.mHourPageUpDownInterval);
this.mMinuteField = this.createEditField(this.mMinutePlaceHolder,
- this.mMaxLength, true, this.mMinMinute, this.mMaxMinute,
- this.mMinSecPageUpDownInterval);
+ true, this.mMaxLength, this.mMaxLength, this.mMinMinute,
+ this.mMaxMinute, this.mMinSecPageUpDownInterval);
if (this.mHour12) {
- let dayPeriodLength =
- Math.max(this.mAMIndicator.length, this.mPMIndicator.length);
-
this.mDayPeriodField = this.createEditField(
- this.mDayPeriodPlaceHolder, dayPeriodLength, false);
+ this.mDayPeriodPlaceHolder, false);
}
if (second != undefined) {
options["second"] = "numeric";
this.mSecondField = this.createEditField(this.mSecondPlaceHolder,
- this.mMaxLength, true, this.mMinSecond, this.mMaxSecond,
+ true, this.mMaxLength, this.mMaxLength, this.mMinSecond, this.mMaxSecond,
this.mMinSecPageUpDownInterval);
}
if (millisecond != undefined) {
this.mMillisecField = this.createEditField(this.mMillisecPlaceHolder,
- this.mMillisecMaxLength, true, this.mMinMillisecond,
- this.mMaxMillisecond, this.mMinSecPageUpDownInterval);
+ true, this.mMillisecMaxLength, this.mMillisecMaxLength,
+ this.mMinMillisecond, this.mMaxMillisecond,
+ this.mMinSecPageUpDownInterval);
}
let fragment = document.createDocumentFragment();
let formatter = Intl.DateTimeFormat(this.mLocales, options);
formatter.formatToParts(Date.now()).map(part => {
switch (part.type) {
case "hour":
fragment.appendChild(this.mHourField);
@@ -708,34 +698,33 @@
<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))) {
+ let { hour, minute, second, millisecond } = this.getCurrentValue();
+ let dayPeriod = this.getDayPeriodValue();
+
+ if (this.isEmpty(hour) || this.isEmpty(minute) ||
+ (this.mDayPeriodField && this.isEmpty(dayPeriod)) ||
+ (this.mSecondField && this.isEmpty(second)) ||
+ (this.mMillisecField && this.isEmpty(millisecond))) {
// 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, minute, second, millisecond } = this.getCurrentValue();
-
// Convert to a valid time string according to:
// https://html.spec.whatwg.org/multipage/infrastructure.html#valid-time-string
if (this.mHour12) {
- let dayPeriod = this.getDayPeriodValue();
if (dayPeriod == this.mPMIndicator && hour < this.mMaxHour) {
hour += this.mMaxHour;
} else if (dayPeriod == this.mAMIndicator &&
hour == this.mMaxHour) {
hour = 0;
}
}
@@ -949,17 +938,18 @@
if (targetField.classList.contains("numeric") && key.match(/[0-9]/)) {
let buffer = targetField.getAttribute("typeBuffer") || "";
buffer = buffer.concat(key);
this.setFieldValue(targetField, buffer);
let n = Number(buffer);
let max = targetField.getAttribute("max");
- if (buffer.length >= targetField.maxLength || n * 10 > max) {
+ let maxLength = targetField.getAttribute("maxLength");
+ if (buffer.length >= maxLength || n * 10 > max) {
buffer = "";
this.advanceToNextField();
}
targetField.setAttribute("typeBuffer", buffer);
}
]]>
</body>
</method>
@@ -978,71 +968,66 @@
this.log("NaN on setFieldValue!");
return;
}
if (aField == this.mHourField) {
if (this.mHour12) {
// Try to change to 12hr format if user input is 0 or greater
// than 12.
- if (value == 0 && aValue.length == aField.maxLength) {
+ let maxLength = aField.getAttribute("maxlength");
+ if (value == 0 && aValue.length == maxLength) {
value = this.mMaxHour;
} else {
value = (value > this.mMaxHour) ? value % this.mMaxHour : value;
}
} else if (value > this.mMaxHour) {
value = this.mMaxHour;
}
}
aField.setAttribute("rawValue", value);
- let minDigits = aField.size;
+ let minDigits = aField.getAttribute("mindigits");
let formatted = value.toLocaleString(this.mLocales, {
minimumIntegerDigits: minDigits,
useGrouping: false
});
- aField.value = formatted;
- if (document.activeElement == this.mInputElement &&
- this.mLastFocusedField && this.mLastFocusedField == aField) {
- aField.select();
- }
+ aField.textContent = formatted;
this.updateResetButtonVisibility();
]]>
</body>
</method>
<method name="getDayPeriodValue">
<parameter name="aValue"/>
<body>
<![CDATA[
if (!this.mDayPeriodField) {
return "";
}
- return this.mDayPeriodField.value;
+ let placeholder = this.mDayPeriodField.placeholder;
+ let value = this.mDayPeriodField.textContent;
+
+ return (value == placeholder ? "" : value);
]]>
</body>
</method>
<method name="setDayPeriodValue">
<parameter name="aValue"/>
<body>
<![CDATA[
if (!this.mDayPeriodField) {
return;
}
- this.mDayPeriodField.value = aValue;
- if (document.activeElement == this.mInputElement &&
- this.mLastFocusedField &&
- this.mLastFocusedField == this.mDayPeriodField) {
- this.mDayPeriodField.select();
- }
+ this.mDayPeriodField.textContent = aValue;
this.updateResetButtonVisibility();
]]>
</body>
</method>
<method name="isAnyValueAvailable">
<parameter name="aForPicker"/>
<body>
@@ -1175,49 +1160,57 @@
dump("[DateTimeBox] " + aMsg + "\n");
}
]]>
</body>
</method>
<method name="createEditField">
<parameter name="aPlaceHolder"/>
- <parameter name="aLength"/>
<parameter name="aIsNumeric"/>
- <parameter name="aMin"/>
- <parameter name="aMax"/>
+ <parameter name="aMinDigits"/>
+ <parameter name="aMaxLength"/>
+ <parameter name="aMinValue"/>
+ <parameter name="aMaxValue"/>
<parameter name="aPageUpDownInterval"/>
<body>
<![CDATA[
const HTML_NS = "http://www.w3.org/1999/xhtml";
- let field = document.createElementNS(HTML_NS, "input");
- field.classList.add("textbox-input", "datetime-input");
+ let field = document.createElementNS(HTML_NS, "span");
+ field.classList.add("datetime-edit-field");
+ field.textContent = aPlaceHolder;
+ field.placeholder = aPlaceHolder;
+ field.tabIndex = this.mInputElement.tabIndex;
+
+ field.setAttribute("readonly", this.mInputElement.readOnly);
+ field.setAttribute("disabled", this.mInputElement.disabled);
+ // Set property as well for convenience.
field.disabled = this.mInputElement.disabled;
field.readOnly = this.mInputElement.readOnly;
- field.tabIndex = this.mInputElement.tabIndex;
- field.placeholder = aPlaceHolder;
-
- field.setAttribute("size", aLength);
- field.setAttribute("maxlength", aLength);
if (aIsNumeric) {
field.classList.add("numeric");
// Maximum value allowed.
- field.setAttribute("min", aMin);
+ field.setAttribute("min", aMinValue);
// Minumim value allowed.
- field.setAttribute("max", aMax);
+ field.setAttribute("max", aMaxValue);
// Interval when pressing pageUp/pageDown key.
field.setAttribute("pginterval", aPageUpDownInterval);
// Used to store what the user has already typed in the field,
// cleared when value is cleared and when field is blurred.
field.setAttribute("typeBuffer", "");
// Used to store the non-formatted number, clered when value is
// cleared.
field.setAttribute("rawValue", "");
+ // Minimum digits to display, padded with leading 0s.
+ field.setAttribute("mindigits", aMinDigits);
+ // Maximum length for the field, will be advance to the next field
+ // automatically if exceeded.
+ field.setAttribute("maxlength", aMaxLength);
}
return field;
]]>
</body>
</method>
<method name="updateResetButtonVisibility">
@@ -1236,17 +1229,18 @@
<body>
<![CDATA[
this.log("focusInnerTextBox");
let editRoot =
document.getAnonymousElementByAttribute(this, "anonid", "edit-wrapper");
for (let child = editRoot.firstChild; child; child = child.nextSibling) {
- if (child instanceof HTMLInputElement) {
+ if ((child instanceof HTMLSpanElement) &&
+ child.classList.contains("datetime-edit-field")) {
child.focus();
break;
}
}
]]>
</body>
</method>
@@ -1289,17 +1283,18 @@
let next = aReverse ? focusedInput.previousElementSibling
: focusedInput.nextElementSibling;
if (!next && !aReverse) {
this.setInputValueFromFields();
return;
}
while (next) {
- if (next.type == "text" && !next.disabled) {
+ if ((next instanceof HTMLSpanElement) &&
+ next.classList.contains("datetime-edit-field")) {
next.focus();
break;
}
next = aReverse ? next.previousElementSibling
: next.nextElementSibling;
}
]]>
</body>
@@ -1326,18 +1321,36 @@
aName != "readonly") {
return;
}
let editRoot =
document.getAnonymousElementByAttribute(this, "anonid", "edit-wrapper");
for (let child = editRoot.firstChild; child; child = child.nextSibling) {
- if (child instanceof HTMLInputElement) {
- child.setAttribute(aName, aValue);
+ if ((child instanceof HTMLSpanElement) &&
+ child.classList.contains("datetime-edit-field")) {
+
+ switch (aName) {
+ case "tabindex":
+ child.setAttribute(aName, aValue);
+ break;
+ case "disabled": {
+ let value = this.mInputElement.disabled;
+ child.setAttribute("disabled", value);
+ child.disabled = value;
+ break;
+ }
+ case "readonly": {
+ let value = this.mInputElement.readOnly;
+ child.setAttribute("readonly", value);
+ child.readOnly = value;
+ break;
+ }
+ }
}
}
]]>
</body>
</method>
<method name="removeEditAttribute">
<parameter name="aName"/>
@@ -1349,18 +1362,25 @@
aName != "readonly") {
return;
}
let editRoot =
document.getAnonymousElementByAttribute(this, "anonid", "edit-wrapper");
for (let child = editRoot.firstChild; child; child = child.nextSibling) {
- if (child instanceof HTMLInputElement) {
+ if ((child instanceof HTMLSpanElement) &&
+ child.classList.contains("datetime-edit-field")) {
child.removeAttribute(aName);
+ // Update property as well.
+ if (aName == "readonly") {
+ child.readOnly = false;
+ } else if (aName == "disabled") {
+ child.disabled = false;
+ }
}
}
]]>
</body>
</method>
<method name="isEmpty">
<parameter name="aValue"/>
@@ -1397,17 +1417,17 @@
]]>
</body>
</method>
<method name="clearFieldValue">
<parameter name="aField"/>
<body>
<![CDATA[
- aField.value = "";
+ aField.textContent = aField.placeholder;
if (aField.classList.contains("numeric")) {
aField.setAttribute("typeBuffer", "");
aField.setAttribute("rawValue", "");
}
this.updateResetButtonVisibility();
]]>
</body>
</method>
@@ -1530,19 +1550,22 @@
<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") {
+ if ((target instanceof HTMLSpanElement) &&
+ target.classList.contains("datetime-edit-field")) {
+ if (target.disabled) {
+ return;
+ }
this.mLastFocusedField = target;
- target.select();
}
]]>
</body>
</method>
<method name="onBlur">
<parameter name="aEvent"/>
<body>