Bug 1456833 - Remove nsIDateTimeInputArea interface
This patch removes nsIDateTimeInputArea interface, implemented by the datetime
bindings, with events dispatched on <datetimebox> or the input.
It also removes two methods on HTMLInputElement that serves no purpose other
than allow browser-content.js to talk to the datetime bindings (which are both
in JavaScript).
MozReview-Commit-ID: 9jBpRcVWvHc
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -2214,42 +2214,16 @@ void HTMLInputElement::GetDateTimeInputB
if (NS_WARN_IF(!IsDateTimeInputType(mType)) || !mDateTimeInputBoxValue) {
return;
}
aValue = *mDateTimeInputBoxValue;
}
void
-HTMLInputElement::UpdateDateTimeInputBox(const DateTimeValue& aValue)
-{
- if (NS_WARN_IF(!IsDateTimeInputType(mType))) {
- return;
- }
-
- nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
- if (frame) {
- frame->SetValueFromPicker(aValue);
- }
-}
-
-void
-HTMLInputElement::SetDateTimePickerState(bool aOpen)
-{
- if (NS_WARN_IF(!IsDateTimeInputType(mType))) {
- return;
- }
-
- nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
- if (frame) {
- frame->SetPickerState(aOpen);
- }
-}
-
-void
HTMLInputElement::OpenDateTimePicker(const DateTimeValue& aInitialValue)
{
if (NS_WARN_IF(!IsDateTimeInputType(mType))) {
return;
}
mDateTimeInputBoxValue = new DateTimeValue(aInitialValue);
nsContentUtils::DispatchChromeEvent(OwnerDoc(),
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -855,18 +855,16 @@ public:
void MozSetFileArray(const Sequence<OwningNonNull<File>>& aFiles);
void MozSetDirectory(const nsAString& aDirectoryPath, ErrorResult& aRv);
/*
* The following functions are called from datetime picker to let input box
* know the current state of the picker or to update the input box on changes.
*/
void GetDateTimeInputBoxValue(DateTimeValue& aValue);
- void UpdateDateTimeInputBox(const DateTimeValue& aValue);
- void SetDateTimePickerState(bool aOpen);
/*
* The following functions are called from datetime input box XBL to control
* and update the picker.
*/
void OpenDateTimePicker(const DateTimeValue& aInitialValue);
void UpdateDateTimePicker(const DateTimeValue& aValue);
void CloseDateTimePicker();
--- a/dom/html/moz.build
+++ b/dom/html/moz.build
@@ -17,17 +17,16 @@ MOCHITEST_MANIFESTS += [
MOCHITEST_CHROME_MANIFESTS += [
'test/chrome.ini',
'test/forms/chrome.ini',
]
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
XPIDL_SOURCES += [
- 'nsIDateTimeInputArea.idl',
'nsIFormSubmitObserver.idl',
'nsIImageDocument.idl',
'nsIMenuBuilder.idl',
]
XPIDL_MODULE = 'content_html'
EXPORTS += [
deleted file mode 100644
--- a/dom/html/nsIDateTimeInputArea.idl
+++ /dev/null
@@ -1,59 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * 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/. */
-
-#include "nsISupports.idl"
-
-[scriptable, uuid(465c0cc3-24cb-48ce-af1a-b18402326b05)]
-interface nsIDateTimeInputArea : nsISupports
-{
- /**
- * Called from DOM/Layout when input element value has changed.
- */
- void notifyInputElementValueChanged();
-
- /**
- * Called from DOM/Layout when input element min, max or step attribute has
- * changed.
- */
- void notifyMinMaxStepAttrChanged();
-
- /**
- * Called when date/time picker value has changed.
- */
- void setValueFromPicker(in jsval value);
-
- /**
- * Called from DOM/Layout to set focus on inner text box.
- */
- void focusInnerTextBox();
-
- /**
- * Called from DOM/Layout to blur inner text box.
- */
- void blurInnerTextBox();
-
- /**
- * Called from DOM/Layout to know whether the current entered value is valid.
- */
- boolean hasBadInput();
-
- /**
- * Set the current state of the picker, true if it's opened, false otherwise.
- */
- void setPickerState(in boolean isOpen);
-
- /**
- * Set the attribute of the inner text boxes. Only "tabindex", "readonly",
- * and "disabled" are allowed.
- */
- void setEditAttribute(in DOMString name, in DOMString value);
-
- /**
- * Remove the attribute of the inner text boxes. Only "tabindex", "readonly",
- * and "disabled" are allowed.
- */
- void removeEditAttribute(in DOMString name);
-};
--- a/dom/webidl/HTMLInputElement.webidl
+++ b/dom/webidl/HTMLInputElement.webidl
@@ -236,22 +236,16 @@ dictionary DateTimeValue {
long month;
long day;
};
partial interface HTMLInputElement {
[Pref="dom.forms.datetime", ChromeOnly]
DateTimeValue getDateTimeInputBoxValue();
- [Pref="dom.forms.datetime", ChromeOnly]
- void updateDateTimeInputBox(optional DateTimeValue value);
-
- [Pref="dom.forms.datetime", ChromeOnly]
- void setDateTimePickerState(boolean open);
-
[Pref="dom.forms.datetime", ChromeOnly,
BinaryName="getMinimumAsDouble"]
double getMinimum();
[Pref="dom.forms.datetime", ChromeOnly,
BinaryName="getMaximumAsDouble"]
double getMaximum();
--- a/layout/forms/nsDateTimeControlFrame.cpp
+++ b/layout/forms/nsDateTimeControlFrame.cpp
@@ -13,18 +13,18 @@
#include "nsContentUtils.h"
#include "nsCheckboxRadioFrame.h"
#include "nsGkAtoms.h"
#include "nsContentUtils.h"
#include "nsContentCreatorFunctions.h"
#include "mozilla/dom/HTMLInputElement.h"
#include "mozilla/dom/MutationEventBinding.h"
+#include "nsDOMTokenList.h"
#include "nsNodeInfoManager.h"
-#include "nsIDateTimeInputArea.h"
#include "nsIObserverService.h"
#include "jsapi.h"
#include "nsJSUtils.h"
#include "nsThreadUtils.h"
using namespace mozilla;
using namespace mozilla::dom;
@@ -48,109 +48,104 @@ nsDateTimeControlFrame::nsDateTimeContro
void
nsDateTimeControlFrame::DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData)
{
aPostDestroyData.AddAnonymousContent(mInputAreaContent.forget());
nsContainerFrame::DestroyFrom(aDestructRoot, aPostDestroyData);
}
+class DispatchDateTimeEvent : public Runnable
+{
+public:
+ explicit DispatchDateTimeEvent(nsIContent* aContent, nsString aEventName)
+ : mozilla::Runnable("DispatchDateTimeEvent")
+ , mContent(aContent)
+ , mEventName(aEventName)
+ {
+ }
+ NS_IMETHOD Run() override {
+ nsContentUtils::DispatchTrustedEvent(mContent->OwnerDoc(), mContent,
+ mEventName,
+ false, false);
+ return NS_OK;
+ }
+ nsCOMPtr<nsIContent> mContent;
+ nsString mEventName;
+};
+
void
nsDateTimeControlFrame::OnValueChanged()
{
- nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
- do_QueryInterface(mInputAreaContent);
- if (inputAreaContent) {
- inputAreaContent->NotifyInputElementValueChanged();
- }
+ RefPtr<Runnable> event =
+ new DispatchDateTimeEvent(mInputAreaContent,
+ NS_LITERAL_STRING("MozDateTimeValueChanged"));
+ nsContentUtils::AddScriptRunner(event);
}
void
nsDateTimeControlFrame::OnMinMaxStepAttrChanged()
{
- nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
- do_QueryInterface(mInputAreaContent);
- if (inputAreaContent) {
- inputAreaContent->NotifyMinMaxStepAttrChanged();
- }
-}
-
-void
-nsDateTimeControlFrame::SetValueFromPicker(const DateTimeValue& aValue)
-{
- nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
- do_QueryInterface(mInputAreaContent);
- if (inputAreaContent) {
- AutoJSAPI api;
- if (!api.Init(mContent->OwnerDoc()->GetScopeObject())) {
- return;
- }
-
- JSObject* wrapper = mContent->GetWrapper();
- if (!wrapper) {
- return;
- }
-
- JSObject* scope = xpc::GetXBLScope(api.cx(), wrapper);
- AutoJSAPI jsapi;
- if (!scope || !jsapi.Init(scope)) {
- return;
- }
-
- JS::Rooted<JS::Value> jsValue(jsapi.cx());
- if (!ToJSValue(jsapi.cx(), aValue, &jsValue)) {
- return;
- }
-
- inputAreaContent->SetValueFromPicker(jsValue);
- }
-}
-
-void
-nsDateTimeControlFrame::SetPickerState(bool aOpen)
-{
- nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
- do_QueryInterface(mInputAreaContent);
- if (inputAreaContent) {
- inputAreaContent->SetPickerState(aOpen);
- }
+ RefPtr<Runnable> event =
+ new DispatchDateTimeEvent(mInputAreaContent,
+ NS_LITERAL_STRING("MozNotifyMinMaxStepAttrChanged"));
+ nsContentUtils::AddScriptRunner(event);
}
void
nsDateTimeControlFrame::HandleFocusEvent()
{
- nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
- do_QueryInterface(mInputAreaContent);
- if (inputAreaContent) {
- inputAreaContent->FocusInnerTextBox();
- }
+ RefPtr<Runnable> event =
+ new DispatchDateTimeEvent(mInputAreaContent,
+ NS_LITERAL_STRING("MozFocusInnerTextBox"));
+ nsContentUtils::AddScriptRunner(event);
}
void
nsDateTimeControlFrame::HandleBlurEvent()
{
- nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
- do_QueryInterface(mInputAreaContent);
- if (inputAreaContent) {
- inputAreaContent->BlurInnerTextBox();
- }
+ RefPtr<Runnable> event =
+ new DispatchDateTimeEvent(mInputAreaContent,
+ NS_LITERAL_STRING("MozBlurInnerTextBox"));
+ nsContentUtils::AddScriptRunner(event);
}
bool
nsDateTimeControlFrame::HasBadInput()
{
- nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
- do_QueryInterface(mInputAreaContent);
-
- bool result = false;
- if (inputAreaContent) {
- inputAreaContent->HasBadInput(&result);
+ // Incomplete field does not imply bad input.
+ nsCOMPtr<nsINodeList> nodeList =
+ mInputAreaContent->GetComposedDoc()->GetAnonymousElementByAttribute(
+ mInputAreaContent,
+ nsGkAtoms::anonid,
+ NS_LITERAL_STRING("edit-wrapper"))->ChildNodes();
+ uint32_t length = nodeList->Length();
+ for (uint32_t i = 0; i < length; i++) {
+ if (!nodeList->Item(i)->IsElement()) {
+ continue;
+ }
+ Element* element = nodeList->Item(i)->AsElement();
+ if (element->ClassList()->Contains(NS_LITERAL_STRING("datetime-edit-field"))) {
+ nsAutoString value;
+ element->GetAttr(kNameSpaceID_None, nsGkAtoms::value, value);
+ if (value.IsEmpty()) {
+ return false;
+ }
+ }
}
- return result;
+ // All fields are available but input element's value is empty implies
+ // it has been sanitized.
+ nsAutoString value;
+ HTMLInputElement::FromNode(mContent)->GetValue(value, CallerType::System);
+ if (value.IsEmpty()) {
+ return true;
+ }
+
+ return false;
}
nscoord
nsDateTimeControlFrame::GetMinISize(gfxContext* aRenderingContext)
{
nscoord result;
DISPLAY_MIN_WIDTH(this, result);
@@ -333,69 +328,42 @@ nsDateTimeControlFrame::CreateAnonymousC
RefPtr<NodeInfo> nodeInfo =
nodeInfoManager->GetNodeInfo(nsGkAtoms::datetimebox, nullptr,
kNameSpaceID_XUL, nsINode::ELEMENT_NODE);
NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
NS_TrustedNewXULElement(getter_AddRefs(mInputAreaContent), nodeInfo.forget());
aElements.AppendElement(mInputAreaContent);
- nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
- do_QueryInterface(mInputAreaContent);
- if (inputAreaContent) {
- // Propogate our tabindex.
- nsAutoString tabIndexStr;
- if (mContent->AsElement()->GetAttr(kNameSpaceID_None,
- nsGkAtoms::tabindex,
- tabIndexStr)) {
- inputAreaContent->SetEditAttribute(NS_LITERAL_STRING("tabindex"),
- tabIndexStr);
- }
-
- // Propagate our readonly state.
- nsAutoString readonly;
- if (mContent->AsElement()->GetAttr(kNameSpaceID_None,
- nsGkAtoms::readonly,
- readonly)) {
- inputAreaContent->SetEditAttribute(NS_LITERAL_STRING("readonly"),
- readonly);
- }
-
- SyncDisabledState();
- }
-
return NS_OK;
}
void
nsDateTimeControlFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
uint32_t aFilter)
{
if (mInputAreaContent) {
aElements.AppendElement(mInputAreaContent);
}
}
void
nsDateTimeControlFrame::SyncDisabledState()
{
- NS_ASSERTION(mInputAreaContent, "The input area content must exist!");
- nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
- do_QueryInterface(mInputAreaContent);
- if (!inputAreaContent) {
- return;
+ EventStates eventStates = mContent->AsElement()->State();
+ if (eventStates.HasState(NS_EVENT_STATE_DISABLED)) {
+ mInputAreaContent->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, EmptyString(), true);
+ } else {
+ mInputAreaContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, true);
}
- EventStates eventStates = mContent->AsElement()->State();
- if (eventStates.HasState(NS_EVENT_STATE_DISABLED)) {
- inputAreaContent->SetEditAttribute(NS_LITERAL_STRING("disabled"),
- EmptyString());
- } else {
- inputAreaContent->RemoveEditAttribute(NS_LITERAL_STRING("disabled"));
- }
+ RefPtr<Runnable> event =
+ new DispatchDateTimeEvent(mInputAreaContent,
+ NS_LITERAL_STRING("MozDateTimeAttributeChanged"));
+ nsContentUtils::AddScriptRunner(event);
}
nsresult
nsDateTimeControlFrame::AttributeChanged(int32_t aNameSpaceID,
nsAtom* aAttribute,
int32_t aModType)
{
NS_ASSERTION(mInputAreaContent, "The input area content must exist!");
@@ -406,49 +374,34 @@ nsDateTimeControlFrame::AttributeChanged
aAttribute == nsGkAtoms::readonly ||
aAttribute == nsGkAtoms::tabindex) {
MOZ_ASSERT(mContent->IsHTMLElement(nsGkAtoms::input), "bad cast");
auto contentAsInputElem = static_cast<dom::HTMLInputElement*>(GetContent());
// If script changed the <input>'s type before setting these attributes
// then we don't need to do anything since we are going to be reframed.
if (contentAsInputElem->ControlType() == NS_FORM_INPUT_TIME ||
contentAsInputElem->ControlType() == NS_FORM_INPUT_DATE) {
- nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
- do_QueryInterface(mInputAreaContent);
if (aAttribute == nsGkAtoms::value) {
- if (inputAreaContent) {
- nsContentUtils::AddScriptRunner(NewRunnableMethod(
- "nsIDateTimeInputArea::NotifyInputElementValueChanged",
- inputAreaContent,
- &nsIDateTimeInputArea::NotifyInputElementValueChanged));
- }
+ RefPtr<Runnable> event =
+ new DispatchDateTimeEvent(mInputAreaContent,
+ NS_LITERAL_STRING("MozDateTimeValueChanged"));
+ nsContentUtils::AddScriptRunner(event);
} else {
- if (aModType == MutationEventBinding::REMOVAL) {
- if (inputAreaContent) {
- nsAtomString name(aAttribute);
- inputAreaContent->RemoveEditAttribute(name);
- }
- } else {
- MOZ_ASSERT(aModType == MutationEventBinding::ADDITION ||
- aModType == MutationEventBinding::MODIFICATION);
- if (inputAreaContent) {
- nsAtomString name(aAttribute);
- nsAutoString value;
- contentAsInputElem->GetAttr(aNameSpaceID, aAttribute, value);
- inputAreaContent->SetEditAttribute(name, value);
- }
- }
+ RefPtr<Runnable> event =
+ new DispatchDateTimeEvent(mInputAreaContent,
+ NS_LITERAL_STRING("MozDateTimeAttributeChanged"));
+ nsContentUtils::AddScriptRunner(event);
}
}
}
}
return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
aModType);
}
void
nsDateTimeControlFrame::ContentStatesChanged(EventStates aStates)
{
if (aStates.HasState(NS_EVENT_STATE_DISABLED)) {
- nsContentUtils::AddScriptRunner(new SyncDisabledStateEvent(this));
+ SyncDisabledState();
}
}
--- a/layout/forms/nsDateTimeControlFrame.h
+++ b/layout/forms/nsDateTimeControlFrame.h
@@ -71,47 +71,21 @@ public:
void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
uint32_t aFilter) override;
nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
int32_t aModType) override;
void OnValueChanged();
void OnMinMaxStepAttrChanged();
- void SetValueFromPicker(const DateTimeValue& aValue);
void HandleFocusEvent();
void HandleBlurEvent();
- void SetPickerState(bool aOpen);
bool HasBadInput();
private:
- class SyncDisabledStateEvent;
- friend class SyncDisabledStateEvent;
- class SyncDisabledStateEvent : public mozilla::Runnable
- {
- public:
- explicit SyncDisabledStateEvent(nsDateTimeControlFrame* aFrame)
- : mozilla::Runnable("nsDateTimeControlFrame::SyncDisabledStateEvent")
- , mFrame(aFrame)
- {}
-
- NS_IMETHOD Run() override
- {
- nsDateTimeControlFrame* frame =
- static_cast<nsDateTimeControlFrame*>(mFrame.GetFrame());
- NS_ENSURE_STATE(frame);
-
- frame->SyncDisabledState();
- return NS_OK;
- }
-
- private:
- WeakFrame mFrame;
- };
-
/**
* Sync the disabled state of the anonymous children up with our content's.
*/
void SyncDisabledState();
// Anonymous child which is bound via XBL to an element that wraps the input
// area and reset button.
RefPtr<mozilla::dom::Element> mInputAreaContent;
--- a/toolkit/content/browser-content.js
+++ b/toolkit/content/browser-content.js
@@ -1857,17 +1857,20 @@ let DateTimePickerListener = {
this._inputElement = null;
},
/**
* Cleanup function called when picker is closed.
*/
close() {
this.removeListeners();
- this._inputElement.setDateTimePickerState(false);
+ let win = this._inputElement.ownerGlobal;
+ this._inputElement.dispatchEvent(
+ new win.CustomEvent("MozSetDateTimePickerState",
+ { detail: false }, win));
this._inputElement = null;
},
/**
* Called after picker is opened to start listening for input box update
* events.
*/
addListeners() {
@@ -1916,17 +1919,21 @@ let DateTimePickerListener = {
*/
receiveMessage(aMessage) {
switch (aMessage.name) {
case "FormDateTime:PickerClosed": {
this.close();
break;
}
case "FormDateTime:PickerValueChanged": {
- this._inputElement.updateDateTimeInputBox(aMessage.data);
+ let win = this._inputElement.ownerGlobal;
+
+ this._inputElement.dispatchEvent(
+ new win.CustomEvent("MozPickerValueChanged",
+ { detail: Cu.cloneInto(aMessage.data, win) }, win));
break;
}
default:
break;
}
},
/**
@@ -1945,17 +1952,21 @@ let DateTimePickerListener = {
if (this._inputElement) {
// This happens when we're trying to open a picker when another picker
// is still open. We ignore this request to let the first picker
// close gracefully.
return;
}
this._inputElement = aEvent.originalTarget;
- this._inputElement.setDateTimePickerState(true);
+
+ let win = this._inputElement.ownerGlobal;
+ this._inputElement.dispatchEvent(
+ new win.CustomEvent("MozSetDateTimePickerState",
+ { detail: true }, win));
this.addListeners();
let value = this._inputElement.getDateTimeInputBoxValue();
sendAsyncMessage("FormDateTime:OpenPicker", {
rect: this.getBoundingContentRect(this._inputElement),
dir: this.getComputedDirection(this._inputElement),
type: this._inputElement.type,
detail: {
--- a/toolkit/content/widgets/datetimebox.xml
+++ b/toolkit/content/widgets/datetimebox.xml
@@ -46,16 +46,17 @@
this.mMaxYear = 275760;
this.mMonthDayLength = 2;
this.mYearLength = 4;
this.mMonthPageUpDownInterval = 3;
this.mDayPageUpDownInterval = 7;
this.mYearPageUpDownInterval = 10;
this.buildEditFields();
+ this.updateEditAttribute();
if (this.mInputElement.value) {
this.setFieldsFromInputValue();
}
]]>
</constructor>
<method name="buildEditFields">
@@ -382,17 +383,17 @@
if (value < min) {
value = min;
} else if (value > max) {
value = max;
}
}
- aField.setAttribute("rawValue", value);
+ aField.setAttribute("value", value);
// Display formatted value based on locale.
let minDigits = aField.getAttribute("mindigits");
let formatted = value.toLocaleString(this.mLocales, {
minimumIntegerDigits: minDigits,
useGrouping: false
});
@@ -1079,17 +1080,17 @@
} else {
value = (value > this.mMaxHour) ? value % this.mMaxHour : value;
}
} else if (value > this.mMaxHour) {
value = this.mMaxHour;
}
}
- aField.setAttribute("rawValue", value);
+ aField.setAttribute("value", value);
let minDigits = aField.getAttribute("mindigits");
let formatted = value.toLocaleString(this.mLocales, {
minimumIntegerDigits: minDigits,
useGrouping: false
});
aField.textContent = formatted;
@@ -1119,16 +1120,17 @@
<parameter name="aValue"/>
<body>
<![CDATA[
if (!this.hasDayPeriodField()) {
return;
}
this.mDayPeriodField.textContent = aValue;
+ this.mDayPeriodField.setAttribute("value", aValue);
this.updateResetButtonVisibility();
]]>
</body>
</method>
<method name="isAnyFieldAvailable">
<parameter name="aForPicker"/>
<body>
@@ -1214,17 +1216,17 @@
- elements here -->
</html:span>
<html:button class="datetime-reset-button" anonid="reset-button"
tabindex="-1" xbl:inherits="disabled" aria-label="&datetime.reset.label;"/>
</html:div>
</content>
- <implementation implements="nsIDateTimeInputArea">
+ <implementation>
<constructor>
<![CDATA[
this.DEBUG = false;
this.mInputElement = this.parentNode;
this.mLocales = window.getRegionalPrefsLocales();
this.mIsRTL = false;
let intlUtils = window.intlUtils;
@@ -1257,16 +1259,24 @@
capture: true,
mozSystemGroup: true
}, false);
// This is to open the picker when input element is clicked (this
// includes padding area).
this.mInputElement.addEventListener("click", this,
{ mozSystemGroup: true },
false);
+
+ this.mInputElement.addEventListener("MozPickerValueChanged", this,
+ { mozSystemGroup: true },
+ false);
+
+ this.mInputElement.addEventListener("MozSetDateTimePickerState", this,
+ { mozSystemGroup: true },
+ false);
]]>
</constructor>
<destructor>
<![CDATA[
this.EVENTS.forEach((eventName) => {
this.removeEventListener(eventName, this, { mozSystemGroup: true });
});
@@ -1279,17 +1289,20 @@
this.mInputElement = null;
]]>
</destructor>
<property name="EVENTS" readonly="true">
<getter>
<![CDATA[
- return ["focus", "blur", "copy", "cut", "paste", "mousedown"];
+ return ["focus", "blur", "copy", "cut", "paste", "mousedown",
+ "MozDateTimeValueChanged", "MozNotifyMinMaxStepAttrChanged",
+ "MozFocusInnerTextBox", "MozBlurInnerTextBox",
+ "MozDateTimeAttributeChanged"];
]]>
</getter>
</property>
<method name="log">
<parameter name="aMsg"/>
<body>
<![CDATA[
@@ -1321,30 +1334,33 @@
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.setAttribute("aria-label", aLabel);
+ // Used to store the non-formatted value, cleared when value is
+ // cleared.
+ // nsDateTimeControlFrame::HasBadInput() will read this to decide
+ // if the input has value.
+ field.setAttribute("value", "");
+
if (aIsNumeric) {
field.classList.add("numeric");
// Maximum value allowed.
field.setAttribute("min", aMinValue);
// Minumim value allowed.
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);
// Set spinbutton ARIA role
field.setAttribute("role", "spinbutton");
@@ -1386,16 +1402,17 @@
let editRoot =
document.getAnonymousElementByAttribute(this, "anonid", "edit-wrapper");
for (let child = editRoot.firstChild; child; child = child.nextSibling) {
if ((child instanceof HTMLSpanElement) &&
child.classList.contains("datetime-edit-field")) {
this.mLastFocusedField = child;
child.focus();
+ this.log("focused");
break;
}
}
]]>
</body>
</method>
<method name="blurInnerTextBox">
@@ -1441,35 +1458,16 @@
<parameter name="aValue"/>
<body>
<![CDATA[
this.setFieldsFromPicker(aValue);
]]>
</body>
</method>
- <method name="hasBadInput">
- <body>
- <![CDATA[
- // Incomplete field does not imply bad input.
- if (this.isAnyFieldEmpty()) {
- return false;
- }
-
- // All fields are available but input element's value is empty implies
- // it has been sanitized.
- if (!this.mInputElement.value) {
- return true;
- }
-
- return false;
- ]]>
- </body>
- </method>
-
<method name="advanceToNextField">
<parameter name="aReverse"/>
<body>
<![CDATA[
this.log("advanceToNextField");
let focusedInput = this.mLastFocusedField;
let next = aReverse ? focusedInput.previousElementSibling
@@ -1497,82 +1495,39 @@
<body>
<![CDATA[
this.log("picker is now " + (aIsOpen ? "opened" : "closed"));
this.mIsPickerOpen = aIsOpen;
]]>
</body>
</method>
- <method name="setEditAttribute">
- <parameter name="aName"/>
- <parameter name="aValue"/>
+ <method name="updateEditAttribute">
<body>
<![CDATA[
- this.log("setAttribute: " + aName + "=" + aValue);
-
- if (aName != "tabindex" && aName != "disabled" &&
- aName != "readonly") {
- return;
- }
+ this.log("updateEditAttribute");
let editRoot =
document.getAnonymousElementByAttribute(this, "anonid", "edit-wrapper");
for (let child = editRoot.firstChild; child; child = child.nextSibling) {
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>
+ // "disabled" and "readonly" must be set as attributes because they
+ // are not defined properties of HTMLSpanElement, and the stylesheet
+ // checks the literal string attribute values.
+ child.setAttribute("disabled", this.mInputElement.disabled);
+ child.setAttribute("readonly", this.mInputElement.readOnly);
- <method name="removeEditAttribute">
- <parameter name="aName"/>
- <body>
- <![CDATA[
- this.log("removeAttribute: " + aName);
-
- if (aName != "tabindex" && aName != "disabled" &&
- aName != "readonly") {
- return;
- }
+ // Set property as well for convenience.
+ child.disabled = this.mInputElement.disabled;
+ child.readOnly = this.mInputElement.readOnly;
- let editRoot =
- document.getAnonymousElementByAttribute(this, "anonid", "edit-wrapper");
-
- for (let child = editRoot.firstChild; child; child = child.nextSibling) {
- 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;
- }
+ // tabIndex works on all elements
+ child.tabIndex = this.mInputElement.tabIndex;
}
}
]]>
</body>
</method>
<method name="isEmpty">
<parameter name="aValue"/>
@@ -1584,31 +1539,31 @@
<method name="getFieldValue">
<parameter name="aField"/>
<body>
<![CDATA[
if (!aField || !aField.classList.contains("numeric")) {
return undefined;
}
- let value = aField.getAttribute("rawValue");
+ let value = aField.getAttribute("value");
// Avoid returning 0 when field is empty.
return (this.isEmpty(value) ? undefined : Number(value));
]]>
</body>
</method>
<method name="clearFieldValue">
<parameter name="aField"/>
<body>
<![CDATA[
aField.textContent = aField.placeholder;
+ aField.setAttribute("value", "");
if (aField.classList.contains("numeric")) {
aField.setAttribute("typeBuffer", "");
- aField.setAttribute("rawValue", "");
}
this.updateResetButtonVisibility();
]]>
</body>
</method>
<method name="setFieldValue">
<body>
@@ -1692,16 +1647,44 @@
<method name="handleEvent">
<parameter name="aEvent"/>
<body>
<![CDATA[
this.log("handleEvent: " + aEvent.type);
switch (aEvent.type) {
+ case "MozDateTimeValueChanged": {
+ this.notifyInputElementValueChanged();
+ break;
+ }
+ case "MozNotifyMinMaxStepAttrChanged": {
+ this.notifyMinMaxStepAttrChanged();
+ break;
+ }
+ case "MozFocusInnerTextBox": {
+ this.focusInnerTextBox();
+ break;
+ }
+ case "MozBlurInnerTextBox": {
+ this.blurInnerTextBox();
+ break;
+ }
+ case "MozDateTimeAttributeChanged": {
+ this.updateEditAttribute();
+ break;
+ }
+ case "MozPickerValueChanged": {
+ this.setValueFromPicker(aEvent.detail);
+ break;
+ }
+ case "MozSetDateTimePickerState": {
+ this.setPickerState(aEvent.detail);
+ break;
+ }
case "keypress": {
this.onKeyPress(aEvent);
break;
}
case "click": {
this.onClick(aEvent);
break;
}