From 50c461e172b288ee77449a35a2fd8da832898fe1 Mon Sep 17 00:00:00 2001 From: "bryner%brianryner.com" Date: Tue, 26 Oct 2004 00:34:03 +0000 Subject: [PATCH] Support nested bind elements (bug 265471). Remove use of nsIXTFPrivate, to make the code cleaner (and more efficient, as well). Implement the readonly property for inputs. git-svn-id: svn://10.0.0.236/trunk@164403 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/extensions/xforms/Makefile.in | 10 +- ...lement.h => nsIInstanceElementPrivate.idl} | 29 +- ...msControl.h => nsIModelElementPrivate.idl} | 68 ++-- ...XFormsElement.cpp => nsIXFormsControl.idl} | 44 +-- .../xforms/nsIXFormsModelElement.idl | 10 + mozilla/extensions/xforms/nsXFormsControl.cpp | 187 ----------- .../xforms/nsXFormsInputElement.cpp | 128 +++++-- .../xforms/nsXFormsInstanceElement.cpp | 116 +++---- .../xforms/nsXFormsInstanceElement.h | 24 +- .../xforms/nsXFormsModelElement.cpp | 244 ++++++++------ .../extensions/xforms/nsXFormsModelElement.h | 37 +-- mozilla/extensions/xforms/nsXFormsModule.cpp | 1 + .../extensions/xforms/nsXFormsStubElement.cpp | 7 +- .../extensions/xforms/nsXFormsStubElement.h | 4 +- .../xforms/nsXFormsSubmissionElement.cpp | 119 ++----- .../xforms/nsXFormsSubmissionElement.h | 8 +- mozilla/extensions/xforms/nsXFormsUtils.cpp | 312 ++++++++++++++++++ mozilla/extensions/xforms/nsXFormsUtils.h | 124 +++++++ 18 files changed, 878 insertions(+), 594 deletions(-) rename mozilla/extensions/xforms/{nsXFormsElement.h => nsIInstanceElementPrivate.idl} (73%) rename mozilla/extensions/xforms/{nsXFormsControl.h => nsIModelElementPrivate.idl} (55%) rename mozilla/extensions/xforms/{nsXFormsElement.cpp => nsIXFormsControl.idl} (64%) delete mode 100644 mozilla/extensions/xforms/nsXFormsControl.cpp create mode 100644 mozilla/extensions/xforms/nsXFormsUtils.cpp create mode 100644 mozilla/extensions/xforms/nsXFormsUtils.h diff --git a/mozilla/extensions/xforms/Makefile.in b/mozilla/extensions/xforms/Makefile.in index 76b9b2f8683..db20dfe02af 100644 --- a/mozilla/extensions/xforms/Makefile.in +++ b/mozilla/extensions/xforms/Makefile.in @@ -65,12 +65,16 @@ REQUIRES = \ js \ $(NULL) -XPIDLSRCS = nsIXFormsModelElement.idl +XPIDLSRCS = \ + nsIXFormsModelElement.idl \ + nsIInstanceElementPrivate.idl \ + nsIModelElementPrivate.idl \ + nsIXFormsControl.idl \ + $(NULL) CPPSRCS = \ nsXFormsElementFactory.cpp \ - nsXFormsElement.cpp \ - nsXFormsControl.cpp \ + nsXFormsUtils.cpp \ nsXFormsModelElement.cpp \ nsXFormsInputElement.cpp \ nsXFormsSubmissionElement.cpp \ diff --git a/mozilla/extensions/xforms/nsXFormsElement.h b/mozilla/extensions/xforms/nsIInstanceElementPrivate.idl similarity index 73% rename from mozilla/extensions/xforms/nsXFormsElement.h rename to mozilla/extensions/xforms/nsIInstanceElementPrivate.idl index 79e4aaefc2f..f81ff2132ab 100644 --- a/mozilla/extensions/xforms/nsXFormsElement.h +++ b/mozilla/extensions/xforms/nsIInstanceElementPrivate.idl @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -36,24 +36,19 @@ * * ***** END LICENSE BLOCK ***** */ -#ifndef nsXFormsElement_h_ -#define nsXFormsElement_h_ +#include "nsISupports.idl" -#include "prtypes.h" -#include "nsIID.h" +/** + * Private interface implemented by the instance element. + */ -// base class for all XForms elements +interface nsIDOMDocument; -#define NS_NAMESPACE_XFORMS "http://www.w3.org/2002/xforms" -#define NS_NAMESPACE_XHTML "http://www.w3.org/1999/xhtml" - -class nsXFormsElement +[uuid(8c9dd10d-4189-4a7b-a2eb-fd695cf33b27)] +interface nsIInstanceElementPrivate : nsISupports { -protected: - NS_HIDDEN_(nsresult) CloneScriptingInterfaces(const nsIID *aIIDList, - unsigned int aIIDCount, - PRUint32 *aOutCount, - nsIID ***aOutArray); + /** + * The document which holds the live instance data. + */ + attribute nsIDOMDocument document; }; - -#endif diff --git a/mozilla/extensions/xforms/nsXFormsControl.h b/mozilla/extensions/xforms/nsIModelElementPrivate.idl similarity index 55% rename from mozilla/extensions/xforms/nsXFormsControl.h rename to mozilla/extensions/xforms/nsIModelElementPrivate.idl index 3ec7b858272..cc799661251 100644 --- a/mozilla/extensions/xforms/nsXFormsControl.h +++ b/mozilla/extensions/xforms/nsIModelElementPrivate.idl @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -36,41 +36,49 @@ * * ***** END LICENSE BLOCK ***** */ -#ifndef nsXFormsControl_h_ -#define nsXFormsControl_h_ +/** + * Private interface implemented by the model element for other + * elements to use. + */ -#include "nscore.h" -#include "nsIXTFXMLVisualWrapper.h" -#include "nsIDOMNode.h" -#include "nsCOMPtr.h" -#include "nsXFormsElement.h" +#include "nsIXFormsModelElement.idl" -class nsXFormsModelElement; -class nsIDOMElement; -class nsIDOMXPathResult; +interface nsIXFormsControl; +interface nsISchemaType; +interface nsIInstanceElementPrivate; -#define NS_XFORMSCONTROL_IID \ -{0x49bad098, 0xaa62, 0x49be, {0x98, 0x7b, 0xdb, 0x32, 0x66, 0x92, 0x1e, 0x0a}} - -// Common implementation for XForms form controls - -class nsXFormsControl : public nsXFormsElement, - public nsISupports +[uuid(b21b65d3-3305-4ce0-a604-3648cff61aca)] +interface nsIModelElementPrivate : nsIXFormsModelElement { -public: - NS_DEFINE_STATIC_IID_ACCESSOR(NS_XFORMSCONTROL_IID) + /** + * Called by form control elements when they are bound to or unbound from + * this model. These form controls will be refreshed when refresh() is + * called on the model. + */ + void addFormControl(in nsIXFormsControl control); + void removeFormControl(in nsIXFormsControl control); - NS_DECL_ISUPPORTS + /** + * Determine the type for a form control based on the schema included by + * this model. + */ + nsISchemaType getTypeForControl(in nsIXFormsControl control); - virtual NS_HIDDEN_(void) Refresh() = 0; + /** + * Notification that an instance element has started or finished loading + * its instance data. Model contstruction cannot complete until all of + * the instances have loaded their data. + */ + void instanceLoadStarted(); + void instanceLoadFinished(in boolean success); - NS_HIDDEN_(nsXFormsModelElement*) GetModelAndBind(nsIDOMElement **aBindElement); - NS_HIDDEN_(already_AddRefed) - EvaluateBinding(PRUint16 aResultType, - nsXFormsModelElement **aModel, nsIDOMElement **aBind); + /** + * Locate the instance element child with the given id. + */ + nsIInstanceElementPrivate findInstanceElement(in AString id); -protected: - nsCOMPtr mWrapper; + /** + * Track whether there is a form submit in progress for this model. + */ + attribute boolean submissionActive; }; - -#endif diff --git a/mozilla/extensions/xforms/nsXFormsElement.cpp b/mozilla/extensions/xforms/nsIXFormsControl.idl similarity index 64% rename from mozilla/extensions/xforms/nsXFormsElement.cpp rename to mozilla/extensions/xforms/nsIXFormsControl.idl index bb4a9890dd3..f4920cd733f 100644 --- a/mozilla/extensions/xforms/nsXFormsElement.cpp +++ b/mozilla/extensions/xforms/nsIXFormsControl.idl @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -36,34 +36,18 @@ * * ***** END LICENSE BLOCK ***** */ -#include "nsXFormsElement.h" -#include "nsMemory.h" +/** + * Interface implemented by all XForms form control classes. + */ -nsresult -nsXFormsElement::CloneScriptingInterfaces(const nsIID *aIIDList, - unsigned int aIIDCount, - PRUint32 *aOutCount, - nsIID ***aOutArray) +#include "nsISupports.idl" + +[uuid(8377c845-5d55-4eee-9a76-0f86751dcbc8)] +interface nsIXFormsControl : nsISupports { - nsIID **iids = NS_STATIC_CAST(nsIID**, - nsMemory::Alloc(aIIDCount * sizeof(nsIID*))); - if (!iids) { - return NS_ERROR_OUT_OF_MEMORY; - } - - for (PRUint32 i = 0; i < aIIDCount; ++i) { - iids[i] = NS_STATIC_CAST(nsIID*, - nsMemory::Clone(&aIIDList[i], sizeof(nsIID))); - - if (!iids[i]) { - for (PRUint32 j = 0; j < i; ++j) - nsMemory::Free(iids[j]); - nsMemory::Free(iids); - return NS_ERROR_OUT_OF_MEMORY; - } - } - - *aOutArray = iids; - *aOutCount = aIIDCount; - return NS_OK; -} + /** + * This tells the form control to update its state based on the current + * instance data. + */ + void refresh(); +}; diff --git a/mozilla/extensions/xforms/nsIXFormsModelElement.idl b/mozilla/extensions/xforms/nsIXFormsModelElement.idl index 56ef9f12937..e328fbbfd9a 100644 --- a/mozilla/extensions/xforms/nsIXFormsModelElement.idl +++ b/mozilla/extensions/xforms/nsIXFormsModelElement.idl @@ -38,6 +38,16 @@ #include "domstubs.idl" +/** + * The nsIXFormsModelElement interface defines scriptable methods for + * manipulating instance data and updating computed and displayed values. + * + * For more information on this interface please see + * http://www.w3.org/TR/xforms/ + * + * @status FROZEN + */ + interface nsIDOMDocument; interface nsIDOMDOMException; diff --git a/mozilla/extensions/xforms/nsXFormsControl.cpp b/mozilla/extensions/xforms/nsXFormsControl.cpp deleted file mode 100644 index cc1dc0ffbcf..00000000000 --- a/mozilla/extensions/xforms/nsXFormsControl.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/* -*- 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 - * - * 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 ***** */ - -#include "nsXFormsControl.h" -#include "nsXFormsModelElement.h" -#include "nsString.h" -#include "nsXFormsAtoms.h" -#include "nsIDOMElement.h" -#include "nsIDocument.h" -#include "nsINameSpaceManager.h" -#include "nsINodeInfo.h" -#include "nsIDOMNodeList.h" -#include "nsIDOMXPathEvaluator.h" -#include "nsIDOMXPathResult.h" -#include "nsIDOMXPathNSResolver.h" - -NS_IMPL_ISUPPORTS1(nsXFormsControl, nsXFormsControl) - -nsXFormsModelElement* -nsXFormsControl::GetModelAndBind(nsIDOMElement **aBindElement) -{ - *aBindElement = nsnull; - NS_ENSURE_TRUE(mWrapper, nsnull); - - nsCOMPtr node; - mWrapper->GetElementNode(getter_AddRefs(node)); - - nsCOMPtr domDoc; - node->GetOwnerDocument(getter_AddRefs(domDoc)); - if (!domDoc) - return nsnull; - - nsAutoString bindId; - node->GetAttribute(NS_LITERAL_STRING("bind"), bindId); - - nsCOMPtr modelWrapper; - - if (!bindId.IsEmpty()) { - // Get the bind element with the given id. - domDoc->GetElementById(bindId, aBindElement); - - if (*aBindElement) { - // Walk up the tree looking for the containing model. - (*aBindElement)->GetParentNode(getter_AddRefs(modelWrapper)); - - nsAutoString localName, namespaceURI; - nsCOMPtr temp; - - while (modelWrapper) { - modelWrapper->GetLocalName(localName); - if (localName.EqualsLiteral("model")) { - modelWrapper->GetNamespaceURI(namespaceURI); - if (namespaceURI.EqualsLiteral(NS_NAMESPACE_XFORMS)) - break; - } - - temp.swap(modelWrapper); - temp->GetParentNode(getter_AddRefs(modelWrapper)); - } - } - } else { - // If no bind was given, we use model. - nsAutoString modelId; - node->GetAttribute(NS_LITERAL_STRING("model"), modelId); - - if (modelId.IsEmpty()) { - // No model given, so use the first one in the document. - nsCOMPtr nodes; - domDoc->GetElementsByTagNameNS(NS_LITERAL_STRING(NS_NAMESPACE_XFORMS), - NS_LITERAL_STRING("model"), - getter_AddRefs(nodes)); - - if (!nodes) - return nsnull; - - nodes->Item(0, getter_AddRefs(modelWrapper)); - } else { - nsCOMPtr wrapperElement; - domDoc->GetElementById(modelId, getter_AddRefs(wrapperElement)); - modelWrapper = wrapperElement; - } - } - - nsCOMPtr modelPrivate = do_QueryInterface(modelWrapper); - nsCOMPtr modelElement; - if (modelPrivate) - modelPrivate->GetInner(getter_AddRefs(modelElement)); - - nsISupports *modelRaw = NS_STATIC_CAST(nsISupports*, modelElement.get()); - return NS_STATIC_CAST(nsXFormsModelElement*, - NS_STATIC_CAST(nsIXFormsModelElement*, modelRaw)); -} - -already_AddRefed -nsXFormsControl::EvaluateBinding(PRUint16 aResultType, - nsXFormsModelElement **aModel, - nsIDOMElement **aBind) -{ - // A control may be attached to a model by either using the 'bind' - // attribute to give the id of a bind element, or using the 'model' - // attribute to give the id of a model. If neither of these are given, - // the control belongs to the first model in the document. - - *aBind = nsnull; - - NS_IF_ADDREF(*aModel = GetModelAndBind(aBind)); - if (!*aModel) - return nsnull; - - nsCOMPtr resolverNode; - nsAutoString expr; - - if (*aBind) { - resolverNode = *aBind; - resolverNode->GetAttribute(NS_LITERAL_STRING("nodeset"), expr); - } else { - mWrapper->GetElementNode(getter_AddRefs(resolverNode)); - resolverNode->GetAttribute(NS_LITERAL_STRING("ref"), expr); - } - - if (expr.IsEmpty()) - return nsnull; - - // Get the instance data and evaluate the xpath expression. - // XXXfixme when xpath extensions are implemented (instance()) - nsCOMPtr instanceDoc; - (*aModel)->GetInstanceDocument(NS_LITERAL_STRING(""), - getter_AddRefs(instanceDoc)); - - if (!instanceDoc) - return nsnull; - - nsCOMPtr eval = do_QueryInterface(instanceDoc); - nsCOMPtr resolver; - eval->CreateNSResolver(resolverNode, getter_AddRefs(resolver)); - NS_ENSURE_TRUE(resolver, nsnull); - - nsCOMPtr docElement; - instanceDoc->GetDocumentElement(getter_AddRefs(docElement)); - if (!docElement) - return nsnull; // this will happen if the doc is still loading - - nsCOMPtr result; - eval->Evaluate(expr, docElement, resolver, aResultType, nsnull, - getter_AddRefs(result)); - - nsIDOMXPathResult *xpResult = nsnull; - if (result) - CallQueryInterface(result, &xpResult); // addrefs - - return xpResult; -} diff --git a/mozilla/extensions/xforms/nsXFormsInputElement.cpp b/mozilla/extensions/xforms/nsXFormsInputElement.cpp index bbd56135db4..7f3388bfcbc 100644 --- a/mozilla/extensions/xforms/nsXFormsInputElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsInputElement.cpp @@ -45,14 +45,17 @@ #include "nsString.h" #include "nsIXTFXMLVisualWrapper.h" #include "nsIDOMDocument.h" -#include "nsXFormsControl.h" +#include "nsIXFormsControl.h" #include "nsISchema.h" -#include "nsXFormsModelElement.h" #include "nsIDOMHTMLInputElement.h" #include "nsXFormsAtoms.h" #include "nsAutoPtr.h" #include "nsIDOMXPathResult.h" #include "nsIDOMFocusListener.h" +#include "nsXFormsUtils.h" +#include "nsIModelElementPrivate.h" +#include "nsIContent.h" +#include "nsIDOMXPathExpression.h" static const nsIID sScriptingIIDs[] = { NS_IDOMELEMENT_IID, @@ -60,15 +63,16 @@ static const nsIID sScriptingIIDs[] = { NS_IDOM3NODE_IID }; -class nsXFormsInputElement : public nsXFormsControl, - public nsIXTFXMLVisual, - public nsIDOMFocusListener +class nsXFormsInputElement : public nsIXTFXMLVisual, + public nsIDOMFocusListener, + public nsIXFormsControl { public: NS_DECL_ISUPPORTS NS_DECL_NSIXTFXMLVISUAL NS_DECL_NSIXTFVISUAL NS_DECL_NSIXTFELEMENT + NS_DECL_NSIXFORMSCONTROL // nsIDOMEventListener NS_IMETHOD HandleEvent(nsIDOMEvent *aEvent); @@ -77,11 +81,11 @@ public: NS_IMETHOD Focus(nsIDOMEvent *aEvent); NS_IMETHOD Blur(nsIDOMEvent *aEvent); - // nsXFormsControl - virtual NS_HIDDEN_(void) Refresh(); + nsXFormsInputElement() : mElement(nsnull) {} private: nsCOMPtr mInput; + nsIDOMElement *mElement; }; NS_IMPL_ADDREF(nsXFormsInputElement) @@ -92,6 +96,7 @@ NS_INTERFACE_MAP_BEGIN(nsXFormsInputElement) NS_INTERFACE_MAP_ENTRY(nsIXTFElement) NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener) NS_INTERFACE_MAP_ENTRY(nsIDOMFocusListener) + NS_INTERFACE_MAP_ENTRY(nsIXFormsControl) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXTFXMLVisual) NS_INTERFACE_MAP_END @@ -101,12 +106,19 @@ NS_IMETHODIMP nsXFormsInputElement::OnCreated(nsIXTFXMLVisualWrapper *aWrapper) { aWrapper->SetNotificationMask(nsIXTFElement::NOTIFY_WILL_SET_ATTRIBUTE | - nsIXTFElement::NOTIFY_ATTRIBUTE_SET); - - mWrapper = aWrapper; + nsIXTFElement::NOTIFY_ATTRIBUTE_SET | + nsIXTFElement::NOTIFY_PARENT_CHANGED); nsCOMPtr node; - mWrapper->GetElementNode(getter_AddRefs(node)); + aWrapper->GetElementNode(getter_AddRefs(node)); + + // It's ok to keep a weak pointer to mElement. mElement will have an + // owning reference to this object, so as long as we null out mElement in + // OnDestroyed, it will always be valid. + + mElement = node; + NS_ASSERTION(mElement, "Wrapper is not an nsIDOMElement, we'll crash soon"); + nsCOMPtr domDoc; node->GetOwnerDocument(getter_AddRefs(domDoc)); @@ -191,9 +203,9 @@ nsXFormsInputElement::GetIsAttributeHandler(PRBool *aIsHandler) NS_IMETHODIMP nsXFormsInputElement::GetScriptingInterfaces(PRUint32 *aCount, nsIID ***aArray) { - return CloneScriptingInterfaces(sScriptingIIDs, - NS_ARRAY_LENGTH(sScriptingIIDs), - aCount, aArray); + return nsXFormsUtils::CloneScriptingInterfaces(sScriptingIIDs, + NS_ARRAY_LENGTH(sScriptingIIDs), + aCount, aArray); } NS_IMETHODIMP @@ -217,6 +229,9 @@ nsXFormsInputElement::WillChangeParent(nsIDOMElement *aNewParent) NS_IMETHODIMP nsXFormsInputElement::ParentChanged(nsIDOMElement *aNewParent) { + // We need to re-evaluate our instance data binding when our parent + // changes, since xmlns declarations in effect could have changed. + Refresh(); return NS_OK; } @@ -261,7 +276,9 @@ nsXFormsInputElement::WillSetAttribute(nsIAtom *aName, const nsAString &aValue) { if (aName == nsXFormsAtoms::bind || aName == nsXFormsAtoms::ref) { nsCOMPtr bindElement; - nsXFormsModelElement *model = GetModelAndBind(getter_AddRefs(bindElement)); + nsCOMPtr model; + + model = do_QueryInterface(nsXFormsUtils::GetModelAndBind(mElement, getter_AddRefs(bindElement))); if (model) model->RemoveFormControl(this); } @@ -324,11 +341,13 @@ nsXFormsInputElement::Blur(nsIDOMEvent *aEvent) if (!mInput) return NS_OK; - nsRefPtr model; + nsCOMPtr modelNode; nsCOMPtr bindElement; nsCOMPtr result = - EvaluateBinding(nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, - getter_AddRefs(model), getter_AddRefs(bindElement)); + nsXFormsUtils::EvaluateNodeBinding(mElement, + nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, + getter_AddRefs(modelNode), + getter_AddRefs(bindElement)); if (!result) return NS_OK; @@ -372,26 +391,54 @@ nsXFormsInputElement::Blur(nsIDOMEvent *aEvent) // other methods -void +NS_IMETHODIMP nsXFormsInputElement::Refresh() { if (!mInput) - return; + return NS_OK; - nsRefPtr model; + nsCOMPtr modelNode; nsCOMPtr bindElement; nsCOMPtr result = - EvaluateBinding(nsIDOMXPathResult::STRING_TYPE, - getter_AddRefs(model), getter_AddRefs(bindElement)); + nsXFormsUtils::EvaluateNodeBinding(mElement, + nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, + getter_AddRefs(modelNode), + getter_AddRefs(bindElement)); + + nsCOMPtr model = do_QueryInterface(modelNode); if (model) { model->AddFormControl(this); - if (result) { - nsAutoString nodeValue; - result->GetStringValue(nodeValue); + nsCOMPtr resultNode; + if (result) + result->GetSingleNodeValue(getter_AddRefs(resultNode)); - nsCOMPtr type = model->GetTypeForControl(this); + if (resultNode) { + PRUint16 nodeType = 0; + resultNode->GetNodeType(&nodeType); + + nsAutoString text; + + switch (nodeType) { + case nsIDOMNode::TEXT_NODE: + case nsIDOMNode::ATTRIBUTE_NODE: + resultNode->GetNodeValue(text); + break; + case nsIDOMNode::ELEMENT_NODE: + { + nsCOMPtr firstChild; + resultNode->GetFirstChild(getter_AddRefs(firstChild)); + if (firstChild) + firstChild->GetNodeValue(text); + break; + } + default: + NS_ERROR("form control references invalid node type in instance data"); + } + + nsCOMPtr type; + model->GetTypeForControl(this, getter_AddRefs(type)); nsCOMPtr biType = do_QueryInterface(type); PRUint16 typeValue = nsISchemaBuiltinType::BUILTIN_TYPE_STRING; @@ -402,14 +449,35 @@ nsXFormsInputElement::Refresh() mInput->SetAttribute(NS_LITERAL_STRING("type"), NS_LITERAL_STRING("checkbox")); - mInput->SetChecked(nodeValue.EqualsLiteral("true") || - nodeValue.EqualsLiteral("1")); + mInput->SetChecked(text.EqualsLiteral("true") || + text.EqualsLiteral("1")); } else { mInput->RemoveAttribute(NS_LITERAL_STRING("type")); - mInput->SetValue(nodeValue); + mInput->SetValue(text); } + + PRBool isReadOnly = PR_FALSE; + nsCOMPtr nodeContent = do_QueryInterface(resultNode); + if (nodeContent) { + nsIDOMXPathExpression *expr = + NS_STATIC_CAST(nsIDOMXPathExpression*, + nodeContent->GetProperty(nsXFormsAtoms::readonly)); + + if (expr) { + expr->Evaluate(mElement, + nsIDOMXPathResult::BOOLEAN_TYPE, nsnull, + getter_AddRefs(result)); + if (result) { + result->GetBooleanValue(&isReadOnly); + } + } + } + + mInput->SetReadOnly(isReadOnly); } } + + return NS_OK; } NS_HIDDEN_(nsresult) diff --git a/mozilla/extensions/xforms/nsXFormsInstanceElement.cpp b/mozilla/extensions/xforms/nsXFormsInstanceElement.cpp index cc90dced0bf..acd8c163845 100644 --- a/mozilla/extensions/xforms/nsXFormsInstanceElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsInstanceElement.cpp @@ -46,6 +46,8 @@ #include "nsIDOMEventReceiver.h" #include "nsIDOMXMLDocument.h" #include "nsIDOMDOMImplementation.h" +#include "nsIXTFGenericElementWrapper.h" +#include "nsXFormsUtils.h" static const nsIID sScriptingIIDs[] = { NS_IDOMELEMENT_IID, @@ -59,12 +61,17 @@ NS_IMPL_RELEASE(nsXFormsInstanceElement) NS_INTERFACE_MAP_BEGIN(nsXFormsInstanceElement) NS_INTERFACE_MAP_ENTRY(nsIXTFGenericElement) NS_INTERFACE_MAP_ENTRY(nsIXTFElement) - NS_INTERFACE_MAP_ENTRY(nsIXTFPrivate) + NS_INTERFACE_MAP_ENTRY(nsIInstanceElementPrivate) NS_INTERFACE_MAP_ENTRY(nsIDOMLoadListener) NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXTFGenericElement) NS_INTERFACE_MAP_END +nsXFormsInstanceElement::nsXFormsInstanceElement() + : mElement(nsnull) +{ +} + NS_IMETHODIMP nsXFormsInstanceElement::OnDestroyed() { @@ -93,9 +100,9 @@ NS_IMETHODIMP nsXFormsInstanceElement::GetScriptingInterfaces(PRUint32 *aCount, nsIID ***aArray) { - return CloneScriptingInterfaces(sScriptingIIDs, - NS_ARRAY_LENGTH(sScriptingIIDs), - aCount, aArray); + return nsXFormsUtils::CloneScriptingInterfaces(sScriptingIIDs, + NS_ARRAY_LENGTH(sScriptingIIDs), + aCount, aArray); } NS_IMETHODIMP @@ -206,12 +213,8 @@ nsXFormsInstanceElement::DoneAddingChildren() // and have all of our child elements, so this is our first opportunity // to create the instance document. - nsCOMPtr element; - mWrapper->GetElementNode(getter_AddRefs(element)); - NS_ASSERTION(element, "no wrapper element"); - nsAutoString src; - element->GetAttribute(NS_LITERAL_STRING("src"), src); + mElement->GetAttribute(NS_LITERAL_STRING("src"), src); if (src.IsEmpty()) { // If we don't have a linked external instance, use our inline data. @@ -238,7 +241,16 @@ nsXFormsInstanceElement::OnCreated(nsIXTFGenericElementWrapper *aWrapper) nsIXTFElement::NOTIFY_ATTRIBUTE_REMOVED | nsIXTFElement::NOTIFY_DONE_ADDING_CHILDREN); - mWrapper = aWrapper; + nsCOMPtr node; + aWrapper->GetElementNode(getter_AddRefs(node)); + + // It's ok to keep a weak pointer to mElement. mElement will have an + // owning reference to this object, so as long as we null out mElement in + // OnDestroyed, it will always be valid. + + mElement = node; + NS_ASSERTION(mElement, "Wrapper is not an nsIDOMElement, we'll crash soon"); + return NS_OK; } @@ -247,9 +259,9 @@ nsXFormsInstanceElement::OnCreated(nsIXTFGenericElementWrapper *aWrapper) NS_IMETHODIMP nsXFormsInstanceElement::Load(nsIDOMEvent *aEvent) { - nsXFormsModelElement *model = GetModel(); + nsCOMPtr model = GetModel(); if (model) - model->RemovePendingInstance(); + model->InstanceLoadFinished(PR_TRUE); return NS_OK; } @@ -269,11 +281,9 @@ nsXFormsInstanceElement::Unload(nsIDOMEvent *aEvent) NS_IMETHODIMP nsXFormsInstanceElement::Abort(nsIDOMEvent *aEvent) { - nsXFormsModelElement *model = GetModel(); - if (model) { - model->RemovePendingInstance(); - model->DispatchEvent(eEvent_LinkException); - } + nsCOMPtr model = GetModel(); + if (model) + model->InstanceLoadFinished(PR_FALSE); return NS_OK; } @@ -281,11 +291,9 @@ nsXFormsInstanceElement::Abort(nsIDOMEvent *aEvent) NS_IMETHODIMP nsXFormsInstanceElement::Error(nsIDOMEvent *aEvent) { - nsXFormsModelElement *model = GetModel(); - if (model) { - model->RemovePendingInstance(); - model->DispatchEvent(eEvent_LinkException); - } + nsCOMPtr model = GetModel(); + if (model) + model->InstanceLoadFinished(PR_FALSE); return NS_OK; } @@ -298,17 +306,21 @@ nsXFormsInstanceElement::HandleEvent(nsIDOMEvent *aEvent) return NS_OK; } -// nsIXTFPrivate +// nsIInstanceElementPrivate NS_IMETHODIMP -nsXFormsInstanceElement::GetInner(nsISupports **aInner) +nsXFormsInstanceElement::GetDocument(nsIDOMDocument **aDocument) { - NS_ENSURE_ARG_POINTER(aInner); - - NS_ADDREF(*aInner = NS_STATIC_CAST(nsIXTFGenericElement*, this)); + NS_IF_ADDREF(*aDocument = mDocument); return NS_OK; } +NS_IMETHODIMP +nsXFormsInstanceElement::SetDocument(nsIDOMDocument *aDocument) +{ + mDocument = aDocument; + return NS_OK; +} // private methods @@ -321,11 +333,8 @@ nsXFormsInstanceElement::CloneInlineInstance() return rv; // don't warn, we might just not be in the document yet // look for our first child element (skip over text nodes, etc.) - nsCOMPtr element; - mWrapper->GetElementNode(getter_AddRefs(element)); nsCOMPtr child, temp; - - element->GetFirstChild(getter_AddRefs(child)); + mElement->GetFirstChild(getter_AddRefs(child)); while (child) { PRUint16 nodeType; child->GetNodeType(&nodeType); @@ -363,30 +372,23 @@ nsXFormsInstanceElement::LoadExternalInstance(const nsAString &aSrc) nsCOMPtr xmlDoc = do_QueryInterface(mDocument); NS_ASSERTION(xmlDoc, "we created a document but it's not an XMLDocument?"); - nsCOMPtr element; - mWrapper->GetElementNode(getter_AddRefs(element)); - PRBool success; xmlDoc->Load(aSrc, &success); - nsXFormsModelElement *model = GetModel(); + nsCOMPtr model = GetModel(); if (model) { - if (success) - model->AddPendingInstance(); - else - model->DispatchEvent(eEvent_LinkException); + model->InstanceLoadStarted(); + if (!success) { + model->InstanceLoadFinished(PR_FALSE); + } } } nsresult nsXFormsInstanceElement::CreateInstanceDocument() { - nsCOMPtr element; - mWrapper->GetElementNode(getter_AddRefs(element)); - NS_ASSERTION(element, "no wrapper element"); - nsCOMPtr doc; - nsresult rv = element->GetOwnerDocument(getter_AddRefs(doc)); + nsresult rv = mElement->GetOwnerDocument(getter_AddRefs(doc)); NS_ENSURE_SUCCESS(rv, rv); if (!doc) // could be we just aren't inserted yet, so don't warn @@ -400,30 +402,16 @@ nsXFormsInstanceElement::CreateInstanceDocument() getter_AddRefs(mDocument)); } -nsXFormsModelElement* +already_AddRefed nsXFormsInstanceElement::GetModel() { - nsCOMPtr element; - mWrapper->GetElementNode(getter_AddRefs(element)); - NS_ASSERTION(element, "no wrapper element"); - nsCOMPtr parentNode; - element->GetParentNode(getter_AddRefs(parentNode)); + mElement->GetParentNode(getter_AddRefs(parentNode)); - nsCOMPtr modelElt = do_QueryInterface(parentNode); - if (!modelElt) - return nsnull; - - nsCOMPtr xtfPriv = do_QueryInterface(modelElt); - NS_ENSURE_TRUE(xtfPriv, nsnull); - - nsCOMPtr modelInner; - xtfPriv->GetInner(getter_AddRefs(modelInner)); - NS_ENSURE_TRUE(modelInner, nsnull); - - nsISupports *isupp = NS_STATIC_CAST(nsISupports*, modelInner.get()); - return NS_STATIC_CAST(nsXFormsModelElement*, - NS_STATIC_CAST(nsIXFormsModelElement*, isupp)); + nsIModelElementPrivate *model = nsnull; + if (parentNode) + CallQueryInterface(parentNode, &model); + return model; } nsresult diff --git a/mozilla/extensions/xforms/nsXFormsInstanceElement.h b/mozilla/extensions/xforms/nsXFormsInstanceElement.h index dbb111cb58e..0da0d686f6d 100644 --- a/mozilla/extensions/xforms/nsXFormsInstanceElement.h +++ b/mozilla/extensions/xforms/nsXFormsInstanceElement.h @@ -46,24 +46,23 @@ #define nsXFormsInstanceElement_h_ #include "nsIXTFGenericElement.h" -#include "nsIXTFPrivate.h" -#include "nsXFormsElement.h" #include "nsIDOMDocument.h" #include "nsCOMPtr.h" -#include "nsIXTFGenericElementWrapper.h" #include "nsIDOMLoadListener.h" -#include "nsXFormsModelElement.h" +#include "nsIModelElementPrivate.h" +#include "nsIInstanceElementPrivate.h" -class nsXFormsInstanceElement : public nsXFormsElement, - public nsIXTFGenericElement, - public nsIXTFPrivate, +class nsIDOMElement; + +class nsXFormsInstanceElement : public nsIXTFGenericElement, + public nsIInstanceElementPrivate, public nsIDOMLoadListener { public: NS_DECL_ISUPPORTS NS_DECL_NSIXTFELEMENT NS_DECL_NSIXTFGENERICELEMENT - NS_DECL_NSIXTFPRIVATE + NS_DECL_NSIINSTANCEELEMENTPRIVATE // nsIDOMEventListener NS_IMETHOD HandleEvent(nsIDOMEvent *aEvent); @@ -75,17 +74,16 @@ public: NS_IMETHOD Abort(nsIDOMEvent *aEvent); NS_IMETHOD Error(nsIDOMEvent *aEvent); - NS_HIDDEN_(nsIDOMDocument*) GetDocument() { return mDocument; } - NS_HIDDEN_(void) SetDocument(nsIDOMDocument *doc) { mDocument = doc; } + nsXFormsInstanceElement() NS_HIDDEN; private: NS_HIDDEN_(nsresult) CloneInlineInstance(); NS_HIDDEN_(void) LoadExternalInstance(const nsAString &aSrc); NS_HIDDEN_(nsresult) CreateInstanceDocument(); - NS_HIDDEN_(nsXFormsModelElement*) GetModel(); + NS_HIDDEN_(already_AddRefed) GetModel(); - nsCOMPtr mDocument; - nsCOMPtr mWrapper; + nsCOMPtr mDocument; + nsIDOMElement *mElement; }; NS_HIDDEN_(nsresult) diff --git a/mozilla/extensions/xforms/nsXFormsModelElement.cpp b/mozilla/extensions/xforms/nsXFormsModelElement.cpp index 05a54ac034b..40636576b83 100644 --- a/mozilla/extensions/xforms/nsXFormsModelElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsModelElement.cpp @@ -62,11 +62,12 @@ #include "nsIScriptGlobalObject.h" #include "nsIContent.h" #include "nsNetUtil.h" -#include "nsXFormsControl.h" +#include "nsIXFormsControl.h" #include "nsXFormsTypes.h" #include "nsXFormsXPathParser.h" #include "nsXFormsXPathAnalyzer.h" -#include "nsXFormsInstanceElement.h" +#include "nsIInstanceElementPrivate.h" +#include "nsXFormsUtils.h" #include "nsISchemaLoader.h" #include "nsAutoPtr.h" @@ -121,8 +122,8 @@ NS_IMPL_RELEASE(nsXFormsModelElement) NS_INTERFACE_MAP_BEGIN(nsXFormsModelElement) NS_INTERFACE_MAP_ENTRY(nsIXTFElement) NS_INTERFACE_MAP_ENTRY(nsIXTFGenericElement) - NS_INTERFACE_MAP_ENTRY(nsIXTFPrivate) NS_INTERFACE_MAP_ENTRY(nsIXFormsModelElement) + NS_INTERFACE_MAP_ENTRY(nsIModelElementPrivate) NS_INTERFACE_MAP_ENTRY(nsISchemaLoadListener) NS_INTERFACE_MAP_ENTRY(nsIWebServiceErrorHandler) NS_INTERFACE_MAP_ENTRY(nsIDOMLoadListener) @@ -188,9 +189,9 @@ nsXFormsModelElement::GetIsAttributeHandler(PRBool *aIsHandler) NS_IMETHODIMP nsXFormsModelElement::GetScriptingInterfaces(PRUint32 *aCount, nsIID ***aArray) { - return CloneScriptingInterfaces(sScriptingIIDs, - NS_ARRAY_LENGTH(sScriptingIIDs), - aCount, aArray); + return nsXFormsUtils::CloneScriptingInterfaces(sScriptingIIDs, + NS_ARRAY_LENGTH(sScriptingIIDs), + aCount, aArray); } NS_IMETHODIMP @@ -395,7 +396,7 @@ nsXFormsModelElement::HandleDefault(nsIDOMEvent *aEvent, PRBool *aHandled) // refresh all of our form controls PRInt32 controlCount = mFormControls.Count(); for (PRInt32 i = 0; i < controlCount; ++i) { - NS_STATIC_CAST(nsXFormsControl*, mFormControls[i])->Refresh(); + NS_STATIC_CAST(nsIXFormsControl*, mFormControls[i])->Refresh(); } } else if (type.EqualsLiteral("xforms-revalidate")) { Revalidate(); @@ -438,15 +439,6 @@ nsXFormsModelElement::OnCreated(nsIXTFGenericElementWrapper *aWrapper) return NS_OK; } -// nsIXTFPrivate -NS_IMETHODIMP -nsXFormsModelElement::GetInner(nsISupports **aInner) -{ - NS_ENSURE_ARG_POINTER(aInner); - NS_ADDREF(*aInner = NS_STATIC_CAST(nsIXFormsModelElement*, this)); - return NS_OK; -} - // nsIXFormsModelElement NS_IMETHODIMP @@ -455,7 +447,7 @@ nsXFormsModelElement::GetInstanceDocument(const nsAString& aInstanceID, { NS_ENSURE_ARG_POINTER(aDocument); - NS_IF_ADDREF(*aDocument = FindInstanceDocument(aInstanceID)); + *aDocument = FindInstanceDocument(aInstanceID).get(); // transfer reference return *aDocument ? NS_OK : NS_ERROR_FAILURE; } @@ -609,16 +601,64 @@ nsXFormsModelElement::Error(nsIDOMEvent* aEvent) return NS_OK; } -// internal methods +// nsIModelElementPrivate -nsXFormsInstanceElement * -nsXFormsModelElement::FindInstanceElement(const nsAString &aID) +NS_IMETHODIMP +nsXFormsModelElement::AddFormControl(nsIXFormsControl *aControl) { + if (mFormControls.IndexOf(aControl) == -1) + mFormControls.AppendElement(aControl); + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsModelElement::RemoveFormControl(nsIXFormsControl *aControl) +{ + mFormControls.RemoveElement(aControl); + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsModelElement::GetTypeForControl(nsIXFormsControl *aControl, + nsISchemaType **aType) +{ + *aType = nsnull; + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsModelElement::InstanceLoadStarted() +{ + ++mPendingInstanceCount; + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsModelElement::InstanceLoadFinished(PRBool aSuccess) +{ + --mPendingInstanceCount; + if (!aSuccess) { + DispatchEvent(eEvent_LinkException); + } else if (IsComplete()) { + nsresult rv = FinishConstruction(); + if (NS_SUCCEEDED(rv)) + DispatchEvent(eEvent_Refresh); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsModelElement::FindInstanceElement(const nsAString &aID, + nsIInstanceElementPrivate **aElement) +{ + *aElement = nsnull; + nsCOMPtr children; mElement->GetChildNodes(getter_AddRefs(children)); if (!children) - return nsnull; + return NS_OK; PRUint32 childCount = 0; children->GetLength(&childCount); @@ -637,40 +677,42 @@ nsXFormsModelElement::FindInstanceElement(const nsAString &aID) element->GetAttribute(NS_LITERAL_STRING("id"), id); if (aID.IsEmpty() || aID.Equals(id)) { - // make sure this is an xforms instance element - nsAutoString namespaceURI, localName; - element->GetNamespaceURI(namespaceURI); - element->GetLocalName(localName); - - if (localName.EqualsLiteral("instance") && - namespaceURI.EqualsLiteral(NS_NAMESPACE_XFORMS)) { - - // This is the requested instance, so get its document. - nsCOMPtr xtfPriv = do_QueryInterface(element); - NS_ENSURE_TRUE(xtfPriv, nsnull); - - nsCOMPtr instanceInner; - xtfPriv->GetInner(getter_AddRefs(instanceInner)); - NS_ENSURE_TRUE(instanceInner, nsnull); - - nsISupports *isupp = NS_STATIC_CAST(nsISupports*, instanceInner.get()); - nsXFormsInstanceElement *instance = - NS_STATIC_CAST(nsXFormsInstanceElement*, - NS_STATIC_CAST(nsIXTFGenericElement*, isupp)); - - return instance; - } + CallQueryInterface(element, aElement); + if (*aElement) + break; } } - return nsnull; + return NS_OK; } -nsIDOMDocument * +NS_IMETHODIMP +nsXFormsModelElement::GetSubmissionActive(PRBool *aIsActive) +{ + *aIsActive = mSubmissionActive; + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsModelElement::SetSubmissionActive(PRBool aIsActive) +{ + mSubmissionActive = aIsActive; + return NS_OK; +} + +// internal methods + +already_AddRefed nsXFormsModelElement::FindInstanceDocument(const nsAString &aID) { - nsXFormsInstanceElement *instance = FindInstanceElement(aID); - return instance ? instance->GetDocument() : nsnull; + nsCOMPtr instance; + nsXFormsModelElement::FindInstanceElement(aID, getter_AddRefs(instance)); + + nsIDOMDocument *doc = nsnull; + if (instance) + instance->GetDocument(&doc); // addrefs + + return doc; } nsresult @@ -683,7 +725,8 @@ nsXFormsModelElement::FinishConstruction() // we get the instance data from our instance child nodes - nsIDOMDocument *firstInstanceDoc = FindInstanceDocument(EmptyString()); + nsCOMPtr firstInstanceDoc = + FindInstanceDocument(EmptyString()); if (!firstInstanceDoc) return NS_OK; @@ -710,7 +753,7 @@ nsXFormsModelElement::FinishConstruction() if (localName.EqualsLiteral("bind")) { child->GetNamespaceURI(namespaceURI); if (namespaceURI.EqualsLiteral(NS_NAMESPACE_XFORMS)) { - if (!ProcessBind(xpath, firstInstanceRoot, + if (!ProcessBind(xpath, firstInstanceRoot, nsnull, nsCOMPtr(do_QueryInterface(child)))) { DispatchEvent(eEvent_BindingException); return NS_OK; @@ -744,18 +787,10 @@ ReleaseExpr(void *aElement, PRBool nsXFormsModelElement::ProcessBind(nsIDOMXPathEvaluator *aEvaluator, - nsIDOMNode *aContextNode, - nsIDOMElement *aBindElement) + nsIDOMNode *aContextNode, + nsIDOMXPathResult *aOuterNodeset, + nsIDOMElement *aBindElement) { - // Get the expression for the nodes that this applies to. - nsAutoString expr; - aBindElement->GetAttribute(NS_LITERAL_STRING("nodeset"), expr); - if (expr.IsEmpty()) - return PR_TRUE; - - nsCOMPtr resolver; - aEvaluator->CreateNSResolver(aBindElement, getter_AddRefs(resolver)); - // Get the model item properties specified by this . nsCOMPtr props[eModel__count]; nsAutoString exprStrings[eModel__count]; @@ -763,6 +798,9 @@ nsXFormsModelElement::ProcessBind(nsIDOMXPathEvaluator *aEvaluator, nsresult rv = NS_OK; nsAutoString attrStr; + nsCOMPtr resolver; + aEvaluator->CreateNSResolver(aBindElement, getter_AddRefs(resolver)); + for (int i = 0; i < eModel__count; ++i) { sModelPropsList[i]->ToString(attrStr); @@ -777,15 +815,20 @@ nsXFormsModelElement::ProcessBind(nsIDOMXPathEvaluator *aEvaluator, } } - if (propCount == 0) - return PR_TRUE; // successful, but nothing to do - + // Find the nodeset that this bind applies to. nsCOMPtr result; - rv = aEvaluator->Evaluate(expr, aContextNode, resolver, - nsIDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, - nsnull, getter_AddRefs(result)); - if (NS_FAILED(rv)) - return PR_FALSE; + + nsAutoString expr; + aBindElement->GetAttribute(NS_LITERAL_STRING("nodeset"), expr); + if (expr.IsEmpty()) { + result = aOuterNodeset; + } else { + rv = aEvaluator->Evaluate(expr, aContextNode, resolver, + nsIDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, + nsnull, getter_AddRefs(result)); + if (NS_FAILED(rv)) + return PR_FALSE; // dispatch a binding exception + } PRUint32 snapLen; rv = result->GetSnapshotLength(&snapLen); @@ -839,7 +882,38 @@ nsXFormsModelElement::ProcessBind(nsIDOMXPathEvaluator *aEvaluator, } } - + // Now evaluate any child elements. + nsCOMPtr childContext; + result->SnapshotItem(0, getter_AddRefs(childContext)); + + nsCOMPtr children; + aBindElement->GetChildNodes(getter_AddRefs(children)); + if (children) { + PRUint32 childCount = 0; + children->GetLength(&childCount); + + nsCOMPtr child; + nsAutoString value; + + for (PRUint32 k = 0; k < childCount; ++k) { + children->Item(k, getter_AddRefs(child)); + if (child) { + child->GetLocalName(value); + if (!value.EqualsLiteral("bind")) + continue; + + child->GetNamespaceURI(value); + if (!value.EqualsLiteral(NS_NAMESPACE_XFORMS)) + continue; + + if (!ProcessBind(aEvaluator, childContext, result, + nsCOMPtr(do_QueryInterface(child)))) + return PR_FALSE; + + } + } + } + return PR_TRUE; } @@ -864,36 +938,6 @@ nsXFormsModelElement::DispatchEvent(nsXFormsModelEvent aEvent) return target->DispatchEvent(event, &cancelled); } -already_AddRefed -nsXFormsModelElement::GetTypeForControl(nsXFormsControl *aControl) -{ - return nsnull; -} - -void -nsXFormsModelElement::AddFormControl(nsXFormsControl *aControl) -{ - if (mFormControls.IndexOf(aControl) == -1) - mFormControls.AppendElement(aControl); -} - -void -nsXFormsModelElement::RemoveFormControl(nsXFormsControl *aControl) -{ - mFormControls.RemoveElement(aControl); -} - -void -nsXFormsModelElement::RemovePendingInstance() -{ - --mPendingInstanceCount; - if (IsComplete()) { - nsresult rv = FinishConstruction(); - if (NS_SUCCEEDED(rv)) - DispatchEvent(eEvent_Refresh); - } -} - /* static */ void nsXFormsModelElement::Startup() { diff --git a/mozilla/extensions/xforms/nsXFormsModelElement.h b/mozilla/extensions/xforms/nsXFormsModelElement.h index 5c0603725ff..9dca2faa2a3 100644 --- a/mozilla/extensions/xforms/nsXFormsModelElement.h +++ b/mozilla/extensions/xforms/nsXFormsModelElement.h @@ -40,8 +40,7 @@ #define nsXFormsModelElement_h_ #include "nsIXTFGenericElement.h" -#include "nsIXTFPrivate.h" -#include "nsIXFormsModelElement.h" +#include "nsIModelElementPrivate.h" #include "nsISchema.h" #include "nsCOMArray.h" #include "nsVoidArray.h" @@ -49,7 +48,6 @@ #include "nsIDOMLoadListener.h" #include "nsIDOMDocument.h" #include "nsXFormsMDG.h" -#include "nsXFormsElement.h" #include "nsISchemaLoader.h" #include "nsISchema.h" @@ -58,7 +56,6 @@ class nsIDOMElement; class nsIDOMNode; class nsIDOMXPathEvaluator; class nsXFormsControl; -class nsXFormsInstanceElement; enum nsXFormsModelEvent { eEvent_ModelConstruct, @@ -76,10 +73,8 @@ enum nsXFormsModelEvent { eEvent_ComputeException }; -class nsXFormsModelElement : public nsXFormsElement, - public nsIXTFGenericElement, - public nsIXTFPrivate, - public nsIXFormsModelElement, +class nsXFormsModelElement : public nsIXTFGenericElement, + public nsIModelElementPrivate, public nsISchemaLoadListener, public nsIDOMLoadListener { @@ -89,8 +84,8 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSIXTFELEMENT NS_DECL_NSIXTFGENERICELEMENT - NS_DECL_NSIXTFPRIVATE NS_DECL_NSIXFORMSMODELELEMENT + NS_DECL_NSIMODELELEMENTPRIVATE NS_DECL_NSISCHEMALOADLISTENER NS_DECL_NSIWEBSERVICEERRORHANDLER NS_DECL_NSIDOMEVENTLISTENER @@ -102,30 +97,20 @@ public: NS_IMETHOD Abort(nsIDOMEvent* aEvent); NS_IMETHOD Error(nsIDOMEvent* aEvent); - NS_HIDDEN_(nsresult) DispatchEvent(nsXFormsModelEvent aEvent); - - NS_HIDDEN_(already_AddRefed) - GetTypeForControl(nsXFormsControl *aControl); - - NS_HIDDEN_(void) AddFormControl(nsXFormsControl *aControl); - NS_HIDDEN_(void) RemoveFormControl(nsXFormsControl *aControl); - - NS_HIDDEN_(void) AddPendingInstance() { ++mPendingInstanceCount; } - NS_HIDDEN_(void) RemovePendingInstance(); - - NS_HIDDEN_(nsXFormsInstanceElement*) FindInstanceElement(const nsAString &aID); - NS_HIDDEN_(nsIDOMDocument*) FindInstanceDocument(const nsAString &aID); - - NS_HIDDEN_(PRBool) IsSubmissionActive() { return mSubmissionActive; } - NS_HIDDEN_(void) SetSubmissionActive(PRBool val) { mSubmissionActive = val; } - // Called after nsXFormsAtoms is registered static NS_HIDDEN_(void) Startup(); private: + NS_HIDDEN_(nsresult) DispatchEvent(nsXFormsModelEvent aEvent); + + NS_HIDDEN_(already_AddRefed) + FindInstanceDocument(const nsAString &aID); + NS_HIDDEN_(nsresult) FinishConstruction(); + NS_HIDDEN_(PRBool) ProcessBind(nsIDOMXPathEvaluator *aEvaluator, nsIDOMNode *aContextNode, + nsIDOMXPathResult *aOuterNodeset, nsIDOMElement *aBindElement); NS_HIDDEN_(void) RemoveModelFromDocument(); diff --git a/mozilla/extensions/xforms/nsXFormsModule.cpp b/mozilla/extensions/xforms/nsXFormsModule.cpp index d297a184e6b..070cfff850a 100644 --- a/mozilla/extensions/xforms/nsXFormsModule.cpp +++ b/mozilla/extensions/xforms/nsXFormsModule.cpp @@ -40,6 +40,7 @@ #include "nsXFormsElementFactory.h" #include "nsXFormsAtoms.h" #include "nsXFormsModelElement.h" +#include "nsXFormsUtils.h" NS_GENERIC_FACTORY_CONSTRUCTOR(nsXFormsElementFactory) diff --git a/mozilla/extensions/xforms/nsXFormsStubElement.cpp b/mozilla/extensions/xforms/nsXFormsStubElement.cpp index f710d7def50..eb13b4c1d52 100644 --- a/mozilla/extensions/xforms/nsXFormsStubElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsStubElement.cpp @@ -41,6 +41,7 @@ #include "nsIDOMEventTarget.h" #include "nsIDOM3Node.h" #include "nsMemory.h" +#include "nsXFormsUtils.h" static const nsIID sScriptingIIDs[] = { NS_IDOMELEMENT_IID, @@ -73,9 +74,9 @@ nsXFormsStubElement::GetIsAttributeHandler(PRBool *aIsAttributeHandler) NS_IMETHODIMP nsXFormsStubElement::GetScriptingInterfaces(PRUint32 *aCount, nsIID ***aArray) { - return CloneScriptingInterfaces(sScriptingIIDs, - NS_ARRAY_LENGTH(sScriptingIIDs), - aCount, aArray); + return nsXFormsUtils::CloneScriptingInterfaces(sScriptingIIDs, + NS_ARRAY_LENGTH(sScriptingIIDs), + aCount, aArray); } NS_IMETHODIMP diff --git a/mozilla/extensions/xforms/nsXFormsStubElement.h b/mozilla/extensions/xforms/nsXFormsStubElement.h index c5bf5fbe514..2c71c99193d 100644 --- a/mozilla/extensions/xforms/nsXFormsStubElement.h +++ b/mozilla/extensions/xforms/nsXFormsStubElement.h @@ -40,10 +40,8 @@ #define nsXFormsStubElement_h_ #include "nsIXTFGenericElement.h" -#include "nsXFormsElement.h" -class nsXFormsStubElement : public nsXFormsElement, - public nsIXTFGenericElement +class nsXFormsStubElement : public nsIXTFGenericElement { NS_DECL_ISUPPORTS NS_DECL_NSIXTFELEMENT diff --git a/mozilla/extensions/xforms/nsXFormsSubmissionElement.cpp b/mozilla/extensions/xforms/nsXFormsSubmissionElement.cpp index 0e25740b044..89858004b93 100644 --- a/mozilla/extensions/xforms/nsXFormsSubmissionElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsSubmissionElement.cpp @@ -45,11 +45,8 @@ #include -#include "nsXFormsModelElement.h" -#include "nsXFormsInstanceElement.h" #include "nsXFormsSubmissionElement.h" -#include "nsXFormsAtoms.h" -#include "nsIXFormsModelElement.h" +#include "nsIInstanceElementPrivate.h" #include "nsIXTFGenericElementWrapper.h" #include "nsIDOMDocument.h" #include "nsIDOMElement.h" @@ -61,9 +58,6 @@ #include "nsIDOM3Node.h" #include "nsIDOMXMLDocument.h" #include "nsIDOMXPathResult.h" -#include "nsIDOMXPathEvaluator.h" -#include "nsIDOMXPathNSResolver.h" -#include "nsIDOMXPathExpression.h" #include "nsIDOMSerializer.h" #include "nsIDOMDOMImplementation.h" #include "nsIDOMProcessingInstruction.h" @@ -89,6 +83,7 @@ #include "nsMemory.h" #include "nsCOMPtr.h" #include "nsNetUtil.h" +#include "nsXFormsUtils.h" // namespace literals #define NAMESPACE_XML_SCHEMA \ @@ -272,9 +267,9 @@ nsXFormsSubmissionElement::GetIsAttributeHandler(PRBool *aIsAttributeHandler) NS_IMETHODIMP nsXFormsSubmissionElement::GetScriptingInterfaces(PRUint32 *aCount, nsIID ***aArray) { - return CloneScriptingInterfaces(sScriptingIIDs, - NS_ARRAY_LENGTH(sScriptingIIDs), - aCount, aArray); + return nsXFormsUtils::CloneScriptingInterfaces(sScriptingIIDs, + NS_ARRAY_LENGTH(sScriptingIIDs), + aCount, aArray); } NS_IMETHODIMP @@ -448,26 +443,16 @@ nsXFormsSubmissionElement::OnStopRequest(nsIRequest *request, nsISupports *ctx, // private methods -nsXFormsModelElement* +already_AddRefed nsXFormsSubmissionElement::GetModel() { nsCOMPtr parentNode; mElement->GetParentNode(getter_AddRefs(parentNode)); - nsCOMPtr modelElt = do_QueryInterface(parentNode); - if (!modelElt) - return nsnull; - - nsCOMPtr xtfPriv = do_QueryInterface(modelElt); - NS_ENSURE_TRUE(xtfPriv, nsnull); - - nsCOMPtr modelInner; - xtfPriv->GetInner(getter_AddRefs(modelInner)); - NS_ENSURE_TRUE(modelInner, nsnull); - - nsISupports *isupp = NS_STATIC_CAST(nsISupports*, modelInner.get()); - return NS_STATIC_CAST(nsXFormsModelElement*, - NS_STATIC_CAST(nsIXFormsModelElement*, isupp)); + nsIModelElementPrivate *model = nsnull; + if (parentNode) + CallQueryInterface(parentNode, &model); + return model; } nsresult @@ -510,9 +495,14 @@ nsXFormsSubmissionElement::LoadReplaceInstance(nsIChannel *channel) } } - nsXFormsInstanceElement *instance = - GetModel()->FindInstanceElement(EmptyString()); - instance->SetDocument(newDoc); + nsCOMPtr model = GetModel(); + if (model) { + nsCOMPtr instance; + model->FindInstanceElement(EmptyString(), getter_AddRefs(instance)); + if (instance) { + instance->SetDocument(newDoc); + } + } return NS_OK; } @@ -553,8 +543,12 @@ nsXFormsSubmissionElement::Submit() nsresult rv; // 1. ensure that we are not currently processing a xforms-submit on our model - nsXFormsModelElement *model = GetModel(); - NS_ENSURE_STATE(!model->IsSubmissionActive()); + nsCOMPtr model = GetModel(); + + PRBool submissionActive = PR_FALSE; + model->GetSubmissionActive(&submissionActive); + NS_ENSURE_STATE(!submissionActive); + model->SetSubmissionActive(PR_TRUE); @@ -595,7 +589,8 @@ nsXFormsSubmissionElement::SubmitEnd(PRBool succeeded) { LOG(("xforms submission complete [succeeded=%d]\n", succeeded)); - GetModel()->SetSubmissionActive(PR_FALSE); + nsCOMPtr model = GetModel(); + model->SetSubmissionActive(PR_FALSE); nsCOMPtr domDoc; mElement->GetOwnerDocument(getter_AddRefs(domDoc)); @@ -628,60 +623,18 @@ nsXFormsSubmissionElement::SubmitEnd(PRBool succeeded) nsresult nsXFormsSubmissionElement::GetSelectedInstanceData(nsIDOMNode **result) { - // XXX need to support 'instance(id)' xpath function. for now, we assume - // that any xpath expression is relative to the first element. + nsCOMPtr model; + nsCOMPtr bind; + nsCOMPtr xpRes = + nsXFormsUtils::EvaluateNodeBinding(mElement, + nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, + getter_AddRefs(model), + getter_AddRefs(bind)); - nsCOMPtr instance; - GetDefaultInstanceData(getter_AddRefs(instance)); - NS_ENSURE_TRUE(instance, NS_ERROR_UNEXPECTED); + if (!xpRes) + return NS_ERROR_UNEXPECTED; - nsAutoString value; - mElement->GetAttribute(NS_LITERAL_STRING("bind"), value); - if (value.IsEmpty()) - { - // inspect 'ref' attribute - mElement->GetAttribute(NS_LITERAL_STRING("ref"), value); - } - else - { - // ok, value contains the 'ID' of a element. - nsCOMPtr doc; - mElement->GetOwnerDocument(getter_AddRefs(doc)); - - nsCOMPtr bindElement; - doc->GetElementById(value, getter_AddRefs(bindElement)); - NS_ENSURE_TRUE(bindElement, NS_ERROR_UNEXPECTED); - - bindElement->GetAttribute(NS_LITERAL_STRING("nodeset"), value); - } - - if (value.IsEmpty()) - { - // select first element - // instance->GetFirstChild(result); - NS_ADDREF(*result = instance); - return NS_OK; - } - - // evaluate 'value' as an xpath expression - - nsCOMPtr domDoc; - mElement->GetOwnerDocument(getter_AddRefs(domDoc)); - nsCOMPtr xpath = do_QueryInterface(domDoc); - NS_ENSURE_TRUE(xpath, NS_ERROR_UNEXPECTED); - - nsCOMPtr resolver; - xpath->CreateNSResolver(instance, getter_AddRefs(resolver)); - NS_ENSURE_TRUE(resolver, NS_ERROR_UNEXPECTED); - - nsCOMPtr xpathResult; - xpath->Evaluate(value, instance, resolver, - nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, nsnull, - getter_AddRefs(xpathResult)); - nsCOMPtr nodeset = do_QueryInterface(xpathResult); - NS_ENSURE_TRUE(nodeset, NS_ERROR_UNEXPECTED); - - return nodeset->GetSingleNodeValue(result); + return xpRes->GetSingleNodeValue(result); } PRBool diff --git a/mozilla/extensions/xforms/nsXFormsSubmissionElement.h b/mozilla/extensions/xforms/nsXFormsSubmissionElement.h index 891d7576603..48cded7823a 100644 --- a/mozilla/extensions/xforms/nsXFormsSubmissionElement.h +++ b/mozilla/extensions/xforms/nsXFormsSubmissionElement.h @@ -42,10 +42,9 @@ #include "nsIXTFGenericElement.h" #include "nsIRequestObserver.h" #include "nsIInputStream.h" -#include "nsXFormsElement.h" #include "nsCOMPtr.h" +#include "nsIModelElementPrivate.h" -class nsXFormsModelElement; class nsIMultiplexInputStream; class nsIDOMElement; class nsIChannel; @@ -55,8 +54,7 @@ class nsString; class SubmissionAttachmentArray; -class nsXFormsSubmissionElement : public nsXFormsElement, - public nsIXTFGenericElement, +class nsXFormsSubmissionElement : public nsIXTFGenericElement, public nsIRequestObserver { public: @@ -69,7 +67,7 @@ public: : mElement(nsnull) {} - NS_HIDDEN_(nsXFormsModelElement *) GetModel(); + NS_HIDDEN_(already_AddRefed) GetModel(); NS_HIDDEN_(nsresult) LoadReplaceInstance(nsIChannel *); NS_HIDDEN_(nsresult) LoadReplaceAll(nsIChannel *); diff --git a/mozilla/extensions/xforms/nsXFormsUtils.cpp b/mozilla/extensions/xforms/nsXFormsUtils.cpp new file mode 100644 index 00000000000..fdc5f6de875 --- /dev/null +++ b/mozilla/extensions/xforms/nsXFormsUtils.cpp @@ -0,0 +1,312 @@ +/* -*- 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 + * + * 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 ***** */ + +#include "nsXFormsUtils.h" +#include "nsString.h" +#include "nsXFormsAtoms.h" +#include "nsIDOMElement.h" +#include "nsIDocument.h" +#include "nsINameSpaceManager.h" +#include "nsINodeInfo.h" +#include "nsIDOMNodeList.h" +#include "nsIDOMXPathEvaluator.h" +#include "nsIDOMXPathResult.h" +#include "nsIDOMXPathNSResolver.h" +#include "nsIDOMDocument.h" +#include "nsIXFormsModelElement.h" + +/* static */ nsIDOMNode* +nsXFormsUtils::GetModelAndBind(nsIDOMElement *aElement, + nsIDOMElement **aBindElement) +{ + *aBindElement = nsnull; + NS_ENSURE_TRUE(aElement, nsnull); + + nsCOMPtr domDoc; + aElement->GetOwnerDocument(getter_AddRefs(domDoc)); + if (!domDoc) + return nsnull; + + nsAutoString bindId; + aElement->GetAttribute(NS_LITERAL_STRING("bind"), bindId); + + nsCOMPtr modelWrapper; + + if (!bindId.IsEmpty()) { + // Get the bind element with the given id. + domDoc->GetElementById(bindId, aBindElement); + + if (*aBindElement) { + // Walk up the tree looking for the containing model. + (*aBindElement)->GetParentNode(getter_AddRefs(modelWrapper)); + + nsAutoString localName, namespaceURI; + nsCOMPtr temp; + + while (modelWrapper) { + modelWrapper->GetLocalName(localName); + if (localName.EqualsLiteral("model")) { + modelWrapper->GetNamespaceURI(namespaceURI); + if (namespaceURI.EqualsLiteral(NS_NAMESPACE_XFORMS)) + break; + } + + temp.swap(modelWrapper); + temp->GetParentNode(getter_AddRefs(modelWrapper)); + } + } + } else { + // If no bind was given, we use model. + nsAutoString modelId; + aElement->GetAttribute(NS_LITERAL_STRING("model"), modelId); + + if (modelId.IsEmpty()) { + // No model given, so use the first one in the document. + nsCOMPtr nodes; + domDoc->GetElementsByTagNameNS(NS_LITERAL_STRING(NS_NAMESPACE_XFORMS), + NS_LITERAL_STRING("model"), + getter_AddRefs(nodes)); + + if (!nodes) + return nsnull; + + nodes->Item(0, getter_AddRefs(modelWrapper)); + } else { + nsCOMPtr wrapperElement; + domDoc->GetElementById(modelId, getter_AddRefs(wrapperElement)); + modelWrapper = wrapperElement; + } + } + + // We're releasing this reference, but the node is owned by the DOM. + return modelWrapper; +} + +/* static */ already_AddRefed +nsXFormsUtils::EvaluateXPath(const nsAString &aExpression, + nsIDOMNode *aContextNode, + nsIDOMNode *aResolverNode, + PRUint16 aResultType) +{ + nsCOMPtr doc; + aContextNode->GetOwnerDocument(getter_AddRefs(doc)); + NS_ENSURE_TRUE(doc, nsnull); + + nsCOMPtr eval = do_QueryInterface(doc); + NS_ENSURE_TRUE(eval, nsnull); + + nsCOMPtr resolver; + eval->CreateNSResolver(aResolverNode, getter_AddRefs(resolver)); + NS_ENSURE_TRUE(resolver, nsnull); + + nsCOMPtr supResult; + eval->Evaluate(aExpression, aContextNode, resolver, aResultType, nsnull, + getter_AddRefs(supResult)); + + nsIDOMXPathResult *result = nsnull; + if (supResult) + CallQueryInterface(supResult, &result); // addrefs + return result; +} + +/* static */ already_AddRefed +nsXFormsUtils::FindBindContext(nsIDOMElement *aElement, + nsIXFormsModelElement *aModel) +{ + // Figure out the context node for this . + // The outermost bind has the root element of the [first] instance document + // as its context node. For inner binds, the first node in the nodeset + // of the parent is used as the context node. + + nsCOMPtr modelNode = do_QueryInterface(aModel); + + nsCOMPtr parentNode; + aElement->GetParentNode(getter_AddRefs(parentNode)); + if (!parentNode) + return nsnull; // illegal, a bind must be contained in a model. + + if (parentNode == modelNode) { + // This is the outermost bind. + nsCOMPtr instanceDoc; + aModel->GetInstanceDocument(NS_LITERAL_STRING(""), + getter_AddRefs(instanceDoc)); + if (!instanceDoc) + return nsnull; + + nsIDOMElement *docElement = nsnull; + instanceDoc->GetDocumentElement(&docElement); // addrefs + return docElement; + } + + // The context node is the first node in the nodeset of the parent bind. + nsCOMPtr parentNodeSet = + EvaluateNodeset(nsCOMPtr(do_QueryInterface(parentNode)), + nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE); + + nsIDOMNode *nodeResult = nsnull; + if (parentNodeSet) + parentNodeSet->GetSingleNodeValue(&nodeResult); // addrefs + + return nodeResult; +} + +/* static */ already_AddRefed +nsXFormsUtils::EvaluateNodeset(nsIDOMElement *aElement, PRUint16 aResultType) +{ + // The first thing we need to do is ensure that we have a nodeset attribute. + // If we don't, we walk up and check for it on outer bind elements. + // While we're walking up, we also locate the model element. + + nsCOMPtr model; + nsCOMPtr bindElement, element = aElement; + nsCOMPtr temp; + nsAutoString nodeset; + + while (element) { + model = do_QueryInterface(element); + if (model) + break; + + if (!bindElement) { + element->GetAttribute(NS_LITERAL_STRING("nodeset"), nodeset); + if (!nodeset.IsEmpty()) { + // Verify that this is a element; + nsAutoString value; + element->GetNamespaceURI(value); + if (value.EqualsLiteral(NS_NAMESPACE_XFORMS)) { + element->GetLocalName(value); + if (value.EqualsLiteral("bind")) { + bindElement = element; + } + } + } + } + + element->GetParentNode(getter_AddRefs(temp)); + element = do_QueryInterface(temp); + } + + if (!bindElement || !model) + return nsnull; + + nsCOMPtr contextNode = FindBindContext(bindElement, model); + if (!contextNode) + return nsnull; + + return EvaluateXPath(nodeset, contextNode, bindElement, aResultType); +} + +/* static */ already_AddRefed +nsXFormsUtils::EvaluateNodeBinding(nsIDOMElement *aElement, + PRUint16 aResultType, + nsIDOMNode **aModel, + nsIDOMElement **aBind) +{ + // A control may be attached to a model by either using the 'bind' + // attribute to give the id of a bind element, or using the 'model' + // attribute to give the id of a model. If neither of these are given, + // the control belongs to the first model in the document. + + *aBind = nsnull; + + NS_IF_ADDREF(*aModel = GetModelAndBind(aElement, aBind)); + if (!*aModel) + return nsnull; + + // If there is a bind element, we just evaluate its nodeset. + if (*aBind) + return EvaluateNodeset(*aBind, aResultType); + + // If not, we expect there to be a ref attribute. + nsAutoString expr; + aElement->GetAttribute(NS_LITERAL_STRING("ref"), expr); + + if (expr.IsEmpty()) + return nsnull; + + // Get the instance data and evaluate the xpath expression. + // XXXfixme when xpath extensions are implemented (instance()) + nsCOMPtr instanceDoc; + nsCOMPtr model = do_QueryInterface(*aModel); + if (!model) { + // The referenced model is not actually a model element, or does not exist. + return nsnull; + } + + model->GetInstanceDocument(NS_LITERAL_STRING(""), + getter_AddRefs(instanceDoc)); + + if (!instanceDoc) + return nsnull; + + nsCOMPtr docElement; + instanceDoc->GetDocumentElement(getter_AddRefs(docElement)); + if (!docElement) + return nsnull; // this will happen if the doc is still loading + + return EvaluateXPath(expr, docElement, aElement, aResultType); +} + +/* static */ nsresult +nsXFormsUtils::CloneScriptingInterfaces(const nsIID *aIIDList, + unsigned int aIIDCount, + PRUint32 *aOutCount, + nsIID ***aOutArray) +{ + nsIID **iids = NS_STATIC_CAST(nsIID**, + nsMemory::Alloc(aIIDCount * sizeof(nsIID*))); + if (!iids) { + return NS_ERROR_OUT_OF_MEMORY; + } + + for (PRUint32 i = 0; i < aIIDCount; ++i) { + iids[i] = NS_STATIC_CAST(nsIID*, + nsMemory::Clone(&aIIDList[i], sizeof(nsIID))); + + if (!iids[i]) { + for (PRUint32 j = 0; j < i; ++j) + nsMemory::Free(iids[j]); + nsMemory::Free(iids); + return NS_ERROR_OUT_OF_MEMORY; + } + } + + *aOutArray = iids; + *aOutCount = aIIDCount; + return NS_OK; +} diff --git a/mozilla/extensions/xforms/nsXFormsUtils.h b/mozilla/extensions/xforms/nsXFormsUtils.h new file mode 100644 index 00000000000..4a040be121a --- /dev/null +++ b/mozilla/extensions/xforms/nsXFormsUtils.h @@ -0,0 +1,124 @@ +/* -*- 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 + * + * 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 ***** */ + +#ifndef nsXFormsUtils_h_ +#define nsXFormsUtils_h_ + +/** + * This class has static helper methods that don't fit into a specific place + * in the class hierarchy. + */ + +#include "prtypes.h" +#include "nsCOMPtr.h" +#include "nsIDOMXPathResult.h" + +class nsIDOMNode; +class nsIDOMElement; +class nsIXFormsModelElement; + +#define NS_NAMESPACE_XFORMS "http://www.w3.org/2002/xforms" +#define NS_NAMESPACE_XHTML "http://www.w3.org/1999/xhtml" + +class nsXFormsUtils +{ +public: + /** + * Locate the model that |aElement| is bound to, and if applicable, the + * element that it uses. The model is returned and the + * bind element is returned (addrefed) in |aBindElement|. + */ + + static NS_HIDDEN_(nsIDOMNode*) + GetModelAndBind(nsIDOMElement *aElement, nsIDOMElement **aBindElement); + + /** + * Evaluate a 'bind' or 'ref' attribute on |aElement|. |aResultType| is + * used as the desired result type for the XPath evaluation. The model and + * bind elements (if applicable) are located as part of this evaluation, + * and are returned (addrefed) in |aModel| and |aBind|. + * + * The return value is an XPathResult as returned from + * nsIDOMXPathEvaluator::Evaluate(). + */ + static NS_HIDDEN_(already_AddRefed) + EvaluateNodeBinding(nsIDOMElement *aElement, + PRUint16 aResultType, + nsIDOMNode **aModel, + nsIDOMElement **aBind); + + + /** + * Given a bind element |aElement|, return the nodeset that it applies to. + * |aResultType| is used as the desired result type for the XPath + * evaluation. + */ + static NS_HIDDEN_(already_AddRefed) + EvaluateNodeset(nsIDOMElement *aElement, PRUint16 aResultType); + + /** + * Given a bind element |aElement|, find the context node to be used + * for evaluating its nodeset. + */ + static NS_HIDDEN_(already_AddRefed) + FindBindContext(nsIDOMElement *aBindElement, + nsIXFormsModelElement *aModelElement); + + /** + * Convenience method for doing XPath evaluations. This gets a + * nsIDOMXPathEvaluator from |aContextNode|'s ownerDocument, and calls + * nsIDOMXPathEvaluator::Evalute using the given expression, context node, + * namespace resolver, and result type. + */ + static NS_HIDDEN_(already_AddRefed) + EvaluateXPath(const nsAString &aExpression, + nsIDOMNode *aContextNode, + nsIDOMNode *aResolverNode, + PRUint16 aResultType); + + /** + * Clone the set of IIDs in |aIIDList| into |aOutArray|. + * |aOutCount| is set to |aIIDCount|. + */ + static NS_HIDDEN_(nsresult) CloneScriptingInterfaces(const nsIID *aIIDList, + unsigned int aIIDCount, + PRUint32 *aOutCount, + nsIID ***aOutArray); +}; + +#endif