Bug 1301312 - Part 5: Handle input element's attribute change explicitly. r?smaug
MozReview-Commit-ID: AswWoeGasXZ
--- a/dom/html/nsIDateTimeInputArea.idl
+++ b/dom/html/nsIDateTimeInputArea.idl
@@ -28,9 +28,21 @@ interface nsIDateTimeInputArea : nsISupp
* Called from DOM/Layout to blur inner text box.
*/
void blurInnerTextBox();
/**
* 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/layout/forms/nsDateTimeControlFrame.cpp
+++ b/layout/forms/nsDateTimeControlFrame.cpp
@@ -311,53 +311,64 @@ nsDateTimeControlFrame::CreateAnonymousC
RefPtr<NodeInfo> nodeInfo =
nodeInfoManager->GetNodeInfo(nsGkAtoms::datetimebox, nullptr,
kNameSpaceID_XUL, nsIDOMNode::ELEMENT_NODE);
NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
NS_TrustedNewXULElement(getter_AddRefs(mInputAreaContent), nodeInfo.forget());
aElements.AppendElement(mInputAreaContent);
- // Propogate our tabindex.
- nsAutoString tabIndexStr;
- if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::tabindex, tabIndexStr)) {
- mInputAreaContent->SetAttr(kNameSpaceID_None, nsGkAtoms::tabindex,
- tabIndexStr, false);
- }
+ nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
+ do_QueryInterface(mInputAreaContent);
+ if (inputAreaContent) {
+ // Propogate our tabindex.
+ nsAutoString tabIndexStr;
+ if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::tabindex, tabIndexStr)) {
+ inputAreaContent->SetEditAttribute(NS_LITERAL_STRING("tabindex"),
+ tabIndexStr);
+ }
- // Propagate our readonly state.
- nsAutoString readonly;
- if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::readonly, readonly)) {
- mInputAreaContent->SetAttr(kNameSpaceID_None, nsGkAtoms::readonly, readonly,
- false);
+ // Propagate our readonly state.
+ nsAutoString readonly;
+ if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::readonly, readonly)) {
+ inputAreaContent->SetEditAttribute(NS_LITERAL_STRING("readonly"),
+ readonly);
+ }
+
+ SyncDisabledState();
}
- 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);
+ inputAreaContent->SetEditAttribute(NS_LITERAL_STRING("disabled"),
+ EmptyString());
} else {
- mInputAreaContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, true);
+ inputAreaContent->RemoveEditAttribute(NS_LITERAL_STRING("disabled"));
}
}
nsresult
nsDateTimeControlFrame::AttributeChanged(int32_t aNameSpaceID,
nsIAtom* aAttribute,
int32_t aModType)
{
@@ -369,32 +380,38 @@ nsDateTimeControlFrame::AttributeChanged
aAttribute == nsGkAtoms::readonly ||
aAttribute == nsGkAtoms::tabindex) {
MOZ_ASSERT(mContent->IsHTMLElement(nsGkAtoms::input), "bad cast");
auto contentAsInputElem = static_cast<dom::HTMLInputElement*>(mContent);
// 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->GetType() == NS_FORM_INPUT_TIME ||
contentAsInputElem->GetType() == NS_FORM_INPUT_DATE) {
+ nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
+ do_QueryInterface(mInputAreaContent);
if (aAttribute == nsGkAtoms::value) {
- nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
- do_QueryInterface(mInputAreaContent);
if (inputAreaContent) {
nsContentUtils::AddScriptRunner(NewRunnableMethod(inputAreaContent,
&nsIDateTimeInputArea::NotifyInputElementValueChanged));
}
} else {
if (aModType == nsIDOMMutationEvent::REMOVAL) {
- mInputAreaContent->UnsetAttr(aNameSpaceID, aAttribute, true);
+ if (inputAreaContent) {
+ nsAtomString name(aAttribute);
+ inputAreaContent->RemoveEditAttribute(name);
+ }
} else {
MOZ_ASSERT(aModType == nsIDOMMutationEvent::ADDITION ||
aModType == nsIDOMMutationEvent::MODIFICATION);
- nsAutoString value;
- mContent->GetAttr(aNameSpaceID, aAttribute, value);
- mInputAreaContent->SetAttr(aNameSpaceID, aAttribute, value, true);
+ if (inputAreaContent) {
+ nsAtomString name(aAttribute);
+ nsAutoString value;
+ mContent->GetAttr(aNameSpaceID, aAttribute, value);
+ inputAreaContent->SetEditAttribute(name, value);
+ }
}
}
}
}
}
return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
aModType);
--- a/toolkit/content/widgets/datetimebox.xml
+++ b/toolkit/content/widgets/datetimebox.xml
@@ -1275,16 +1275,63 @@
<body>
<![CDATA[
this.log("picker is now " + (aIsOpen ? "opened" : "closed"));
this.mIsPickerOpen = aIsOpen;
]]>
</body>
</method>
+ <method name="setEditAttribute">
+ <parameter name="aName"/>
+ <parameter name="aValue"/>
+ <body>
+ <![CDATA[
+ this.log("setAttribute: " + aName + "=" + aValue);
+
+ if (aName != "tabindex" && aName != "disabled" &&
+ 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);
+ }
+ }
+ ]]>
+ </body>
+ </method>
+
+ <method name="removeEditAttribute">
+ <parameter name="aName"/>
+ <body>
+ <![CDATA[
+ this.log("removeAttribute: " + aName);
+
+ if (aName != "tabindex" && aName != "disabled" &&
+ 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.removeAttribute(aName);
+ }
+ }
+ ]]>
+ </body>
+ </method>
+
<method name="isEmpty">
<parameter name="aValue"/>
<body>
return (aValue == undefined || 0 === aValue.length);
</body>
</method>
<method name="stripDirFormattingChars">
@@ -1357,25 +1404,25 @@
}
]]>
</body>
</method>
<method name="isDisabled">
<body>
<![CDATA[
- return this.hasAttribute("disabled");
+ return this.mInputElement.hasAttribute("disabled");
]]>
</body>
</method>
<method name="isReadonly">
<body>
<![CDATA[
- return this.hasAttribute("readonly");
+ return this.mInputElement.hasAttribute("readonly");
]]>
</body>
</method>
<method name="handleEvent">
<parameter name="aEvent"/>
<body>
<![CDATA[