From d30efc9d1a8d2325df6a0a5e56c0a24d22d70cbc Mon Sep 17 00:00:00 2001 From: "aaronr%us.ibm.com" Date: Sun, 27 Jul 2008 00:35:16 +0000 Subject: [PATCH] [XForms] NPOTDB [1.1] support @resource on instance element Bug 421468, p=msterlin r=olli+aaronr git-svn-id: svn://10.0.0.236/branches/MOZILLA_1_8_BRANCH@253297 18797224-902f-48f8-a5cc-f745e15eee43 --- .../xforms/nsIModelElementPrivate.idl | 8 +- mozilla/extensions/xforms/nsXFormsAtoms.cpp | 4 +- mozilla/extensions/xforms/nsXFormsAtoms.h | 1 + .../xforms/nsXFormsInstanceElement.cpp | 186 +++++++++++++----- .../xforms/nsXFormsInstanceElement.h | 7 +- .../xforms/nsXFormsModelElement.cpp | 15 +- 6 files changed, 171 insertions(+), 50 deletions(-) diff --git a/mozilla/extensions/xforms/nsIModelElementPrivate.idl b/mozilla/extensions/xforms/nsIModelElementPrivate.idl index b7ba27d8ef9..2dbcfb3cb66 100644 --- a/mozilla/extensions/xforms/nsIModelElementPrivate.idl +++ b/mozilla/extensions/xforms/nsIModelElementPrivate.idl @@ -48,7 +48,7 @@ interface nsISchemaBuiltinType; * Private interface implemented by the model element for other * elements to use. */ -[uuid(e0c08554-0509-45b4-b3e5-b25c6cad8153)] +[uuid(bbc19255-4341-45fb-a9dc-23f4add8a7c3)] interface nsIModelElementPrivate : nsIXFormsModelElement { /** @@ -63,9 +63,13 @@ interface nsIModelElementPrivate : nsIXFormsModelElement * Notification that an instance element has started or finished loading * its instance data. Model construction cannot complete until all of * the instances have loaded their data. + * + * The 'uri' parameter for instanceLoadFinished is the uri of @src or + * @resource on the instance element and is needed to add the uri to + * the context info if the link fails. */ void instanceLoadStarted(); - void instanceLoadFinished(in boolean success); + void instanceLoadFinished(in boolean success, in AString uri); /** * Locate the instance element child with the given id. diff --git a/mozilla/extensions/xforms/nsXFormsAtoms.cpp b/mozilla/extensions/xforms/nsXFormsAtoms.cpp index 023ba9a9f39..741c8a991f0 100644 --- a/mozilla/extensions/xforms/nsXFormsAtoms.cpp +++ b/mozilla/extensions/xforms/nsXFormsAtoms.cpp @@ -67,6 +67,7 @@ nsIAtom* nsXFormsAtoms::instanceDocumentOwner; nsIAtom* nsXFormsAtoms::externalMessagesProperty; nsIAtom* nsXFormsAtoms::deferredEventListProperty; nsIAtom* nsXFormsAtoms::attrBased; +nsIAtom* nsXFormsAtoms::resource; const nsStaticAtom nsXFormsAtoms::Atoms_info[] = { { "src", &nsXFormsAtoms::src }, @@ -96,7 +97,8 @@ const nsStaticAtom nsXFormsAtoms::Atoms_info[] = { { "instanceDocumentOwner", &nsXFormsAtoms::instanceDocumentOwner }, { "ExternalMessagesProperty", &nsXFormsAtoms::externalMessagesProperty }, { "DeferredEventListProperty",&nsXFormsAtoms::deferredEventListProperty }, - { "attrBased", &nsXFormsAtoms::attrBased } + { "attrBased", &nsXFormsAtoms::attrBased }, + { "resource", &nsXFormsAtoms::resource } }; void diff --git a/mozilla/extensions/xforms/nsXFormsAtoms.h b/mozilla/extensions/xforms/nsXFormsAtoms.h index 227a11d7903..d5a00016e5f 100644 --- a/mozilla/extensions/xforms/nsXFormsAtoms.h +++ b/mozilla/extensions/xforms/nsXFormsAtoms.h @@ -75,6 +75,7 @@ class nsXFormsAtoms static NS_HIDDEN_(nsIAtom *) externalMessagesProperty; static NS_HIDDEN_(nsIAtom *) deferredEventListProperty; static NS_HIDDEN_(nsIAtom *) attrBased; + static NS_HIDDEN_(nsIAtom *) resource; static NS_HIDDEN_(void) InitAtoms(); diff --git a/mozilla/extensions/xforms/nsXFormsInstanceElement.cpp b/mozilla/extensions/xforms/nsXFormsInstanceElement.cpp index f3a8b66e72c..0b5de6fc668 100644 --- a/mozilla/extensions/xforms/nsXFormsInstanceElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsInstanceElement.cpp @@ -22,6 +22,7 @@ * Contributor(s): * Brian Ryner * Olli Pettay + * Merle Sterling * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -90,8 +91,23 @@ nsXFormsInstanceElement::AttributeSet(nsIAtom *aName, if (!mInitialized || mLazy) return NS_OK; + // @src has precedence over inline content which has precedence + // over @resource. if (aName == nsXFormsAtoms::src) { LoadExternalInstance(aNewValue); + } else if (aName == nsXFormsAtoms::resource) { + // If @resource is set or changed, it only matters if there is + // no @src or inline content. + nsAutoString src; + mElement->GetAttribute(NS_LITERAL_STRING("src"), src); + if (src.IsEmpty()) { + // Check for inline content. + nsCOMPtr child; + GetFirstChildElement(getter_AddRefs(child)); + if (!child) { + LoadExternalInstance(aNewValue); + } + } } return NS_OK; @@ -103,6 +119,8 @@ nsXFormsInstanceElement::AttributeRemoved(nsIAtom *aName) if (!mInitialized || mLazy) return NS_OK; + // @src has precdence over inline content which has precedence + // over @resource. if (aName == nsXFormsAtoms::src) { PRBool restart = PR_FALSE; if (mChannel) { @@ -114,19 +132,34 @@ nsXFormsInstanceElement::AttributeRemoved(nsIAtom *aName) mChannel = nsnull; mListener = nsnull; } - // We no longer have an external instance to use. Reset our instance - // document to whatever inline content we have. - nsresult rv = CloneInlineInstance(); + + // We no longer have an external (@src) instance to use. Next in precedence + // would be inline content so we'll use that if it exists. If there is no + // inline content, then we'll look for @resource (the instance may have had + // both @src and @resource and no inline content). + nsresult rv; + nsCOMPtr child; + GetFirstChildElement(getter_AddRefs(child)); + if (child) { + // Reset our instance document to whatever inline content we have. + rv = CloneInlineInstance(child); + } else { + nsAutoString resource; + mElement->GetAttribute(NS_LITERAL_STRING("resource"), resource); + if (!resource.IsEmpty()) { + LoadExternalInstance(resource); + } + } // if we had already started to load an external instance document, then // as part of that we would have told the model to wait for that external // document to load before it finishes the model construction. Since we // aren't loading from an external document any longer, tell the model that - // there is need to wait for us anymore. + // there is no need to wait for us anymore. if (restart) { nsCOMPtr model = GetModel(); if (model) { - model->InstanceLoadFinished(PR_TRUE); + model->InstanceLoadFinished(PR_TRUE, EmptyString()); } } return rv; @@ -260,19 +293,21 @@ nsXFormsInstanceElement::OnStopRequest(nsIRequest *request, nsISupports *ctx, SetInstanceDocument(nsnull); } } - } - // Replace the principal for the loaded document - nsCOMPtr iDoc(do_QueryInterface(mDocument)); - nsresult rv = ReplacePrincipal(iDoc); - if (NS_FAILED(rv)) { - SetInstanceDocument(nsnull); - return rv; + // Replace the principal for the loaded document + nsCOMPtr iDoc(do_QueryInterface(mDocument)); + nsresult rv = ReplacePrincipal(iDoc); + if (NS_FAILED(rv)) { + SetInstanceDocument(nsnull); + return rv; + } } nsCOMPtr model = GetModel(); if (model) { - model->InstanceLoadFinished(succeeded); + nsCAutoString uri; + request->GetName(uri); + model->InstanceLoadFinished(succeeded, NS_ConvertASCIItoUTF16(uri)); } mListener = nsnull; @@ -458,7 +493,9 @@ nsXFormsInstanceElement::ParentChanged(nsIDOMElement *aNewParent) } // If we don't have a linked external instance, use our inline data. - nsresult rv = CloneInlineInstance(); + nsCOMPtr child; + GetFirstChildElement(getter_AddRefs(child)); + nsresult rv = CloneInlineInstance(child); if (NS_FAILED(rv)) return rv; return BackupOriginalDocument(); @@ -475,48 +512,69 @@ nsXFormsInstanceElement::Initialize() } // Normal instance - nsAutoString src; + // If the src attribute is given, then it takes precedence over inline + // content and the resource attribute, and the XML data for the instance + // is obtained from the link. If the src attribute is omitted, then the + // data for the instance is obtained from inline content if it is given + // or the resource attribute otherwise. If both the resource attribute + // and inline content are provided, the inline content takes precedence. + nsresult rv = NS_OK; + nsAutoString src, resource; mElement->GetAttribute(NS_LITERAL_STRING("src"), src); - if (src.IsEmpty()) { - return CloneInlineInstance(); + if (!src.IsEmpty()) { + LoadExternalInstance(src); + } else { + // If we have a first child element then we have inline content. + nsCOMPtr child; + GetFirstChildElement(getter_AddRefs(child)); + if (child) { + rv = CloneInlineInstance(child); + } else { + // No @src or inline content, better have @resource + mElement->GetAttribute(NS_LITERAL_STRING("resource"), resource); + LoadExternalInstance(resource); + } } - LoadExternalInstance(src); - return NS_OK; + return rv; } // private methods nsresult -nsXFormsInstanceElement::CloneInlineInstance() +nsXFormsInstanceElement::CloneInlineInstance(nsIDOMNode *aChild) { // Clear out our existing instance data nsresult rv = CreateInstanceDocument(EmptyString()); if (NS_FAILED(rv)) return rv; // don't warn, we might just not be in the document yet - // look for our first child element (skip over text nodes, etc.) - nsCOMPtr child, temp; - mElement->GetFirstChild(getter_AddRefs(child)); - while (child) { - PRUint16 nodeType; - child->GetNodeType(&nodeType); - if (nodeType == nsIDOMNode::ELEMENT_NODE) - break; - - temp.swap(child); - temp->GetNextSibling(getter_AddRefs(child)); - } - - // There needs to be a child element, or it is not a valid XML document - if (!child) { + // aChild must be the first child element under xf:instance or it is not + // a valid XML document. + if (!aChild) { nsXFormsUtils::ReportError(NS_LITERAL_STRING("inlineInstanceNoChildError"), mElement); + nsCOMPtr model(GetModel()); nsCOMPtr modelNode(do_QueryInterface(model)); - nsXFormsUtils::DispatchEvent(modelNode, eEvent_LinkException); + // Context Info: 'resource-uri' + // ID of the failed instance preceded by the # fragment identifier. + nsAutoString idStr; + mElement->GetAttribute(NS_LITERAL_STRING("id"), idStr); + if (!idStr.IsEmpty()) { + nsAutoString resourceURI; + resourceURI.AssignLiteral("#"); + resourceURI.Append(idStr); + nsCOMPtr contextInfo = + new nsXFormsContextInfo(mElement); + NS_ENSURE_TRUE(contextInfo, NS_ERROR_OUT_OF_MEMORY); + contextInfo->SetStringValue("resource-uri", resourceURI); + mContextInfo.AppendObject(contextInfo); + } + nsXFormsUtils::DispatchEvent(modelNode, eEvent_LinkException, nsnull, + mElement, &mContextInfo); nsXFormsUtils::HandleFatalError(mElement, NS_LITERAL_STRING("XFormsLinkException")); return NS_ERROR_FAILURE; @@ -524,8 +582,8 @@ nsXFormsInstanceElement::CloneInlineInstance() // Check for siblings to first child element node. This is an error, since // the inline content is then not a well-formed XML document. - nsCOMPtr sibling; - child->GetNextSibling(getter_AddRefs(sibling)); + nsCOMPtr sibling, temp; + aChild->GetNextSibling(getter_AddRefs(sibling)); while (sibling) { PRUint16 nodeType; sibling->GetNodeType(&nodeType); @@ -533,9 +591,25 @@ nsXFormsInstanceElement::CloneInlineInstance() if (nodeType == nsIDOMNode::ELEMENT_NODE) { nsXFormsUtils::ReportError(NS_LITERAL_STRING("inlineInstanceMultipleElementsError"), mElement); + nsCOMPtr model(GetModel()); nsCOMPtr modelNode(do_QueryInterface(model)); - nsXFormsUtils::DispatchEvent(modelNode, eEvent_LinkException); + // Context Info: 'resource-uri' + // ID of the failed instance preceded by the # fragment identifier. + nsAutoString idStr; + mElement->GetAttribute(NS_LITERAL_STRING("id"), idStr); + if (!idStr.IsEmpty()) { + nsAutoString resourceURI; + resourceURI.AssignLiteral("#"); + resourceURI.Append(idStr); + nsCOMPtr contextInfo = + new nsXFormsContextInfo(mElement); + NS_ENSURE_TRUE(contextInfo, NS_ERROR_OUT_OF_MEMORY); + contextInfo->SetStringValue("resource-uri", resourceURI); + mContextInfo.AppendObject(contextInfo); + } + nsXFormsUtils::DispatchEvent(modelNode, eEvent_LinkException, nsnull, + mElement, &mContextInfo); nsXFormsUtils::HandleFatalError(mElement, NS_LITERAL_STRING("XFormsLinkException")); return NS_ERROR_FAILURE; @@ -547,7 +621,7 @@ nsXFormsInstanceElement::CloneInlineInstance() // Clone and insert content into new document nsCOMPtr newNode; - rv = mDocument->ImportNode(child, PR_TRUE, getter_AddRefs(newNode)); + rv = mDocument->ImportNode(aChild, PR_TRUE, getter_AddRefs(newNode)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr nodeReturn; @@ -565,9 +639,9 @@ nsXFormsInstanceElement::LoadExternalInstance(const nsAString &aSrc) PRBool restart = PR_FALSE; if (mChannel) { // probably hit this condition because someone changed the value of our - // src attribute while we are already trying to load the previously - // specified document. We'll stop the current load effort and kick off the - // new attempt. + // src or resource attribute while we are already trying to load the + // previously specified document. We'll stop the current load effort and + // kick off the new attempt. restart = PR_TRUE; mChannel->Cancel(NS_BINDING_ABORTED); mChannel = nsnull; @@ -636,7 +710,9 @@ nsXFormsInstanceElement::LoadExternalInstance(const nsAString &aSrc) model->InstanceLoadStarted(); } if (NS_FAILED(rv)) { - model->InstanceLoadFinished(PR_FALSE); + // Context Info: 'resource-uri' + // The resource URI of the link that failed. + model->InstanceLoadFinished(PR_FALSE, aSrc); } } } @@ -690,6 +766,28 @@ nsXFormsInstanceElement::GetModel() return model; } +nsresult +nsXFormsInstanceElement::GetFirstChildElement(nsIDOMNode **aChild) +{ + // look for our first child element (skip over text nodes, etc.) + nsCOMPtr child, temp; + mElement->GetFirstChild(getter_AddRefs(child)); + while (child) { + PRUint16 nodeType; + child->GetNodeType(&nodeType); + + if (nodeType == nsIDOMNode::ELEMENT_NODE) + break; + + temp.swap(child); + temp->GetNextSibling(getter_AddRefs(child)); + } + + NS_IF_ADDREF(*aChild = child); + + return NS_OK; +} + nsresult NS_NewXFormsInstanceElement(nsIXTFElement **aResult) { diff --git a/mozilla/extensions/xforms/nsXFormsInstanceElement.h b/mozilla/extensions/xforms/nsXFormsInstanceElement.h index d8ebd21239f..cb17b23a10d 100644 --- a/mozilla/extensions/xforms/nsXFormsInstanceElement.h +++ b/mozilla/extensions/xforms/nsXFormsInstanceElement.h @@ -41,6 +41,7 @@ #include "nsXFormsStubElement.h" #include "nsIDOMDocument.h" +#include "nsCOMArray.h" #include "nsCOMPtr.h" #include "nsIModelElementPrivate.h" #include "nsIInstanceElementPrivate.h" @@ -48,6 +49,7 @@ #include "nsIStreamListener.h" #include "nsIChannelEventSink.h" #include "nsIInterfaceRequestor.h" +#include "nsIXFormsContextInfo.h" class nsIDocument; class nsIDOMElement; @@ -84,10 +86,11 @@ public: nsXFormsInstanceElement() NS_HIDDEN; private: - NS_HIDDEN_(nsresult) CloneInlineInstance(); + NS_HIDDEN_(nsresult) CloneInlineInstance(nsIDOMNode *aChild); NS_HIDDEN_(void) LoadExternalInstance(const nsAString &aSrc); NS_HIDDEN_(nsresult) CreateInstanceDocument(const nsAString &aQualifiedName); NS_HIDDEN_(already_AddRefed) GetModel(); + NS_HIDDEN_(nsresult) GetFirstChildElement(nsIDOMNode **aChild); /** * Replace principal for document to be the same as for the owning document. @@ -108,6 +111,8 @@ private: PRBool mInitialized; PRBool mLazy; nsCOMPtr mChannel; + // Context Info for events. + nsCOMArray mContextInfo; }; NS_HIDDEN_(nsresult) diff --git a/mozilla/extensions/xforms/nsXFormsModelElement.cpp b/mozilla/extensions/xforms/nsXFormsModelElement.cpp index 63b8c17e575..2ccfdd0e730 100644 --- a/mozilla/extensions/xforms/nsXFormsModelElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsModelElement.cpp @@ -1562,7 +1562,8 @@ nsXFormsModelElement::InstanceLoadStarted() } NS_IMETHODIMP -nsXFormsModelElement::InstanceLoadFinished(PRBool aSuccess) +nsXFormsModelElement::InstanceLoadFinished(PRBool aSuccess, + const nsAString& aURI) { if (!aSuccess) { // This will leave mPendingInstanceCount in an invalid state, which is @@ -1570,7 +1571,17 @@ nsXFormsModelElement::InstanceLoadFinished(PRBool aSuccess) // should stop. If we decrease mPendingInstanceCount, the model would // finish construction, which is wrong. nsXFormsUtils::ReportError(NS_LITERAL_STRING("instanceLoadError"), mElement); - nsXFormsUtils::DispatchEvent(mElement, eEvent_LinkException); + if (!aURI.IsEmpty()) { + // Context Info: 'resource-uri' + // The resource URI of the link that failed. + nsCOMPtr contextInfo = + new nsXFormsContextInfo(mElement); + NS_ENSURE_TRUE(contextInfo, NS_ERROR_OUT_OF_MEMORY); + contextInfo->SetStringValue("resource-uri", aURI); + mContextInfo.AppendObject(contextInfo); + } + nsXFormsUtils::DispatchEvent(mElement, eEvent_LinkException, nsnull, + nsnull, &mContextInfo); return NS_OK; }