diff --git a/mozilla/extensions/xforms/nsIModelElementPrivate.idl b/mozilla/extensions/xforms/nsIModelElementPrivate.idl index c1693434fc2..2f49a73e6b1 100644 --- a/mozilla/extensions/xforms/nsIModelElementPrivate.idl +++ b/mozilla/extensions/xforms/nsIModelElementPrivate.idl @@ -75,7 +75,7 @@ interface nsIModelElementPrivate : nsIXFormsModelElement /** * Notification that an instance element has started or finished loading - * its instance data. Model contstruction cannot complete until all of + * its instance data. Model construction cannot complete until all of * the instances have loaded their data. */ void instanceLoadStarted(); @@ -163,4 +163,11 @@ interface nsIModelElementPrivate : nsIXFormsModelElement */ void GetTypeFromNode(in nsIDOMNode aInstanceData, out AString aType, out AString aNSUri); + + /** + * Notification that all of the external message loads have finished loading. + * Model contstruction cannot complete until all of the external messages + * have loaded their data. + */ + void messageLoadFinished(); }; diff --git a/mozilla/extensions/xforms/nsXFormsAtoms.cpp b/mozilla/extensions/xforms/nsXFormsAtoms.cpp index 177ef1cab60..516db31f4ef 100644 --- a/mozilla/extensions/xforms/nsXFormsAtoms.cpp +++ b/mozilla/extensions/xforms/nsXFormsAtoms.cpp @@ -64,6 +64,7 @@ nsIAtom *nsXFormsAtoms::readyForBindProperty; nsIAtom *nsXFormsAtoms::fatalError; nsIAtom *nsXFormsAtoms::isInstanceDocument; nsIAtom *nsXFormsAtoms::instanceDocumentOwner; +nsIAtom *nsXFormsAtoms::externalMessagesProperty; const nsStaticAtom nsXFormsAtoms::Atoms_info[] = { { "src", &nsXFormsAtoms::src }, @@ -90,7 +91,8 @@ const nsStaticAtom nsXFormsAtoms::Atoms_info[] = { { "ReadyForBindProperty", &nsXFormsAtoms::readyForBindProperty }, { "fatalError", &nsXFormsAtoms::fatalError }, { "isInstanceDocument", &nsXFormsAtoms::isInstanceDocument }, - { "instanceDocumentOwner", &nsXFormsAtoms::instanceDocumentOwner } + { "instanceDocumentOwner", &nsXFormsAtoms::instanceDocumentOwner }, + { "ExternalMessagesProperty", &nsXFormsAtoms::externalMessagesProperty } }; void diff --git a/mozilla/extensions/xforms/nsXFormsAtoms.h b/mozilla/extensions/xforms/nsXFormsAtoms.h index fa8eec4cd2e..a5ab9de6eaa 100644 --- a/mozilla/extensions/xforms/nsXFormsAtoms.h +++ b/mozilla/extensions/xforms/nsXFormsAtoms.h @@ -72,6 +72,7 @@ class nsXFormsAtoms static NS_HIDDEN_(nsIAtom *) fatalError; static NS_HIDDEN_(nsIAtom *) isInstanceDocument; static NS_HIDDEN_(nsIAtom *) instanceDocumentOwner; + static NS_HIDDEN_(nsIAtom *) externalMessagesProperty; static NS_HIDDEN_(void) InitAtoms(); diff --git a/mozilla/extensions/xforms/nsXFormsInstanceElement.cpp b/mozilla/extensions/xforms/nsXFormsInstanceElement.cpp index b1fbbe053cf..8128895eba5 100644 --- a/mozilla/extensions/xforms/nsXFormsInstanceElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsInstanceElement.cpp @@ -187,7 +187,9 @@ nsXFormsInstanceElement::OnChannelRedirect(nsIChannel *OldChannel, NS_ENSURE_STATE(doc); if (!nsXFormsUtils::CheckSameOrigin(doc, newURI)) { - nsXFormsUtils::ReportError(NS_LITERAL_STRING("instanceLoadOrigin"), domDoc); + const PRUnichar *strings[] = { NS_LITERAL_STRING("instance").get() }; + nsXFormsUtils::ReportError(NS_LITERAL_STRING("externalLinkLoadOrigin"), + strings, 1, mElement, mElement); return NS_ERROR_ABORT; } diff --git a/mozilla/extensions/xforms/nsXFormsLabelElement.cpp b/mozilla/extensions/xforms/nsXFormsLabelElement.cpp index 89c72636704..281e780a6a7 100644 --- a/mozilla/extensions/xforms/nsXFormsLabelElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsLabelElement.cpp @@ -233,12 +233,11 @@ nsXFormsLabelElement::LoadExternalLabel(const nsAString& aSrc) // URI doesn't exist; report error. mChannel = nsnull; - // XXX Passing |mElement| as |aContext| param to ReportError leads - // to an infinite loop. Avoid for now. const nsPromiseFlatString& flat = PromiseFlatString(aSrc); - const PRUnichar *strings[] = { flat.get() }; - nsXFormsUtils::ReportError(NS_LITERAL_STRING("labelLink1Error"), - strings, 1, mElement, nsnull); + const PRUnichar *strings[] = { flat.get(), + NS_LITERAL_STRING("label").get() }; + nsXFormsUtils::ReportError(NS_LITERAL_STRING("externalLink1Error"), + strings, 2, mElement, mElement); nsCOMPtr modelPriv = nsXFormsUtils::GetModel(mElement); @@ -247,8 +246,9 @@ nsXFormsLabelElement::LoadExternalLabel(const nsAString& aSrc) } } } else { - nsXFormsUtils::ReportError(NS_LITERAL_STRING("labelLinkLoadOrigin"), - domDoc); + const PRUnichar *strings[] = { NS_LITERAL_STRING("label").get() }; + nsXFormsUtils::ReportError(NS_LITERAL_STRING("externalLinkLoadOrigin"), + strings, 1, mElement, mElement); } } } @@ -378,13 +378,12 @@ nsXFormsLabelElement::OnStopRequest(nsIRequest *aRequest, if (aStatusCode == NS_BINDING_ABORTED) return NS_OK; - // XXX Passing |mElement| as |aContext| param to ReportError leads - // to an infinite loop. Avoid for now. nsAutoString src; mElement->GetAttribute(NS_LITERAL_STRING("src"), src); - const PRUnichar *strings[] = { src.get() }; - nsXFormsUtils::ReportError(NS_LITERAL_STRING("labelLink2Error"), - strings, 1, mElement, nsnull); + const PRUnichar *strings[] = { NS_LITERAL_STRING("label").get(), + src.get() }; + nsXFormsUtils::ReportError(NS_LITERAL_STRING("externalLink2Error"), + strings, 2, mElement, mElement); nsCOMPtr modelPriv = nsXFormsUtils::GetModel(mElement); diff --git a/mozilla/extensions/xforms/nsXFormsMessageElement.cpp b/mozilla/extensions/xforms/nsXFormsMessageElement.cpp index cb3bc3b5055..ffc32fba3c4 100644 --- a/mozilla/extensions/xforms/nsXFormsMessageElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsMessageElement.cpp @@ -78,6 +78,9 @@ #include "nsIDOMSerializer.h" #include "nsIServiceManager.h" #include "nsIDelegateInternal.h" +#include "nsNetUtil.h" +#include "nsIDOMDocumentEvent.h" +#include "nsIChannelEventSink.h" #define EPHEMERAL_STYLE \ "position:absolute;z-index:2147483647; \ @@ -121,7 +124,10 @@ class nsXFormsEventListener; */ class nsXFormsMessageElement : public nsXFormsXMLVisualStub, public nsIDOMEventListener, - public nsIXFormsActionModuleElement + public nsIXFormsActionModuleElement, + public nsIStreamListener, + public nsIInterfaceRequestor, + public nsIChannelEventSink { public: NS_DECL_ISUPPORTS_INHERITED @@ -138,7 +144,13 @@ public: NS_IMETHOD GetInsertionPoint(nsIDOMElement **aElement); NS_IMETHOD ParentChanged(nsIDOMElement *aNewParent); NS_IMETHOD WillChangeParent(nsIDOMElement *aNewParent); + NS_IMETHOD AttributeSet(nsIAtom *aName, const nsAString &aSrc); + NS_IMETHOD AttributeRemoved(nsIAtom *aName); + NS_DECL_NSICHANNELEVENTSINK + NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSISTREAMLISTENER + NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSIDOMEVENTLISTENER NS_DECL_NSIXFORMSACTIONMODULEELEMENT @@ -161,8 +173,16 @@ public: eType_Alert }; + enum StopType { + eStopType_None, + eStopType_Security, + eStopType_LinkError + }; + + nsXFormsMessageElement(MessageType aType) : - mType(aType), mElement(nsnull), mPosX(-1), mPosY(-1) {} + mType(aType), mElement(nsnull), mPosX(-1), mPosY(-1), + mStopType(eStopType_None) {} private: nsresult HandleEphemeralMessage(nsIDOMDocument* aDoc, nsIDOMEvent* aEvent); nsresult HandleModalAndModelessMessage(nsIDOMDocument* aDoc, nsAString& aLevel); @@ -173,6 +193,22 @@ private: PRBool aIsLink, /*out*/ nsAString& aURL); + /** + * Begin the process of testing to see if this message element could get held + * up later by linking to an external resource. Run this when the element is + * set up and it will try to access any external resource that this message + * may later try to access. If we can't get to it by the time the message + * is triggered, then throw a xforms-link-error. + */ + nsresult TestExternalFile(); + + /** + * Either add or subtract from the number of messages with external resources + * currently loading in this document. aAdd == PR_TRUE will add to the total + * otherwise we will subtract from the total (as long as it isn't already 0). + */ + void AddRemoveExternalResource(PRBool aAdd); + MessageType mType; nsCOMPtr mVisualElement; @@ -184,12 +220,17 @@ private: nsCOMPtr mEphemeralTimer; nsCOMPtr mDocument; + nsCOMPtr mChannel; + StopType mStopType; }; NS_IMPL_ADDREF_INHERITED(nsXFormsMessageElement, nsXFormsXMLVisualStub) NS_IMPL_RELEASE_INHERITED(nsXFormsMessageElement, nsXFormsXMLVisualStub) NS_INTERFACE_MAP_BEGIN(nsXFormsMessageElement) + NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink) + NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) + NS_INTERFACE_MAP_ENTRY(nsIStreamListener) NS_INTERFACE_MAP_ENTRY(nsIXFormsActionModuleElement) NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener) NS_INTERFACE_MAP_END_INHERITING(nsXFormsXMLVisualStub) @@ -203,7 +244,9 @@ nsXFormsMessageElement::OnCreated(nsIXTFXMLVisualWrapper *aWrapper) NS_ENSURE_SUCCESS(rv, rv); aWrapper->SetNotificationMask(nsIXTFElement::NOTIFY_WILL_CHANGE_DOCUMENT | - nsIXTFElement::NOTIFY_PARENT_CHANGED); + nsIXTFElement::NOTIFY_PARENT_CHANGED | + nsIXTFElement::NOTIFY_ATTRIBUTE_SET | + nsIXTFElement::NOTIFY_ATTRIBUTE_REMOVED); nsCOMPtr node; rv = aWrapper->GetElementNode(getter_AddRefs(node)); @@ -261,6 +304,12 @@ nsXFormsMessageElement::WillChangeDocument(nsIDOMDocument *aNewDocument) if (msg == this) doc->UnsetProperty(nsXFormsAtoms::messageProperty); } + + // If we are currently trying to load an external message, cancel the + // request. + if (mChannel) { + mChannel->Cancel(NS_BINDING_ABORTED); + } } mDocument = aNewDocument; @@ -272,6 +321,7 @@ nsXFormsMessageElement::OnDestroyed() { mElement = nsnull; mVisualElement = nsnull; + mChannel = nsnull; return NS_OK; } @@ -391,6 +441,39 @@ nsXFormsMessageElement::ParentChanged(nsIDOMElement *aNewParent) return NS_OK; } +NS_IMETHODIMP +nsXFormsMessageElement::AttributeSet(nsIAtom *aName, const nsAString &aValue) +{ + if (aName == nsXFormsAtoms::src) { + // If we are currently trying to load an external message, cancel the + // request. + if (mChannel) { + mChannel->Cancel(NS_BINDING_ABORTED); + } + + mStopType = eStopType_None; + TestExternalFile(); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsMessageElement::AttributeRemoved(nsIAtom *aName) +{ + if (aName == nsXFormsAtoms::src) { + // If we are currently trying to test an external resource, cancel the + // request. + if (mChannel) { + mChannel->Cancel(NS_BINDING_ABORTED); + } + + mStopType = eStopType_None; + } + + return NS_OK; +} + NS_IMETHODIMP nsXFormsMessageElement::HandleAction(nsIDOMEvent* aEvent, nsIXFormsActionElement *aParentAction) @@ -398,6 +481,35 @@ nsXFormsMessageElement::HandleAction(nsIDOMEvent* aEvent, if (!mElement) return NS_OK; + // If TestExternalFile fails, then there is an external link that we need + // to use that we can't reach right now. If it won't load, then might as + // well stop here. We don't want to be popping up empty windows + // or windows that will just end up showing 404 messages. + if (mStopType == eStopType_LinkError) { + // we couldn't successfully link to our external resource. Better throw + // the xforms-link-error event + nsCOMPtr modelPriv = + nsXFormsUtils::GetModel(mElement); + nsCOMPtr model = do_QueryInterface(modelPriv); + nsXFormsUtils::DispatchEvent(model, eEvent_LinkError); + return NS_OK; + } + + // If we couldn't test the external link due to it not living in an + // acceptable domain, then no sense going any further down this path. + if (mStopType == eStopType_Security) { + return NS_OK; + } + + // If there is still a channel, then someone must have changed the value of + // the src attribute since the document finished loading and we haven't yet + // determined whether the new link is valid or not. For now we'll assume + // that the value is good rather than returning a link error. Also + // canceling the channel since it is too late now. + if (mChannel) { + mChannel->Cancel(NS_BINDING_ABORTED); + } + if (mType != eType_Normal) { nsCOMPtr target; @@ -703,7 +815,6 @@ nsXFormsMessageElement::HandleModalAndModelessMessage(nsIDOMDocument* aDoc, arg = nsXFormsAtoms::messageProperty; } - //XXX Add support for xforms-link-error. nsCOMPtr messageWindow; // The 2nd argument is the window name, and if a window with the name exists, // it gets reused. Using "_blank" makes sure we get a new window each time. @@ -926,6 +1037,274 @@ nsXFormsMessageElement::HideEphemeral() nsITimer::TYPE_ONE_SHOT); } +nsresult +nsXFormsMessageElement::TestExternalFile() +{ + // Let's see if checking for any external resources is even necessary. Single + // node binding trumps linking attributes in order of precendence. If we + // find single node binding in evidence, then return NS_OK to show that + // this message element has access to the info that it needs. + nsAutoString snb; + mElement->GetAttribute(NS_LITERAL_STRING("bind"), snb); + if (!snb.IsEmpty()) { + return NS_OK; + } + mElement->GetAttribute(NS_LITERAL_STRING("ref"), snb); + if (!snb.IsEmpty()) { + return NS_OK; + } + + // if no linking attribute, no need to go on + nsAutoString src; + mElement->GetAttribute(NS_LITERAL_STRING("src"), src); + if (src.IsEmpty()) { + return NS_OK; + } + + nsCOMPtr domDoc; + mElement->GetOwnerDocument(getter_AddRefs(domDoc)); + nsCOMPtr doc(do_QueryInterface(domDoc)); + NS_ENSURE_STATE(doc); + nsCOMPtr uri; + NS_NewURI(getter_AddRefs(uri), src, doc->GetDocumentCharacterSet().get(), + doc->GetDocumentURI()); + NS_ENSURE_STATE(uri); + + if (!nsXFormsUtils::CheckSameOrigin(doc, uri)) { + nsAutoString tagName; + mElement->GetLocalName(tagName); + const PRUnichar *strings[] = { tagName.get() }; + nsXFormsUtils::ReportError(NS_LITERAL_STRING("externalLinkLoadOrigin"), + strings, 1, mElement, mElement); + // Keep the the dialog from popping up. Won't be able to reach the + // resource anyhow. + mStopType = eStopType_Security; + return NS_ERROR_FAILURE; + } + + nsCOMPtr loadGroup = doc->GetDocumentLoadGroup(); + NS_WARN_IF_FALSE(loadGroup, "No load group!"); + + // Using the same load group as the main document and creating + // the channel with LOAD_NORMAL flag delays the dispatching of + // the 'load' event until message data document has been loaded. + nsresult rv = NS_NewChannel(getter_AddRefs(mChannel), uri, nsnull, loadGroup, + this, nsIRequest::LOAD_NORMAL); + NS_ENSURE_TRUE(mChannel, rv); + + // See if it's an http channel. We'll look at the http status code more + // closely and only request the "HEAD" to keep the response small. + // Especially since we are requesting this for every message in the document + // and in most cases we pass off the URL to another browser service to + // get and display the message so no good to try to look at the contents + // anyway. + + // XXX ephemeral messages should probably get their full contents here once + // they are set up to handle external resources. + nsCOMPtr httpChannel = do_QueryInterface(mChannel); + if (httpChannel) { + PRBool isReallyHTTP = PR_FALSE; + uri->SchemeIs("http", &isReallyHTTP); + if (!isReallyHTTP) { + uri->SchemeIs("https", &isReallyHTTP); + } + if (isReallyHTTP) { + httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("HEAD")); + } + } + + rv = mChannel->AsyncOpen(this, nsnull); + if (NS_FAILED(rv)) { + mChannel = nsnull; + + // URI doesn't exist; report error. + // set up the error strings + nsAutoString tagName; + mElement->GetLocalName(tagName); + const PRUnichar *strings[] = { src.get(), tagName.get() }; + nsXFormsUtils::ReportError(NS_LITERAL_STRING("externalLink1Error"), + strings, 2, mElement, mElement); + mStopType = eStopType_LinkError; + return NS_ERROR_FAILURE; + } + + // channel should be running along smoothly, increment the count + AddRemoveExternalResource(PR_TRUE); + return NS_OK; +} + +// nsIInterfaceRequestor + +NS_IMETHODIMP +nsXFormsMessageElement::GetInterface(const nsIID &aIID, void **aResult) +{ + *aResult = nsnull; + return QueryInterface(aIID, aResult); +} + +// nsIChannelEventSink + +NS_IMETHODIMP +nsXFormsMessageElement::OnChannelRedirect(nsIChannel *OldChannel, + nsIChannel *aNewChannel, + PRUint32 aFlags) +{ + NS_PRECONDITION(aNewChannel, "Redirect without a channel?"); + + nsCOMPtr newURI; + nsresult rv = aNewChannel->GetURI(getter_AddRefs(newURI)); + NS_ENSURE_SUCCESS(rv, rv); + + NS_ENSURE_STATE(mElement); + nsCOMPtr domDoc; + mElement->GetOwnerDocument(getter_AddRefs(domDoc)); + nsCOMPtr doc(do_QueryInterface(domDoc)); + NS_ENSURE_STATE(doc); + + if (!nsXFormsUtils::CheckSameOrigin(doc, newURI)) { + nsAutoString tagName; + mElement->GetLocalName(tagName); + const PRUnichar *strings[] = { tagName.get() }; + nsXFormsUtils::ReportError(NS_LITERAL_STRING("externalLinkLoadOrigin"), + strings, 1, mElement, mElement); + return NS_ERROR_ABORT; + } + + return NS_OK; +} + +// nsIStreamListener + +NS_IMETHODIMP +nsXFormsMessageElement::OnStartRequest(nsIRequest *aRequest, + nsISupports *aContext) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsMessageElement::OnDataAvailable(nsIRequest *aRequest, + nsISupports *aContext, + nsIInputStream *aInputStream, + PRUint32 aOffset, + PRUint32 aCount) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsMessageElement::OnStopRequest(nsIRequest *aRequest, + nsISupports *aContext, + nsresult aStatusCode) +{ + + // We are done with the load request, whatever the result, so make sure to + // null out mChannel before we return. Keep in mind that if this is the last + // message channel to be loaded for the xforms document then when + // AddRemoveExternalResource is called, it may result in xforms-ready firing. + // Should there be a message acting as a handler for xforms-ready, it will + // start the logic to display itself (HandleAction()). So we can't call + // AddRemoveExternalResource to remove this channel from the count until we've + // set the mStopType to be the proper value. Entering this function, + // mStopType will be eStopType_None, so if we need mStopType to be any other + // value (like in an error condition), please make sure it is set before + // AddRemoveExternalResource is called. + + if (NS_FAILED(aStatusCode)) { + // NS_BINDING_ABORTED means that we have been cancelled by a later + // AttributeSet() call (which will also reset mStopType). So don't treat + // like an error. + if (aStatusCode != NS_BINDING_ABORTED) { + nsAutoString src, tagName; + mElement->GetLocalName(tagName); + mElement->GetAttribute(NS_LITERAL_STRING("src"), src); + const PRUnichar *strings[] = { tagName.get(), src.get() }; + nsXFormsUtils::ReportError(NS_LITERAL_STRING("externalLink2Error"), + strings, 2, mElement, mElement); + mStopType = eStopType_LinkError; + AddRemoveExternalResource(PR_FALSE); + mChannel = nsnull; + + return NS_OK; + } + } + + PRUint32 responseStatus; + nsCOMPtr httpChannel = do_QueryInterface(mChannel); + if (NS_SUCCEEDED(aStatusCode) && httpChannel) { + nsresult rv = httpChannel->GetResponseStatus(&responseStatus); + + // If responseStatus is 4xx or 5xx, it is an error. 2xx is success. + // 3xx (various flavors of redirection) COULD be successful. Can't really + // follow those to conclusion so we'll assume they were successful. + if (NS_FAILED(rv) || (responseStatus >= 400)) { + nsAutoString src, tagName; + mElement->GetLocalName(tagName); + mElement->GetAttribute(NS_LITERAL_STRING("src"), src); + const PRUnichar *strings[] = { tagName.get(), src.get() }; + nsXFormsUtils::ReportError(NS_LITERAL_STRING("externalLink2Error"), + strings, 2, mElement, mElement); + mStopType = eStopType_LinkError; + } + } + + AddRemoveExternalResource(PR_FALSE); + mChannel = nsnull; + + return NS_OK; +} + +void +nsXFormsMessageElement::AddRemoveExternalResource(PRBool aAdd) +{ + // if this message doesn't have a channel established already or it has + // already returned, then no sense bumping the counter. + if (!mChannel) { + return; + } + + nsCOMPtr domDoc; + mElement->GetOwnerDocument(getter_AddRefs(domDoc)); + if (!domDoc) { + return; + } + + nsCOMPtr doc = do_QueryInterface(domDoc); + PRUint32 loadingMessages = NS_REINTERPRET_CAST(PRUint32, + doc->GetProperty(nsXFormsAtoms::externalMessagesProperty)); + if (aAdd) { + loadingMessages++; + } else { + if (loadingMessages) { + loadingMessages--; + } + } + doc->SetProperty(nsXFormsAtoms::externalMessagesProperty, + NS_REINTERPRET_CAST(void *, loadingMessages), nsnull); + + if (!loadingMessages) { + // no outstanding loads left, let the model in the document know in case + // the models are waiting to send out the xforms-ready event + + nsCOMPtr modelPriv = + nsXFormsUtils::GetModel(mElement); + if (modelPriv) { + // if there are no more messages loading then it is probably the case + // that my mChannel is going to get nulled out as soon as this function + // returns. If the model is waiting for this notification, then it may + // kick off the message right away and we should probably ensure that + // mChannel is gone before HandleAction is called. So...if the channel + // isn't pending, let's null it out right here. + PRBool isPending = PR_TRUE; + mChannel->IsPending(&isPending); + if (!isPending) { + mChannel = nsnull; + } + modelPriv->MessageLoadFinished(); + } + } +} + NS_HIDDEN_(nsresult) NS_NewXFormsMessageElement(nsIXTFElement **aResult) { diff --git a/mozilla/extensions/xforms/nsXFormsModelElement.cpp b/mozilla/extensions/xforms/nsXFormsModelElement.cpp index 53d6bed8489..cdb0beedfa4 100644 --- a/mozilla/extensions/xforms/nsXFormsModelElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsModelElement.cpp @@ -271,7 +271,8 @@ nsXFormsModelElement::nsXFormsModelElement() mInstancesInitialized(PR_FALSE), mReadyHandled(PR_FALSE), mInstanceDocuments(nsnull), - mLazyModel(PR_FALSE) + mLazyModel(PR_FALSE), + mConstructDoneHandled(PR_FALSE) { } @@ -561,6 +562,7 @@ nsXFormsModelElement::HandleDefault(nsIDOMEvent *aEvent, PRBool *aHandled) rv = Rebuild(); } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_ModelConstructDone].name)) { rv = ConstructDone(); + mConstructDoneHandled = PR_TRUE; } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Reset].name)) { Reset(); } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_BindingException].name)) { @@ -1577,6 +1579,19 @@ nsXFormsModelElement::MaybeNotifyCompletion() nsXFormsModelElement::ProcessDeferredBinds(domDoc); + nsCOMPtr doc = do_QueryInterface(domDoc); + if (doc) { + PRUint32 loadingMessages = NS_REINTERPRET_CAST(PRUint32, + doc->GetProperty(nsXFormsAtoms::externalMessagesProperty)); + if (loadingMessages) { + // if we are still waiting for external messages to load, then put off + // the xforms-ready until a model in the document is notified that they + // are finished loading + + return; + } + } + for (i = 0; i < models->Count(); ++i) { nsXFormsModelElement *model = NS_STATIC_CAST(nsXFormsModelElement *, models->ElementAt(i)); @@ -1823,6 +1838,51 @@ nsXFormsModelElement::RemoveInstanceElement(nsIInstanceElementPrivate *aInstEle) return NS_OK; } +nsresult +nsXFormsModelElement::MessageLoadFinished() +{ + // This is our signal that all external message links have been tested. If + // we were waiting for this to send out xforms-ready, then now is the time. + + // if this document hasn't processed xforms-model-construct-done, yet (which + // must precede xforms-ready), then we'll send out the xforms-ready later + // as part of our normal handling. If we've already become ready, then this + // event was probably generated by a change in the src attribute on the + // message element. Ignore it in that case. + if (!mConstructDoneHandled || mReadyHandled) { + return NS_OK; + } + + nsCOMPtr domDoc; + mElement->GetOwnerDocument(getter_AddRefs(domDoc)); + const nsVoidArray *models = GetModelList(domDoc); + nsCOMPtrdoc = do_QueryInterface(domDoc); + nsCOMArray *deferredBindList = + NS_STATIC_CAST(nsCOMArray *, + doc->GetProperty(nsXFormsAtoms::deferredBindListProperty)); + + // if we've already gotten the xforms-model-construct-done event and not + // yet the xforms-ready, we've hit a window where we may still be + // processing the deferred control binding. If so, we'll leave now and + // leave it to MaybeNotifyCompletion to generate the xforms-ready event. + if (deferredBindList) { + return NS_OK; + } + + + // if we reached here, then we had to wait on sending out the xforms-ready + // events until the external messages were tested. Now we are finally + // ready to send out xforms-ready to all of the models. + for (int i = 0; i < models->Count(); ++i) { + nsXFormsModelElement *model = + NS_STATIC_CAST(nsXFormsModelElement *, models->ElementAt(i)); + model->mReadyHandled = PR_TRUE; + nsXFormsUtils::DispatchEvent(model->mElement, eEvent_Ready); + } + + return NS_OK; +} + /* static */ void nsXFormsModelElement::Startup() { diff --git a/mozilla/extensions/xforms/nsXFormsModelElement.h b/mozilla/extensions/xforms/nsXFormsModelElement.h index 3f06b84e1b2..adcfad4d19a 100644 --- a/mozilla/extensions/xforms/nsXFormsModelElement.h +++ b/mozilla/extensions/xforms/nsXFormsModelElement.h @@ -276,7 +276,7 @@ private: PRBool mInstancesInitialized; /** - * Indicates whether the model's handled the xforms-ready event already + * Indicates whether the model has handled the xforms-ready event */ PRBool mReadyHandled; @@ -303,6 +303,12 @@ private: * @see http://www.w3.org/TR/xforms/slice6.html#model-prop-p3ptype */ nsClassHashtable mNodeToP3PType; + + /** + * Indicates whether the model has handled the xforms-model-construct-done + * event + */ + PRBool mConstructDoneHandled; }; /** diff --git a/mozilla/extensions/xforms/resources/locale/en-US/xforms.properties b/mozilla/extensions/xforms/resources/locale/en-US/xforms.properties index bfad8bd18e2..f1ca377c5e2 100644 --- a/mozilla/extensions/xforms/resources/locale/en-US/xforms.properties +++ b/mozilla/extensions/xforms/resources/locale/en-US/xforms.properties @@ -50,25 +50,24 @@ exprEvaluateError = XForms Error (11): Error evaluating XPath expression: %S noModelError = XForms Error (12): Could not find model for element instanceParseError = XForms Error (13): Could not parse new instance data submitSendOrigin = XForms Error (14): Security check failed! Trying to submit data to a different domain than document -instanceLoadOrigin = XForms Error (15): Security check failed! Trying to load instance data from a different domain than document -controlBindError = XForms Error (16): Could not bind control to instance data -labelLinkLoadOrigin = XForms Error (17): Security check failed! Trying to load label data from a different domain than document -labelLink1Error = XForms Error (18): External file (%S) for Label element not found -labelLink2Error = XForms Error (19): Failed to load Label element from external file: %S -invalidSeparator = XForms Error (20): Submission separator may only be either "&" or ";", but found "%S". -instanceBindError = XForms Error (21): Submission failed trying to replace instance document '%S'. Instance document doesn't exist in same model as submission element. -instanceInstanceLoad = XForms Error (22): Instance document not allowed to load external instance: %S -rangeSetSliderNaN = XForms Error (23): NaN passed to setSlider() -rangeNullObjects = XForms Error (24): One or more of the passed objects were null -rangeNullInit = XForms Error (25): One or more init() parameters is NaN -rangeBeginEndError = XForms Error (26): Begin is higher than end? -encodingMemoryError = XForms Error (27): Not enough available memory to encode file %S, size = %S. -uploadBoundTypeError = XForms Error (28): Upload element not bound to valid datatype. Must be bound to datatype 'xsd:anyURI', 'xsd:base64Binary', or 'xsd:hexBinary'. -copyError = XForms Error (29): A copy element was found whose parent is not an itemset element -submitMailtoInit = XForms Error (30): No mailto: handler found -submitMailtoFailed = XForms Error (31): Failed to load a mail client for a mailto: submission -invalidQName = XForms Error (32): Failed to create node. %S is not a valid QName. -innerBindRefError = XForms Error (33): You are refering to an inner bind, which is undefined in XForms 1.0 +controlBindError = XForms Error (15): Could not bind control to instance data +invalidSeparator = XForms Error (16): Submission separator may only be either "&" or ";", but found "%S". +instanceBindError = XForms Error (17): Submission failed trying to replace instance document '%S'. Instance document doesn't exist in same model as submission element. +instanceInstanceLoad = XForms Error (18): Instance document not allowed to load external instance: %S +rangeSetSliderNaN = XForms Error (19): NaN passed to setSlider() +rangeNullObjects = XForms Error (20): One or more of the passed objects were null +rangeNullInit = XForms Error (21): One or more init() parameters is NaN +rangeBeginEndError = XForms Error (22): Begin is higher than end? +encodingMemoryError = XForms Error (23): Not enough available memory to encode file %S, size = %S. +uploadBoundTypeError = XForms Error (24): Upload element not bound to valid datatype. Must be bound to datatype 'xsd:anyURI', 'xsd:base64Binary', or 'xsd:hexBinary'. +copyError = XForms Error (25): A copy element was found whose parent is not an itemset element +submitMailtoInit = XForms Error (26): No mailto: handler found +submitMailtoFailed = XForms Error (27): Failed to load a mail client for a mailto: submission +invalidQName = XForms Error (28): Failed to create node. %S is not a valid QName. +innerBindRefError = XForms Error (29): You are refering to an inner bind, which is undefined in XForms 1.0 +externalLink1Error = XForms Error (30): External file (%S) for %S element not found +externalLink2Error = XForms Error (31): Failed to load %S element from external file: %S +externalLinkLoadOrigin = XForms Error (32): Security check failed! Trying to load %S data from a different domain than document # Warning Messages: warnSOAP = XForms Warning (1): You are using the SOAP post feature, which is an experimental feature! Beware that the functionality might change, and forms may stop working at any time.