[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
This commit is contained in:
aaronr%us.ibm.com
2008-07-27 00:35:16 +00:00
parent 0882edd60b
commit d30efc9d1a
6 changed files with 171 additions and 50 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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();

View File

@@ -22,6 +22,7 @@
* Contributor(s):
* Brian Ryner <bryner@brianryner.com>
* Olli Pettay <Olli.Pettay@helsinki.fi>
* Merle Sterling <msterlin@us.ibm.com>
*
* 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<nsIDOMNode> 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<nsIDOMNode> 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<nsIModelElementPrivate> 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<nsIDocument> iDoc(do_QueryInterface(mDocument));
nsresult rv = ReplacePrincipal(iDoc);
if (NS_FAILED(rv)) {
SetInstanceDocument(nsnull);
return rv;
// Replace the principal for the loaded document
nsCOMPtr<nsIDocument> iDoc(do_QueryInterface(mDocument));
nsresult rv = ReplacePrincipal(iDoc);
if (NS_FAILED(rv)) {
SetInstanceDocument(nsnull);
return rv;
}
}
nsCOMPtr<nsIModelElementPrivate> 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<nsIDOMNode> 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<nsIDOMNode> 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<nsIDOMNode> 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<nsIModelElementPrivate> model(GetModel());
nsCOMPtr<nsIDOMNode> 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<nsXFormsContextInfo> 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<nsIDOMNode> sibling;
child->GetNextSibling(getter_AddRefs(sibling));
nsCOMPtr<nsIDOMNode> 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<nsIModelElementPrivate> model(GetModel());
nsCOMPtr<nsIDOMNode> 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<nsXFormsContextInfo> 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<nsIDOMNode> 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<nsIDOMNode> 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<nsIDOMNode> 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)
{

View File

@@ -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<nsIModelElementPrivate>) 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<nsIChannel> mChannel;
// Context Info for events.
nsCOMArray<nsIXFormsContextInfo> mContextInfo;
};
NS_HIDDEN_(nsresult)

View File

@@ -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<nsXFormsContextInfo> 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;
}