fixes bug 265216 "Tracking bug for XForms Group Module" patch by allan@beaufour.dk r=bryner

This commit is contained in:
darin%meer.net 2004-11-24 20:47:23 +00:00
Родитель 30fd3c6d9a
Коммит 898bfde5e8
14 изменённых файлов: 707 добавлений и 127 удалений

Просмотреть файл

@ -1,3 +1,4 @@
# vim:set ts=8 sw=8 sts=8 noet:
# #
# ***** BEGIN LICENSE BLOCK ***** # ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
@ -70,6 +71,7 @@ XPIDLSRCS = \
nsIInstanceElementPrivate.idl \ nsIInstanceElementPrivate.idl \
nsIModelElementPrivate.idl \ nsIModelElementPrivate.idl \
nsIXFormsControl.idl \ nsIXFormsControl.idl \
nsIXFormsContextControl.idl \
nsIXFormsActionElement.idl \ nsIXFormsActionElement.idl \
nsIXFormsActionModuleElement.idl \ nsIXFormsActionModuleElement.idl \
$(NULL) $(NULL)
@ -79,6 +81,7 @@ CPPSRCS = \
nsXFormsUtils.cpp \ nsXFormsUtils.cpp \
nsXFormsModelElement.cpp \ nsXFormsModelElement.cpp \
nsXFormsInputElement.cpp \ nsXFormsInputElement.cpp \
nsXFormsGroupElement.cpp \
nsXFormsOutputElement.cpp \ nsXFormsOutputElement.cpp \
nsXFormsTriggerElement.cpp \ nsXFormsTriggerElement.cpp \
nsXFormsSubmissionElement.cpp \ nsXFormsSubmissionElement.cpp \

Просмотреть файл

@ -0,0 +1,62 @@
/* -*- 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
*
* 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
* Novell, Inc.
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Allan Beaufour <abeaufour@novell.com>
*
* 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 "nsISupports.idl"
interface nsIDOMElement;
/**
* Interface for elements that sets the XPath context of its children.
*/
[uuid(38a904ba-147c-4c7f-9356-9fff88107868)]
interface nsIXFormsContextControl : nsISupports
{
/**
* Used by children to retrieve the context of their parent.
*
* @param aModelID The modelID
* @param aContextNode The context node
* @param aContextPosition The context position
* @param aContextSize The context size
*
* @note The actual model ID must be returned. An empty |aModelID| should
* only be returned if the default model has an id="".
*/
void getContext(out AString aModelID, out nsIDOMElement aContextNode, out long aContextPosition, out long aContextSize);
};

Просмотреть файл

@ -45,6 +45,7 @@
// Form controls // Form controls
NS_HIDDEN_(nsresult) NS_NewXFormsInputElement(nsIXTFElement **aElement); NS_HIDDEN_(nsresult) NS_NewXFormsInputElement(nsIXTFElement **aElement);
NS_HIDDEN_(nsresult) NS_NewXFormsGroupElement(nsIXTFElement **aElement);
NS_HIDDEN_(nsresult) NS_NewXFormsOutputElement(nsIXTFElement **aElement); NS_HIDDEN_(nsresult) NS_NewXFormsOutputElement(nsIXTFElement **aElement);
NS_HIDDEN_(nsresult) NS_NewXFormsTriggerElement(nsIXTFElement **aElement); NS_HIDDEN_(nsresult) NS_NewXFormsTriggerElement(nsIXTFElement **aElement);
NS_HIDDEN_(nsresult) NS_NewXFormsSubmitElement(nsIXTFElement **aElement); NS_HIDDEN_(nsresult) NS_NewXFormsSubmitElement(nsIXTFElement **aElement);
@ -77,6 +78,8 @@ nsXFormsElementFactory::CreateElement(const nsAString& aTagName,
return NS_NewXFormsStubElement(aElement); return NS_NewXFormsStubElement(aElement);
if (aTagName.EqualsLiteral("input")) if (aTagName.EqualsLiteral("input"))
return NS_NewXFormsInputElement(aElement); return NS_NewXFormsInputElement(aElement);
if (aTagName.EqualsLiteral("group"))
return NS_NewXFormsGroupElement(aElement);
if (aTagName.EqualsLiteral("output")) if (aTagName.EqualsLiteral("output"))
return NS_NewXFormsOutputElement(aElement); return NS_NewXFormsOutputElement(aElement);
if (aTagName.EqualsLiteral("label")) if (aTagName.EqualsLiteral("label"))

Просмотреть файл

@ -0,0 +1,343 @@
/* -*- 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
* Novell, Inc.
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Allan Beaufour <abeaufour@novell.com>
*
* 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 "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#include "nsIDOM3Node.h"
#include "nsIDOMElement.h"
#include "nsIDOMDocument.h"
#include "nsIDOMEventTarget.h"
#include "nsIDOMXPathResult.h"
#include "nsIDOMHTMLDivElement.h"
#include "nsIXTFXMLVisual.h"
#include "nsIXTFXMLVisualWrapper.h"
#include "nsIXFormsControl.h"
#include "nsIXFormsContextControl.h"
#include "nsIModelElementPrivate.h"
#include "nsXFormsAtoms.h"
#include "nsXFormsStubElement.h"
#include "nsXFormsUtils.h"
#ifdef DEBUG
// #define DEBUG_XF_GROUP
#endif
/**
* Implementation of the XForms \<group\> control.
*
* @see http://www.w3.org/TR/xforms/slice9.html#id2631290
*
* @todo If a \<label\> is the first element child for \<group\> it is the
* label for the entire group
*
* @todo "Setting the input focus on a group results in the focus being set to
* the first form control in the navigation order within that group."
* (spec. 9.1.1)
*
* @bug If a group only has a model attribute, the group fails to set this for
* children, as it is impossible to distinguish between a failure and absence
* of binding attributes when calling EvaluateNodeBinding().
*/
class nsXFormsGroupElement : public nsIXFormsControl,
public nsXFormsXMLVisualStub,
public nsIXFormsContextControl
{
protected:
/** The DOM element for the node */
nsCOMPtr<nsIDOMElement> mElement;
/** The UI HTML element used to represent the tag */
nsCOMPtr<nsIDOMHTMLDivElement> mHTMLElement;
/** Have DoneAddingChildren() been called? */
PRBool mDoneAddingChildren;
/** The context node for the children of this element */
nsCOMPtr<nsIDOMElement> mContextNode;
/** The current ID of the model node is bound to */
nsString mModelID;
/** Process element */
nsresult Process();
public:
NS_DECL_ISUPPORTS_INHERITED
// Constructor
nsXFormsGroupElement();
~nsXFormsGroupElement();
// nsIXTFXMLVisual overrides
NS_IMETHOD OnCreated(nsIXTFXMLVisualWrapper *aWrapper);
// nsIXTFVisual overrides
NS_IMETHOD GetVisualContent(nsIDOMElement **aElement);
NS_IMETHOD GetInsertionPoint(nsIDOMElement **aElement);
// nsIXTFElement overrides
NS_IMETHOD OnDestroyed();
NS_IMETHOD WillSetAttribute(nsIAtom *aName, const nsAString &aValue);
NS_IMETHOD AttributeSet(nsIAtom *aName, const nsAString &aValue);
NS_IMETHOD DoneAddingChildren();
// nsIXFormsControl
NS_DECL_NSIXFORMSCONTROL
// nsIXFormsContextControl
NS_DECL_NSIXFORMSCONTEXTCONTROL
};
NS_IMPL_ISUPPORTS_INHERITED2(nsXFormsGroupElement,
nsXFormsXMLVisualStub,
nsIXFormsControl,
nsIXFormsContextControl)
MOZ_DECL_CTOR_COUNTER(nsXFormsGroupElement)
nsXFormsGroupElement::nsXFormsGroupElement()
: mElement(nsnull)
{
MOZ_COUNT_CTOR(nsXFormsGroupElement);
}
nsXFormsGroupElement::~nsXFormsGroupElement()
{
MOZ_COUNT_DTOR(nsXFormsGroupElement);
}
// nsIXTFXMLVisual
NS_IMETHODIMP
nsXFormsGroupElement::OnCreated(nsIXTFXMLVisualWrapper *aWrapper)
{
#ifdef DEBUG_XF_GROUP
printf("nsXFormsGroupElement::OnCreated(aWrapper=%p)\n", (void*) aWrapper);
#endif
// Initialize member(s)
nsCOMPtr<nsIDOMElement> node;
aWrapper->GetElementNode(getter_AddRefs(node));
mElement = node;
NS_ASSERTION(mElement, "Wrapper is not an nsIDOMElement, we'll crash soon");
mDoneAddingChildren = PR_FALSE;
// Create HTML tag
nsCOMPtr<nsIDOMDocument> domDoc;
node->GetOwnerDocument(getter_AddRefs(domDoc));
nsCOMPtr<nsIDOMElement> domElement;
domDoc->CreateElementNS(NS_LITERAL_STRING(NS_NAMESPACE_XHTML),
NS_LITERAL_STRING("div"),
getter_AddRefs(domElement));
mHTMLElement = do_QueryInterface(domElement);
NS_ENSURE_TRUE(mHTMLElement, NS_ERROR_FAILURE);
// Setup which notifications to receive
aWrapper->SetNotificationMask(nsIXTFElement::NOTIFY_DONE_ADDING_CHILDREN |
nsIXTFElement::NOTIFY_ATTRIBUTE_SET |
nsIXTFElement::NOTIFY_WILL_SET_ATTRIBUTE);
return NS_OK;
}
// nsIXTFVisual
NS_IMETHODIMP
nsXFormsGroupElement::GetVisualContent(nsIDOMElement * *aVisualContent)
{
NS_ADDREF(*aVisualContent = mHTMLElement);
return NS_OK;
}
NS_IMETHODIMP
nsXFormsGroupElement::GetInsertionPoint(nsIDOMElement **aElement)
{
NS_ADDREF(*aElement = mHTMLElement);
return NS_OK;
}
// nsIXTFElement
NS_IMETHODIMP
nsXFormsGroupElement::OnDestroyed()
{
mHTMLElement = nsnull;
mContextNode = nsnull;
mElement = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsXFormsGroupElement::WillSetAttribute(nsIAtom *aName, const nsAString& aNewValue)
{
if (aName == nsXFormsAtoms::bind || aName == nsXFormsAtoms::ref) {
nsCOMPtr<nsIDOMNode> modelNode = nsXFormsUtils::GetModel(mElement);
nsCOMPtr<nsIModelElementPrivate> model = do_QueryInterface(modelNode);
if (model) {
model->RemoveFormControl(this);
}
}
return NS_OK;
}
NS_IMETHODIMP
nsXFormsGroupElement::AttributeSet(nsIAtom *aName, const nsAString& aNewValue)
{
if (aName == nsXFormsAtoms::bind || aName == nsXFormsAtoms::ref) {
Refresh();
}
return NS_OK;
}
NS_IMETHODIMP
nsXFormsGroupElement::DoneAddingChildren()
{
#ifdef DEBUG_XF_GROUP
printf("nsXFormsGroupElement::DoneAddingChildren()\n");
#endif
mDoneAddingChildren = PR_TRUE;
Refresh();
return NS_OK;
}
// nsXFormsControl
nsresult
nsXFormsGroupElement::Refresh()
{
#ifdef DEBUG_XF_GROUP
printf("nsXFormsGroupElement::Refresh(mDoneAddingChildren=%d)\n", mDoneAddingChildren);
#endif
nsresult rv = NS_OK;
if (mDoneAddingChildren) {
rv = Process();
}
return rv;
}
// nsXFormsGroupElement
nsresult
nsXFormsGroupElement::Process()
{
#ifdef DEBUG_XF_GROUP
printf("nsXFormsGroupElement::Process()\n");
#endif
mModelID.Truncate();
nsCOMPtr<nsIDOMNode> modelNode;
nsCOMPtr<nsIDOMElement> bindElement;
nsCOMPtr<nsIDOMXPathResult> result =
nsXFormsUtils::EvaluateNodeBinding(mElement,
nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR,
NS_LITERAL_STRING("ref"),
EmptyString(),
nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE,
getter_AddRefs(modelNode),
getter_AddRefs(bindElement));
nsCOMPtr<nsIModelElementPrivate> model = do_QueryInterface(modelNode);
if (model) {
model->AddFormControl(this);
}
NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
// Get model ID
nsCOMPtr<nsIDOMElement> modelElement = do_QueryInterface(modelNode);
NS_ENSURE_TRUE(modelElement, NS_ERROR_FAILURE);
modelElement->GetAttribute(NS_LITERAL_STRING("id"), mModelID);
// Get context node, if any
nsCOMPtr<nsIDOMNode> singleNode;
result->GetSingleNodeValue(getter_AddRefs(singleNode));
mContextNode = do_QueryInterface(singleNode);
NS_ENSURE_TRUE(mContextNode, NS_ERROR_FAILURE);
return NS_OK;
}
// nsIXFormsContextControl
nsresult
nsXFormsGroupElement::GetContext(nsAString& aModelID,
nsIDOMElement **aContextNode,
PRInt32 *aContextPosition,
PRInt32 *aContextSize)
{
#ifdef DEBUG_XF_GROUP
printf("nsXFormsGroupElement::GetContext()\n");
#endif
NS_ENSURE_ARG(aContextSize);
NS_ENSURE_ARG(aContextPosition);
/** @todo Not too elegant to call Process() here, but DoneAddingChildren is,
* logically, called on children before us. We need a notification
* that goes from the document node and DOWN, where the controls
* should Refresh().
*/
*aContextPosition = 1;
*aContextSize = 1;
nsresult rv = Process();
NS_ENSURE_SUCCESS(rv, rv);
NS_IF_ADDREF(*aContextNode = mContextNode);
aModelID = mModelID;
return NS_OK;
}
// Factory
NS_HIDDEN_(nsresult)
NS_NewXFormsGroupElement(nsIXTFElement **aResult)
{
*aResult = new nsXFormsGroupElement();
if (!*aResult)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aResult);
return NS_OK;
}

Просмотреть файл

@ -216,13 +216,9 @@ NS_IMETHODIMP
nsXFormsInputElement::WillSetAttribute(nsIAtom *aName, const nsAString &aValue) nsXFormsInputElement::WillSetAttribute(nsIAtom *aName, const nsAString &aValue)
{ {
if (aName == nsXFormsAtoms::bind || aName == nsXFormsAtoms::ref) { if (aName == nsXFormsAtoms::bind || aName == nsXFormsAtoms::ref) {
nsCOMPtr<nsIDOMElement> bindElement; nsCOMPtr<nsIDOMNode> modelNode = nsXFormsUtils::GetModel(mElement);
nsCOMPtr<nsIModelElementPrivate> model;
model = do_QueryInterface( nsCOMPtr<nsIModelElementPrivate> model = do_QueryInterface(modelNode);
nsXFormsUtils::GetModelAndBind(mElement,
nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR,
getter_AddRefs(bindElement)));
if (model) if (model)
model->RemoveFormControl(this); model->RemoveFormControl(this);
} }
@ -315,6 +311,10 @@ nsXFormsInputElement::Refresh()
nsCOMPtr<nsIModelElementPrivate> model = do_QueryInterface(modelNode); nsCOMPtr<nsIModelElementPrivate> model = do_QueryInterface(modelNode);
// @bug / todo: If \<input\> has binding attributes that are invalid, we
// should clear the content. But the content should be left if the element
// is unbound.
// @see https://bugzilla.mozilla.org/show_bug.cgi?id=265216
if (model) { if (model) {
model->AddFormControl(this); model->AddFormControl(this);

Просмотреть файл

@ -180,13 +180,9 @@ NS_IMETHODIMP
nsXFormsOutputElement::WillSetAttribute(nsIAtom *aName, const nsAString &aValue) nsXFormsOutputElement::WillSetAttribute(nsIAtom *aName, const nsAString &aValue)
{ {
if (aName == nsXFormsAtoms::bind || aName == nsXFormsAtoms::ref) { if (aName == nsXFormsAtoms::bind || aName == nsXFormsAtoms::ref) {
nsCOMPtr<nsIDOMElement> bindElement; nsCOMPtr<nsIDOMNode> modelNode = nsXFormsUtils::GetModel(mElement);
nsCOMPtr<nsIModelElementPrivate> model;
model = do_QueryInterface( nsCOMPtr<nsIModelElementPrivate> model = do_QueryInterface(modelNode);
nsXFormsUtils::GetModelAndBind(mElement,
nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR,
getter_AddRefs(bindElement)));
if (model) if (model)
model->RemoveFormControl(this); model->RemoveFormControl(this);
} }

Просмотреть файл

@ -54,10 +54,8 @@ NS_IMETHODIMP
nsXFormsRebuildElement::HandleAction(nsIDOMEvent* aEvent, nsXFormsRebuildElement::HandleAction(nsIDOMEvent* aEvent,
nsIXFormsActionElement *aParentAction) nsIXFormsActionElement *aParentAction)
{ {
nsCOMPtr<nsIDOMNode> model = nsCOMPtr<nsIDOMNode> model = nsXFormsUtils::GetModel(mElement);
nsXFormsUtils::GetModelAndBind(mElement,
nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR,
nsnull);
if (model) { if (model) {
if (aParentAction) { if (aParentAction) {
aParentAction->SetRebuild(model, PR_FALSE); aParentAction->SetRebuild(model, PR_FALSE);

Просмотреть файл

@ -54,10 +54,8 @@ NS_IMETHODIMP
nsXFormsRecalculateElement::HandleAction(nsIDOMEvent* aEvent, nsXFormsRecalculateElement::HandleAction(nsIDOMEvent* aEvent,
nsIXFormsActionElement *aParentAction) nsIXFormsActionElement *aParentAction)
{ {
nsCOMPtr<nsIDOMNode> model = nsCOMPtr<nsIDOMNode> model = nsXFormsUtils::GetModel(mElement);
nsXFormsUtils::GetModelAndBind(mElement,
nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR,
nsnull);
if (model) { if (model) {
if (aParentAction) { if (aParentAction) {
aParentAction->SetRecalculate(model, PR_FALSE); aParentAction->SetRecalculate(model, PR_FALSE);

Просмотреть файл

@ -54,10 +54,8 @@ NS_IMETHODIMP
nsXFormsRefreshElement::HandleAction(nsIDOMEvent* aEvent, nsXFormsRefreshElement::HandleAction(nsIDOMEvent* aEvent,
nsIXFormsActionElement *aParentAction) nsIXFormsActionElement *aParentAction)
{ {
nsCOMPtr<nsIDOMNode> model = nsCOMPtr<nsIDOMNode> model = nsXFormsUtils::GetModel(mElement);
nsXFormsUtils::GetModelAndBind(mElement,
nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR,
nsnull);
if (model) { if (model) {
if (aParentAction) { if (aParentAction) {
aParentAction->SetRefresh(model, PR_FALSE); aParentAction->SetRefresh(model, PR_FALSE);

Просмотреть файл

@ -53,10 +53,8 @@ NS_IMETHODIMP
nsXFormsResetElement::HandleAction(nsIDOMEvent* aEvent, nsXFormsResetElement::HandleAction(nsIDOMEvent* aEvent,
nsIXFormsActionElement *aParentAction) nsIXFormsActionElement *aParentAction)
{ {
nsCOMPtr<nsIDOMNode> model = nsCOMPtr<nsIDOMNode> model = nsXFormsUtils::GetModel(mElement);
nsXFormsUtils::GetModelAndBind(mElement,
nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR,
nsnull);
if (model) { if (model) {
if (aParentAction) { if (aParentAction) {
aParentAction->SetRebuild(model, PR_FALSE); aParentAction->SetRebuild(model, PR_FALSE);

Просмотреть файл

@ -54,10 +54,8 @@ NS_IMETHODIMP
nsXFormsRevalidateElement::HandleAction(nsIDOMEvent* aEvent, nsXFormsRevalidateElement::HandleAction(nsIDOMEvent* aEvent,
nsIXFormsActionElement *aParentAction) nsIXFormsActionElement *aParentAction)
{ {
nsCOMPtr<nsIDOMNode> model = nsCOMPtr<nsIDOMNode> model = nsXFormsUtils::GetModel(mElement);
nsXFormsUtils::GetModelAndBind(mElement,
nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR,
nsnull);
if (model) { if (model) {
if (aParentAction) { if (aParentAction) {
aParentAction->SetRevalidate(model, PR_FALSE); aParentAction->SetRevalidate(model, PR_FALSE);

Просмотреть файл

@ -65,11 +65,8 @@ nsXFormsSetValueElement::HandleAction(nsIDOMEvent* aEvent,
if (!mElement) if (!mElement)
return NS_OK; return NS_OK;
nsCOMPtr<nsIDOMElement> bind; nsCOMPtr<nsIDOMNode> dommodel = nsXFormsUtils::GetModel(mElement);
nsCOMPtr<nsIDOMNode> dommodel =
nsXFormsUtils::GetModelAndBind(mElement,
nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR,
getter_AddRefs(bind));
if (!dommodel) if (!dommodel)
return NS_OK; return NS_OK;

Просмотреть файл

@ -52,6 +52,7 @@
#include "nsIDOMText.h" #include "nsIDOMText.h"
#include "nsIXFormsModelElement.h" #include "nsIXFormsModelElement.h"
#include "nsIXFormsContextControl.h"
#include "nsIDOMDocumentEvent.h" #include "nsIDOMDocumentEvent.h"
#include "nsIDOMEvent.h" #include "nsIDOMEvent.h"
#include "nsIDOMEventTarget.h" #include "nsIDOMEventTarget.h"
@ -179,8 +180,8 @@ nsXFormsUtils::Init()
return NS_OK; return NS_OK;
} }
/* static */ nsIDOMNode* /* static */ void
nsXFormsUtils::GetParentModel(nsIDOMElement *aElement) nsXFormsUtils::GetParentModel(nsIDOMElement *aElement, nsIDOMNode **aModel)
{ {
nsCOMPtr<nsIDOMNode> modelWrapper; nsCOMPtr<nsIDOMNode> modelWrapper;
@ -201,76 +202,108 @@ nsXFormsUtils::GetParentModel(nsIDOMElement *aElement)
temp.swap(modelWrapper); temp.swap(modelWrapper);
temp->GetParentNode(getter_AddRefs(modelWrapper)); temp->GetParentNode(getter_AddRefs(modelWrapper));
} }
*aModel = nsnull;
// We're releasing this reference, but the node is owned by the DOM. modelWrapper.swap(*aModel);
return modelWrapper;
} }
/* static */ nsIDOMNode* /**
nsXFormsUtils::GetModelAndBind(nsIDOMElement *aElement, * beaufour: Section 7.4 in the specification does a really bad job of
PRUint32 aElementFlags, * explaining how to find the model, so the code below is my interpretation of
nsIDOMElement **aBindElement) * it...
{ *
NS_ENSURE_TRUE(aElement, nsnull); * @see http://bugzilla.mozilla.org/show_bug.cgi?id=265216
*/
/* static */ nsresult
nsXFormsUtils::GetNodeContext(nsIDOMElement *aElement,
PRUint32 aElementFlags,
nsIDOMNode **aModel,
nsIDOMElement **aBindElement,
nsIDOMElement **aContextNode,
PRInt32 *aContextPosition,
PRInt32 *aContextSize)
{
*aBindElement = nsnull;
NS_ENSURE_ARG(aElement);
NS_ENSURE_ARG_POINTER(aContextNode);
// Find correct model element
nsCOMPtr<nsIDOMDocument> domDoc; nsCOMPtr<nsIDOMDocument> domDoc;
aElement->GetOwnerDocument(getter_AddRefs(domDoc)); aElement->GetOwnerDocument(getter_AddRefs(domDoc));
if (!domDoc) NS_ENSURE_TRUE(domDoc, NS_ERROR_FAILURE);
return nsnull;
if (aBindElement) {
*aBindElement = nsnull;
nsAutoString bindId;
aElement->GetAttribute(NS_LITERAL_STRING("bind"), bindId);
if (!bindId.IsEmpty()) {
// Get the bind element with the given id.
domDoc->GetElementById(bindId, aBindElement);
if (*aBindElement)
return GetParentModel(*aBindElement);
}
}
if (aElementFlags & ELEMENT_WITH_MODEL_ATTR) { nsAutoString bindId;
// If no bind was given, we use model. aElement->GetAttribute(NS_LITERAL_STRING("bind"), bindId);
///
/// @todo: Is there a need for ELEMENT_WITH_BIND_ATTR?
if (!bindId.IsEmpty()) {
// CASE 1: Use @bind
domDoc->GetElementById(bindId, aBindElement);
if (*aBindElement)
GetParentModel(*aBindElement, aModel);
// Error: There was a bind attribute, but it did not lead us to a model.
NS_ENSURE_TRUE(*aModel, NS_ERROR_FAILURE);
} else if (aElementFlags & ELEMENT_WITH_MODEL_ATTR) {
// CASE 2: Use @model
// If bind did not set model, and the element has a model attribute we use this
nsAutoString modelId; nsAutoString modelId;
aElement->GetAttribute(NS_LITERAL_STRING("model"), modelId); aElement->GetAttribute(NS_LITERAL_STRING("model"), modelId);
if (!modelId.IsEmpty()) {
nsCOMPtr<nsIDOMElement> modelElement;
domDoc->GetElementById(modelId, getter_AddRefs(modelElement));
NS_IF_ADDREF(*aModel = modelElement);
nsCOMPtr<nsIDOMNode> modelWrapper; // Not tag found for that ID
NS_ENSURE_TRUE(*aModel, NS_ERROR_FAILURE);
if (modelId.IsEmpty()) {
// No model given, so use the first one in the document.
nsCOMPtr<nsIDOMNodeList> 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<nsIDOMElement> wrapperElement;
domDoc->GetElementById(modelId, getter_AddRefs(wrapperElement));
modelWrapper = wrapperElement;
} }
// We're releasing this reference, but the node is owned by the DOM.
return modelWrapper;
} }
// If no bind was given, we assume the given element is a child nsresult rv = FindParentContext(aElement,
// of the model. aModel,
return GetParentModel(aElement); aContextNode,
aContextPosition,
aContextSize);
// CASE 3/4: Use parent's model / first model in document.
// If FindParentContext() does not find a parent context but |aModel| is not
// set, it sets the model to the first model in the document.
return rv;
}
/* static */ already_AddRefed<nsIDOMNode>
nsXFormsUtils::GetModel(nsIDOMElement *aElement,
PRUint32 aElementFlags)
{
nsCOMPtr<nsIDOMNode> model;
nsCOMPtr<nsIDOMElement> contextNode;
nsCOMPtr<nsIDOMElement> bind;
nsresult rv = GetNodeContext(aElement,
aElementFlags,
getter_AddRefs(model),
getter_AddRefs(bind),
getter_AddRefs(contextNode));
NS_ENSURE_SUCCESS(rv, nsnull);
nsIDOMNode *result = nsnull;
if (model)
CallQueryInterface(model, &result); // addrefs
return result;
} }
/* static */ already_AddRefed<nsIDOMXPathResult> /* static */ already_AddRefed<nsIDOMXPathResult>
nsXFormsUtils::EvaluateXPath(const nsAString &aExpression, nsXFormsUtils::EvaluateXPath(const nsAString &aExpression,
nsIDOMNode *aContextNode, nsIDOMNode *aContextNode,
nsIDOMNode *aResolverNode, nsIDOMNode *aResolverNode,
PRUint16 aResultType) PRUint16 aResultType,
PRInt32 aContextPosition,
PRInt32 aContextSize)
{ {
nsCOMPtr<nsIDOMDocument> doc; nsCOMPtr<nsIDOMDocument> doc;
aContextNode->GetOwnerDocument(getter_AddRefs(doc)); aContextNode->GetOwnerDocument(getter_AddRefs(doc));
@ -283,6 +316,8 @@ nsXFormsUtils::EvaluateXPath(const nsAString &aExpression,
eval->CreateNSResolver(aResolverNode, getter_AddRefs(resolver)); eval->CreateNSResolver(aResolverNode, getter_AddRefs(resolver));
NS_ENSURE_TRUE(resolver, nsnull); NS_ENSURE_TRUE(resolver, nsnull);
///
/// @todo Evaluate() should use aContextPosition and aContextSize
nsCOMPtr<nsISupports> supResult; nsCOMPtr<nsISupports> supResult;
eval->Evaluate(aExpression, aContextNode, resolver, aResultType, nsnull, eval->Evaluate(aExpression, aContextNode, resolver, aResultType, nsnull,
getter_AddRefs(supResult)); getter_AddRefs(supResult));
@ -389,16 +424,25 @@ nsXFormsUtils::EvaluateNodeBinding(nsIDOMElement *aElement,
nsIDOMNode **aModel, nsIDOMNode **aModel,
nsIDOMElement **aBind) nsIDOMElement **aBind)
{ {
// A control may be attached to a model by either using the 'bind' if (!aElement || !aBind || !aModel) {
// attribute to give the id of a bind element, or using the 'model' return nsnull;
// 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; *aBind = nsnull;
*aModel = nsnull;
NS_IF_ADDREF(*aModel = GetModelAndBind(aElement, aElementFlags, aBind)); nsCOMPtr<nsIDOMElement> contextNode;
if (!*aModel) PRInt32 contextPosition;
return nsnull; PRInt32 contextSize;
nsresult rv = GetNodeContext(aElement,
aElementFlags,
aModel,
aBind,
getter_AddRefs(contextNode),
&contextPosition,
&contextSize);
NS_ENSURE_SUCCESS(rv, nsnull);
// If there is a bind element, we just evaluate its nodeset. // If there is a bind element, we just evaluate its nodeset.
if (*aBind) if (*aBind)
@ -415,27 +459,34 @@ nsXFormsUtils::EvaluateNodeBinding(nsIDOMElement *aElement,
expr.Assign(aDefaultRef); expr.Assign(aDefaultRef);
} }
// Get the instance data and evaluate the xpath expression. if (!contextNode) {
// XXXfixme when xpath extensions are implemented (instance()) nsCOMPtr<nsIDOMDocument> instanceDoc;
nsCOMPtr<nsIDOMDocument> instanceDoc; nsCOMPtr<nsIXFormsModelElement> model = do_QueryInterface(*aModel);
nsCOMPtr<nsIXFormsModelElement> model = do_QueryInterface(*aModel); if (!model) {
if (!model) { // The referenced model is not actually a model element, or does not exist.
// The referenced model is not actually a model element, or does not exist. return nsnull;
return nsnull; }
model->GetInstanceDocument(NS_LITERAL_STRING(""),
getter_AddRefs(instanceDoc));
if (!instanceDoc)
return nsnull;
instanceDoc->GetDocumentElement(getter_AddRefs(contextNode));
if (!contextNode) {
return nsnull; // this will happen if the doc is still loading
}
} }
model->GetInstanceDocument(NS_LITERAL_STRING(""), // Evaluate |expr|
getter_AddRefs(instanceDoc)); return EvaluateXPath(expr,
contextNode,
if (!instanceDoc) aElement,
return nsnull; aResultType,
contextSize,
nsCOMPtr<nsIDOMElement> docElement; contextPosition);
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 */ void /* static */ void
@ -694,3 +745,93 @@ nsXFormsUtils::CloneScriptingInterfaces(const nsIID *aIIDList,
*aOutCount = aIIDCount; *aOutCount = aIIDCount;
return NS_OK; return NS_OK;
} }
/* static */ nsresult
nsXFormsUtils::FindParentContext(nsIDOMElement *aElement,
nsIDOMNode **aModel,
nsIDOMElement **aContextNode,
PRInt32 *aContextPosition,
PRInt32 *aContextSize)
{
NS_ENSURE_ARG(aElement);
NS_ENSURE_ARG_POINTER(aModel);
NS_ENSURE_ARG_POINTER(aContextNode);
nsCOMPtr<nsIDOMNode> elementNode = do_QueryInterface(aElement);
NS_ENSURE_TRUE(elementNode, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMNode> curNode;
nsresult rv = elementNode->GetParentNode(getter_AddRefs(curNode));
NS_ENSURE_SUCCESS(rv, NS_OK);
// If a model is set, get its ID
nsAutoString childModelID;
if (*aModel) {
nsCOMPtr<nsIDOMElement> modelElement = do_QueryInterface(*aModel);
NS_ENSURE_TRUE(modelElement, NS_ERROR_FAILURE);
modelElement->GetAttribute(NS_LITERAL_STRING("id"), childModelID);
}
// Find our context:
// Iterate over all parents and find first one that implements nsIXFormsContextControl,
// and has the same model as us.
nsCOMPtr<nsIDOMNode> temp;
nsAutoString contextModelID;
while (curNode) {
nsCOMPtr<nsIXFormsContextControl> contextControl = do_QueryInterface(curNode);
nsCOMPtr<nsIDOMElement> cElement = do_QueryInterface(curNode);
if (contextControl && cElement) {
PRInt32 cSize;
PRInt32 cPosition;
nsCOMPtr<nsIDOMElement> tempNode;
rv = contextControl->GetContext(contextModelID, getter_AddRefs(tempNode), &cPosition, &cSize);
NS_ENSURE_SUCCESS(rv, rv);
// If the call failed, it means that we _have_ a parent which sets the
// context but it is invalid, ie. the XPath expression could have
// generated an error.
if (childModelID.IsEmpty()
|| childModelID.Equals(contextModelID)) {
NS_ADDREF(*aContextNode = tempNode);
if (aContextSize)
*aContextSize = cSize;
if (aContextPosition)
*aContextPosition = cPosition;
break;
}
}
// Next ancestor
temp.swap(curNode);
rv = temp->GetParentNode(getter_AddRefs(curNode));
NS_ENSURE_SUCCESS(rv, NS_OK);
}
// Child had no model set, set it
if (!*aModel) {
nsCOMPtr<nsIDOMDocument> domDoc;
nsresult rv = aElement->GetOwnerDocument(getter_AddRefs(domDoc));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(domDoc, NS_ERROR_FAILURE);
if (!*aContextNode || contextModelID.IsEmpty()) {
// We have either not found a context node, or we have found one where
// the model ID is empty. That means we use the first model in document
nsCOMPtr<nsIDOMNodeList> nodes;
domDoc->GetElementsByTagNameNS(NS_LITERAL_STRING(NS_NAMESPACE_XFORMS),
NS_LITERAL_STRING("model"),
getter_AddRefs(nodes));
// No model element in document!
NS_ENSURE_TRUE(nodes, NS_ERROR_FAILURE);
nodes->Item(0, aModel);
} else {
// Get the model with the correct ID
nsCOMPtr<nsIDOMElement> modelElement;
domDoc->GetElementById(contextModelID, getter_AddRefs(modelElement));
NS_IF_ADDREF(*aModel = modelElement);
}
}
return NS_OK;
}

Просмотреть файл

@ -133,18 +133,43 @@ public:
* Locate the model that is a parent of |aElement|. This method walks up the * Locate the model that is a parent of |aElement|. This method walks up the
* content tree looking for the containing model. * content tree looking for the containing model.
*/ */
static NS_HIDDEN_(nsIDOMNode*) static NS_HIDDEN_(void)
GetParentModel(nsIDOMElement *aElement); GetParentModel(nsIDOMElement *aElement, nsIDOMNode **aModel);
/** /**
* Locate the model that |aElement| is bound to, and if applicable, the * Find the evaluation context for an element.
* \<bind\> element that it uses. The model is returned and the *
* bind element is returned (addrefed) in |aBindElement|. * That is, the model it is bound to (|aModel|), and if applicable the
* \<bind\> element that it uses (|aBindElement| and the context node
* (|aContextNode|).
*
* @param aElement The element
* @param aElementFlags Flags describing characteristics of aElement
* @param aModel The \<model\> for the element
* @param aBindElement The \<bind\> the element is bound to (if any)
* @param aContextNode The context node for the element
*/ */
static NS_HIDDEN_(nsIDOMNode*) static NS_HIDDEN_(nsresult)
GetModelAndBind(nsIDOMElement *aElement, GetNodeContext(nsIDOMElement *aElement,
PRUint32 aElementFlags, PRUint32 aElementFlags,
nsIDOMElement **aBindElement); nsIDOMNode **aModel,
nsIDOMElement **aBindElement,
nsIDOMElement **aContextNode,
PRInt32 *aContextPosition = nsnull,
PRInt32 *aContextSize = nsnull);
/**
* Locate the model for an element.
*
* @note Actually it is just a shortcut for GetNodeContext().
*
* @param aElement The element
* @param aElementFlags Flags describing characteristics of aElement
* @return The model
*/
static NS_HIDDEN_(already_AddRefed<nsIDOMNode>)
GetModel(nsIDOMElement *aElement,
PRUint32 aElementFlags = ELEMENT_WITH_MODEL_ATTR);
/** /**
* Evaluate a 'bind' or |aBindingAttr| attribute on |aElement|. * Evaluate a 'bind' or |aBindingAttr| attribute on |aElement|.
@ -191,7 +216,9 @@ public:
EvaluateXPath(const nsAString &aExpression, EvaluateXPath(const nsAString &aExpression,
nsIDOMNode *aContextNode, nsIDOMNode *aContextNode,
nsIDOMNode *aResolverNode, nsIDOMNode *aResolverNode,
PRUint16 aResultType); PRUint16 aResultType,
PRInt32 aContextPosition = 1,
PRInt32 aContextSize = 1);
/** /**
* Given a node in the instance data, get its string value according * Given a node in the instance data, get its string value according
@ -247,6 +274,24 @@ public:
unsigned int aIIDCount, unsigned int aIIDCount,
PRUint32 *aOutCount, PRUint32 *aOutCount,
nsIID ***aOutArray); nsIID ***aOutArray);
/**
* Returns the context for the element, if set by a parent node.
*
* Controls inheriting from nsIXFormsContextControl sets the context for its children.
*
* @param aElement The document element of the caller
* @param aModel The model for |aElement| (if (!*aModel), it is set)
* @param aContextNode The resulting context node
* @param aContextPosition The resulting context position
* @param aContextSize The resulting context size
*/
static NS_HIDDEN_(nsresult) FindParentContext(nsIDOMElement *aElement,
nsIDOMNode **aModel,
nsIDOMElement **aContextNode,
PRInt32 *aContextPosition,
PRInt32 *aContextSize);
}; };
#endif #endif