From 6358cf1f6514615367db7e0461057870ed586cf5 Mon Sep 17 00:00:00 2001 From: "aaronr%us.ibm.com" Date: Fri, 19 Jan 2007 22:22:07 +0000 Subject: [PATCH] [XForms] Some controls should not be allowed to bind to complexContent. Bug 356190, patch by msterlin, r=olli+aaronr git-svn-id: svn://10.0.0.236/trunk@218683 18797224-902f-48f8-a5cc-f745e15eee43 --- .../extensions/xforms/nsXFormsControlStub.cpp | 54 ++++++++++++++++++- .../extensions/xforms/nsXFormsControlStub.h | 18 +++++++ .../xforms/nsXFormsInputElement.cpp | 35 ++++++++++++ .../xforms/nsXFormsOutputElement.cpp | 17 ++++++ .../xforms/nsXFormsSelect1Element.cpp | 19 +++++++ .../xforms/nsXFormsSelectElement.cpp | 19 +++++++ mozilla/extensions/xforms/nsXFormsUtils.cpp | 32 +++++++++++ mozilla/extensions/xforms/nsXFormsUtils.h | 9 ++++ .../resources/locale/en-US/xforms.properties | 1 + 9 files changed, 203 insertions(+), 1 deletion(-) diff --git a/mozilla/extensions/xforms/nsXFormsControlStub.cpp b/mozilla/extensions/xforms/nsXFormsControlStub.cpp index 866f457e57e..3134c72dd78 100644 --- a/mozilla/extensions/xforms/nsXFormsControlStub.cpp +++ b/mozilla/extensions/xforms/nsXFormsControlStub.cpp @@ -183,12 +183,31 @@ nsXFormsControlStub::ResetBoundNode(const nsString &aBindAttribute, *aContextChanged = (oldBoundNode != mBoundNode); - if (!mBoundNode) { + // Some controls may not be bound to certain types of content. If the content + // is a disallowed type, report the error and dispatch a binding exception + // event. + PRBool isAllowed = PR_TRUE; + IsContentAllowed(&isAllowed); + + if (!mBoundNode || !isAllowed) { // If there's no result (ie, no instance node) returned by the above, it // means that the binding is not pointing to an instance data node, so we // should disable the control. mAppearDisabled = PR_TRUE; + if (!isAllowed) { + // build the error string that we want output to the ErrorConsole + nsAutoString localName; + mElement->GetLocalName(localName); + const PRUnichar *strings[] = { localName.get() }; + + nsXFormsUtils::ReportError( + NS_LITERAL_STRING("boundTypeErrorComplexContent"), + strings, 1, mElement, mElement); + + nsXFormsUtils::DispatchEvent(mElement, eEvent_BindingException); + } + nsCOMPtr wrapper(do_QueryInterface(mElement)); NS_ENSURE_STATE(wrapper); @@ -817,6 +836,39 @@ nsXFormsControlStub::GetBoundBuiltinType(PRUint16 *aBuiltinType) return mModel->GetRootBuiltinType(schemaType, aBuiltinType); } +NS_IMETHODIMP +nsXFormsControlStub::IsContentAllowed(PRBool *aIsAllowed) +{ + NS_ENSURE_ARG_POINTER(aIsAllowed); + *aIsAllowed = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsControlStub::IsContentComplex(PRBool *aIsComplex) +{ + NS_ENSURE_ARG_POINTER(aIsComplex); + *aIsComplex = PR_FALSE; + + if (mBoundNode) { + // If the bound node has any Element children, then it has complexContent. + nsCOMPtr currentNode; + mBoundNode->GetFirstChild(getter_AddRefs(currentNode)); + while (currentNode) { + PRUint16 nodeType; + currentNode->GetNodeType(&nodeType); + if (nodeType == nsIDOMNode::ELEMENT_NODE) { + *aIsComplex = PR_TRUE; + break; + } + + nsCOMPtr node; + currentNode->GetNextSibling(getter_AddRefs(node)); + currentNode.swap(node); + } + } + return NS_OK; +} NS_IMPL_ISUPPORTS_INHERITED3(nsXFormsControlStub, nsXFormsStubElement, diff --git a/mozilla/extensions/xforms/nsXFormsControlStub.h b/mozilla/extensions/xforms/nsXFormsControlStub.h index 7a8e6034b11..eb60e41ffc7 100644 --- a/mozilla/extensions/xforms/nsXFormsControlStub.h +++ b/mozilla/extensions/xforms/nsXFormsControlStub.h @@ -129,6 +129,24 @@ public: */ void AddRemoveSNBAttr(nsIAtom *aName, const nsAString &aValue); + /** + * This function is overridden by controls that are restricted in the + * type of content that may be bound to the control. For example, + * xf:input may only be bound to simpleContent. + * + * @param aIsAllowed Indicates whether the control is allowed to bind + * to the content type. + */ + NS_IMETHOD IsContentAllowed(PRBool *aIsAllowed); + + /** + * This function determines if the content to which the control is being + * bound is complex; ie contains Element children. + * + * @param aIsComplex Indicates whether the content is complex. + */ + NS_IMETHOD IsContentComplex(PRBool *aIsComplex); + // nsIXFormsContextControl NS_DECL_NSIXFORMSCONTEXTCONTROL diff --git a/mozilla/extensions/xforms/nsXFormsInputElement.cpp b/mozilla/extensions/xforms/nsXFormsInputElement.cpp index bd33d54314a..21766779167 100644 --- a/mozilla/extensions/xforms/nsXFormsInputElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsInputElement.cpp @@ -50,6 +50,8 @@ public: nsRestrictionFlag *aRestriction, nsAString &aUnallowedTypes); + NS_IMETHOD IsContentAllowed(PRBool *aIsAllowed); + nsXFormsInputElement(const nsAString& aType) : nsXFormsDelegateStub(aType) {} @@ -79,6 +81,22 @@ nsXFormsInputElement::IsTypeAllowed(PRUint16 aType, PRBool *aIsAllowed, return NS_OK; } +NS_IMETHODIMP +nsXFormsInputElement::IsContentAllowed(PRBool *aIsAllowed) +{ + NS_ENSURE_ARG_POINTER(aIsAllowed); + *aIsAllowed = PR_TRUE; + + + // For input and secret elements, complexContent is not allowed. + PRBool isComplex = PR_FALSE; + IsContentComplex(&isComplex); + if (isComplex) { + *aIsAllowed = PR_FALSE; + } + return NS_OK; +} + class nsXFormsTextareaElement : public nsXFormsDelegateStub { public: @@ -87,6 +105,8 @@ public: nsRestrictionFlag *aRestriction, nsAString &aAllowedTypes); + NS_IMETHOD IsContentAllowed(PRBool *aIsAllowed); + nsXFormsTextareaElement() : nsXFormsDelegateStub(NS_LITERAL_STRING("textarea")) {} @@ -115,6 +135,21 @@ nsXFormsTextareaElement::IsTypeAllowed(PRUint16 aType, PRBool *aIsAllowed, return NS_OK; } +NS_IMETHODIMP +nsXFormsTextareaElement::IsContentAllowed(PRBool *aIsAllowed) +{ + NS_ENSURE_ARG_POINTER(aIsAllowed); + *aIsAllowed = PR_TRUE; + + // Textareas may not be bound to complexContent. + PRBool isComplex = PR_FALSE; + IsContentComplex(&isComplex); + if (isComplex) { + *aIsAllowed = PR_FALSE; + } + return NS_OK; +} + // Creators NS_HIDDEN_(nsresult) diff --git a/mozilla/extensions/xforms/nsXFormsOutputElement.cpp b/mozilla/extensions/xforms/nsXFormsOutputElement.cpp index 70794d94ba9..cc8a9b7d9dd 100755 --- a/mozilla/extensions/xforms/nsXFormsOutputElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsOutputElement.cpp @@ -84,6 +84,8 @@ public: NS_IMETHOD SetValue(const nsAString& aValue); NS_IMETHOD GetHasBoundNode(PRBool *aHasBoundNode); + NS_IMETHOD IsContentAllowed(PRBool *aIsAllowed); + nsXFormsOutputElement(); private: @@ -197,6 +199,21 @@ nsXFormsOutputElement::SetValue(const nsAString& aValue) return NS_ERROR_NOT_AVAILABLE; } +NS_IMETHODIMP +nsXFormsOutputElement::IsContentAllowed(PRBool *aIsAllowed) +{ + NS_ENSURE_ARG_POINTER(aIsAllowed); + *aIsAllowed = PR_TRUE; + + // Output may not be bound to complexContent. + PRBool isComplex = PR_FALSE; + IsContentComplex(&isComplex); + if (isComplex) { + *aIsAllowed = PR_FALSE; + } + return NS_OK; +} + NS_HIDDEN_(nsresult) NS_NewXFormsOutputElement(nsIXTFElement **aResult) { diff --git a/mozilla/extensions/xforms/nsXFormsSelect1Element.cpp b/mozilla/extensions/xforms/nsXFormsSelect1Element.cpp index 70f0328d793..3b336e52dcc 100644 --- a/mozilla/extensions/xforms/nsXFormsSelect1Element.cpp +++ b/mozilla/extensions/xforms/nsXFormsSelect1Element.cpp @@ -80,6 +80,8 @@ public: // nsIXFormsDelegate overrides NS_IMETHOD GetXFormsAccessors(nsIXFormsAccessors **aAccessor); + NS_IMETHOD IsContentAllowed(PRBool *aIsAllowed); + nsXFormsSelect1Element(const nsAString& aType) : nsXFormsDelegateStub(aType) {} @@ -193,6 +195,23 @@ nsXFormsSelect1Element::GetXFormsAccessors(nsIXFormsAccessors **aAccessor) return NS_OK; } +NS_IMETHODIMP +nsXFormsSelect1Element::IsContentAllowed(PRBool *aIsAllowed) +{ + NS_ENSURE_ARG_POINTER(aIsAllowed); + *aIsAllowed = PR_TRUE; + + // For select1 elements, non-simpleContent is only allowed if the select + // element contains an itemset. + PRBool isComplex = PR_FALSE; + IsContentComplex(&isComplex); + if (isComplex && !nsXFormsUtils::NodeHasItemset(mElement)) { + *aIsAllowed = PR_FALSE; + } + + return NS_OK; +} + NS_HIDDEN_(nsresult) NS_NewXFormsSelect1Element(nsIXTFElement **aResult) { diff --git a/mozilla/extensions/xforms/nsXFormsSelectElement.cpp b/mozilla/extensions/xforms/nsXFormsSelectElement.cpp index dec6d4a610f..df8ec3c6331 100644 --- a/mozilla/extensions/xforms/nsXFormsSelectElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsSelectElement.cpp @@ -75,6 +75,8 @@ public: // nsIXFormsDelegate overrides NS_IMETHOD GetXFormsAccessors(nsIXFormsAccessors **aAccessor); + NS_IMETHOD IsContentAllowed(PRBool *aIsAllowed); + #ifdef DEBUG_smaug virtual const char* Name() { return "select"; } #endif @@ -165,6 +167,23 @@ nsXFormsSelectElement::GetXFormsAccessors(nsIXFormsAccessors **aAccessor) return NS_OK; } +NS_IMETHODIMP +nsXFormsSelectElement::IsContentAllowed(PRBool *aIsAllowed) +{ + NS_ENSURE_ARG_POINTER(aIsAllowed); + *aIsAllowed = PR_TRUE; + + // For select elements, non-simpleContent is only allowed if the select + // element contains an itemset. + PRBool isComplex = PR_FALSE; + IsContentComplex(&isComplex); + if (isComplex && !nsXFormsUtils::NodeHasItemset(mElement)) { + *aIsAllowed = PR_FALSE; + } + + return NS_OK; +} + NS_HIDDEN_(nsresult) NS_NewXFormsSelectElement(nsIXTFElement **aResult) { diff --git a/mozilla/extensions/xforms/nsXFormsUtils.cpp b/mozilla/extensions/xforms/nsXFormsUtils.cpp index ad3550c10d3..c65d67d515f 100644 --- a/mozilla/extensions/xforms/nsXFormsUtils.cpp +++ b/mozilla/extensions/xforms/nsXFormsUtils.cpp @@ -2719,3 +2719,35 @@ nsXFormsUtils::SetSingleNodeBindingValue(nsIDOMElement *aElement, return PR_FALSE; } +/* static */ PRBool +nsXFormsUtils::NodeHasItemset(nsIDOMNode *aNode) +{ + PRBool hasItemset = PR_FALSE; + + nsCOMPtr children; + aNode->GetChildNodes(getter_AddRefs(children)); + + PRUint32 childCount = 0; + if (children) { + children->GetLength(&childCount); + } + + for (PRUint32 i = 0; i < childCount; ++i) { + nsCOMPtr child; + children->Item(i, getter_AddRefs(child)); + if (nsXFormsUtils::IsXFormsElement(child, NS_LITERAL_STRING("itemset"))) { + hasItemset = PR_TRUE; + break; + } else if (nsXFormsUtils::IsXFormsElement(child, + NS_LITERAL_STRING("choices"))) { + // The choices element may have an itemset. + hasItemset = nsXFormsUtils::NodeHasItemset(child); + if (hasItemset) { + // No need to look at any other children. + break; + } + } + } + return hasItemset; +} + diff --git a/mozilla/extensions/xforms/nsXFormsUtils.h b/mozilla/extensions/xforms/nsXFormsUtils.h index 90e69697776..3d02e76f67b 100644 --- a/mozilla/extensions/xforms/nsXFormsUtils.h +++ b/mozilla/extensions/xforms/nsXFormsUtils.h @@ -704,6 +704,15 @@ public: static NS_HIDDEN_(nsresult) GetDaysFromDateTime(const nsAString & aValue, PRInt32 * aDays); + /** + * Determine whether the given node contains an xf:itemset as a child. + * In valid XForms documents this should only be possible if aNode is an + * xf:select/1 or an xf:choices element. This function is used primarily + * as a worker function for select/1's IsContentAllowed override. + + */ + static NS_HIDDEN_(PRBool) NodeHasItemset(nsIDOMNode *aNode); + private: /** * Do same origin checks on aBaseDocument and aTestURI. Hosts can be diff --git a/mozilla/extensions/xforms/resources/locale/en-US/xforms.properties b/mozilla/extensions/xforms/resources/locale/en-US/xforms.properties index 7dcd4ed76ff..45c19f09fdc 100644 --- a/mozilla/extensions/xforms/resources/locale/en-US/xforms.properties +++ b/mozilla/extensions/xforms/resources/locale/en-US/xforms.properties @@ -77,6 +77,7 @@ modelLoopError = XForms Error (38): There seems to be an infinite loop in duplicateSchema = XForms Error (39): Ignoring duplicate schema with target namespace: %S boundTypeErrorInclusive = XForms Error (40): %S element not bound to valid datatype. Must be bound to one of these datatypes or a type derived from one of these datatypes: %S. boundTypeErrorExclusive = XForms Error (41): %S element not bound to valid datatype. Must not be bound to one of these datatypes or a type derived from one of these datatypes: %S. +boundTypeErrorComplexContent = XForms Error (42): %S element may not be bound to complex content. # Warning Messages: warnSOAP = XForms Warning (1): You are using the SOAP post feature, which is an experimental feature! Beware that the functionality might change, and forms may stop working at any time.