[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:
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user