diff --git a/mozilla/extensions/xforms/Makefile.in b/mozilla/extensions/xforms/Makefile.in
index 9dd17fd07e3..cb180e662c9 100644
--- a/mozilla/extensions/xforms/Makefile.in
+++ b/mozilla/extensions/xforms/Makefile.in
@@ -71,6 +71,7 @@ REQUIRES = \
schemavalidation \
intl \
pref \
+ htmlparser \
$(NULL)
XPIDLSRCS = \
@@ -145,6 +146,7 @@ CPPSRCS = \
nsXFormsControlStub.cpp \
nsXFormsUtilityService.cpp \
nsXFormsDelegateStub.cpp \
+ nsXFormsLazyInstanceElement.cpp \
$(NULL)
EXTRA_DSO_LDOPTS = $(MOZ_COMPONENT_LIBS)
diff --git a/mozilla/extensions/xforms/contents.rdf b/mozilla/extensions/xforms/contents.rdf
deleted file mode 100755
index e21f0bdcdb1..00000000000
--- a/mozilla/extensions/xforms/contents.rdf
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/mozilla/extensions/xforms/nsIInstanceElementPrivate.idl b/mozilla/extensions/xforms/nsIInstanceElementPrivate.idl
index bb396f9e308..a114bd55447 100644
--- a/mozilla/extensions/xforms/nsIInstanceElementPrivate.idl
+++ b/mozilla/extensions/xforms/nsIInstanceElementPrivate.idl
@@ -39,6 +39,7 @@
#include "nsISupports.idl"
interface nsIDOMDocument;
+interface nsIDOMElement;
/**
* Private interface implemented by the instance element.
@@ -50,6 +51,7 @@ interface nsIInstanceElementPrivate : nsISupports
* The document which holds the live instance data.
*/
attribute nsIDOMDocument document;
+ readonly attribute nsIDOMElement element;
void backupOriginalDocument();
void restoreOriginalDocument();
};
diff --git a/mozilla/extensions/xforms/nsIModelElementPrivate.idl b/mozilla/extensions/xforms/nsIModelElementPrivate.idl
index 3d12f0affec..6709f36935b 100644
--- a/mozilla/extensions/xforms/nsIModelElementPrivate.idl
+++ b/mozilla/extensions/xforms/nsIModelElementPrivate.idl
@@ -42,6 +42,11 @@ interface nsIXFormsControl;
interface nsISchemaType;
interface nsIInstanceElementPrivate;
interface nsIDOMNode;
+%{C++
+ #include "nsCOMArray.h"
+%}
+
+[ptr] native nsCOMArrayPtr(nsCOMArray);
/**
* Private interface implemented by the model element for other
@@ -119,4 +124,21 @@ interface nsIModelElementPrivate : nsIXFormsModelElement
* @param aBoundNode The node the control is bound to
*/
void setStates(in nsIXFormsControl aControl, in nsIDOMNode aBoundNode);
+
+ /**
+ * The list of instance elements held by this model. Includes lazy-authored
+ * instance elements
+ */
+ readonly attribute nsCOMArrayPtr instanceList;
+
+ /**
+ * Add an instance element to the model's instance list
+ * @param aInstanceElement The instance element to add to the list
+ */
+ void addInstanceElement(in nsIInstanceElementPrivate aInstanceElement);
+
+ /**
+ * This attribute is set when the model's instance was lazy authored
+ */
+ readonly attribute boolean lazyAuthored;
};
diff --git a/mozilla/extensions/xforms/nsXFormsControlStub.cpp b/mozilla/extensions/xforms/nsXFormsControlStub.cpp
index 769572aa5cf..34eec696556 100644
--- a/mozilla/extensions/xforms/nsXFormsControlStub.cpp
+++ b/mozilla/extensions/xforms/nsXFormsControlStub.cpp
@@ -159,6 +159,19 @@ nsXFormsControlStubBase::ResetBoundNode(const nsString &aBindAttribute,
if (mBoundNode && mModel) {
mModel->SetStates(this, mBoundNode);
+ } else if (mModel) {
+ // we should have been successful. Must be pointing to a node that
+ // doesn't exist in the instance document. Disable the control
+ // per 4.2.2 in the spec
+
+ // Set pseudo class
+ ///
+ /// @bug Set via attributes right now. Bug 271720. (XXX)
+ mElement->SetAttribute(NS_LITERAL_STRING("disabled"),
+ NS_LITERAL_STRING("1"));
+ mElement->RemoveAttribute(NS_LITERAL_STRING("enabled"));
+ // Dispatch event
+ nsXFormsUtils::DispatchEvent(mElement, eEvent_Disabled);
}
if (aResult) {
diff --git a/mozilla/extensions/xforms/nsXFormsInstanceElement.cpp b/mozilla/extensions/xforms/nsXFormsInstanceElement.cpp
index 6a79007a3bf..d099026e09a 100644
--- a/mozilla/extensions/xforms/nsXFormsInstanceElement.cpp
+++ b/mozilla/extensions/xforms/nsXFormsInstanceElement.cpp
@@ -140,9 +140,9 @@ nsXFormsInstanceElement::OnCreated(nsIXTFGenericElementWrapper *aWrapper)
{
aWrapper->SetNotificationMask(nsIXTFElement::NOTIFY_ATTRIBUTE_SET |
nsIXTFElement::NOTIFY_ATTRIBUTE_REMOVED |
+ nsIXTFElement::NOTIFY_PARENT_CHANGED |
nsIXTFElement::NOTIFY_BEGIN_ADDING_CHILDREN |
nsIXTFElement::NOTIFY_DONE_ADDING_CHILDREN);
- // XXX observe nsIXTFElement::NOTIFY_PARENT_CHANGED ??
nsCOMPtr node;
aWrapper->GetElementNode(getter_AddRefs(node));
@@ -157,6 +157,23 @@ nsXFormsInstanceElement::OnCreated(nsIXTFGenericElementWrapper *aWrapper)
return NS_OK;
}
+NS_IMETHODIMP
+nsXFormsInstanceElement::ParentChanged(nsIDOMElement *aNewParent)
+{
+ if (!aNewParent)
+ return NS_OK;
+
+ // Once we are set up in the DOM, can find the model and make sure that this
+ // instance is on the list of instance elements that model keeps
+ nsCOMPtr model = GetModel();
+ NS_ENSURE_TRUE(model, NS_ERROR_FAILURE);
+ nsCOMPtr instance =
+ NS_STATIC_CAST(nsIInstanceElementPrivate*, this);
+ model->AddInstanceElement(this);
+
+ return NS_OK;
+}
+
// nsIInterfaceRequestor
NS_IMETHODIMP
@@ -298,10 +315,11 @@ nsXFormsInstanceElement::RestoreOriginalDocument()
{
nsresult rv = NS_OK;
- // This is called when xforms-ready is received by the model. By now we know
- // that the instance document, whether external or inline, is loaded into
- // mDocument. Get the root node, clone it, and insert it into our copy of
- // the document. This is the magic behind getting xforms-reset to work.
+ // This is called when xforms-reset is received by the model. We assume
+ // that the backup of the instance document has been populated and is
+ // loaded into mOriginalDocument. Get the backup's root node, clone it, and
+ // insert it into the live copy of the instance document. This is the magic
+ // behind getting xforms-reset to work.
if(mDocument && mOriginalDocument) {
nsCOMPtr newNode, instanceRootNode, nodeReturn;
nsCOMPtr instanceRoot;
@@ -332,6 +350,12 @@ nsXFormsInstanceElement::RestoreOriginalDocument()
return rv;
}
+NS_IMETHODIMP
+nsXFormsInstanceElement::GetElement(nsIDOMElement **aElement)
+{
+ NS_IF_ADDREF(*aElement = mElement);
+ return NS_OK;
+}
// private methods
@@ -446,7 +470,7 @@ nsXFormsInstanceElement::CreateInstanceDocument()
NS_ENSURE_SUCCESS(rv, rv);
rv = domImpl->CreateDocument(EmptyString(), EmptyString(), nsnull,
- getter_AddRefs(mDocument));
+ getter_AddRefs(mDocument));
NS_ENSURE_SUCCESS(rv, rv);
// I don't know if not being able to create a backup document is worth
diff --git a/mozilla/extensions/xforms/nsXFormsInstanceElement.h b/mozilla/extensions/xforms/nsXFormsInstanceElement.h
index 27853e67899..bb3a369bc62 100644
--- a/mozilla/extensions/xforms/nsXFormsInstanceElement.h
+++ b/mozilla/extensions/xforms/nsXFormsInstanceElement.h
@@ -78,6 +78,7 @@ public:
NS_IMETHOD BeginAddingChildren();
NS_IMETHOD DoneAddingChildren();
NS_IMETHOD OnCreated(nsIXTFGenericElementWrapper *aWrapper);
+ NS_IMETHOD ParentChanged(nsIDOMElement *aNewParent);
nsXFormsInstanceElement() NS_HIDDEN;
diff --git a/mozilla/extensions/xforms/nsXFormsLazyInstanceElement.cpp b/mozilla/extensions/xforms/nsXFormsLazyInstanceElement.cpp
new file mode 100644
index 00000000000..6a85a8d0731
--- /dev/null
+++ b/mozilla/extensions/xforms/nsXFormsLazyInstanceElement.cpp
@@ -0,0 +1,191 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla XForms support.
+ *
+ * The Initial Developer of the Original Code is
+ * IBM Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Aaron Reed
+ *
+ * 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
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsXFormsLazyInstanceElement.h"
+#include "nsIDOMElement.h"
+#include "nsIDocument.h"
+#include "nsIDOMDOMImplementation.h"
+
+NS_IMPL_ISUPPORTS_INHERITED2(nsXFormsLazyInstanceElement,
+ nsXFormsStubElement,
+ nsIInstanceElementPrivate,
+ nsIInterfaceRequestor)
+
+nsXFormsLazyInstanceElement::nsXFormsLazyInstanceElement()
+{
+}
+
+// nsIInstanceElementPrivate
+
+NS_IMETHODIMP
+nsXFormsLazyInstanceElement::GetDocument(nsIDOMDocument **aDocument)
+{
+ NS_IF_ADDREF(*aDocument = mDocument);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXFormsLazyInstanceElement::SetDocument(nsIDOMDocument *aDocument)
+{
+ mDocument = aDocument;
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP
+nsXFormsLazyInstanceElement::BackupOriginalDocument()
+{
+ nsresult rv = NS_OK;
+
+ // This is called when xforms-ready is received by the model. By now we know
+ // that the lazy instance document has been populated and is loaded into
+ // mDocument. Get the root node, clone it, and insert it into our copy of
+ // the document. This is the magic behind getting xforms-reset to work.
+ if(mDocument && mOriginalDocument) {
+ nsCOMPtr newNode;
+ nsCOMPtr instanceRoot;
+ rv = mDocument->GetDocumentElement(getter_AddRefs(instanceRoot));
+ NS_ENSURE_SUCCESS(rv, rv);
+ NS_ENSURE_TRUE(instanceRoot, NS_ERROR_FAILURE);
+
+ nsCOMPtr nodeReturn;
+ rv = instanceRoot->CloneNode(PR_TRUE, getter_AddRefs(newNode));
+ if(NS_SUCCEEDED(rv)) {
+ rv = mOriginalDocument->AppendChild(newNode, getter_AddRefs(nodeReturn));
+ NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
+ "failed to set up original instance document");
+ }
+ }
+ return rv;
+}
+
+NS_IMETHODIMP
+nsXFormsLazyInstanceElement::RestoreOriginalDocument()
+{
+ nsresult rv = NS_OK;
+
+ // This is called when xforms-reset is received by the model. We assume
+ // that the backup of the lazy instance document has been populated and is
+ // loaded into mOriginalDocument. Get the backup's root node, clone it, and
+ // insert it into the live copy of the instance document. This is the magic
+ // behind getting xforms-reset to work.
+ if(mDocument && mOriginalDocument) {
+ nsCOMPtr newNode, instanceRootNode, nodeReturn;
+ nsCOMPtr instanceRoot;
+
+ // first remove all the old stuff
+ rv = mDocument->GetDocumentElement(getter_AddRefs(instanceRoot));
+ if(NS_SUCCEEDED(rv)) {
+ if(instanceRoot) {
+ rv = mDocument->RemoveChild(instanceRoot, getter_AddRefs(nodeReturn));
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ }
+
+ // now all of the garbage is out o' there! Put the original data back
+ // into mDocument
+ rv = mOriginalDocument->GetDocumentElement(getter_AddRefs(instanceRoot));
+ NS_ENSURE_SUCCESS(rv, rv);
+ NS_ENSURE_TRUE(instanceRoot, NS_ERROR_FAILURE);
+ instanceRootNode = do_QueryInterface(instanceRoot);
+
+ rv = instanceRootNode->CloneNode(PR_TRUE, getter_AddRefs(newNode));
+ if(NS_SUCCEEDED(rv)) {
+ rv = mDocument->AppendChild(newNode, getter_AddRefs(nodeReturn));
+ NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
+ "failed to restore original instance document");
+ }
+ }
+ return rv;
+}
+
+NS_IMETHODIMP
+nsXFormsLazyInstanceElement::GetElement(nsIDOMElement **aElement)
+{
+ *aElement = nsnull;
+ return NS_OK;
+}
+
+// nsIInterfaceRequestor
+
+NS_IMETHODIMP
+nsXFormsLazyInstanceElement::GetInterface(const nsIID & aIID, void **aResult)
+{
+ *aResult = nsnull;
+ return QueryInterface(aIID, aResult);
+}
+
+nsresult
+nsXFormsLazyInstanceElement::CreateLazyInstanceDocument(nsIDOMDocument *aXFormsDocument)
+{
+ NS_ENSURE_ARG(aXFormsDocument);
+
+ // Do not try to load an instance document if the current document is not
+ // associated with a DOM window. This could happen, for example, if some
+ // XForms document loaded itself as instance data (which is what the Forms
+ // 1.0 testsuite does).
+ nsCOMPtr d = do_QueryInterface(aXFormsDocument);
+ if (d && !d->GetScriptGlobalObject())
+ return NS_ERROR_FAILURE;
+
+ nsCOMPtr domImpl;
+ nsresult rv = aXFormsDocument->GetImplementation(getter_AddRefs(domImpl));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = domImpl->CreateDocument(EmptyString(), EmptyString(), nsnull,
+ getter_AddRefs(mDocument));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Lazy authored instance documents have a root named "instanceData"
+ nsCOMPtr instanceDataElement;
+ nsCOMPtr childReturn;
+ rv = mDocument->CreateElementNS(EmptyString(),
+ NS_LITERAL_STRING("instanceData"),
+ getter_AddRefs(instanceDataElement));
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = mDocument->AppendChild(instanceDataElement, getter_AddRefs(childReturn));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // I don't know if not being able to create a backup document is worth
+ // failing this function. Since it probably won't be used often, we'll
+ // let it slide. But it probably does mean that things are going south
+ // with the browser.
+ domImpl->CreateDocument(EmptyString(), EmptyString(), nsnull,
+ getter_AddRefs(mOriginalDocument));
+ return rv;
+}
diff --git a/mozilla/extensions/xforms/nsXFormsLazyInstanceElement.h b/mozilla/extensions/xforms/nsXFormsLazyInstanceElement.h
new file mode 100644
index 00000000000..e4a4cf4b759
--- /dev/null
+++ b/mozilla/extensions/xforms/nsXFormsLazyInstanceElement.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla XForms support.
+ *
+ * The Initial Developer of the Original Code is
+ * IBM Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Aaron Reed
+ *
+ * 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
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsXFormsLazyInstanceElement_h_
+#define nsXFormsLazyInstanceElement_h_
+
+#include "nsXFormsStubElement.h"
+#include "nsIDOMDocument.h"
+#include "nsCOMPtr.h"
+#include "nsIModelElementPrivate.h"
+#include "nsIInstanceElementPrivate.h"
+#include "nsIInterfaceRequestor.h"
+
+class nsIDOMElement;
+
+/**
+ * Implementation of the XForms \ element created through lazy
+ * authoring. It creates an instance document by cloning the contained
+ * instance data.
+ */
+
+class nsXFormsLazyInstanceElement : public nsXFormsStubElement,
+ public nsIInstanceElementPrivate,
+ public nsIInterfaceRequestor
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_NSIINSTANCEELEMENTPRIVATE
+ NS_DECL_NSIINTERFACEREQUESTOR
+
+ NS_HIDDEN_(nsresult) CreateLazyInstanceDocument(nsIDOMDocument *aXFormsDocument);
+
+ nsXFormsLazyInstanceElement() NS_HIDDEN;
+
+private:
+
+ nsCOMPtr mDocument;
+ nsCOMPtr mOriginalDocument;
+};
+
+#endif
diff --git a/mozilla/extensions/xforms/nsXFormsModelElement.cpp b/mozilla/extensions/xforms/nsXFormsModelElement.cpp
index a77f2ad710e..8198c1acb39 100644
--- a/mozilla/extensions/xforms/nsXFormsModelElement.cpp
+++ b/mozilla/extensions/xforms/nsXFormsModelElement.cpp
@@ -76,6 +76,7 @@
#include "nsISchema.h"
#include "nsAutoPtr.h"
#include "nsArray.h"
+#include "nsXFormsLazyInstanceElement.h"
#ifdef DEBUG
//#define DEBUG_MODEL
@@ -248,7 +249,9 @@ nsXFormsModelElement::nsXFormsModelElement()
mSchemaTotal(0),
mPendingInstanceCount(0),
mDocumentLoaded(PR_FALSE),
- mNeedsRefresh(PR_FALSE)
+ mNeedsRefresh(PR_FALSE),
+ mInstanceList(16),
+ mLazyModel(PR_FALSE)
{
}
@@ -268,6 +271,8 @@ nsXFormsModelElement::OnDestroyed()
mElement = nsnull;
mSchemas = nsnull;
+
+ mInstanceList.Clear();
return NS_OK;
}
@@ -398,6 +403,22 @@ nsXFormsModelElement::DoneAddingChildren()
}
}
+ // If all of the children are added and there aren't any instance elements,
+ // yet, then we need to make sure that one is ready in case the form author
+ // is using lazy authoring.
+ PRUint32 instCount = mInstanceList.Count();
+ if (!instCount) {
+ nsCOMPtr domDoc;
+ mElement->GetOwnerDocument(getter_AddRefs(domDoc));
+ if (domDoc) {
+ nsXFormsLazyInstanceElement *lazyInstance =
+ new nsXFormsLazyInstanceElement();
+ lazyInstance->CreateLazyInstanceDocument(domDoc);
+ AddInstanceElement(lazyInstance);
+ mLazyModel = PR_TRUE;
+ }
+ }
+
// 2. construct an XPath data model from inline or external initial instance
// data. This is done by our child instance elements as they are inserted
// into the document, and all of the instances will be processed by this
@@ -990,32 +1011,34 @@ nsXFormsModelElement::FindInstanceElement(const nsAString &aID,
{
*aElement = nsnull;
- nsCOMPtr children;
- mElement->GetChildNodes(getter_AddRefs(children));
+ PRUint32 instCount = mInstanceList.Count();
+ if (instCount) {
+ nsCOMPtr element;
+ nsAutoString id;
+ for (int i = 0; i < instCount; ++i) {
+ nsIInstanceElementPrivate* instEle = mInstanceList.ObjectAt(i);
+ instEle->GetElement(getter_AddRefs(element));
- if (!children)
- return NS_OK;
-
- PRUint32 childCount = 0;
- children->GetLength(&childCount);
-
- nsCOMPtr node;
- nsCOMPtr element;
- nsAutoString id;
-
- for (PRUint32 i = 0; i < childCount; ++i) {
- children->Item(i, getter_AddRefs(node));
- NS_ASSERTION(node, "incorrect NodeList length?");
-
- element = do_QueryInterface(node);
- if (!element)
- continue;
-
- element->GetAttribute(NS_LITERAL_STRING("id"), id);
- if (aID.IsEmpty() || aID.Equals(id)) {
- CallQueryInterface(element, aElement);
- if (*aElement)
+ if (aID.IsEmpty()) {
+ NS_ADDREF(instEle);
+ *aElement = instEle;
break;
+ } else if (!element) {
+ // this should only happen if the instance on the list is lazy authored
+ // and as far as I can tell, a lazy authored instance should be the
+ // first (and only) instance in the model and unable to have an ID.
+ // But that isn't clear to me reading the spec, so for now
+ // we'll play it safe in case the WG more clearly defines lazy authoring
+ // in the future.
+ continue;
+ }
+
+ element->GetAttribute(NS_LITERAL_STRING("id"), id);
+ if (aID.Equals(id)) {
+ NS_ADDREF(instEle);
+ *aElement = instEle;
+ break;
+ }
}
}
@@ -1155,6 +1178,12 @@ nsXFormsModelElement::GetContext(nsAString &aModelID,
return NS_OK;
}
+NS_IMETHODIMP
+nsXFormsModelElement::GetLazyAuthored(PRBool *aLazyInstance)
+{
+ *aLazyInstance = mLazyModel;
+ return NS_OK;
+}
// internal methods
@@ -1244,40 +1273,23 @@ nsXFormsModelElement::Ready()
void
nsXFormsModelElement::BackupOrRestoreInstanceData(PRBool restore)
{
- // I imagine that this can be done more elegantly. But in the end, the
- // bulk of the work is walking the model's children looking for instance
- // elements. After one is found, just need to ask the instance element to
- // backup or restore.
- nsCOMPtr children;
- mElement->GetChildNodes(getter_AddRefs(children));
+ PRUint32 instCount = mInstanceList.Count();
+ if (instCount) {
+ for (int i = 0; i < instCount; ++i) {
+ nsIInstanceElementPrivate *instance = mInstanceList.ObjectAt(i);
- if (!children)
- return;
-
- PRUint32 childCount = 0;
- children->GetLength(&childCount);
-
- nsCOMPtr node;
- nsCOMPtr instance;
-
- for (PRUint32 i = 0; i < childCount; ++i) {
- children->Item(i, getter_AddRefs(node));
- NS_ASSERTION(node, "incorrect NodeList length?");
-
- instance = do_QueryInterface(node);
- if (!instance)
- continue;
-
- // Don't know what to do with error if we get one.
- // Restore/BackupOriginalDocument will already output warnings.
- if(restore) {
- instance->RestoreOriginalDocument();
- }
- else {
- instance->BackupOriginalDocument();
+ // Don't know what to do with error if we get one.
+ // Restore/BackupOriginalDocument will already output warnings.
+ if(restore) {
+ instance->RestoreOriginalDocument();
+ }
+ else {
+ instance->BackupOriginalDocument();
+ }
}
}
+
}
@@ -1614,6 +1626,26 @@ nsXFormsModelElement::SetStates(nsIXFormsControl *aControl, nsIDOMNode *aBoundNo
return SetStatesInternal(aControl, aBoundNode, PR_TRUE);
}
+NS_IMETHODIMP
+nsXFormsModelElement::GetInstanceList(nsCOMArray **aInstanceList)
+{
+ if (aInstanceList) {
+ *aInstanceList = &mInstanceList;
+ }
+ return NS_OK;
+}
+
+nsresult
+nsXFormsModelElement::AddInstanceElement(nsIInstanceElementPrivate *aInstEle)
+{
+ // always append to the end of the list. We need to keep the elements in
+ // document order since the first instance element is the default instance
+ // document for the model.
+ mInstanceList.AppendObject(aInstEle);
+
+ return NS_OK;
+}
+
/* static */ void
nsXFormsModelElement::Startup()
{
diff --git a/mozilla/extensions/xforms/nsXFormsModelElement.h b/mozilla/extensions/xforms/nsXFormsModelElement.h
index 0aacac6989c..e0f56a02051 100644
--- a/mozilla/extensions/xforms/nsXFormsModelElement.h
+++ b/mozilla/extensions/xforms/nsXFormsModelElement.h
@@ -209,6 +209,15 @@ private:
// This flag indicates whether a xforms-rebuild has been called, but no
// xforms-revalidate yet
PRBool mNeedsRefresh;
+
+ /**
+ * List of instance elements contained by this model, including lazy-authored
+ * instance elements.
+ */
+ nsCOMArray mInstanceList;
+
+ /** Indicates whether the model's instance was built by lazy authoring */
+ PRBool mLazyModel;
};
/**
diff --git a/mozilla/extensions/xforms/nsXFormsSubmissionElement.cpp b/mozilla/extensions/xforms/nsXFormsSubmissionElement.cpp
index 449ee89a2ca..17c5f02a805 100644
--- a/mozilla/extensions/xforms/nsXFormsSubmissionElement.cpp
+++ b/mozilla/extensions/xforms/nsXFormsSubmissionElement.cpp
@@ -775,11 +775,20 @@ nsXFormsSubmissionElement::SerializeDataXML(nsIDOMNode *data,
// add namespaces from the main document to the submission document, but only
// if the instance data is local, not remote.
- PRBool hasSrc = PR_FALSE;
+ PRBool serialize = PR_FALSE;
nsCOMPtr instanceElement(do_QueryInterface(instanceNode));
- instanceElement->HasAttribute(NS_LITERAL_STRING("src"), &hasSrc);
- if (!hasSrc) {
+ // make sure that this is a DOMElement. It won't be if it was lazy
+ // authored. Lazy authored instance documents don't inherit namespaces
+ // from parent nodes or the original document (in formsPlayer and Novell,
+ // at least).
+ if (instanceElement) {
+ PRBool hasSrc = PR_FALSE;
+ instanceElement->HasAttribute(NS_LITERAL_STRING("src"), &hasSrc);
+ serialize = !hasSrc;
+ }
+
+ if (serialize) {
rv = AddNameSpaces(newDocElm, node);
NS_ENSURE_SUCCESS(rv, rv);
diff --git a/mozilla/extensions/xforms/nsXFormsUtilityService.cpp b/mozilla/extensions/xforms/nsXFormsUtilityService.cpp
index 2c082170fe4..847b0ae9abc 100644
--- a/mozilla/extensions/xforms/nsXFormsUtilityService.cpp
+++ b/mozilla/extensions/xforms/nsXFormsUtilityService.cpp
@@ -116,12 +116,10 @@ nsXFormsUtilityService::IsNodeAssocWithModel( nsIDOMNode *aNode,
if (modelNode && (modelNode == aModel)) {
*aModelAssocWithNode = PR_TRUE;
- }
- else {
+ } else {
*aModelAssocWithNode = PR_FALSE;
}
- }
- else {
+ } else {
// We are assuming that if the node coming in isn't a proper XForms element,
// then it is an instance element in an instance doc. Now we just have
// to determine if the given model contains this instance document.
@@ -137,26 +135,16 @@ nsXFormsUtilityService::IsNodeAssocWithModel( nsIDOMNode *aNode,
// document. If it is equal to the document that contains aNode,
// then aNode is associated with this aModel element and we can return
// true.
- nsCOMPtr children;
- aModel->GetChildNodes(getter_AddRefs(children));
-
- if (!children)
- return NS_OK;
-
- PRUint32 childCount = 0;
- children->GetLength(&childCount);
-
- nsCOMPtr node;
+ nsCOMPtrmodel = do_QueryInterface(modelEle);
nsCOMPtr instElement;
nsCOMPtr instDocument;
-
- for (PRUint32 i = 0; i < childCount; ++i) {
- children->Item(i, getter_AddRefs(node));
- NS_ASSERTION(node, "incorrect NodeList length?");
-
- instElement = do_QueryInterface(node);
- if (!instElement)
- continue;
+
+ nsCOMArray *instList = nsnull;
+ model->GetInstanceList(&instList);
+ NS_ENSURE_TRUE(instList, NS_ERROR_FAILURE);
+
+ for (int i = 0; i < instList->Count(); ++i) {
+ instElement = instList->ObjectAt(i);
instElement->GetDocument(getter_AddRefs(instDocument));
if (instDocument) {
diff --git a/mozilla/extensions/xforms/nsXFormsUtils.cpp b/mozilla/extensions/xforms/nsXFormsUtils.cpp
index 0368cbe0688..1d9b8358267 100644
--- a/mozilla/extensions/xforms/nsXFormsUtils.cpp
+++ b/mozilla/extensions/xforms/nsXFormsUtils.cpp
@@ -87,6 +87,7 @@
#include "nsIURI.h"
#include "nsIPrivateDOMEvent.h"
#include "nsIDOMNamedNodeMap.h"
+#include "nsIParserService.h"
#define CANCELABLE 0x01
#define BUBBLES 0x02
@@ -536,6 +537,73 @@ nsXFormsUtils::EvaluateNodeBinding(nsIDOMElement *aElement,
aDeps,
aIndexesUsed);
+ // If the evaluation failed because the node wasn't there and we should be
+ // lazy authoring, then create it (if the situation qualifies, of course).
+ // Novell only allows lazy authoring of single bound nodes.
+ if (aResultType == nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE) {
+ if (res) {
+ nsCOMPtr node;
+ rv = res->GetSingleNodeValue(getter_AddRefs(node));
+ if (NS_SUCCEEDED(rv) && !node) {
+ PRBool lazy = PR_FALSE;
+ if (*aModel)
+ (*aModel)->GetLazyAuthored(&lazy);
+ if (lazy) {
+ // according to sec 4.2.2 in the spec, "An instance data element node
+ // will be created using the binding expression from the user
+ // interface control as the name. If the name is not a valid QName,
+ // processing halts with an exception (xforms-binding-exception)"
+ nsCOMPtr parserService =
+ do_GetService(NS_PARSERSERVICE_CONTRACTID);
+ if (NS_SUCCEEDED(rv) && parserService) {
+ const PRUnichar* colon;
+ rv = parserService->CheckQName(expr, PR_TRUE, &colon);
+ if (NS_SUCCEEDED(rv)) {
+ nsAutoString namespaceURI(EmptyString());
+
+ // if we detect a namespace, we'll add it to the node, otherwise
+ // we'll use the empty namespace. If we should have gotten a
+ // namespace and didn't, then we might as well give up.
+ if (colon) {
+ nsCOMPtr dom3node = do_QueryInterface(aElement);
+ rv = dom3node->LookupNamespaceURI(Substring(expr.get(), colon),
+ namespaceURI);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ if (NS_SUCCEEDED(rv)) {
+ nsCOMArray *instList = nsnull;
+ (*aModel)->GetInstanceList(&instList);
+ nsCOMPtr instance =
+ instList->ObjectAt(0);
+ nsCOMPtr domdoc;
+ instance->GetDocument(getter_AddRefs(domdoc));
+ nsCOMPtr instanceDataEle;
+ nsCOMPtr childReturn;
+ rv = domdoc->CreateElementNS(namespaceURI, expr,
+ getter_AddRefs(instanceDataEle));
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr instanceRoot;
+ rv = domdoc->GetDocumentElement(getter_AddRefs(instanceRoot));
+ rv = instanceRoot->AppendChild(instanceDataEle,
+ getter_AddRefs(childReturn));
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ // now that we inserted the lazy authored node, try to bind
+ // again
+ res = EvaluateXPath(expr, contextNode, aElement, aResultType,
+ contextPosition, contextSize, aDeps,
+ aIndexesUsed);
+ } else {
+ nsXFormsUtils::DispatchEvent(aElement, eEvent_BindingException);
+ }
+ }
+ }
+ }
+ }
+ }
+
res.swap(*aResult); // exchanges ref
return NS_OK;
@@ -1116,22 +1184,14 @@ nsXFormsUtils::GetInstanceNodeForData(nsIDOMNode *aInstanceDataNode,
instanceDoc = do_QueryInterface(aInstanceDataNode);
NS_ENSURE_TRUE(instanceDoc, NS_ERROR_UNEXPECTED);
- nsCOMPtr modelElem = do_QueryInterface(aModel);
- NS_ENSURE_STATE(modelElem);
- nsCOMPtr nodeList;
- nsresult rv = modelElem->GetElementsByTagNameNS(NS_LITERAL_STRING(NS_NAMESPACE_XFORMS),
- NS_LITERAL_STRING("instance"),
- getter_AddRefs(nodeList));
- NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMArray *instList = nsnull;
+ aModel->GetInstanceList(&instList);
+ NS_ENSURE_TRUE(instList, NS_ERROR_FAILURE);
- PRUint32 childCount = 0;
- nodeList->GetLength(&childCount);
PRUint32 i;
+ PRUint32 childCount = instList->Count();
for (i = 0; i < childCount; ++i) {
- nodeList->Item(i, aInstanceNode);
- nsCOMPtr instPriv = do_QueryInterface(*aInstanceNode);
- if (!instPriv)
- continue;
+ nsCOMPtr instPriv = instList->ObjectAt(i);
nsCOMPtr tmpDoc;
instPriv->GetDocument(getter_AddRefs(tmpDoc));