diff --git a/extensions/xforms/Makefile.in b/extensions/xforms/Makefile.in index 192566f1ef33..d255b3d5dcd4 100644 --- a/extensions/xforms/Makefile.in +++ b/extensions/xforms/Makefile.in @@ -88,6 +88,7 @@ XPIDLSRCS = \ nsIXFormsRepeatItemElement.idl \ nsIXFormsSubmitElement.idl \ nsIXFormsSubmissionElement.idl \ + nsIXFormsControlBase.idl \ $(NULL) CPPSRCS = \ diff --git a/extensions/xforms/nsIXFormsContextControl.idl b/extensions/xforms/nsIXFormsContextControl.idl index 8fc80e7a8eb6..6130fbf28641 100644 --- a/extensions/xforms/nsIXFormsContextControl.idl +++ b/extensions/xforms/nsIXFormsContextControl.idl @@ -37,7 +37,7 @@ * ***** END LICENSE BLOCK ***** */ -#include "nsISupports.idl" +#include "nsIXFormsControlBase.idl" interface nsIDOMNode; @@ -45,7 +45,7 @@ interface nsIDOMNode; * Interface for elements that sets the XPath context of its children. */ [uuid(38a904ba-147c-4c7f-9356-9fff88107868)] -interface nsIXFormsContextControl : nsISupports +interface nsIXFormsContextControl : nsIXFormsControlBase { /** * Used by children to retrieve the context of their parent. diff --git a/extensions/xforms/nsIXFormsControl.idl b/extensions/xforms/nsIXFormsControl.idl index 5ae8d6ca10f0..1c7a6614870c 100644 --- a/extensions/xforms/nsIXFormsControl.idl +++ b/extensions/xforms/nsIXFormsControl.idl @@ -52,18 +52,6 @@ interface nsIDOMElement; [uuid(8377c845-5d55-4eee-9a76-0f86751dcbc8)] interface nsIXFormsControl : nsIXFormsContextControl { - /** - * This tells the form control to update its node binding based on the - * current instance data. - */ - void bind(); - - /** - * This tells the form control to update its state based on the current - * instance data. - */ - void refresh(); - /** * Tries to move focus to form control and returns true if succeeded. */ diff --git a/extensions/xforms/nsIXFormsControlBase.idl b/extensions/xforms/nsIXFormsControlBase.idl new file mode 100644 index 000000000000..2314ef07fd18 --- /dev/null +++ b/extensions/xforms/nsIXFormsControlBase.idl @@ -0,0 +1,53 @@ +/* -*- Mode: IDL; 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): + * + * 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 "nsISupports.idl" + +[uuid(b8540fca-a671-4a1d-8471-6e89820f0848)] +interface nsIXFormsControlBase : nsISupports +{ + /** + * This tells the form control to update its node binding based on the + * current instance data. + */ + void bind(); + + /** + * This tells the form control to update its state based on the current + * instance data. + */ + void refresh(); +}; diff --git a/extensions/xforms/nsXFormsChoicesElement.cpp b/extensions/xforms/nsXFormsChoicesElement.cpp index 2908616cbfd1..6ec3ce63de6f 100644 --- a/extensions/xforms/nsXFormsChoicesElement.cpp +++ b/extensions/xforms/nsXFormsChoicesElement.cpp @@ -72,12 +72,13 @@ public: NS_IMETHOD BeginAddingChildren(); NS_IMETHOD DoneAddingChildren(); + // nsIXFormsControlBase overrides + NS_IMETHOD Refresh(); + // nsIXFormsSelectChild NS_DECL_NSIXFORMSSELECTCHILD private: - NS_HIDDEN_(void) Refresh(); - nsIDOMElement *mElement; nsCOMPtr mOptGroup; }; @@ -318,15 +319,14 @@ nsXFormsChoicesElement::SetContext(nsIDOMElement *aContextNode, // internal methods -void +NS_IMETHODIMP nsXFormsChoicesElement::Refresh() { // Remove any existing first child that is not an option, to clear out // any existing label. nsCOMPtr firstChild, child2; nsresult rv = mOptGroup->GetFirstChild(getter_AddRefs(firstChild)); - if (NS_FAILED(rv)) - return; + NS_ENSURE_SUCCESS(rv, rv); nsAutoString value; @@ -343,8 +343,7 @@ nsXFormsChoicesElement::Refresh() nsCOMPtr children; rv = mElement->GetChildNodes(getter_AddRefs(children)); - if (NS_FAILED(rv)) - return; + NS_ENSURE_SUCCESS(rv, rv); PRUint32 childCount; children->GetLength(&childCount); @@ -360,6 +359,8 @@ nsXFormsChoicesElement::Refresh() mOptGroup->InsertBefore(child2, firstChild, getter_AddRefs(child)); } } + + return NS_OK; } NS_HIDDEN_(nsresult) diff --git a/extensions/xforms/nsXFormsControlStub.cpp b/extensions/xforms/nsXFormsControlStub.cpp index 8bf716e465eb..769572aa5cf8 100644 --- a/extensions/xforms/nsXFormsControlStub.cpp +++ b/extensions/xforms/nsXFormsControlStub.cpp @@ -207,13 +207,8 @@ nsXFormsControlStubBase::ProcessNodeBinding(const nsString &aBindingAtt nsCOMPtr domDoc; mElement->GetOwnerDocument(getter_AddRefs(domDoc)); - nsCOMPtr doc = do_QueryInterface(domDoc); - if (!doc) { - return NS_OK; - } - nsIDocument *test = NS_STATIC_CAST(nsIDocument *, - doc->GetProperty(nsXFormsAtoms::readyForBindProperty)); - if (!test) { + + if (!nsXFormsUtils::IsDocumentReadyForBind(domDoc)) { nsXFormsModelElement::DeferElementBind(domDoc, this); return NS_OK; } @@ -630,10 +625,11 @@ nsXFormsControlStubBase::MaybeRemoveFromModel(nsIAtom *aName, } } -NS_IMPL_ISUPPORTS_INHERITED2(nsXFormsControlStub, +NS_IMPL_ISUPPORTS_INHERITED3(nsXFormsControlStub, nsXFormsXMLVisualStub, nsIXFormsContextControl, - nsIXFormsControl) + nsIXFormsControl, + nsIXFormsControlBase) NS_IMPL_ISUPPORTS_INHERITED2(nsXFormsBindableControlStub, diff --git a/extensions/xforms/nsXFormsControlStub.h b/extensions/xforms/nsXFormsControlStub.h index 0cb3b089b64c..3889247ffc48 100644 --- a/extensions/xforms/nsXFormsControlStub.h +++ b/extensions/xforms/nsXFormsControlStub.h @@ -56,6 +56,7 @@ #include "nsXFormsUtils.h" #include "nsIXTFXMLVisualWrapper.h" #include "nsIXTFBindableElementWrapper.h" +#include "nsIXFormsControlBase.h" class nsIDOMEvent; class nsIDOMXPathResult; @@ -240,6 +241,7 @@ class nsXFormsControlStub : public nsXFormsControlStubBase, { public: NS_DECL_ISUPPORTS_INHERITED + // nsIXTFXMLVisual overrides /** This sets the notification mask and initializes mElement */ NS_IMETHOD OnCreated(nsIXTFXMLVisualWrapper *aWrapper) @@ -289,7 +291,12 @@ public: { return nsXFormsControlStubBase::AttributeRemoved(aName); } - + + NS_IMETHOD Bind() + { + return nsXFormsControlStubBase::Bind(); + } + /** Constructor */ nsXFormsControlStub() : nsXFormsControlStubBase() {}; }; diff --git a/extensions/xforms/nsXFormsItemElement.cpp b/extensions/xforms/nsXFormsItemElement.cpp index 5c6ecbd0cf08..76663b481a9d 100644 --- a/extensions/xforms/nsXFormsItemElement.cpp +++ b/extensions/xforms/nsXFormsItemElement.cpp @@ -83,11 +83,13 @@ public: NS_IMETHOD BeginAddingChildren(); NS_IMETHOD DoneAddingChildren(); + // nsIXFormsControlBase overrides + NS_IMETHOD Refresh(); + // nsIXFormsSelectChild NS_DECL_NSIXFORMSSELECTCHILD private: - NS_HIDDEN_(void) Refresh(); NS_HIDDEN_(nsresult) GetValue(nsString &aValue); nsIDOMElement *mElement; @@ -325,7 +327,7 @@ nsXFormsItemElement::GetValue(nsString &aValue) return NS_OK; } -void +NS_IMETHODIMP nsXFormsItemElement::Refresh() { // Clear out all of the existing option text @@ -338,8 +340,7 @@ nsXFormsItemElement::Refresh() nsCOMPtr children; nsresult rv = mElement->GetChildNodes(getter_AddRefs(children)); - if (NS_FAILED(rv)) - return; + NS_ENSURE_SUCCESS(rv, rv); PRUint32 childCount; children->GetLength(&childCount); @@ -377,6 +378,8 @@ nsXFormsItemElement::Refresh() nsCOMPtr childReturn; mOption->AppendChild(container, getter_AddRefs(childReturn)); + + return NS_OK; } NS_HIDDEN_(nsresult) diff --git a/extensions/xforms/nsXFormsItemSetElement.cpp b/extensions/xforms/nsXFormsItemSetElement.cpp index 7b668f211e6a..4074e74e8ef5 100644 --- a/extensions/xforms/nsXFormsItemSetElement.cpp +++ b/extensions/xforms/nsXFormsItemSetElement.cpp @@ -44,11 +44,16 @@ #include "nsIXTFGenericElementWrapper.h" #include "nsIDOMDocument.h" #include "nsIDOMNodeList.h" +#include "nsIDocument.h" #include "nsXFormsUtils.h" +#include "nsXFormsModelElement.h" #include "nsArray.h" +#include "nsIXFormsControlBase.h" +#include "nsIXFormsControl.h" class nsXFormsItemSetElement : public nsXFormsStubElement, - public nsIXFormsSelectChild + public nsIXFormsSelectChild, + public nsIXFormsControlBase { public: nsXFormsItemSetElement() : mElement(nsnull) {} @@ -66,19 +71,22 @@ public: NS_IMETHOD BeginAddingChildren(); NS_IMETHOD DoneAddingChildren(); + // nsIXFormsControlBase overrides + NS_IMETHOD Bind(); + NS_IMETHOD Refresh(); + // nsIXFormsSelectChild NS_DECL_NSIXFORMSSELECTCHILD private: - NS_HIDDEN_(void) Refresh(); - nsIDOMElement *mElement; nsCOMArray mItems; }; -NS_IMPL_ISUPPORTS_INHERITED1(nsXFormsItemSetElement, +NS_IMPL_ISUPPORTS_INHERITED2(nsXFormsItemSetElement, nsXFormsStubElement, - nsIXFormsSelectChild) + nsIXFormsSelectChild, + nsIXFormsControlBase) NS_IMETHODIMP nsXFormsItemSetElement::OnCreated(nsIXTFGenericElementWrapper *aWrapper) @@ -226,16 +234,30 @@ nsXFormsItemSetElement::SetContext(nsIDOMElement *aContextNode, // internal methods -void +NS_IMETHODIMP +nsXFormsItemSetElement::Bind() +{ + return NS_OK; +} + +NS_IMETHODIMP nsXFormsItemSetElement::Refresh() { mItems.Clear(); - // We need to create item elements for each element referenced by the // nodeset. Each of these items will create an anonymous HTML option element // which will return from GetAnonymousNodes. We then clone our template // content and insert the cloned content as children of the HTML option. + nsCOMPtr domDoc; + mElement->GetOwnerDocument(getter_AddRefs(domDoc)); + + if (!nsXFormsUtils::IsDocumentReadyForBind(domDoc)) { + // not ready to bind yet, defer + nsXFormsModelElement::DeferElementBind(domDoc, this); + return NS_OK; + } + nsCOMPtr model; nsCOMPtr result; nsXFormsUtils::EvaluateNodeBinding(mElement, @@ -245,8 +267,9 @@ nsXFormsItemSetElement::Refresh() nsIDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, getter_AddRefs(model), getter_AddRefs(result)); + if (!result) - return; + return NS_OK; nsCOMPtr node, templateNode, cloneNode; nsCOMPtr itemNode, itemWrapperNode; @@ -259,7 +282,7 @@ nsXFormsItemSetElement::Refresh() nsCOMPtr document; mElement->GetOwnerDocument(getter_AddRefs(document)); if (!document) - return; + return NS_OK; PRUint32 nodeCount; result->GetSnapshotLength(&nodeCount); @@ -273,7 +296,7 @@ nsXFormsItemSetElement::Refresh() getter_AddRefs(itemNode)); if (!itemNode) - return; + return NS_OK; nsCOMPtr modelElement = do_QueryInterface(model); nsAutoString modelID; @@ -296,6 +319,19 @@ nsXFormsItemSetElement::Refresh() mItems.AppendObject(item); } + + // refresh parent control, since we are being defered + nsCOMPtr parentNode; + mElement->GetParentNode(getter_AddRefs(parentNode)); + if (parentNode) { + + nsCOMPtr stub = do_QueryInterface(parentNode); + if (stub) { + stub->Refresh(); + } + } + + return NS_OK; } NS_HIDDEN_(nsresult) diff --git a/extensions/xforms/nsXFormsModelElement.cpp b/extensions/xforms/nsXFormsModelElement.cpp index 201bff36daa7..e4cbf35ef4b3 100644 --- a/extensions/xforms/nsXFormsModelElement.cpp +++ b/extensions/xforms/nsXFormsModelElement.cpp @@ -70,7 +70,6 @@ #include "nsXFormsUtils.h" #include "nsXFormsSchemaValidator.h" #include "nsIAttribute.h" - #include "nsISchemaLoader.h" #include "nsISchema.h" #include "nsAutoPtr.h" @@ -1565,7 +1564,7 @@ DeleteBindList(void *aObject, /* static */ nsresult nsXFormsModelElement::DeferElementBind(nsIDOMDocument *aDoc, - nsIXFormsControl *aControl) + nsIXFormsControlBase *aControl) { nsCOMPtr doc = do_QueryInterface(aDoc); @@ -1573,12 +1572,12 @@ nsXFormsModelElement::DeferElementBind(nsIDOMDocument *aDoc, return NS_ERROR_FAILURE; } - nsCOMArray *deferredBindList = - NS_STATIC_CAST(nsCOMArray *, + nsCOMArray *deferredBindList = + NS_STATIC_CAST(nsCOMArray *, doc->GetProperty(nsXFormsAtoms::deferredBindListProperty)); if (!deferredBindList) { - deferredBindList = new nsCOMArray(16); + deferredBindList = new nsCOMArray(16); NS_ENSURE_TRUE(deferredBindList, NS_ERROR_OUT_OF_MEMORY); doc->SetProperty(nsXFormsAtoms::deferredBindListProperty, deferredBindList, @@ -1605,16 +1604,16 @@ nsXFormsModelElement::ProcessDeferredBinds(nsIDOMDocument *aDoc) doc->SetProperty(nsXFormsAtoms::readyForBindProperty, doc); - nsCOMArray *deferredBindList = - NS_STATIC_CAST(nsCOMArray *, + nsCOMArray *deferredBindList = + NS_STATIC_CAST(nsCOMArray *, doc->GetProperty(nsXFormsAtoms::deferredBindListProperty)); if (deferredBindList) { for (int i = 0; i < deferredBindList->Count(); ++i) { - nsIXFormsControl *control = deferredBindList->ObjectAt(i); - if (control) { - control->Bind(); - control->Refresh(); + nsIXFormsControlBase *base = deferredBindList->ObjectAt(i); + if (base) { + base->Bind(); + base->Refresh(); } } diff --git a/extensions/xforms/nsXFormsModelElement.h b/extensions/xforms/nsXFormsModelElement.h index a434fa89ccde..7919474718be 100644 --- a/extensions/xforms/nsXFormsModelElement.h +++ b/extensions/xforms/nsXFormsModelElement.h @@ -94,6 +94,12 @@ public: NS_IMETHOD HandleDefault(nsIDOMEvent *aEvent, PRBool *aHandled); NS_IMETHOD OnCreated(nsIXTFGenericElementWrapper *aWrapper); + // nsIXFormsControlBase overrides + NS_IMETHOD Bind() { + // dummy method, so does nothing + return NS_OK; + }; + // Called after nsXFormsAtoms is registered static NS_HIDDEN_(void) Startup(); @@ -106,7 +112,7 @@ public: * @param aControl XForms control waiting to be bound */ static NS_HIDDEN_(nsresult) DeferElementBind(nsIDOMDocument *aDoc, - nsIXFormsControl *aControl); + nsIXFormsControlBase *aControl); private: diff --git a/extensions/xforms/nsXFormsStubElement.h b/extensions/xforms/nsXFormsStubElement.h index 1cf76c32bec0..5b1920622d4b 100644 --- a/extensions/xforms/nsXFormsStubElement.h +++ b/extensions/xforms/nsXFormsStubElement.h @@ -42,6 +42,7 @@ #include "nsIXTFGenericElement.h" #include "nsIXTFXMLVisual.h" #include "nsIXTFBindableElement.h" +#include "nsIXFormsControlBase.h" /** * An implementation of a generic non-UI XForms element. diff --git a/extensions/xforms/nsXFormsUtils.cpp b/extensions/xforms/nsXFormsUtils.cpp index 84cb6a18a02a..180d601ae23b 100644 --- a/extensions/xforms/nsXFormsUtils.cpp +++ b/extensions/xforms/nsXFormsUtils.cpp @@ -60,6 +60,7 @@ #include "nsIDOMSerializer.h" #include "nsIContent.h" #include "nsIAttribute.h" +#include "nsXFormsAtoms.h" #include "nsIXFormsContextControl.h" #include "nsIDOMDocumentEvent.h" @@ -1300,3 +1301,13 @@ nsXFormsUtils::ReportError(const nsString& aMessageName, const PRUnichar **aPara } } +/* static */ PRBool +nsXFormsUtils::IsDocumentReadyForBind(nsIDOMDocument *aDocument) +{ + nsCOMPtr doc = do_QueryInterface(aDocument); + + nsIDocument *test = NS_STATIC_CAST(nsIDocument *, + doc->GetProperty(nsXFormsAtoms::readyForBindProperty)); + return test ? PR_TRUE : PR_FALSE; +} + diff --git a/extensions/xforms/nsXFormsUtils.h b/extensions/xforms/nsXFormsUtils.h index 4809a532dc35..b1198158fd7d 100644 --- a/extensions/xforms/nsXFormsUtils.h +++ b/extensions/xforms/nsXFormsUtils.h @@ -411,6 +411,14 @@ public: nsXFormsUtils::ReportError(aMessageName, nsnull, 0, aElement, aElement, aErrorFlag); } + /** + * Returns whether the aDocument is ready to bind data (all instance documents + * loaded). + * + * @param aDocument Document to check + */ + static NS_HIDDEN_(PRBool) IsDocumentReadyForBind(nsIDOMDocument *aDocument); + }; #endif