From 89c8cacb044fb1f67af0a9e7143ee663c8d8fffd Mon Sep 17 00:00:00 2001 From: "allan%beaufour.dk" Date: Tue, 17 May 2005 11:30:43 +0000 Subject: [PATCH] Fix timing issues wrt. model placement. Bug 283737, r=smaug+me, a=mkaply, patch by aaronr@us.ibm.com, NPOTB git-svn-id: svn://10.0.0.236/trunk@173506 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/extensions/xforms/nsXFormsAtoms.cpp | 6 +- mozilla/extensions/xforms/nsXFormsAtoms.h | 2 + .../extensions/xforms/nsXFormsControlStub.cpp | 26 +++++-- .../xforms/nsXFormsModelElement.cpp | 70 +++++++++++++++++++ .../extensions/xforms/nsXFormsModelElement.h | 19 +++++ 5 files changed, 118 insertions(+), 5 deletions(-) diff --git a/mozilla/extensions/xforms/nsXFormsAtoms.cpp b/mozilla/extensions/xforms/nsXFormsAtoms.cpp index 3f1ab91d831..df250177018 100644 --- a/mozilla/extensions/xforms/nsXFormsAtoms.cpp +++ b/mozilla/extensions/xforms/nsXFormsAtoms.cpp @@ -59,6 +59,8 @@ nsIAtom *nsXFormsAtoms::selected; nsIAtom *nsXFormsAtoms::appearance; nsIAtom *nsXFormsAtoms::incremental; nsIAtom *nsXFormsAtoms::clazz; +nsIAtom *nsXFormsAtoms::deferredBindListProperty; +nsIAtom *nsXFormsAtoms::readyForBindProperty; const nsStaticAtom nsXFormsAtoms::Atoms_info[] = { { "src", &nsXFormsAtoms::src }, @@ -80,7 +82,9 @@ const nsStaticAtom nsXFormsAtoms::Atoms_info[] = { { "selected", &nsXFormsAtoms::selected }, { "appearance", &nsXFormsAtoms::appearance }, { "incremental", &nsXFormsAtoms::incremental }, - { "class", &nsXFormsAtoms::clazz } + { "class", &nsXFormsAtoms::clazz }, + { "DeferredBindListProperty", &nsXFormsAtoms::deferredBindListProperty }, + { "ReadyForBindProperty", &nsXFormsAtoms::readyForBindProperty } }; void diff --git a/mozilla/extensions/xforms/nsXFormsAtoms.h b/mozilla/extensions/xforms/nsXFormsAtoms.h index dc7956225df..731b951fe3c 100644 --- a/mozilla/extensions/xforms/nsXFormsAtoms.h +++ b/mozilla/extensions/xforms/nsXFormsAtoms.h @@ -64,6 +64,8 @@ class nsXFormsAtoms static NS_HIDDEN_(nsIAtom *) incremental; static NS_HIDDEN_(nsIAtom *) value; static NS_HIDDEN_(nsIAtom *) clazz; + static NS_HIDDEN_(nsIAtom *) deferredBindListProperty; + static NS_HIDDEN_(nsIAtom *) readyForBindProperty; static NS_HIDDEN_(void) InitAtoms(); diff --git a/mozilla/extensions/xforms/nsXFormsControlStub.cpp b/mozilla/extensions/xforms/nsXFormsControlStub.cpp index 5e3a7799200..0d90b3e5b62 100644 --- a/mozilla/extensions/xforms/nsXFormsControlStub.cpp +++ b/mozilla/extensions/xforms/nsXFormsControlStub.cpp @@ -47,6 +47,8 @@ #include "nsIDOMEventTarget.h" #include "nsIDOMXPathResult.h" #include "nsIXTFXMLVisualWrapper.h" +#include "nsIDocument.h" +#include "nsXFormsModelElement.h" /** This class is used to generate xforms-hint and xforms-help events.*/ class nsXFormsHintHelpListener : public nsIDOMEventListener { @@ -187,6 +189,25 @@ nsXFormsControlStub::ProcessNodeBinding(const nsString &aBindingAttr, { nsStringArray indexesUsed; + // let's not go through all of this rigamarol if we don't have a chance + // in heck of binding anyhow. Check to see if the models will be receptive + // to some binding. readyForBindProperty is set when they are. Make sure + // to return NS_OK so that we don't start complaining about binding + // failures in this situation. + + 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) { + nsXFormsModelElement::DeferElementBind(domDoc, this); + return NS_OK; + } + nsresult rv; rv = nsXFormsUtils::EvaluateNodeBinding(mElement, kElementFlags, @@ -205,14 +226,11 @@ nsXFormsControlStub::ProcessNodeBinding(const nsString &aBindingAttr, if (NS_SUCCEEDED(rv) && indexesUsed.Count()) { // add index listeners on repeat elements - nsCOMPtr doc; - mElement->GetOwnerDocument(getter_AddRefs(doc)); - NS_ENSURE_STATE(doc); for (PRInt32 i = 0; i < indexesUsed.Count(); ++i) { // Find the repeat element and add |this| as a listener nsCOMPtr repElem; - doc->GetElementById(*(indexesUsed[i]), getter_AddRefs(repElem)); + domDoc->GetElementById(*(indexesUsed[i]), getter_AddRefs(repElem)); nsCOMPtr rep(do_QueryInterface(repElem)); if (!rep) continue; diff --git a/mozilla/extensions/xforms/nsXFormsModelElement.cpp b/mozilla/extensions/xforms/nsXFormsModelElement.cpp index 6a368465e96..0d40d458f45 100644 --- a/mozilla/extensions/xforms/nsXFormsModelElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsModelElement.cpp @@ -1273,6 +1273,8 @@ nsXFormsModelElement::MaybeNotifyCompletion() NS_STATIC_CAST(nsXFormsModelElement *, models->ElementAt(i)); nsXFormsUtils::DispatchEvent(model->mElement, eEvent_ModelConstructDone); } + + nsXFormsModelElement::ProcessDeferredBinds(domDoc); } nsresult @@ -1497,6 +1499,74 @@ nsXFormsModelElement::Startup() sModelPropsList[eModel_p3ptype] = nsXFormsAtoms::p3ptype; } +static void +DeleteBindList(void *aObject, + nsIAtom *aPropertyName, + void *aPropertyValue, + void *aData) +{ + delete NS_STATIC_CAST(nsCOMArray *, aPropertyValue); +} + +/* static */ nsresult +nsXFormsModelElement::DeferElementBind(nsIDOMDocument *aDoc, + nsIXFormsControl *aControl) +{ + nsCOMPtr doc = do_QueryInterface(aDoc); + + if (!doc || !aControl) { + return NS_ERROR_FAILURE; + } + + nsCOMArray *deferredBindList = + NS_STATIC_CAST(nsCOMArray *, + doc->GetProperty(nsXFormsAtoms::deferredBindListProperty)); + + if (!deferredBindList) { + deferredBindList = new nsCOMArray(16); + NS_ENSURE_TRUE(deferredBindList, NS_ERROR_OUT_OF_MEMORY); + + doc->SetProperty(nsXFormsAtoms::deferredBindListProperty, deferredBindList, + DeleteBindList); + } + + // always append to the end of the list. We need to keep the elements in + // document order when we process the binds later. Otherwise we have trouble + // when an element is trying to bind and should use its parent as a context + // for the xpath evaluation but the parent isn't bound yet. + deferredBindList->AppendObject(aControl); + + return NS_OK; +} + +/* static */ void +nsXFormsModelElement::ProcessDeferredBinds(nsIDOMDocument *aDoc) +{ + nsCOMPtr doc = do_QueryInterface(aDoc); + + if (!doc) { + return; + } + + doc->SetProperty(nsXFormsAtoms::readyForBindProperty, doc); + + 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(); + } + } + + doc->DeleteProperty(nsXFormsAtoms::deferredBindListProperty); + } +} + nsresult NS_NewXFormsModelElement(nsIXTFElement **aResult) { diff --git a/mozilla/extensions/xforms/nsXFormsModelElement.h b/mozilla/extensions/xforms/nsXFormsModelElement.h index 832191a2208..09b6d8f4cc6 100644 --- a/mozilla/extensions/xforms/nsXFormsModelElement.h +++ b/mozilla/extensions/xforms/nsXFormsModelElement.h @@ -94,6 +94,17 @@ public: // Called after nsXFormsAtoms is registered static NS_HIDDEN_(void) Startup(); + /** + * The models are not ready for binding, so defer the binding of the control + * by storing it as a property on the document. The models will run through + * this list when they are ready for binding. + * + * @param aDoc Document that contains aElement + * @param aControl XForms control waiting to be bound + */ + static NS_HIDDEN_(nsresult) DeferElementBind(nsIDOMDocument *aDoc, + nsIXFormsControl *aControl); + private: NS_HIDDEN_(already_AddRefed) @@ -147,6 +158,14 @@ private: nsXFormsEvent aOnEvent, PRUint32 aAttributePos); + /** + * Call the Bind() and Refresh() on controls which was deferred because + * the model was not ready. + * + * @param aDoc Document that contains the XForms control + */ + static NS_HIDDEN_(void) ProcessDeferredBinds(nsIDOMDocument *aDoc); + // Returns true when all external documents have been loaded PRBool IsComplete() const { return (mSchemaTotal == mSchemaCount && mPendingInstanceCount == 0); }