From 6cefd972f910e57848c317fa1175ff1b95f63d45 Mon Sep 17 00:00:00 2001 From: "pedemont%us.ibm.com" Date: Thu, 16 Jun 2005 18:33:55 +0000 Subject: [PATCH] Bug 291501 - labels don't support the src attribute. r=aaronr, r=smaug, a=mkaply --- extensions/xforms/nsXFormsLabelElement.cpp | 208 +++++++++++++++++- .../resources/locale/en-US/xforms.properties | 3 + 2 files changed, 207 insertions(+), 4 deletions(-) diff --git a/extensions/xforms/nsXFormsLabelElement.cpp b/extensions/xforms/nsXFormsLabelElement.cpp index dd69eb964cf..3ec12f46689 100644 --- a/extensions/xforms/nsXFormsLabelElement.cpp +++ b/extensions/xforms/nsXFormsLabelElement.cpp @@ -43,6 +43,7 @@ #include "nsXFormsUtils.h" #include "nsXFormsControlStub.h" +#include "nsXFormsAtoms.h" #include "nsCOMPtr.h" #include "nsIDOMElement.h" #include "nsIDOMXPathResult.h" @@ -51,10 +52,19 @@ #include "nsIDOMText.h" #include "nsIXTFXMLVisualWrapper.h" #include "nsString.h" +#include "nsIDocument.h" +#include "nsNetUtil.h" -class nsXFormsLabelElement : public nsXFormsControlStub +class nsXFormsLabelElement : public nsXFormsControlStub, + public nsIStreamListener, + public nsIInterfaceRequestor { public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSISTREAMLISTENER + NS_DECL_NSIINTERFACEREQUESTOR + // nsIXFormsControl NS_IMETHOD Refresh(); NS_IMETHOD IsEventTarget(PRBool *aOK); @@ -70,17 +80,29 @@ public: NS_IMETHOD ChildInserted(nsIDOMNode *aChild, PRUint32 aIndex); NS_IMETHOD ChildAppended(nsIDOMNode *aChild); NS_IMETHOD ChildRemoved(PRUint32 aIndex); + NS_IMETHOD AttributeSet(nsIAtom *aName, const nsAString &aSrc); + NS_IMETHOD AttributeRemoved(nsIAtom *aName); #ifdef DEBUG_smaug virtual const char* Name() { return "label"; } #endif private: NS_HIDDEN_(void) RefreshLabel(); + NS_HIDDEN_(void) LoadExternalLabel(const nsAString& aValue); nsCOMPtr mOuterSpan; nsCOMPtr mInnerSpan; + + nsCString mSrcAttrText; + nsCOMPtr mChannel; }; +NS_IMPL_ISUPPORTS_INHERITED3(nsXFormsLabelElement, + nsXFormsControlStub, + nsIRequestObserver, + nsIStreamListener, + nsIInterfaceRequestor) + NS_IMETHODIMP nsXFormsLabelElement::OnCreated(nsIXTFXMLVisualWrapper *aWrapper) { @@ -155,6 +177,43 @@ nsXFormsLabelElement::ChildRemoved(PRUint32 aIndex) return NS_OK; } +NS_IMETHODIMP +nsXFormsLabelElement::AttributeSet(nsIAtom *aName, const nsAString &aValue) +{ + if (aName == nsXFormsAtoms::src) { + // If we are currently trying to load an external label, cancel the request. + if (mChannel) { + mChannel->Cancel(NS_BINDING_ABORTED); + } + + LoadExternalLabel(aValue); + + // No need to call RefreshLabel() here, since it is called once the link + // target has been read in, during OnStopRequest() + + return NS_OK; + } + + return nsXFormsControlStub::AttributeSet(aName, aValue); +} + +NS_IMETHODIMP +nsXFormsLabelElement::AttributeRemoved(nsIAtom *aName) +{ + if (aName == nsXFormsAtoms::src) { + // If we are currently trying to load an external label, cancel the request. + if (mChannel) { + mChannel->Cancel(NS_BINDING_ABORTED); + } + + mSrcAttrText.Truncate(); + RefreshLabel(); + return NS_OK; + } + + return nsXFormsControlStub::AttributeRemoved(aName); +} + void nsXFormsLabelElement::RefreshLabel() { @@ -169,14 +228,17 @@ nsXFormsLabelElement::RefreshLabel() nsAutoString labelValue; PRBool foundValue = PR_FALSE; + // handle binding attribute if (mBoundNode) { nsXFormsUtils::GetNodeValue(mBoundNode, labelValue); foundValue = PR_TRUE; } - // if (!foundValue) { - // TODO: src attribute - // } + // handle linking ('src') attribute + if (!foundValue && !mSrcAttrText.IsEmpty()) { + labelValue = NS_ConvertUTF8toUTF16(mSrcAttrText); + foundValue = PR_TRUE; + } nsCOMPtr textNode; mOuterSpan->GetFirstChild(getter_AddRefs(textNode)); @@ -193,6 +255,57 @@ nsXFormsLabelElement::RefreshLabel() } } +void +nsXFormsLabelElement::LoadExternalLabel(const nsAString& aSrc) +{ + nsresult rv = NS_ERROR_FAILURE; + + nsCOMPtr domDoc; + mElement->GetOwnerDocument(getter_AddRefs(domDoc)); + nsCOMPtr doc(do_QueryInterface(domDoc)); + if (doc) { + nsCOMPtr uri; + NS_NewURI(getter_AddRefs(uri), aSrc, doc->GetDocumentCharacterSet().get(), + doc->GetDocumentURI()); + if (uri) { + if (nsXFormsUtils::CheckSameOrigin(doc->GetDocumentURI(), uri)) { + nsCOMPtr loadGroup; + 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 label data document has been loaded. + NS_NewChannel(getter_AddRefs(mChannel), uri, nsnull, loadGroup, + this, nsIRequest::LOAD_NORMAL); + + if (mChannel) { + rv = mChannel->AsyncOpen(this, nsnull); + if (NS_FAILED(rv)) { + // 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); + + nsCOMPtr modelPriv = + nsXFormsUtils::GetModel(mElement); + nsCOMPtr model = do_QueryInterface(modelPriv); + nsXFormsUtils::DispatchEvent(model, eEvent_LinkError); + } + } + } else { + nsXFormsUtils::ReportError(NS_LITERAL_STRING("labelLinkLoadOrigin"), + domDoc); + } + } + } +} + // nsIXFormsControl NS_IMETHODIMP @@ -209,6 +322,93 @@ nsXFormsLabelElement::IsEventTarget(PRBool *aOK) return NS_OK; } +// nsIInterfaceRequestor + +NS_IMETHODIMP +nsXFormsLabelElement::GetInterface(const nsIID &aIID, void **aResult) +{ + *aResult = nsnull; + return QueryInterface(aIID, aResult); +} + +// nsIStreamListener + +NS_IMETHODIMP +nsXFormsLabelElement::OnStartRequest(nsIRequest *aRequest, + nsISupports *aContext) +{ + // Only handle data from text files for now. Cancel any other requests. + nsCOMPtr channel(do_QueryInterface(aRequest)); + if (channel) { + nsCAutoString type; + channel->GetContentType(type); + if (!type.EqualsLiteral("text/plain")) + return NS_ERROR_ILLEGAL_VALUE; + } + + mSrcAttrText.Truncate(); + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsLabelElement::OnDataAvailable(nsIRequest *aRequest, + nsISupports *aContext, + nsIInputStream *aInputStream, + PRUint32 aOffset, + PRUint32 aCount) +{ + nsresult rv; + PRUint32 size, bytesRead; + char buffer[256]; + + while (aCount) { + size = PR_MIN(aCount, sizeof(buffer)); + rv = aInputStream->Read(buffer, size, &bytesRead); + if (NS_FAILED(rv)) + return rv; + mSrcAttrText.Append(buffer, bytesRead); + aCount -= bytesRead; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsLabelElement::OnStopRequest(nsIRequest *aRequest, + nsISupports *aContext, + nsresult aStatusCode) +{ + // Done with load request, so null out channel member + mChannel = nsnull; + + if (NS_FAILED(aStatusCode)) { + // If we received NS_BINDING_ABORTED, then we were cancelled by a later + // AttributeSet() call. Don't do anything and return. + 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); + + nsCOMPtr modelPriv = + nsXFormsUtils::GetModel(mElement); + nsCOMPtr model = do_QueryInterface(modelPriv); + nsXFormsUtils::DispatchEvent(model, eEvent_LinkError); + + mSrcAttrText.Truncate(); + } + + RefreshLabel(); + + return NS_OK; +} + + NS_HIDDEN_(nsresult) NS_NewXFormsLabelElement(nsIXTFElement **aResult) { diff --git a/extensions/xforms/resources/locale/en-US/xforms.properties b/extensions/xforms/resources/locale/en-US/xforms.properties index cb4371ad594..9303fa06630 100644 --- a/extensions/xforms/resources/locale/en-US/xforms.properties +++ b/extensions/xforms/resources/locale/en-US/xforms.properties @@ -14,3 +14,6 @@ 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