diff --git a/mozilla/extensions/xforms/nsIModelElementPrivate.idl b/mozilla/extensions/xforms/nsIModelElementPrivate.idl index 45d28396cf6..3d12f0affec 100644 --- a/mozilla/extensions/xforms/nsIModelElementPrivate.idl +++ b/mozilla/extensions/xforms/nsIModelElementPrivate.idl @@ -113,4 +113,10 @@ interface nsIModelElementPrivate : nsIXFormsModelElement */ unsigned short handleInstanceDataNode(in nsIDOMNode aInstanceDataNode); + /** + * Set MIP states for given control bound to the given bound node. + * @param aControl The control + * @param aBoundNode The node the control is bound to + */ + void setStates(in nsIXFormsControl aControl, in nsIDOMNode aBoundNode); }; diff --git a/mozilla/extensions/xforms/nsXFormsControlStub.cpp b/mozilla/extensions/xforms/nsXFormsControlStub.cpp index 1c70b20ec43..5e3a7799200 100644 --- a/mozilla/extensions/xforms/nsXFormsControlStub.cpp +++ b/mozilla/extensions/xforms/nsXFormsControlStub.cpp @@ -123,7 +123,9 @@ nsXFormsControlStub::RemoveIndexListeners() } NS_IMETHODIMP -nsXFormsControlStub::ResetBoundNode() +nsXFormsControlStub::ResetBoundNode(const nsString &aBindAttribute, + PRUint16 aResultType, + nsIDOMXPathResult **aResult) { // Clear existing bound node, etc. mBoundNode = nsnull; @@ -133,35 +135,40 @@ nsXFormsControlStub::ResetBoundNode() if (!mHasParent || !mBindAttrsCount) return NS_OK; - nsCOMPtr modelNode; nsCOMPtr result; nsresult rv = - ProcessNodeBinding(NS_LITERAL_STRING("ref"), - nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, - getter_AddRefs(result), - getter_AddRefs(modelNode)); + ProcessNodeBinding(aBindAttribute, + aResultType, + getter_AddRefs(result)); - if (NS_SUCCEEDED(rv)) { - if (result) { - // Get context node, if any - result->GetSingleNodeValue(getter_AddRefs(mBoundNode)); - } - rv = NS_OK; - } else { + if (NS_FAILED(rv)) { nsXFormsUtils::ReportError(NS_LITERAL_STRING("controlBindError"), mElement); + return rv; + } + + if (!result) + return NS_OK; + + // Get context node, if any + result->GetSingleNodeValue(getter_AddRefs(mBoundNode)); + + if (mBoundNode && mModel) { + mModel->SetStates(this, mBoundNode); } - return rv; + if (aResult) { + *aResult = nsnull; + result.swap(*aResult); + } + + return NS_OK; } -/** - * @note Refresh() is always called after a Bind(), so if a control decides to - * do all the work in Refresh() this function implements a NOP Bind(). - */ NS_IMETHODIMP nsXFormsControlStub::Bind() { - return ResetBoundNode(); + return ResetBoundNode(NS_LITERAL_STRING("ref"), + nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE); } NS_IMETHODIMP @@ -271,21 +278,12 @@ nsXFormsControlStub::GetRelevantState() return res; } -void -nsXFormsControlStub::ToggleProperty(const nsAString &aOn, - const nsAString &aOff) -{ - if (mElement) { - mElement->SetAttribute(aOn, NS_LITERAL_STRING("1")); - mElement->RemoveAttribute(aOff); - } -} - NS_IMETHODIMP nsXFormsControlStub::HandleDefault(nsIDOMEvent *aEvent, PRBool *aHandled) { NS_ENSURE_ARG(aHandled); + *aHandled = PR_FALSE; if (nsXFormsUtils::EventHandlingAllowed(aEvent, mElement)) { @@ -294,7 +292,6 @@ nsXFormsControlStub::HandleDefault(nsIDOMEvent *aEvent, aEvent->GetTarget(getter_AddRefs(target)); nsCOMPtr targetE(do_QueryInterface(target)); if (targetE && targetE != mElement) { - *aHandled = PR_FALSE; return NS_OK; } @@ -302,39 +299,8 @@ nsXFormsControlStub::HandleDefault(nsIDOMEvent *aEvent, nsAutoString type; aEvent->GetType(type); - *aHandled = PR_TRUE; - /// @todo Change to be less cut-n-paste-stylish. Everything can be extraced - /// from the sXFormsEventsEntries, only problem is the dash in - /// read-only/read-write... (XXX) - if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Valid].name)) { - ToggleProperty(NS_LITERAL_STRING("valid"), - NS_LITERAL_STRING("invalid")); - } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Invalid].name)) { - ToggleProperty(NS_LITERAL_STRING("invalid"), - NS_LITERAL_STRING("valid")); - } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Enabled].name)) { - ToggleProperty(NS_LITERAL_STRING("enabled"), - NS_LITERAL_STRING("disabled")); - } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Disabled].name)) { - ToggleProperty(NS_LITERAL_STRING("disabled"), - NS_LITERAL_STRING("enabled")); - } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Required].name)) { - ToggleProperty(NS_LITERAL_STRING("required"), - NS_LITERAL_STRING("optional")); - } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Optional].name)) { - ToggleProperty(NS_LITERAL_STRING("optional"), - NS_LITERAL_STRING("required")); - } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Readonly].name)) { - ToggleProperty(NS_LITERAL_STRING("read-only"), - NS_LITERAL_STRING("read-write")); - } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Readwrite].name)) { - ToggleProperty(NS_LITERAL_STRING("read-write"), - NS_LITERAL_STRING("read-only")); - } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Focus].name)) { - PRBool tmp; - TryFocus(&tmp); - } else { - *aHandled = PR_FALSE; + if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Focus].name)) { + TryFocus(aHandled); } } @@ -465,16 +431,12 @@ nsXFormsControlStub::ResetProperties() if (!mElement) { return; } - - mElement->RemoveAttribute(NS_LITERAL_STRING("valid")); - mElement->RemoveAttribute(NS_LITERAL_STRING("invalid")); - mElement->RemoveAttribute(NS_LITERAL_STRING("enabled")); - mElement->RemoveAttribute(NS_LITERAL_STRING("disabled")); - mElement->RemoveAttribute(NS_LITERAL_STRING("required")); - mElement->RemoveAttribute(NS_LITERAL_STRING("optional")); - mElement->RemoveAttribute(NS_LITERAL_STRING("read-only")); - mElement->RemoveAttribute(NS_LITERAL_STRING("read-write")); - + + /// + /// @todo removes the attributes we use, until bug 271720 is landed (XXX) + for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(kStateAttributes); ++i) { + mElement->RemoveAttribute(kStateAttributes[i]); + } } void diff --git a/mozilla/extensions/xforms/nsXFormsControlStub.h b/mozilla/extensions/xforms/nsXFormsControlStub.h index 27cf1e29e35..f135e6b3124 100644 --- a/mozilla/extensions/xforms/nsXFormsControlStub.h +++ b/mozilla/extensions/xforms/nsXFormsControlStub.h @@ -88,7 +88,9 @@ public: NS_IMETHOD GetBoundNode(nsIDOMNode **aBoundNode); NS_IMETHOD GetDependencies(nsCOMArray **aDependencies); NS_IMETHOD GetElement(nsIDOMElement **aElement); - NS_IMETHOD ResetBoundNode(); + NS_IMETHOD ResetBoundNode(const nsString &aBindAttribute, + PRUint16 aResultType, + nsIDOMXPathResult **aResult = nsnull); NS_IMETHOD Bind(); NS_IMETHOD TryFocus(PRBool* aOK); @@ -188,15 +190,6 @@ protected: nsIDOMXPathResult **aResult, nsIModelElementPrivate **aModel = nsnull); - /** - * Toggles a property on the control (readonly, relevant, etc.) - * - * @todo This needs to be implemented using pseudo-classes instead of - * attributes (XXX) - */ - void ToggleProperty(const nsAString &aOn, - const nsAString &aOff); - /** * Reset (and reinitialize) the event listener, which is used to create * xforms-hint and xforms-help events. diff --git a/mozilla/extensions/xforms/nsXFormsModelElement.cpp b/mozilla/extensions/xforms/nsXFormsModelElement.cpp index b98bd47335c..6a368465e96 100644 --- a/mozilla/extensions/xforms/nsXFormsModelElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsModelElement.cpp @@ -396,7 +396,8 @@ nsXFormsModelElement::HandleDefault(nsIDOMEvent *aEvent, PRBool *aHandled) nsresult nsXFormsModelElement::ConstructDone() { - InitializeControls(); + nsresult rv = InitializeControls(); + NS_ENSURE_SUCCESS(rv, rv); /// @bug This is not entirely correct. xforms-ready should be sent when /// _all_ models have initialized their controls. @@ -512,40 +513,61 @@ nsXFormsModelElement::Recalculate() } void -nsXFormsModelElement::DispatchEvents(nsIXFormsControl *aControl, - nsIDOMNode *aNode, - PRBool aInitialize) +nsXFormsModelElement::SetSingleState(nsIDOMElement *aElement, + PRBool aState, + nsXFormsEvent aOnEvent, + PRUint32 aAttributePos) { - if (!aControl || !aNode) - return; + nsXFormsEvent event = aState ? aOnEvent : (nsXFormsEvent) (aOnEvent + 1); + + // Dispatch event + nsXFormsUtils::DispatchEvent(aElement, event); + + // Set pseudo class + /// + /// @bug Set via attributes right now. Bug 271720. (XXX) + aElement->SetAttribute(kStateAttributes[aState ? aAttributePos : aAttributePos + 1], + NS_LITERAL_STRING("1")); + aElement->RemoveAttribute(kStateAttributes[aState ? aAttributePos + 1 : aAttributePos]); +} + +nsresult +nsXFormsModelElement::SetStatesInternal(nsIXFormsControl *aControl, + nsIDOMNode *aNode, + PRBool aAllStates) +{ + NS_ENSURE_ARG(aControl); + if (!aNode) + return NS_OK; nsCOMPtr element; aControl->GetElement(getter_AddRefs(element)); + NS_ENSURE_STATE(element); const nsXFormsNodeState *ns = mMDG.GetNodeState(aNode); + NS_ENSURE_STATE(ns); - if (!element || !ns) - return; + /// @todo the last argument (0, 2, 4, and 6) to SetSingleState is the + /// position of the attribute in kStateAttributes. It's hacky and only + /// temporary, until bug 271720 lands. (XXX) + if (aAllStates || ns->ShouldDispatchValid()) { + SetSingleState(element, ns->IsValid(), eEvent_Valid, 0); + } + if (aAllStates || ns->ShouldDispatchReadonly()) { + SetSingleState(element, ns->IsReadonly(), eEvent_Readonly, 2); + } + if (aAllStates || ns->ShouldDispatchRequired()) { + SetSingleState(element, ns->IsRequired(), eEvent_Required, 4); + } + if (aAllStates || ns->ShouldDispatchRelevant()) { + SetSingleState(element, ns->IsRelevant(), eEvent_Enabled, 6); + } - if (aInitialize || ns->ShouldDispatchValid()) { - nsXFormsUtils::DispatchEvent(element, - ns->IsValid() ? eEvent_Valid : eEvent_Invalid); - } - if (aInitialize || ns->ShouldDispatchReadonly()) { - nsXFormsUtils::DispatchEvent(element, - ns->IsReadonly() ? eEvent_Readonly : eEvent_Readwrite); - } - if (aInitialize || ns->ShouldDispatchRequired()) { - nsXFormsUtils::DispatchEvent(element, - ns->IsRequired() ? eEvent_Required : eEvent_Optional); - } - if (aInitialize || ns->ShouldDispatchRelevant()) { - nsXFormsUtils::DispatchEvent(element, - ns->IsRelevant() ? eEvent_Enabled : eEvent_Disabled); - } - if (aInitialize || ns->ShouldDispatchValueChanged()) { + if (ns->ShouldDispatchValueChanged()) { nsXFormsUtils::DispatchEvent(element, eEvent_ValueChanged); } + + return NS_OK; } NS_IMETHODIMP @@ -665,7 +687,8 @@ nsXFormsModelElement::Revalidate() control->GetBoundNode(getter_AddRefs(boundNode)); } if (rebind || refresh) { - DispatchEvents(control, boundNode); + nsresult rv = SetStatesInternal(control, boundNode); + NS_ENSURE_SUCCESS(rv, rv); if (mControlsNeedingRefresh.IndexOf(control) == -1) mControlsNeedingRefresh.AppendElement(control); } @@ -1187,10 +1210,11 @@ nsXFormsModelElement::FinishConstruction() return NS_OK; } -void +nsresult nsXFormsModelElement::InitializeControls() { PRInt32 controlCount = mFormControls.Count(); + nsresult rv; for (PRInt32 i = 0; i < controlCount; ++i) { // Get control nsIXFormsControl *control = NS_STATIC_CAST(nsIXFormsControl*, @@ -1199,17 +1223,24 @@ nsXFormsModelElement::InitializeControls() continue; // Rebind - control->Bind(); + rv = control->Bind(); + NS_ENSURE_SUCCESS(rv, rv); // Get bound node nsCOMPtr boundNode; - control->GetBoundNode(getter_AddRefs(boundNode)); - - // Dispatch events - DispatchEvents(control, boundNode, PR_TRUE); + rv = control->GetBoundNode(getter_AddRefs(boundNode)); + NS_ENSURE_SUCCESS(rv, rv); + + // Set MIP states on control + rv = SetStatesInternal(control, boundNode, PR_TRUE); + NS_ENSURE_SUCCESS(rv, rv); + // Refresh controls - control->Refresh(); - } + rv = control->Refresh(); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; } @@ -1448,6 +1479,12 @@ nsXFormsModelElement::ProcessBind(nsIXFormsXPathEvaluator *aEvaluator, return NS_OK; } +NS_IMETHODIMP +nsXFormsModelElement::SetStates(nsIXFormsControl *aControl, nsIDOMNode *aBoundNode) +{ + return SetStatesInternal(aControl, aBoundNode, PR_TRUE); +} + /* static */ void nsXFormsModelElement::Startup() { diff --git a/mozilla/extensions/xforms/nsXFormsModelElement.h b/mozilla/extensions/xforms/nsXFormsModelElement.h index ad6581b7729..832191a2208 100644 --- a/mozilla/extensions/xforms/nsXFormsModelElement.h +++ b/mozilla/extensions/xforms/nsXFormsModelElement.h @@ -48,6 +48,7 @@ #include "nsCOMPtr.h" #include "nsIDOMDocument.h" #include "nsXFormsMDGEngine.h" +#include "nsXFormsUtils.h" #include "nsISchemaLoader.h" #include "nsISchema.h" @@ -102,32 +103,49 @@ private: NS_HIDDEN_(void) BackupOrRestoreInstanceData(PRBool restore); /** Initializes the MIPs on all form controls */ - NS_HIDDEN_(void) InitializeControls(); + NS_HIDDEN_(nsresult) InitializeControls(); NS_HIDDEN_(nsresult) ProcessBindElements(); NS_HIDDEN_(nsresult) FinishConstruction(); NS_HIDDEN_(nsresult) ConstructDone(); NS_HIDDEN_(void) MaybeNotifyCompletion(); - NS_HIDDEN_(nsresult) ProcessBind(nsIXFormsXPathEvaluator *aEvaluator, + NS_HIDDEN_(nsresult) ProcessBind(nsIXFormsXPathEvaluator *aEvaluator, nsIDOMNode *aContextNode, - PRInt32 aContextPosition, - PRInt32 aContextSize, + PRInt32 aContextPosition, + PRInt32 aContextSize, nsIDOMElement *aBindElement); NS_HIDDEN_(void) RemoveModelFromDocument(); /** - * Dispatch the necessary events to a control, aControl, when the instance - * node, aNode, it is bound to changes state. + * Set the states on the control |aControl| bound to the instance data node + * |aNode|. It dispatches the necessary events and sets the pseudo class + * states. |aAllStates| determines whether all states should be set, or only + * changed. * * @param aControl The event target * @param aNode The instance node - * @param aInitialize Send events for all flags + * @param aAllStates Set all states (PR_TRUE), or only changed */ - NS_HIDDEN_(void) DispatchEvents(nsIXFormsControl *aControl, - nsIDOMNode *aNode, - PRBool aInitialize = PR_FALSE); + NS_HIDDEN_(nsresult) SetStatesInternal(nsIXFormsControl *aControl, + nsIDOMNode *aNode, + PRBool aAllStates = PR_FALSE); + + /** + * Sets the state of a specific state. + * + * @param aElement The element to dispatch events to and set states on + * @param aState The state value + * @param aOnEvent The on event for the state. + * @param aAttributePos The position of the "on" attribute in kStateAttributes + * + * @note aAttributePos is only needed until bug 271720 is landed. + */ + NS_HIDDEN_(void) SetSingleState(nsIDOMElement *aElement, + PRBool aState, + nsXFormsEvent aOnEvent, + PRUint32 aAttributePos); // Returns true when all external documents have been loaded PRBool IsComplete() const { return (mSchemaTotal == mSchemaCount diff --git a/mozilla/extensions/xforms/nsXFormsOutputElement.cpp b/mozilla/extensions/xforms/nsXFormsOutputElement.cpp index 9b6a7be9f9e..547b37f674f 100755 --- a/mozilla/extensions/xforms/nsXFormsOutputElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsOutputElement.cpp @@ -211,8 +211,6 @@ nsXFormsOutputElement::Bind() { if (!mValue || !mHasParent) return NS_OK; - - mBoundNode = nsnull; nsresult rv; rv = mElement->HasAttribute(NS_LITERAL_STRING("ref"), &mHasBinding); @@ -222,24 +220,19 @@ nsXFormsOutputElement::Bind() NS_ENSURE_SUCCESS(rv, rv); } - nsCOMPtr result; if (mHasBinding) { - rv = ProcessNodeBinding(NS_LITERAL_STRING("ref"), - nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, - getter_AddRefs(result)); + rv = nsXFormsControlStub::Bind(); } else { - rv = ProcessNodeBinding(NS_LITERAL_STRING("value"), - nsIDOMXPathResult::STRING_TYPE, - getter_AddRefs(result)); - } - + mBoundNode = nsnull; + // This call does a bit too much, as we do the call again in Refresh(), + // but we need to clear index listeners, bind to the model, get + // evt. context, etc. in Bind(). + rv = ResetBoundNode(NS_LITERAL_STRING("value"), + nsIDOMXPathResult::STRING_TYPE); + } NS_ENSURE_SUCCESS(rv, rv); - if (result) { - result->GetSingleNodeValue(getter_AddRefs(mBoundNode)); - } - - return NS_OK; + return rv; } NS_IMETHODIMP @@ -256,9 +249,9 @@ nsXFormsOutputElement::Refresh() } } else { nsCOMPtr result; - rv = ProcessNodeBinding(NS_LITERAL_STRING("value"), - nsIDOMXPathResult::STRING_TYPE, - getter_AddRefs(result)); + rv = ResetBoundNode(NS_LITERAL_STRING("value"), + nsIDOMXPathResult::STRING_TYPE, + getter_AddRefs(result)); NS_ENSURE_SUCCESS(rv, rv); if (result) { diff --git a/mozilla/extensions/xforms/nsXFormsUtils.cpp b/mozilla/extensions/xforms/nsXFormsUtils.cpp index 2714e2b6e55..2b3f9a48a8f 100644 --- a/mozilla/extensions/xforms/nsXFormsUtils.cpp +++ b/mozilla/extensions/xforms/nsXFormsUtils.cpp @@ -167,6 +167,19 @@ static const EventData sEventDefaultsEntries[] = { static nsDataHashtable sXFormsEvents; static nsDataHashtable sEventDefaults; +/** + * @todo The attribute names used on the elements to reflect the pseudo class + * state until bug 271720 is landed. (XXX) + */ +const nsString kStateAttributes[8] = { NS_LITERAL_STRING("valid"), + NS_LITERAL_STRING("invalid"), + NS_LITERAL_STRING("read-only"), + NS_LITERAL_STRING("read-write"), + NS_LITERAL_STRING("required"), + NS_LITERAL_STRING("optional"), + NS_LITERAL_STRING("enabled"), + NS_LITERAL_STRING("disabled") }; + /* static */ nsresult nsXFormsUtils::Init() { diff --git a/mozilla/extensions/xforms/nsXFormsUtils.h b/mozilla/extensions/xforms/nsXFormsUtils.h index e7cd6349230..e2fd9b62a8c 100644 --- a/mozilla/extensions/xforms/nsXFormsUtils.h +++ b/mozilla/extensions/xforms/nsXFormsUtils.h @@ -65,6 +65,9 @@ class nsIDOMEvent; * XForms event types * * @see http://www.w3.org/TR/xforms/slice4.html#rpm-events + * + * @note nsXFormsModelElement::SetSingleState() assumes a specific order of + * the events from eEvent_Valid to eEvent_Disabled. */ enum nsXFormsEvent { @@ -120,6 +123,12 @@ struct EventData extern const EventData sXFormsEventsEntries[41]; +/** + * @todo The attribute names used on the elements to reflect the pseudo class + * state until bug 271720 is landed. (XXX) + */ +extern const nsString kStateAttributes[8]; + /** * This class has static helper methods that don't fit into a specific place * in the class hierarchy.