[XForms] generate xforms-link-error for help, hint, alert and message elements. Bug 300255, r=smaug+allan

git-svn-id: svn://10.0.0.236/trunk@192790 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
aaronr%us.ibm.com
2006-03-22 18:05:49 +00:00
parent 8d81bda849
commit 0d627e8dde
9 changed files with 495 additions and 40 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -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<nsIModelElementPrivate> 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<nsIModelElementPrivate> modelPriv =
nsXFormsUtils::GetModel(mElement);

View File

@@ -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<nsIDOMElement> mVisualElement;
@@ -184,12 +220,17 @@ private:
nsCOMPtr<nsITimer> mEphemeralTimer;
nsCOMPtr<nsIDOMDocument> mDocument;
nsCOMPtr<nsIChannel> 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<nsIDOMElement> 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<nsIModelElementPrivate> modelPriv =
nsXFormsUtils::GetModel(mElement);
nsCOMPtr<nsIDOMNode> 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<nsIDOMEventTarget> target;
@@ -703,7 +815,6 @@ nsXFormsMessageElement::HandleModalAndModelessMessage(nsIDOMDocument* aDoc,
arg = nsXFormsAtoms::messageProperty;
}
//XXX Add support for xforms-link-error.
nsCOMPtr<nsIDOMWindow> 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<nsIDOMDocument> domDoc;
mElement->GetOwnerDocument(getter_AddRefs(domDoc));
nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
NS_ENSURE_STATE(doc);
nsCOMPtr<nsIURI> 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<nsILoadGroup> 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<nsIHttpChannel> 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<nsIURI> newURI;
nsresult rv = aNewChannel->GetURI(getter_AddRefs(newURI));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_STATE(mElement);
nsCOMPtr<nsIDOMDocument> domDoc;
mElement->GetOwnerDocument(getter_AddRefs(domDoc));
nsCOMPtr<nsIDocument> 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<nsIHttpChannel> 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<nsIDOMDocument> domDoc;
mElement->GetOwnerDocument(getter_AddRefs(domDoc));
if (!domDoc) {
return;
}
nsCOMPtr<nsIDocument> 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<nsIModelElementPrivate> 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)
{

View File

@@ -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<nsIDocument> 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<nsIDOMDocument> domDoc;
mElement->GetOwnerDocument(getter_AddRefs(domDoc));
const nsVoidArray *models = GetModelList(domDoc);
nsCOMPtr<nsIDocument>doc = do_QueryInterface(domDoc);
nsCOMArray<nsIXFormsControlBase> *deferredBindList =
NS_STATIC_CAST(nsCOMArray<nsIXFormsControlBase> *,
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()
{

View File

@@ -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<nsISupportsHashKey, nsString> mNodeToP3PType;
/**
* Indicates whether the model has handled the xforms-model-construct-done
* event
*/
PRBool mConstructDoneHandled;
};
/**

View File

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