/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla XForms support. * * The Initial Developer of the Original Code is * IBM Corporation. * Portions created by the Initial Developer are Copyright (C) 2004 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Brian Ryner * Olli Pettay * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /** * Implementation of the XForms \ element. */ #include "nsXFormsUtils.h" #include "nsXFormsControlStub.h" #include "nsXFormsDelegateStub.h" #include "nsXFormsAtoms.h" #include "nsCOMPtr.h" #include "nsIDOMElement.h" #include "nsIDOMXPathResult.h" #include "nsIDOM3Node.h" #include "nsIDOMDocument.h" #include "nsIDOMText.h" #include "nsString.h" #include "nsIXFormsUIWidget.h" #include "nsIDocument.h" #include "nsNetUtil.h" #include "nsIXFormsItemElement.h" class nsXFormsLabelElement : public nsXFormsDelegateStub, public nsIStreamListener, public nsIInterfaceRequestor { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSISTREAMLISTENER NS_DECL_NSIINTERFACEREQUESTOR // nsIXFormsDelegate NS_IMETHOD GetValue(nsAString& aValue); NS_IMETHOD WidgetAttached(); // nsIXFormsControl NS_IMETHOD IsEventTarget(PRBool *aOK); NS_IMETHOD Refresh(); NS_IMETHOD OnCreated(nsIXTFBindableElementWrapper *aWrapper); NS_IMETHOD OnDestroyed(); // nsIXTFElement overrides 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); nsXFormsLabelElement() : mWidgetLoaded(PR_FALSE) {}; #ifdef DEBUG_smaug virtual const char* Name() { return "label"; } #endif private: NS_HIDDEN_(void) LoadExternalLabel(const nsAString& aValue); /** Set context info for events. * * @param aName Name of the context property. * @param aValue Value of the context property. */ nsresult SetContextInfo(const char *aName, const nsAString &aValue); nsCString mSrcAttrText; nsCOMPtr mChannel; PRBool mWidgetLoaded; // Context Info for events. nsCOMArray mContextInfo; }; NS_IMPL_ISUPPORTS_INHERITED3(nsXFormsLabelElement, nsXFormsDelegateStub, nsIRequestObserver, nsIStreamListener, nsIInterfaceRequestor) NS_IMETHODIMP nsXFormsLabelElement::OnCreated(nsIXTFBindableElementWrapper *aWrapper) { nsresult rv = nsXFormsDelegateStub::OnCreated(aWrapper); NS_ENSURE_SUCCESS(rv, rv); aWrapper->SetNotificationMask(kStandardNotificationMask | nsIXTFElement::NOTIFY_CHILD_INSERTED | nsIXTFElement::NOTIFY_CHILD_APPENDED | nsIXTFElement::NOTIFY_CHILD_REMOVED); return NS_OK; } NS_IMETHODIMP nsXFormsLabelElement::OnDestroyed() { if (mChannel) { // better be a good citizen and tell the browser that we don't need this // resource anymore. mChannel->Cancel(NS_BINDING_ABORTED); mChannel = nsnull; } return nsXFormsDelegateStub::OnDestroyed(); } NS_IMETHODIMP nsXFormsLabelElement::ChildInserted(nsIDOMNode *aChild, PRUint32 aIndex) { Refresh(); return NS_OK; } NS_IMETHODIMP nsXFormsLabelElement::ChildAppended(nsIDOMNode *aChild) { Refresh(); return NS_OK; } NS_IMETHODIMP nsXFormsLabelElement::ChildRemoved(PRUint32 aIndex) { Refresh(); 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 Refresh() here, since it is called once the link // target has been read in, during OnStopRequest() return NS_OK; } return nsXFormsDelegateStub::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(); Refresh(); return NS_OK; } return nsXFormsDelegateStub::AttributeRemoved(aName); } NS_IMETHODIMP nsXFormsLabelElement::GetValue(nsAString& aValue) { // The order of precedence for determining the label is: // single node binding, linking, inline text (8.3.3) nsXFormsDelegateStub::GetValue(aValue); if (aValue.IsVoid() && !mSrcAttrText.IsEmpty()) { // handle linking ('src') attribute aValue = NS_ConvertUTF8toUTF16(mSrcAttrText); } if (aValue.IsVoid()) { NS_ENSURE_STATE(mElement); nsCOMPtr inner(do_QueryInterface(mElement)); if (inner) { inner->GetTextContent(aValue); } } return NS_OK; } NS_IMETHODIMP nsXFormsLabelElement::WidgetAttached() { mWidgetLoaded = PR_TRUE; // We shouldn't report to model that label is ready to work // if label is loading external resource. We will report // about it later when external resource will be loaded. if (!mChannel) nsXFormsDelegateStub::WidgetAttached(); return NS_OK; } 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::CheckConnectionAllowed(mElement, 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; const nsPromiseFlatString& flat = PromiseFlatString(aSrc); 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); nsCOMPtr model = do_QueryInterface(modelPriv); // Context Info: 'resource-uri' // The URI associated with the failed link. nsAutoString resourceURI(aSrc); SetContextInfo("resource-uri", resourceURI); nsXFormsUtils::DispatchEvent(model, eEvent_LinkError, nsnull, mElement, &mContextInfo); } } } else { const PRUnichar *strings[] = { NS_LITERAL_STRING("label").get() }; nsXFormsUtils::ReportError(NS_LITERAL_STRING("externalLinkLoadOrigin"), strings, 1, mElement, mElement); nsCOMPtr modelPriv = nsXFormsUtils::GetModel(mElement); nsCOMPtr model = do_QueryInterface(modelPriv); // Context Info: 'resource-uri' // The URI associated with the failed link. nsAutoString resourceURI(aSrc); SetContextInfo("resource-uri", resourceURI); nsXFormsUtils::DispatchEvent(model, eEvent_LinkError, nsnull, mElement, &mContextInfo); } } } } // nsIXFormsControl NS_IMETHODIMP nsXFormsLabelElement::Refresh() { nsresult rv = nsXFormsDelegateStub::Refresh(); if (NS_FAILED(rv) || rv == NS_OK_XFORMS_NOREFRESH) return rv; nsCOMPtr parent; mElement->GetParentNode(getter_AddRefs(parent)); // If