зеркало из https://github.com/mozilla/pjs.git
XForms Bug 279063 - implement copy element. Patch by aaronr, r=me,smaug,allan
This commit is contained in:
Родитель
f097d6712d
Коммит
cb5730db5b
|
@ -133,6 +133,7 @@ XPIDLSRCS = \
|
|||
nsIXFormsRangeAccessors.idl \
|
||||
nsIXFormsUploadElement.idl \
|
||||
nsIXFormsUploadUIElement.idl \
|
||||
nsIXFormsCopyElement.idl \
|
||||
$(NULL)
|
||||
|
||||
# XForms source files
|
||||
|
@ -191,6 +192,7 @@ CPPSRCS = \
|
|||
nsXFormsRangeElement.cpp \
|
||||
nsXFormsAccessors.cpp \
|
||||
nsXFormsRangeAccessors.cpp \
|
||||
nsXFormsCopyElement.cpp \
|
||||
$(NULL)
|
||||
|
||||
# Standard Mozilla make rules
|
||||
|
|
|
@ -47,7 +47,7 @@ interface nsIDOMNode;
|
|||
* Private interface implemented by the model element for other
|
||||
* elements to use.
|
||||
*/
|
||||
[uuid(8c5e2b7d-043e-4278-bc3e-1519bd9c62ec)]
|
||||
[uuid(ccba3717-ef05-41cd-b831-f7f5ab3b921c)]
|
||||
interface nsIModelElementPrivate : nsIXFormsModelElement
|
||||
{
|
||||
/**
|
||||
|
@ -99,6 +99,13 @@ interface nsIModelElementPrivate : nsIXFormsModelElement
|
|||
void getNodeValue(in nsIDOMNode contextNode,
|
||||
out AString nodeValue);
|
||||
|
||||
/**
|
||||
* Insert a node under an instance node
|
||||
*/
|
||||
void setNodeContent(in nsIDOMNode contextNode,
|
||||
in nsIDOMNode nodeContent,
|
||||
out boolean nodeChanged);
|
||||
|
||||
/**
|
||||
* Validates the instance node against the schemas loaded by the model.
|
||||
*/
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIDOMNode.idl"
|
||||
|
||||
/**
|
||||
* Interface exposing the states of an XForms control.
|
||||
|
@ -44,7 +45,7 @@
|
|||
* For more information on this interface please see
|
||||
* http://developer.mozilla.org/en/docs/XForms:Custom_Controls
|
||||
*/
|
||||
[scriptable, uuid(8e8c5022-a61d-42cf-9551-74215dc611ad)]
|
||||
[scriptable, uuid(74992960-42a9-4479-a1ff-f7f1b37e187a)]
|
||||
interface nsIXFormsAccessors : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -81,4 +82,22 @@ interface nsIXFormsAccessors : nsISupports
|
|||
* true, if XForms control is bound to a node in a data model.
|
||||
*/
|
||||
boolean hasBoundNode();
|
||||
|
||||
/**
|
||||
* Node that the control is bound to in its data model.
|
||||
*/
|
||||
nsIDOMNode getBoundNode();
|
||||
|
||||
/**
|
||||
* Used to set the complete contents of the bound node. This function is
|
||||
* meant to be used like setValue() except that it can be used to set more
|
||||
* than just the first textnode contained under the bound node. If there
|
||||
* is nothing contained under aNode, then all children of the bound node
|
||||
* will be eliminated.
|
||||
*
|
||||
* @param aNode aNode should be a copy of the bound node. setContent
|
||||
* will take the contents of aNode and move them under
|
||||
* bound node.
|
||||
*/
|
||||
void setContent(in nsIDOMNode aNode);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/* -*- 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
|
||||
* IBM Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2005
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Aaron Reed <aaronr@us.ibm.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of 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 ***** */
|
||||
|
||||
/**
|
||||
* This interface is implemented by XForms \<copy\> elements.
|
||||
*/
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIDOMNode.idl"
|
||||
|
||||
[uuid(4af9ad8e-5266-44ac-b9f7-ef2cb9fe2637)]
|
||||
interface nsIXFormsCopyElement : nsISupports
|
||||
{
|
||||
/**
|
||||
* Returns the node that will be deep copied into the instance data if the
|
||||
* item element which contains this copy element is selected.
|
||||
*/
|
||||
readonly attribute nsIDOMNode copyNode;
|
||||
};
|
|
@ -37,11 +37,13 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIDOMNode.idl"
|
||||
#include "nsIXFormsDelegate.idl"
|
||||
|
||||
/**
|
||||
* Interface implemented by the item element.
|
||||
*/
|
||||
[scriptable, uuid(796a2e26-a40b-4ebf-be2c-42faf5fea6c4)]
|
||||
[scriptable, uuid(ec8d3556-8ed2-4143-88d1-6b7b2c8b0b3b)]
|
||||
interface nsIXFormsItemElement : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -67,4 +69,18 @@ interface nsIXFormsItemElement : nsISupports
|
|||
* \<select1\> element, which can then refresh its UI.
|
||||
*/
|
||||
void labelRefreshed();
|
||||
|
||||
/**
|
||||
* Indicates whether the item element contains a value child or a copy
|
||||
* child. We'll assume that if the item is NOT a copy item, then it must
|
||||
* be a value item. Which means that it must contain a XForms value element
|
||||
* child.
|
||||
*/
|
||||
attribute boolean isCopyItem;
|
||||
|
||||
/*
|
||||
* returns the node that the contained copy element is bound to
|
||||
*/
|
||||
readonly attribute nsIDOMNode copyNode;
|
||||
|
||||
};
|
||||
|
|
|
@ -52,7 +52,7 @@ class nsStringArray;
|
|||
* of an XForms select element (choices, item, itemset).
|
||||
*/
|
||||
|
||||
[scriptable, uuid(a29ac2bd-f36a-451e-99e1-0f3bd94ffbef)]
|
||||
[scriptable, uuid(9fac2f59-4ec8-456f-ad06-4e28cd7d5b2c)]
|
||||
interface nsIXFormsSelectChild : nsISupports
|
||||
{
|
||||
/*
|
||||
|
@ -61,4 +61,11 @@ interface nsIXFormsSelectChild : nsISupports
|
|||
* this method returns that \<item\>.
|
||||
*/
|
||||
nsIDOMNode selectItemByValue(in AString value);
|
||||
|
||||
/*
|
||||
* selectItemByNode is used in \<select1\> and \<select\>. If the
|
||||
* XFormsSelectChild is or contains an \<item\>, which has a node 'equal' the
|
||||
* parameter |aNode|, this method returns the first \<item\> that matches.
|
||||
*/
|
||||
nsIDOMNode selectItemByNode(in nsIDOMNode aNode);
|
||||
};
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "nsDOMString.h"
|
||||
#include "nsIEventStateManager.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIXFormsControl.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsXFormsAccessors, nsIXFormsAccessors, nsIClassInfo)
|
||||
|
||||
|
@ -113,6 +114,48 @@ nsXFormsAccessors::IsValid(PRBool *aStateVal)
|
|||
return GetState(NS_EVENT_STATE_VALID, aStateVal);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsAccessors::SetContent(nsIDOMNode *aNode)
|
||||
{
|
||||
NS_ENSURE_STATE(mElement);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> boundNode;
|
||||
nsresult rv = GetBoundNode(getter_AddRefs(boundNode));
|
||||
NS_ENSURE_STATE(boundNode);
|
||||
|
||||
nsCOMPtr<nsIModelElementPrivate> modelPriv = nsXFormsUtils::GetModel(mElement);
|
||||
NS_ENSURE_STATE(modelPriv);
|
||||
|
||||
PRBool changed;
|
||||
rv = modelPriv->SetNodeContent(boundNode, aNode, &changed);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (changed) {
|
||||
nsCOMPtr<nsIDOMNode> model = do_QueryInterface(modelPriv);
|
||||
|
||||
if (model) {
|
||||
rv = nsXFormsUtils::DispatchEvent(model, eEvent_Recalculate);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = nsXFormsUtils::DispatchEvent(model, eEvent_Revalidate);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = nsXFormsUtils::DispatchEvent(model, eEvent_Refresh);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsAccessors::GetBoundNode(nsIDOMNode **aBoundNode)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aBoundNode);
|
||||
if (mDelegate) {
|
||||
nsCOMPtr<nsIXFormsControl> control = do_QueryInterface(mDelegate);
|
||||
return control->GetBoundNode(aBoundNode);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIClassInfo implementation
|
||||
|
||||
static const nsIID sScriptingIIDs[] = {
|
||||
|
|
|
@ -219,6 +219,36 @@ nsXFormsChoicesElement::SelectItemByValue(const nsAString &aValue, nsIDOMNode **
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsChoicesElement::SelectItemByNode(nsIDOMNode *aNode,
|
||||
nsIDOMNode **aSelected)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aSelected);
|
||||
NS_ENSURE_STATE(mElement);
|
||||
*aSelected = nsnull;
|
||||
nsCOMPtr<nsIDOMNodeList> children;
|
||||
nsresult rv = mElement->GetChildNodes(getter_AddRefs(children));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRUint32 childCount = 0;
|
||||
children->GetLength(&childCount);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> childNode;
|
||||
nsCOMPtr<nsIXFormsSelectChild> childItem;
|
||||
|
||||
for (PRUint32 i = 0; i < childCount; ++i) {
|
||||
children->Item(i, getter_AddRefs(childNode));
|
||||
childItem = do_QueryInterface(childNode);
|
||||
if (childItem) {
|
||||
childItem->SelectItemByNode(aNode, aSelected);
|
||||
if (*aSelected)
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// internal methods
|
||||
|
||||
void
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
/* -*- 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) 2005
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Aaron Reed <aaronr@us.ibm.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 "nsIXFormsCopyElement.h"
|
||||
#include "nsXFormsStubElement.h"
|
||||
#include "nsIXTFGenericElementWrapper.h"
|
||||
#include "nsXFormsUtils.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIXFormsItemElement.h"
|
||||
|
||||
/**
|
||||
* Implementation of the XForms \<copy\> element.
|
||||
*
|
||||
* @note The copy element does not display any content, it simply provides
|
||||
* a node to be copied to instance data when the containing XForms item
|
||||
* element is selected.
|
||||
*/
|
||||
|
||||
class nsXFormsCopyElement : public nsXFormsStubElement,
|
||||
public nsIXFormsCopyElement
|
||||
{
|
||||
public:
|
||||
nsXFormsCopyElement() : mElement(nsnull) {}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIXTFGenericElement overrides
|
||||
NS_IMETHOD OnCreated(nsIXTFGenericElementWrapper *aWrapper);
|
||||
|
||||
// nsIXTFElement overrides
|
||||
NS_IMETHOD ParentChanged(nsIDOMElement *aNewParent);
|
||||
NS_IMETHOD DocumentChanged(nsIDOMDocument *aNewParent);
|
||||
|
||||
// nsIXFormsCopyElement
|
||||
NS_DECL_NSIXFORMSCOPYELEMENT
|
||||
|
||||
private:
|
||||
nsIDOMElement *mElement;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(nsXFormsCopyElement,
|
||||
nsXFormsStubElement,
|
||||
nsIXFormsCopyElement)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsCopyElement::OnCreated(nsIXTFGenericElementWrapper *aWrapper)
|
||||
{
|
||||
aWrapper->SetNotificationMask(nsIXTFElement::NOTIFY_PARENT_CHANGED |
|
||||
nsIXTFElement::NOTIFY_DOCUMENT_CHANGED);
|
||||
|
||||
nsCOMPtr<nsIDOMElement> node;
|
||||
aWrapper->GetElementNode(getter_AddRefs(node));
|
||||
|
||||
// It's ok to keep 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;
|
||||
}
|
||||
|
||||
// nsIXTFElement
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsCopyElement::ParentChanged(nsIDOMElement *aNewParent)
|
||||
{
|
||||
if (aNewParent) {
|
||||
if (!nsXFormsUtils::IsXFormsElement(aNewParent,
|
||||
NS_LITERAL_STRING("itemset")) &&
|
||||
!nsXFormsUtils::IsXFormsElement(aNewParent,
|
||||
NS_LITERAL_STRING("contextcontainer"))) {
|
||||
|
||||
// parent of a copy element must always be an itemset. We really can't
|
||||
// enforce this all that well until we have full schema support but for
|
||||
// now we'll at least warn the author. We are also checking for
|
||||
// contextcontainer because under Mozilla, the children of an itemset
|
||||
// element are cloned underneath a contextcontainer which is in turn
|
||||
// contained in a nsXFormsItemElement. Each such item element is then
|
||||
// appended as anonymous content of the itemset.
|
||||
nsXFormsUtils::ReportError(NS_LITERAL_STRING("copyError"), mElement);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsCopyElement::DocumentChanged(nsIDOMDocument* aNewDocument)
|
||||
{
|
||||
if (!aNewDocument)
|
||||
return NS_OK;
|
||||
|
||||
// tell grandparent (xf:item) that it contains a xf:copy element and
|
||||
// not a xf:value element.
|
||||
nsCOMPtr<nsIDOMNode> contextContainer;
|
||||
nsresult rv = mElement->GetParentNode(getter_AddRefs(contextContainer));
|
||||
NS_ENSURE_TRUE(contextContainer, rv);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> itemNode;
|
||||
rv = contextContainer->GetParentNode(getter_AddRefs(itemNode));
|
||||
NS_ENSURE_TRUE(itemNode, rv);
|
||||
|
||||
nsCOMPtr<nsIXFormsItemElement> item = do_QueryInterface(itemNode);
|
||||
|
||||
// It is possible that the grandparent ISN'T an xf:item, if this is the
|
||||
// original template copy element whose parent is the xf:itemset and
|
||||
// grandparent is the xf:select. We'll ignore a copy element in that case
|
||||
// since it really isn't in play.
|
||||
if (item) {
|
||||
item->SetIsCopyItem(PR_TRUE);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIXFormsCopyElement
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsCopyElement::GetCopyNode(nsIDOMNode **aNode)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aNode);
|
||||
*aNode = nsnull;
|
||||
|
||||
nsCOMPtr<nsIModelElementPrivate> model;
|
||||
nsCOMPtr<nsIDOMXPathResult> result;
|
||||
nsresult rv =
|
||||
nsXFormsUtils::EvaluateNodeBinding(mElement,
|
||||
nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR,
|
||||
NS_LITERAL_STRING("ref"), EmptyString(),
|
||||
nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE,
|
||||
getter_AddRefs(model),
|
||||
getter_AddRefs(result));
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (result) {
|
||||
nsCOMPtr<nsIDOMNode> singleNode;
|
||||
result->GetSingleNodeValue(getter_AddRefs(singleNode));
|
||||
|
||||
NS_IF_ADDREF(*aNode = singleNode);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_HIDDEN_(nsresult)
|
||||
NS_NewXFormsCopyElement(nsIXTFElement **aResult)
|
||||
{
|
||||
*aResult = new nsXFormsCopyElement();
|
||||
if (!*aResult)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
|
@ -73,6 +73,7 @@ NS_HIDDEN_(nsresult) NS_NewXFormsValueElement(nsIXTFElement **aElement);
|
|||
NS_HIDDEN_(nsresult) NS_NewXFormsChoicesElement(nsIXTFElement **aElement);
|
||||
NS_HIDDEN_(nsresult) NS_NewXFormsItemSetElement(nsIXTFElement **aElement);
|
||||
NS_HIDDEN_(nsresult) NS_NewXFormsRangeElement(nsIXTFElement **aElement);
|
||||
NS_HIDDEN_(nsresult) NS_NewXFormsCopyElement(nsIXTFElement **aElement);
|
||||
|
||||
//Action Module Elements
|
||||
NS_HIDDEN_(nsresult) NS_NewXFormsDispatchElement(nsIXTFElement **aResult);
|
||||
|
@ -191,6 +192,8 @@ nsXFormsElementFactory::CreateElement(const nsAString& aTagName,
|
|||
return NS_NewXFormsUploadElement(aElement);
|
||||
if (aTagName.EqualsLiteral("range"))
|
||||
return NS_NewXFormsRangeElement(aElement);
|
||||
if (aTagName.EqualsLiteral("copy"))
|
||||
return NS_NewXFormsCopyElement(aElement);
|
||||
|
||||
*aElement = nsnull;
|
||||
return NS_ERROR_FAILURE;
|
||||
|
|
|
@ -56,6 +56,8 @@
|
|||
#include "nsIXFormsLabelElement.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsXFormsModelElement.h"
|
||||
#include "nsIXFormsCopyElement.h"
|
||||
#include "nsIDOMEventTarget.h"
|
||||
|
||||
/**
|
||||
* nsXFormsItemElement implements the XForms \<item\> element.
|
||||
|
@ -69,7 +71,8 @@ class nsXFormsItemElement : public nsXFormsBindableStub,
|
|||
public nsIXFormsItemElement
|
||||
{
|
||||
public:
|
||||
nsXFormsItemElement() : mElement(nsnull), mDoneAddingChildren(PR_FALSE)
|
||||
nsXFormsItemElement() : mElement(nsnull), mDoneAddingChildren(PR_FALSE),
|
||||
mIsCopyItem(PR_FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -91,9 +94,14 @@ public:
|
|||
// nsIXFormsSelectChild
|
||||
NS_DECL_NSIXFORMSSELECTCHILD
|
||||
|
||||
|
||||
private:
|
||||
nsIDOMElement* mElement;
|
||||
PRBool mDoneAddingChildren;
|
||||
|
||||
// If true, indicates that this item contains a xf:copy element (via
|
||||
// xf:itemset) rather than a xf:value element
|
||||
PRBool mIsCopyItem;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED2(nsXFormsItemElement,
|
||||
|
@ -219,12 +227,50 @@ nsXFormsItemElement::SelectItemByValue(const nsAString &aValue, nsIDOMNode **aSe
|
|||
{
|
||||
NS_ENSURE_ARG_POINTER(aSelected);
|
||||
NS_ENSURE_STATE(mElement);
|
||||
|
||||
*aSelected = nsnull;
|
||||
if (mIsCopyItem) {
|
||||
// copy items are selected by node, not by value
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoString value;
|
||||
GetValue(value);
|
||||
if (aValue.Equals(value)) {
|
||||
nsresult rv = GetValue(value);
|
||||
|
||||
if (NS_SUCCEEDED(rv) && aValue.Equals(value)) {
|
||||
NS_ADDREF(*aSelected = mElement);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsItemElement::SelectItemByNode(nsIDOMNode *aNode, nsIDOMNode **aSelected)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aSelected);
|
||||
NS_ENSURE_STATE(mElement);
|
||||
PRBool isCopyItem;
|
||||
*aSelected = nsnull;
|
||||
|
||||
// If this item doesn't contain a copy element but instead has a value
|
||||
// element, then there is no sense testing further.
|
||||
GetIsCopyItem(&isCopyItem);
|
||||
if (!isCopyItem) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMNode> copyNode;
|
||||
nsresult rv = GetCopyNode(getter_AddRefs(copyNode));
|
||||
NS_ENSURE_STATE(copyNode);
|
||||
|
||||
PRUint16 nodeType;
|
||||
copyNode->GetNodeType(&nodeType);
|
||||
|
||||
// copy elements are only allowed to bind to ELEMENT_NODEs per spec. But
|
||||
// test first before doing all of this work.
|
||||
if ((nodeType == nsIDOMNode::ELEMENT_NODE) &&
|
||||
(nsXFormsUtils::AreNodesEqual(copyNode, aNode))) {
|
||||
NS_ADDREF(*aSelected = mElement);
|
||||
} else {
|
||||
*aSelected = nsnull;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -233,7 +279,16 @@ nsXFormsItemElement::SelectItemByValue(const nsAString &aValue, nsIDOMNode **aSe
|
|||
NS_IMETHODIMP
|
||||
nsXFormsItemElement::GetValue(nsAString &aValue)
|
||||
{
|
||||
|
||||
PRBool isCopyItem;
|
||||
GetIsCopyItem(&isCopyItem);
|
||||
if (isCopyItem) {
|
||||
// if this item was built by an itemset and the itemset's template used
|
||||
// a copy element, then there is no value element to be had. No sense
|
||||
// continuing.
|
||||
aValue.Truncate(0);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMNode> firstChild, container;
|
||||
mElement->GetFirstChild(getter_AddRefs(firstChild));
|
||||
|
||||
|
@ -271,6 +326,52 @@ nsXFormsItemElement::GetValue(nsAString &aValue)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsItemElement::GetCopyNode(nsIDOMNode **aNode)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aNode);
|
||||
|
||||
PRBool isCopyItem;
|
||||
GetIsCopyItem(&isCopyItem);
|
||||
if (!isCopyItem) {
|
||||
// If this item doesn't contain a copy element but instead has a value
|
||||
// element, then there is no sense continuing.
|
||||
*aNode = nsnull;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Since this item really contains a copy element, then firstChild MUST be
|
||||
// a contextcontainer since copy elements can only exist as a child of an
|
||||
// itemset.
|
||||
nsCOMPtr<nsIDOMNode> container;
|
||||
mElement->GetFirstChild(getter_AddRefs(container));
|
||||
|
||||
// Find the copy element contained by this item and get the copyNode from it.
|
||||
nsCOMPtr<nsIDOMNodeList> children;
|
||||
nsresult rv = container->GetChildNodes(getter_AddRefs(children));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRUint32 childCount;
|
||||
children->GetLength(&childCount);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> child;
|
||||
nsAutoString value;
|
||||
|
||||
for (PRUint32 i = 0; i < childCount; ++i) {
|
||||
children->Item(i, getter_AddRefs(child));
|
||||
nsCOMPtr<nsIXFormsCopyElement> copyElement = do_QueryInterface(child);
|
||||
if (copyElement) {
|
||||
return copyElement->GetCopyNode(aNode);
|
||||
}
|
||||
}
|
||||
|
||||
// No copy element as a child. Set return node to null and set the copyitem
|
||||
// boolean to false so we don't go through this unnecessary pain again.
|
||||
aNode = nsnull;
|
||||
SetIsCopyItem(PR_FALSE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsXFormsItemElement::Refresh()
|
||||
{
|
||||
|
@ -368,6 +469,21 @@ nsXFormsItemElement::LabelRefreshed()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsItemElement::GetIsCopyItem(PRBool *aIsCopyItem)
|
||||
{
|
||||
NS_ENSURE_ARG(aIsCopyItem);
|
||||
*aIsCopyItem = mIsCopyItem;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsItemElement::SetIsCopyItem(PRBool aIsCopyItem)
|
||||
{
|
||||
mIsCopyItem = aIsCopyItem;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_HIDDEN_(nsresult)
|
||||
NS_NewXFormsItemElement(nsIXTFElement **aResult)
|
||||
{
|
||||
|
|
|
@ -190,6 +190,38 @@ nsXFormsItemSetElement::SelectItemByValue(const nsAString &aValue, nsIDOMNode **
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsItemSetElement::SelectItemByNode(nsIDOMNode *aNode,
|
||||
nsIDOMNode **aSelected)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aSelected);
|
||||
NS_ENSURE_STATE(mElement);
|
||||
*aSelected = nsnull;
|
||||
// nsIXFormsItemSetUIElement is implemented by the XBL binding.
|
||||
nsCOMPtr<nsIXFormsItemSetUIElement> uiItemSet(do_QueryInterface(mElement));
|
||||
NS_ENSURE_STATE(uiItemSet);
|
||||
|
||||
nsCOMPtr<nsIDOMElement> anonContent;
|
||||
uiItemSet->GetAnonymousItemSetContent(getter_AddRefs(anonContent));
|
||||
NS_ENSURE_STATE(anonContent);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> child, tmp;
|
||||
anonContent->GetFirstChild(getter_AddRefs(child));
|
||||
// Trying to select the first possible (generated) \<item\> element.
|
||||
while (child) {
|
||||
nsCOMPtr<nsIXFormsSelectChild> selectChild(do_QueryInterface(child));
|
||||
if (selectChild) {
|
||||
selectChild->SelectItemByNode(aNode, aSelected);
|
||||
if (*aSelected) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
tmp.swap(child);
|
||||
tmp->GetNextSibling(getter_AddRefs(child));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsItemSetElement::Bind()
|
||||
{
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "nsDeque.h"
|
||||
#include "nsIModelElementPrivate.h"
|
||||
#include "nsXFormsUtils.h"
|
||||
#include "nsDOMError.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
//# define DEBUG_XF_MDG
|
||||
|
@ -743,6 +744,101 @@ nsXFormsMDGEngine::SetNodeValueInternal(nsIDOMNode *aContextNode,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXFormsMDGEngine::SetNodeContent(nsIDOMNode *aContextNode,
|
||||
nsIDOMNode *aContentEnvelope,
|
||||
PRBool *aNodeChanged)
|
||||
{
|
||||
NS_ENSURE_ARG(aContextNode);
|
||||
NS_ENSURE_ARG(aContentEnvelope);
|
||||
|
||||
// ok, this is tricky. This function will REPLACE the contents of
|
||||
// aContextNode with the CONTENTS of aContentEnvelope. No, not a clone of
|
||||
// the contents, but the contents themselves. If aContentEnvelope has no
|
||||
// contents, then any contents that aContextNode has will still be removed.
|
||||
// In order to determine whether the incoming node content is the same as what
|
||||
// is already contained in aContextNode, aContentEnvelope MUST be a clone (not
|
||||
// deep) of aContextNode, otherwise aNodeChanged will always be returned as
|
||||
// being PR_TRUE. I took this approach because I think it is much more
|
||||
// efficient for the caller to build a complete list of what goes in the
|
||||
// contents in one go rather than allowing any number of appends to existing
|
||||
// content one node at a time. There are quite a few links in the call chain
|
||||
// to go from nsXFormsDelegateStub to here.
|
||||
|
||||
if (aNodeChanged) {
|
||||
*aNodeChanged = PR_FALSE;
|
||||
}
|
||||
|
||||
const nsXFormsNodeState* ns = GetNodeState(aContextNode);
|
||||
NS_ENSURE_TRUE(ns, NS_ERROR_FAILURE);
|
||||
|
||||
// If the node is read-only and not set by a @calculate MIP,
|
||||
// ignore the call
|
||||
if (ns->IsReadonly()) {
|
||||
///
|
||||
/// @todo Better feedback for readonly nodes? (XXX)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRUint16 nodeType;
|
||||
nsresult rv = aContextNode->GetNodeType(&nodeType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (nodeType != nsIDOMNode::ELEMENT_NODE) {
|
||||
// got to return something pretty unique that we can check down the road in
|
||||
// order to dispatch any error events
|
||||
return NS_ERROR_DOM_WRONG_TYPE_ERR;
|
||||
}
|
||||
|
||||
PRBool nodesEqual = nsXFormsUtils::AreNodesEqual(aContextNode,
|
||||
aContentEnvelope,
|
||||
PR_FALSE);
|
||||
if (nodesEqual) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// remove any child nodes that aContextNode already contains
|
||||
nsCOMPtr<nsIDOMNode> resultNode;
|
||||
nsCOMPtr<nsIDOMNodeList> childList;
|
||||
rv = aContextNode->GetChildNodes(getter_AddRefs(childList));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (childList) {
|
||||
PRUint32 length;
|
||||
rv = childList->GetLength(&length);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
for (PRInt32 i = length-1; i >= 0; i--) {
|
||||
nsCOMPtr<nsIDOMNode> childNode;
|
||||
rv = childList->Item(i, getter_AddRefs(childNode));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aContextNode->RemoveChild(childNode, getter_AddRefs(resultNode));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
||||
// add contents of the envelope under aContextNode
|
||||
nsCOMPtr<nsIDOMNode> childNode;
|
||||
rv = aContentEnvelope->GetFirstChild(getter_AddRefs(childNode));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
while (childNode) {
|
||||
rv = aContextNode->AppendChild(childNode, getter_AddRefs(resultNode));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aContentEnvelope->GetFirstChild(getter_AddRefs(childNode));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// NB: Never reached for Readonly nodes.
|
||||
if (aNodeChanged) {
|
||||
*aNodeChanged = PR_TRUE;
|
||||
}
|
||||
|
||||
// Not calling MarkNodeAsChanged since caller will do a full rebuild
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const nsXFormsNodeState*
|
||||
nsXFormsMDGEngine::GetNodeState(nsIDOMNode *aContextNode)
|
||||
{
|
||||
|
|
|
@ -326,6 +326,7 @@ protected:
|
|||
PRBool aMarkNode = PR_TRUE,
|
||||
PRBool aIsCalculate = PR_FALSE,
|
||||
PRBool *aNodeChanged = nsnull);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -419,6 +420,18 @@ public:
|
|||
nsresult GetNodeValue(nsIDOMNode *aContextNode,
|
||||
nsAString &aNodeValue);
|
||||
|
||||
/**
|
||||
* Set the contents of a node
|
||||
*
|
||||
* @param aContextNode The node to set the contents of
|
||||
* @param aContentEnvelope The container of the contents that need to be
|
||||
* moved under aContextNode
|
||||
* @param aNodeChanged Was node changed?
|
||||
*/
|
||||
nsresult SetNodeContent(nsIDOMNode *aContextNode,
|
||||
nsIDOMNode *aContentEnvelope,
|
||||
PRBool *aNodeChanged = nsnull);
|
||||
|
||||
/**
|
||||
* External interface of GetNCNodeState(), returns const pointer to the node
|
||||
* state.
|
||||
|
|
|
@ -1138,6 +1138,16 @@ nsXFormsModelElement::GetNodeValue(nsIDOMNode *aContextNode,
|
|||
aNodeValue);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsModelElement::SetNodeContent(nsIDOMNode *aContextNode,
|
||||
nsIDOMNode *aNodeContent,
|
||||
PRBool *aNodeChanged)
|
||||
{
|
||||
return mMDG.SetNodeContent(aContextNode,
|
||||
aNodeContent,
|
||||
aNodeChanged);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsModelElement::ValidateNode(nsIDOMNode *aInstanceNode, PRBool *aResult)
|
||||
{
|
||||
|
|
|
@ -95,6 +95,10 @@
|
|||
#include "nsIDOMAbstractView.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
#include "nsIDOMDocumentType.h"
|
||||
#include "nsIDOMEntity.h"
|
||||
#include "nsIDOMNotation.h"
|
||||
|
||||
#define CANCELABLE 0x01
|
||||
#define BUBBLES 0x02
|
||||
|
||||
|
@ -1625,3 +1629,365 @@ nsXFormsUtils::HandleBindingException(nsIDOMElement *aElement)
|
|||
nsnull, getter_AddRefs(messageWindow));
|
||||
return NS_SUCCEEDED(rv);
|
||||
}
|
||||
|
||||
/* static */ PRBool
|
||||
nsXFormsUtils::AreEntitiesEqual(nsIDOMNamedNodeMap *aEntities1,
|
||||
nsIDOMNamedNodeMap *aEntities2)
|
||||
{
|
||||
if (!aEntities1 && !aEntities2) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
if (!aEntities1 || !aEntities2) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRUint32 entLength1, entLength2;
|
||||
nsresult rv1 = aEntities1->GetLength(&entLength1);
|
||||
nsresult rv2 = aEntities2->GetLength(&entLength2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || entLength1 != entLength2) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsAutoString buffer1, buffer2;
|
||||
for (PRUint32 i = 0; i < entLength1; ++i) {
|
||||
nsCOMPtr<nsIDOMNode> entNode1, entNode2;
|
||||
|
||||
rv1 = aEntities1->Item(i, getter_AddRefs(entNode1));
|
||||
rv2 = aEntities2->Item(i, getter_AddRefs(entNode2));
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || !entNode1 || !entNode2) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMEntity> ent1, ent2;
|
||||
ent1 = do_QueryInterface(entNode1);
|
||||
ent2 = do_QueryInterface(entNode2);
|
||||
if (!ent1 || !ent2) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
rv1 = ent1->GetPublicId(buffer1);
|
||||
rv2 = ent2->GetPublicId(buffer2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
rv1 = ent1->GetSystemId(buffer1);
|
||||
rv2 = ent2->GetSystemId(buffer2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
rv1 = ent1->GetNotationName(buffer1);
|
||||
rv2 = ent2->GetNotationName(buffer2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// XXX: These will need to be uncommented when Mozilla supports these from
|
||||
// DOM3
|
||||
#if 0
|
||||
rv1 = ent1->GetInputEncoding(buffer1);
|
||||
rv2 = ent2->GetInputEncoding(buffer2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
rv1 = ent1->GetXmlEncoding(buffer1);
|
||||
rv2 = ent2->GetXmlEncoding(buffer2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
rv1 = ent1->GetXmlVersion(buffer1);
|
||||
rv2 = ent2->GetXmlVersion(buffer2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
/* static */ PRBool
|
||||
nsXFormsUtils::AreNotationsEqual(nsIDOMNamedNodeMap *aNotations1,
|
||||
nsIDOMNamedNodeMap *aNotations2)
|
||||
{
|
||||
if (!aNotations1 && !aNotations2) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
if (!aNotations1 || !aNotations2) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRUint32 notLength1, notLength2;
|
||||
nsresult rv1 = aNotations1->GetLength(¬Length1);
|
||||
nsresult rv2 = aNotations2->GetLength(¬Length2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || notLength1 != notLength2) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsAutoString buffer1, buffer2;
|
||||
for (PRUint32 j = 0; j < notLength1; ++j) {
|
||||
nsCOMPtr<nsIDOMNode> notNode1, notNode2;
|
||||
|
||||
rv1 = aNotations1->Item(j, getter_AddRefs(notNode1));
|
||||
rv2 = aNotations2->Item(j, getter_AddRefs(notNode2));
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || !notNode1 || !notNode2) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMNotation> notation1, notation2;
|
||||
notation1 = do_QueryInterface(notNode1);
|
||||
notation2 = do_QueryInterface(notNode2);
|
||||
if (!notation1 || !notation2) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
rv1 = notation1->GetPublicId(buffer1);
|
||||
rv2 = notation2->GetPublicId(buffer2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
rv1 = notation1->GetSystemId(buffer1);
|
||||
rv2 = notation2->GetSystemId(buffer2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
/* static */ PRBool
|
||||
nsXFormsUtils::AreNodesEqual(nsIDOMNode *aFirstNode, nsIDOMNode *aSecondNode,
|
||||
PRBool aAlreadyNormalized)
|
||||
{
|
||||
if (!aFirstNode || !aSecondNode) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsresult rv1, rv2;
|
||||
PRUint16 firstType, secondType;
|
||||
rv1 = aFirstNode->GetNodeType(&firstType);
|
||||
rv2 = aSecondNode->GetNodeType(&secondType);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || firstType != secondType) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsAutoString buffer1, buffer2;
|
||||
if (firstType == nsIDOMNode::DOCUMENT_TYPE_NODE) {
|
||||
nsCOMPtr<nsIDOMDocumentType> doc1 = do_QueryInterface(aFirstNode);
|
||||
nsCOMPtr<nsIDOMDocumentType> doc2 = do_QueryInterface(aSecondNode);
|
||||
if (!doc1 || !doc2) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
rv1 = doc1->GetName(buffer1);
|
||||
rv2 = doc2->GetName(buffer2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
rv1 = doc1->GetPublicId(buffer1);
|
||||
rv2 = doc2->GetPublicId(buffer2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
rv1 = doc1->GetSystemId(buffer1);
|
||||
rv2 = doc2->GetSystemId(buffer2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
rv1 = doc1->GetInternalSubset(buffer1);
|
||||
rv2 = doc2->GetInternalSubset(buffer2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMNamedNodeMap> map1, map2;
|
||||
rv1 = doc1->GetEntities(getter_AddRefs(map1));
|
||||
rv2 = doc2->GetEntities(getter_AddRefs(map2));
|
||||
|
||||
// XXX need to handle the case where neither has entities?
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool equal = nsXFormsUtils::AreEntitiesEqual(map1, map2);
|
||||
if (!equal) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
rv1 = doc1->GetNotations(getter_AddRefs(map1));
|
||||
rv2 = doc2->GetNotations(getter_AddRefs(map2));
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
equal = nsXFormsUtils::AreNotationsEqual(map1, map2);
|
||||
if (!equal) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rv1 = aFirstNode->GetNodeName(buffer1);
|
||||
rv2 = aSecondNode->GetNodeName(buffer2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
rv1 = aFirstNode->GetLocalName(buffer1);
|
||||
rv2 = aSecondNode->GetLocalName(buffer2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
rv1 = aFirstNode->GetNamespaceURI(buffer1);
|
||||
rv2 = aSecondNode->GetNamespaceURI(buffer2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
rv1 = aFirstNode->GetPrefix(buffer1);
|
||||
rv2 = aSecondNode->GetPrefix(buffer2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
rv1 = aFirstNode->GetNodeValue(buffer1);
|
||||
rv2 = aSecondNode->GetNodeValue(buffer2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool hasAttr1, hasAttr2;
|
||||
rv1 = aFirstNode->HasAttributes(&hasAttr1);
|
||||
rv2 = aSecondNode->HasAttributes(&hasAttr2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || hasAttr1 != hasAttr2) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (hasAttr1) {
|
||||
nsCOMPtr<nsIDOMNamedNodeMap> attrs1, attrs2;
|
||||
PRUint32 attrLength1, attrLength2;
|
||||
|
||||
rv1 = aFirstNode->GetAttributes(getter_AddRefs(attrs1));
|
||||
rv2 = aSecondNode->GetAttributes(getter_AddRefs(attrs2));
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
rv1 = attrs1->GetLength(&attrLength1);
|
||||
rv2 = attrs2->GetLength(&attrLength2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || attrLength1 != attrLength2) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// the order of the attributes on the two nodes doesn't matter. But
|
||||
// every attribute on node1 must exist on node2 (and no more)
|
||||
for (PRUint32 i = 0; i < attrLength1; ++i) {
|
||||
nsCOMPtr<nsIDOMNode> attr1, attr2;
|
||||
rv1 = attrs1->Item(i, getter_AddRefs(attr1));
|
||||
if (!attr1) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
attr1->GetLocalName(buffer1);
|
||||
attr1->GetNamespaceURI(buffer2);
|
||||
attrs2->GetNamedItemNS(buffer2, buffer1, getter_AddRefs(attr2));
|
||||
if (!attr2) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
rv1 = attr1->GetNodeValue(buffer1);
|
||||
rv2 = attr2->GetNodeValue(buffer2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now looking at the child nodes. They have to be 'equal' and at the same
|
||||
// index inside each of the parent nodes.
|
||||
PRBool hasChildren1, hasChildren2;
|
||||
rv1 = aFirstNode->HasChildNodes(&hasChildren1);
|
||||
rv2 = aSecondNode->HasChildNodes(&hasChildren2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || hasChildren1 != hasChildren2) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (hasChildren1) {
|
||||
nsCOMPtr<nsIDOMNodeList> children1, children2;
|
||||
PRUint32 childrenLength1, childrenLength2;
|
||||
|
||||
rv1 = aFirstNode->GetChildNodes(getter_AddRefs(children1));
|
||||
rv2 = aSecondNode->GetChildNodes(getter_AddRefs(children2));
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || !children1 || !children2) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
rv1 = children1->GetLength(&childrenLength1);
|
||||
rv2 = children2->GetLength(&childrenLength2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || childrenLength1 != childrenLength2) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMNode> clone1, clone2;
|
||||
if (!aAlreadyNormalized) {
|
||||
// well we avoided this as long as we can. If we haven't already
|
||||
// normalized all children, now is the time to do it. We'll have to clone
|
||||
// nodes since the normalization process actually changes the DOM.
|
||||
|
||||
rv1 = aFirstNode->CloneNode(PR_TRUE, getter_AddRefs(clone1));
|
||||
if (NS_FAILED(rv1) || !clone1) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
rv2 = aSecondNode->CloneNode(PR_TRUE, getter_AddRefs(clone2));
|
||||
if (NS_FAILED(rv2) || !clone2) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
rv1 = clone1->Normalize();
|
||||
rv2 = clone2->Normalize();
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// since this already worked once on the original nodes, won't bother
|
||||
// checking the results for the clones
|
||||
clone1->GetChildNodes(getter_AddRefs(children1));
|
||||
clone2->GetChildNodes(getter_AddRefs(children2));
|
||||
|
||||
// get length again since normalizing may have eliminated some text nodes
|
||||
rv1 = children1->GetLength(&childrenLength1);
|
||||
rv2 = children2->GetLength(&childrenLength2);
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2) || childrenLength1 != childrenLength2) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
for (PRUint32 i = 0; i < childrenLength1; ++i) {
|
||||
nsCOMPtr<nsIDOMNode> child1, child2;
|
||||
|
||||
rv1 = children1->Item(i, getter_AddRefs(child1));
|
||||
rv2 = children2->Item(i, getter_AddRefs(child2));
|
||||
if (NS_FAILED(rv1) || NS_FAILED(rv2)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool areEqual = nsXFormsUtils::AreNodesEqual(child1, child2, PR_TRUE);
|
||||
if (!areEqual) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
|
||||
}
|
||||
|
|
|
@ -465,6 +465,39 @@ public:
|
|||
* @return Whether handling was successful
|
||||
*/
|
||||
static PRBool HandleBindingException(nsIDOMElement *aElement);
|
||||
|
||||
/**
|
||||
* Returns whether the given NamedNodeMaps of Entities are equal
|
||||
*
|
||||
*/
|
||||
static NS_HIDDEN_(PRBool) AreEntitiesEqual(nsIDOMNamedNodeMap *aEntities1,
|
||||
nsIDOMNamedNodeMap *aEntities2);
|
||||
|
||||
/**
|
||||
* Returns whether the given NamedNodeMaps of Notations are equal
|
||||
*
|
||||
*/
|
||||
static NS_HIDDEN_(PRBool) AreNotationsEqual(nsIDOMNamedNodeMap *aNotations1,
|
||||
nsIDOMNamedNodeMap *aNotations2);
|
||||
|
||||
/**
|
||||
* Returns whether the given nodes are equal as described in the isEqualNode
|
||||
* function defined in the DOM Level 3 Core spec.
|
||||
* http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/DOM3-Core.html#core-Node3-isEqualNode
|
||||
*
|
||||
* XXX: this is just temporary until isEqualNode is implemented in Mozilla
|
||||
* (https://bugzilla.mozilla.org/show_bug.cgi?id=159167)
|
||||
*
|
||||
* @param aFirstNode The first node to compare
|
||||
* @param aSecondNode The second node to compare
|
||||
* @param aAlreadyNormalized Whether the two nodes and their children, etc.
|
||||
* have already been normalized to allow for
|
||||
* more accurate child node comparisons, as
|
||||
* recommended in the DOM Level 3 Core spec.
|
||||
*/
|
||||
static NS_HIDDEN_(PRBool) AreNodesEqual(nsIDOMNode *aFirstNode,
|
||||
nsIDOMNode *aSecondNode,
|
||||
PRBool aAlreadyNormalized = PR_FALSE);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -138,22 +138,49 @@
|
|||
|
||||
this._refreshing = true;
|
||||
|
||||
// if this node contains a non TEXT node, then we have to throw
|
||||
// the 'just string values' logic out the window
|
||||
var boundNode = this.accessors.getBoundNode();
|
||||
var containsNonText = false;
|
||||
if (boundNode && boundNode.hasChildNodes()) {
|
||||
var child = boundNode.firstChild;
|
||||
while (child) {
|
||||
var type = child.nodeType;
|
||||
if (type != Node.TEXT_NODE && type != Node.CDATA_SECTION_NODE) {
|
||||
containsNonText = true;
|
||||
this._accessorValueCache = null;
|
||||
break;
|
||||
}
|
||||
child = child.nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
// We detect if the instance data we bind to has changed. If it has,
|
||||
// changed, we simply update the selection. If it hasn't, that means
|
||||
// we rebuild the select UI. We also rebuild if the delegate cache is
|
||||
// null (first load).
|
||||
if (this._accessorValueCache == null ||
|
||||
this._accessorValueCache == this.accessors.getValue()) {
|
||||
// refresh was not called due to instance data changing, so build the
|
||||
// UI.
|
||||
this._buildSelect();
|
||||
} else {
|
||||
this._accessorValueCache == this.accessors.getValue() ||
|
||||
containsNonText) {
|
||||
// if we reached here and the instance data only contains text
|
||||
// nodes, then we need to rebuild the control since we know it
|
||||
// wasn't due to a simple instance data changing scenario. But if
|
||||
// the bound node contains non TEXT nodes, then it is too expensive
|
||||
// to figure out if this was because a child node changed somewhere
|
||||
// along the way. We'd basically have to cache the whole bound node
|
||||
// subtree to compare against. To avoid this we'll just rebuild the
|
||||
// control from scratch.
|
||||
|
||||
// XXX at a future time we need to figure out which will be more
|
||||
// efficient give the most probable use cases.
|
||||
this._buildSelect(containsNonText);
|
||||
} else if (!containsNonText) {
|
||||
// update selection
|
||||
this._updateSelection();
|
||||
}
|
||||
|
||||
// store the delegate value
|
||||
this._accessorValueCache = this.accessors.getValue();
|
||||
// store the delegate value
|
||||
this._accessorValueCache = this.accessors.getValue();
|
||||
}
|
||||
|
||||
this._refreshing = false;
|
||||
|
||||
|
@ -164,28 +191,92 @@
|
|||
|
||||
<field name="_controlArraySize">0</field>
|
||||
<field name="_controlArray">new Array()</field>
|
||||
<field name="_selectedElementSize">0</field>
|
||||
<field name="_selectedElementArray">new Array()</field>
|
||||
<field name="_defaultHash">null</field>
|
||||
|
||||
<method name="_buildSelect">
|
||||
<parameter name="aContainsNonText"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
// select builds its own UI by parsing it's children.
|
||||
|
||||
// replace new line (\n), tabs (\t) and carriage returns (\r) with "".
|
||||
var value = "";
|
||||
// if delegate.value has something, then only text node(s) should
|
||||
// exist under the bound node
|
||||
|
||||
if (this.accessors.getValue())
|
||||
value = this.accessors.getValue().replace(/\n|\t|\r/g, " ");
|
||||
// holds an array of DOMElements that exist under bound node,
|
||||
this._selectedElementSize = 0;
|
||||
this._selectedElementArray = new Array();
|
||||
|
||||
// get an array of values selected in the bound node
|
||||
var selectedArray = value.split(" ");
|
||||
if (!aContainsNonText) {
|
||||
// replace new line (\n), tabs (\t) and carriage returns (\r) with
|
||||
// "".
|
||||
var value = "";
|
||||
var accessValue = this.accessors.getValue();
|
||||
|
||||
if (accessValue)
|
||||
value = accessValue.replace(/\n|\t|\r/g, " ");
|
||||
|
||||
// get an array of values selected in the bound node
|
||||
var selectedArray = value.split(" ");
|
||||
|
||||
// create a hash from the default values so we can store how often
|
||||
// we encountered them. This allows us to figure out later if any
|
||||
// were not hit, which requires us to send an event.
|
||||
this._defaultHash = new Object();
|
||||
for (var run = 0; run < selectedArray.length; run++) {
|
||||
this._defaultHash[selectedArray[run]] = {hits: 0}
|
||||
}
|
||||
} else {
|
||||
var boundNode = this.accessors.getBoundNode();
|
||||
var child = boundNode ? boundNode.firstChild : null;
|
||||
this._defaultHash = null;
|
||||
while (child) {
|
||||
var type = child.nodeType;
|
||||
if (type == Node.TEXT_NODE ||
|
||||
type == Node.CDATA_SECTION_NODE) {
|
||||
// if child is a text node completely filled with
|
||||
// whitespace let's ignore it and get the next node
|
||||
var string = child.nodeValue;
|
||||
var nonWhitespace = false;
|
||||
if (string) {
|
||||
// this regexp tests whether only whitespace is contained
|
||||
// between the beginning and ending of the string.
|
||||
nonWhitespace = !(/^\s*$/.test(string));
|
||||
}
|
||||
if (nonWhitespace) {
|
||||
// replace new line (\n), tabs (\t) and carriage returns (\r)
|
||||
// with " ".
|
||||
var value = string.replace(/\n|\t|\r/g, " ");
|
||||
|
||||
// get an array of values selected in the bound node
|
||||
var selectedArray = value.split(" ");
|
||||
|
||||
// create a hash from the default values so we can store how
|
||||
// often we encountered them. This allows us to figure out
|
||||
// later if any were not hit, which requires us to send an
|
||||
// event.
|
||||
if (!this._defaultHash) {
|
||||
this._defaultHash = new Object();
|
||||
}
|
||||
for (var run = 0; run < selectedArray.length; run++) {
|
||||
this._defaultHash[selectedArray[run]] = {hits: 0}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// if it's not a text node, we'll assume that we are looking at
|
||||
// a node worth comparing. As such, look for an
|
||||
// item with a copy element that might match this node.
|
||||
this._selectedElementArray[this._selectedElementSize] =
|
||||
{element: child, hits: 0}
|
||||
this._selectedElementSize++;
|
||||
}
|
||||
|
||||
// create a hash from the default values so we can store how often
|
||||
// we encountered them. This allows us to figure out later if any were
|
||||
// not hit, which requires us to send an event.
|
||||
this._defaultHash = new Object();
|
||||
for (var run = 0; run < selectedArray.length; run++) {
|
||||
this._defaultHash[selectedArray[run]] = {hits: 0}
|
||||
if (child == boundNode.lastChild) {
|
||||
break;
|
||||
}
|
||||
child = child.nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
// clear the UI children
|
||||
|
@ -225,12 +316,13 @@
|
|||
var uiElement =
|
||||
child.QueryInterface(Components.interfaces.nsIXFormsItemSetUIElement);
|
||||
var containers = uiElement.anonymousItemSetContent.childNodes;
|
||||
|
||||
// go through each item in the itemset and add it to the
|
||||
// html:select. Select any of the items that contain a value
|
||||
// that also appears under the bound node.
|
||||
for (var y = 0; y < containers.length; y++) {
|
||||
if (containers[y].nodeType == containers[y].ELEMENT_NODE) {
|
||||
var value = this._addItemSetItem(containers[y]);
|
||||
|
||||
// check if we should pre-select this option
|
||||
this.preselectItem(value);
|
||||
this._addItemSetItem(containers[y]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -247,6 +339,18 @@
|
|||
}
|
||||
}
|
||||
|
||||
// check if any default elements were not found
|
||||
for (var j = 0; j < this._selectedElementSize; j++) {
|
||||
if (this._selectedElementArray[j].hits == 0) {
|
||||
// XXX: some of default values not found, we need to throw an
|
||||
// xforms-out-of-range event, but only if the select is 'closed'.
|
||||
// If the select is open, the missing elements should be added
|
||||
// and selected per 8.1.10 in the spec.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
]]>
|
||||
</body>
|
||||
|
@ -365,10 +469,33 @@
|
|||
<body>
|
||||
<![CDATA[
|
||||
var itemElm = aItemElement.QueryInterface(Components.interfaces.nsIXFormsItemElement);
|
||||
var itemValue = itemElm.value;
|
||||
var copyItem = itemElm.isCopyItem;
|
||||
var itemValue = copyItem ? "" : itemElm.value;
|
||||
var itemLabel = itemElm.labelText;
|
||||
|
||||
var option = this._buildSelectItem(itemLabel, itemValue, aItemElement, true);
|
||||
var option = this._buildSelectItem(itemLabel, itemValue, aItemElement,
|
||||
true);
|
||||
|
||||
// if this item contains a copy element AND if the bound node contains
|
||||
// non-text elements, then see if any of these non-text elements match
|
||||
// this copyItem's node.
|
||||
if (copyItem && this._selectedElementSize > 0) {
|
||||
var item = aItemElement.QueryInterface(Components.interfaces.nsIXFormsSelectChild);
|
||||
for (var j = 0; j < this._selectedElementSize; j++ ) {
|
||||
var selectedItem =
|
||||
item.selectItemByNode(this._selectedElementArray[j].element);
|
||||
if (selectedItem) {
|
||||
this._selectedElementArray[j].hits++;
|
||||
option.selected = true;
|
||||
// XXX It is possible that two identical elements are under the
|
||||
// bound node. I guess we shouldn't mark one and not the other
|
||||
// if there is an item in the select that matches it. So we'll
|
||||
// go through the whole list. But this is quite an edge case
|
||||
// and will cause more inefficiency just to prevent an errant
|
||||
// xforms-out-of-range.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add to the control array
|
||||
this._controlArray[this._controlArraySize] =
|
||||
|
@ -377,6 +504,12 @@
|
|||
|
||||
this.uiElement.appendChild(option);
|
||||
|
||||
if (!copyItem) {
|
||||
// if this item contains a value element, then make sure to select
|
||||
// this item if its value exists under the bound node.
|
||||
this.preselectItem(itemValue);
|
||||
}
|
||||
|
||||
return itemValue;
|
||||
]]>
|
||||
</body>
|
||||
|
@ -388,7 +521,7 @@
|
|||
<![CDATA[
|
||||
// if incremental, change instance data and send the value-changed event
|
||||
if (this.incremental) {
|
||||
this._setBoundValue();
|
||||
this._handleSelection();
|
||||
} else {
|
||||
// per the spec, if not incremental, we still need to send the
|
||||
// deselect/select events. which _getSelectedValues() does for us
|
||||
|
@ -398,11 +531,32 @@
|
|||
</body>
|
||||
</method>
|
||||
|
||||
<method name="_setBoundValue">
|
||||
<method name="_handleSelection">
|
||||
<body>
|
||||
<![CDATA[
|
||||
if (this.accessors.hasBoundNode)
|
||||
this.accessors.setValue(this._getSelectedValues());
|
||||
var boundNode = this.accessors.getBoundNode();
|
||||
if (!boundNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
var contentEnvelope = this._getSelectedValues();
|
||||
if (contentEnvelope) {
|
||||
if (boundNode.nodeType == Node.ELEMENT_NODE) {
|
||||
this.accessors.setContent(contentEnvelope);
|
||||
} else {
|
||||
// if some copyItems were selected by the user prior to the call
|
||||
// to _getSelectedValues, then we would not have set up
|
||||
// _delegateValueCache. Since the node we are bound to can't
|
||||
// be set by copyItems (its not an ELEMENT_NODE), any copyItems
|
||||
// in this select would have been deselected during
|
||||
// _getSelectedValues. Thus, anything in the contentEnvelope at
|
||||
// this point should just be strings and so we can set
|
||||
// delegate.value directly and use _delegateValueCache after all.
|
||||
|
||||
this.accessors.setValue(contentEnvelope.nodeValue);
|
||||
this._accessorValueCache = contentEnvelope.nodeValue;
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
@ -416,6 +570,29 @@
|
|||
// select if found, unselect if not
|
||||
var options = this._controlArray;
|
||||
|
||||
var boundNode = this.accessors.getBoundNode();
|
||||
if (!boundNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
// we are cloning boundNode to create a node that we will return.
|
||||
// By the end of this function, assuming all went well,
|
||||
// contentEnvelope will contain the values and copyNodes that are
|
||||
// represented by the selected items in this xf:select. Cloning
|
||||
// the boundNode to use as the envelope so that the caller could
|
||||
// just pass the results straight into accessors.setContent().
|
||||
var contentEnvelope = null;
|
||||
contentEnvelope = boundNode.cloneNode(false);
|
||||
if (!contentEnvelope) {
|
||||
return;
|
||||
}
|
||||
var boundType = boundNode.nodeType;
|
||||
var copyNode;
|
||||
|
||||
// keep in mind, to maintain compatibility with XSmiles and Novell, we
|
||||
// ultimately need to end up with all 'value' elements contained in a
|
||||
// text node and this text node needs to be the first child of the
|
||||
// bound node.
|
||||
for (var i = 0; i < options.length; i++) {
|
||||
var isSelected =
|
||||
options[i].option ? options[i].option.selected : options[i].checkbox.checked;
|
||||
|
@ -426,31 +603,94 @@
|
|||
selectedValues += " ";
|
||||
}
|
||||
|
||||
selectedValues +=
|
||||
options[i].control.QueryInterface(Components.interfaces.nsIXFormsSelectChild).value;
|
||||
var item = options[i].control.QueryInterface(Components.interfaces.nsIXFormsItemElement);
|
||||
if (item.isCopyItem) {
|
||||
if (boundType && (boundType != Node.ELEMENT_NODE)) {
|
||||
// if we are trying to do a copy without being bound to an
|
||||
// element node, then we need to throw a binding exception
|
||||
// per spec.
|
||||
bindingException = document.createEvent("Events");
|
||||
bindingException.initEvent("xforms-binding-exception", true, false);
|
||||
this.dispatchEvent(bindingException);
|
||||
|
||||
// if it wasn't selected before add to the list of newly selected items
|
||||
if (!options[i].wasSelected) {
|
||||
newSelectedControls.push(options[i].control);
|
||||
// we should probably un-select the option so that the list
|
||||
// of selected data is accurate. This WON'T cause a
|
||||
// xforms-select/deselect to fire. Since the user just
|
||||
// selected this item and we are automatically deselecting
|
||||
// it from underneath the user, we'll treat it like nothing
|
||||
// happened.
|
||||
if (options[i].option) {
|
||||
options[i].option.selected = false;
|
||||
} else {
|
||||
options[i].checkbox.checked = false;
|
||||
}
|
||||
} else {
|
||||
copyNode = item.copyNode;
|
||||
if (copyNode) {
|
||||
var clone = copyNode.cloneNode(true);
|
||||
contentEnvelope.appendChild(clone);
|
||||
}
|
||||
|
||||
// if it wasn't selected before add to the list of newly
|
||||
// selected items
|
||||
if (!options[i].wasSelected) {
|
||||
newSelectedControls.push(options[i].control);
|
||||
}
|
||||
|
||||
options[i].wasSelected = true;
|
||||
}
|
||||
} else {
|
||||
// not a copyItem, so grab the item's value and append it to our
|
||||
// space seperated list.
|
||||
selectedValues +=
|
||||
options[i].control.QueryInterface(Components.interfaces.nsIXFormsSelectChild).value;
|
||||
|
||||
// if it wasn't selected before add to the list of newly
|
||||
// selected items
|
||||
if (!options[i].wasSelected) {
|
||||
newSelectedControls.push(options[i].control);
|
||||
}
|
||||
|
||||
options[i].wasSelected = true;
|
||||
}
|
||||
|
||||
options[i].wasSelected = true;
|
||||
} else {
|
||||
// it was selected before, but now unselected
|
||||
if (options[i].wasSelected) {
|
||||
this.dispatchSelectEvent(options[i].control, "xforms-deselect");
|
||||
|
||||
// XXX if this is a copyItem, we'll need to rebuild the model
|
||||
// per spec.
|
||||
}
|
||||
|
||||
options[i].wasSelected = false;
|
||||
}
|
||||
}
|
||||
|
||||
// write out the text nodes before we handle copy
|
||||
if (boundType == Node.ELEMENT_NODE) {
|
||||
if (selectedValues.length > 0) {
|
||||
var textNode = document.createTextNode(selectedValues);
|
||||
if (copyNode) {
|
||||
// making sure all selected 'values' are in the first text node
|
||||
// under the bound node.
|
||||
var firstChild = contentEnvelope.firstChild;
|
||||
contentEnvelope.insertBefore(textNode, firstChild);
|
||||
} else {
|
||||
contentEnvelope.appendChild(textNode);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
contentEnvelope.nodeValue = selectedValues;
|
||||
}
|
||||
|
||||
selectedValues = "";
|
||||
|
||||
// we send xforms-select after all deselect events are thrown
|
||||
for (var i = 0; i < newSelectedControls.length; i++) {
|
||||
this.dispatchSelectEvent(newSelectedControls[i], "xforms-select");
|
||||
}
|
||||
|
||||
return selectedValues;
|
||||
return contentEnvelope;
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
@ -458,6 +698,11 @@
|
|||
<method name="_updateSelection">
|
||||
<body>
|
||||
<![CDATA[
|
||||
// this function only looks through the text values that are stored
|
||||
// under the bound node and selects the xf:items that have
|
||||
// corresponding values to that list. As such, copyItems will
|
||||
// be ignored.
|
||||
|
||||
// get an array of values selected in the bound node
|
||||
var selectedArray = new Array();
|
||||
if (this.accessors.getValue())
|
||||
|
@ -473,8 +718,11 @@
|
|||
var options = this._controlArray;
|
||||
|
||||
for (var i = 0; i < options.length; i++) {
|
||||
var value =
|
||||
options[i].control.QueryInterface(Components.interfaces.nsIXFormsSelectChild).value;
|
||||
var item = options[i].control.QueryInterface(Components.interfaces.nsIXFormsSelectChild);
|
||||
if (item.isCopyItem) {
|
||||
break;
|
||||
}
|
||||
var value = item.value;
|
||||
var selectionValue = (this._defaultHash[value] != null);
|
||||
|
||||
// either a checkbox or an option
|
||||
|
@ -520,7 +768,7 @@
|
|||
<![CDATA[
|
||||
// update instance data if we are not incremental
|
||||
if (!this.incremental) {
|
||||
this._setBoundValue();
|
||||
this._handleSelection();
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
|
@ -531,7 +779,7 @@
|
|||
<body>
|
||||
<![CDATA[
|
||||
// check if we should pre-select this option
|
||||
if (this._defaultHash[aValue] != null) {
|
||||
if (this._defaultHash && this._defaultHash[aValue] != null) {
|
||||
var control = this._controlArray[this._controlArraySize - 1]
|
||||
this._setItemSelection(control, true);
|
||||
|
||||
|
@ -726,10 +974,12 @@
|
|||
<body>
|
||||
<![CDATA[
|
||||
var itemElm = aItemElement.QueryInterface(Components.interfaces.nsIXFormsItemElement);
|
||||
var copyItem = itemElm.isCopyItem;
|
||||
var itemValue = itemElm.value;
|
||||
var itemLabel = itemElm.labelText;
|
||||
|
||||
var item = this._buildSelectItem(itemLabel, itemValue, aItemElement, true);
|
||||
var itemLabel = copyItem ? "" : itemElm.labelText;
|
||||
|
||||
var item = this._buildSelectItem(itemLabel, itemValue, aItemElement,
|
||||
true);
|
||||
|
||||
// add to the control array
|
||||
this._controlArray[this._controlArraySize] =
|
||||
|
@ -738,6 +988,31 @@
|
|||
|
||||
this.uiElement.appendChild(item);
|
||||
|
||||
// if this item contains a copy element AND if the bound node contains
|
||||
// non-text elements, then see if any of these non-text elements match
|
||||
// this copyItem's node.
|
||||
if (copyItem && this._selectedElementSize > 0) {
|
||||
var item = aItemElement.QueryInterface(Components.interfaces.nsIXFormsSelectChild);
|
||||
for (var j = 0; j < this._selectedElementSize; j++ ) {
|
||||
var selectedItem =
|
||||
item.selectItemByNode(this._selectedElementArray[j].element);
|
||||
if (selectedItem) {
|
||||
this._selectedElementArray[j].hits++;
|
||||
item.firstChild.checked = true;
|
||||
// XXX It is possible that two identical elements are under the
|
||||
// bound node. I guess we shouldn't mark one and not the other
|
||||
// if there is an item in the select that matches it. So we'll
|
||||
// go through the whole list. But this is quite an edge case
|
||||
// and will cause more inefficiency just to prevent an errant
|
||||
// xforms-out-of-range.
|
||||
}
|
||||
}
|
||||
} else if (!copyItem) {
|
||||
// if this item contains a value element, then make sure to select
|
||||
// this item if its value exists under the bound node.
|
||||
this.preselectItem(itemValue);
|
||||
}
|
||||
|
||||
return itemValue;
|
||||
]]>
|
||||
</body>
|
||||
|
|
|
@ -154,7 +154,7 @@
|
|||
<![CDATA[
|
||||
if (this.selectionOpen && !this._selected) {
|
||||
if (this.getAttribute("incremental") != "false") {
|
||||
this.accessors.setValue(this.inputField.value);
|
||||
this._handleSelection();
|
||||
}
|
||||
} else {
|
||||
this.togglePopup();
|
||||
|
@ -173,7 +173,28 @@
|
|||
this.togglePopup();
|
||||
if (open && this._selected) {
|
||||
this.updateInputField();
|
||||
this.accessors.setValue(this._selected.value);
|
||||
this._handleSelection();
|
||||
|
||||
// need to keep the xforms-select and xforms-deselect event
|
||||
// dispatching after _handleSelection. That function might
|
||||
// deselect this._selected if this user selected item is a
|
||||
// copyItem bound to a non-element node. We don't want to
|
||||
// dispatch a xforms-select/deselect in that case since it
|
||||
// really isn't considered to be a valid selection to begin with
|
||||
// (causes a xforms-binding-exception).
|
||||
if (this._lastSelectedItem != this._selected) {
|
||||
if (this._lastSelectedItem) {
|
||||
// XXX if this is a copyItem, we'll need to rebuild the
|
||||
// model per spec.
|
||||
this.dispatchSelectEvent(this._lastSelectedItem, "xforms-deselect");
|
||||
}
|
||||
|
||||
if (this._selected) {
|
||||
this.dispatchSelectEvent(this._selected, "xforms-select");
|
||||
}
|
||||
|
||||
this._lastSelectedItem = this._selected;
|
||||
}
|
||||
}
|
||||
} else if (key == aEvent.DOM_VK_UP ||
|
||||
key == aEvent.DOM_VK_DOWN) {
|
||||
|
@ -188,9 +209,28 @@
|
|||
if (!this.popupOpen && this.getAttribute("incremental") != "false") {
|
||||
if (this._selected) {
|
||||
this.updateInputField();
|
||||
this.accessors.setValue(this._selected.value);
|
||||
} else if (this.selectionOpen) {
|
||||
this.accessors.setValue(this.inputField.value);
|
||||
}
|
||||
this._handleSelection();
|
||||
|
||||
// need to keep the xforms-select and xforms-deselect event
|
||||
// dispatching after _handleSelection. That function might
|
||||
// deselect this._selected if the selected item is a copyItem
|
||||
// bound to a non-element node. We don't want to dispatch a
|
||||
// xforms-select/deselect in that case since it really isn't
|
||||
// considered to be a valid selection to begin with (causes
|
||||
// a xforms-binding-exception).
|
||||
if (this._lastSelectedItem != this._selected) {
|
||||
if (this._lastSelectedItem) {
|
||||
// XXX if this is a copyItem, we'll need to rebuild the
|
||||
// model per spec.
|
||||
this.dispatchSelectEvent(this._lastSelectedItem, "xforms-deselect");
|
||||
}
|
||||
|
||||
if (this._selected) {
|
||||
this.dispatchSelectEvent(this._selected, "xforms-select");
|
||||
}
|
||||
|
||||
this._lastSelectedItem = this._selected;
|
||||
}
|
||||
}
|
||||
} else if (key == aEvent.DOM_VK_TAB) {
|
||||
|
@ -232,7 +272,7 @@
|
|||
this._selected = null;
|
||||
}
|
||||
if (this.getAttribute("incremental") != "false") {
|
||||
this.accessors.setValue(this.inputField.value);
|
||||
this._handleSelection();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -346,16 +386,14 @@
|
|||
next = this.findNextSelectable(node, aDown);
|
||||
if (next) {
|
||||
if (this._selected) {
|
||||
this.dispatchSelectEvent(this._selected, "xforms-deselect");
|
||||
this._lastSelected = this._selected;
|
||||
this._selected.setActive(false);
|
||||
this._selected = null;
|
||||
}
|
||||
|
||||
nextItem = next.QueryInterface(Components.interfaces.nsIXFormsItemElement);
|
||||
if (nextItem) {
|
||||
this.dispatchSelectEvent(nextItem, "xforms-select");
|
||||
this._selected = nextItem;
|
||||
this._lastSelectedItem = nextItem;
|
||||
this._selected.setActive(true);
|
||||
this.updateInputField();
|
||||
}
|
||||
|
@ -395,16 +433,29 @@
|
|||
this.hidePopup();
|
||||
|
||||
if (this._selected) {
|
||||
if (this._lastSelectedItem != this._selected) {
|
||||
if (this._lastSelectedItem)
|
||||
this.dispatchSelectEvent(this._lastSelectedItem, "xforms-deselect");
|
||||
this.updateInputField();
|
||||
this._handleSelection();
|
||||
|
||||
// need to keep the xforms-select and xforms-deselect event
|
||||
// dispatching after _handleSelection. That function might
|
||||
// deselect this._selected if the selected item is a copyItem
|
||||
// bound to a non-element node. We don't want to dispatch a
|
||||
// xforms-select/deselect in that case since it really isn't
|
||||
// considered to be a valid selection to begin with (causes
|
||||
// a xforms-binding-exception).
|
||||
if (this._lastSelectedItem != this._selected) {
|
||||
if (this._lastSelectedItem) {
|
||||
// XXX if this is a copyItem, we'll need to rebuild the
|
||||
// model per spec.
|
||||
this.dispatchSelectEvent(this._lastSelectedItem, "xforms-deselect");
|
||||
}
|
||||
|
||||
if (this._selected) {
|
||||
this.dispatchSelectEvent(this._selected, "xforms-select");
|
||||
}
|
||||
|
||||
this.dispatchSelectEvent(this._selected, "xforms-select");
|
||||
this._lastSelectedItem = this._selected;
|
||||
}
|
||||
|
||||
this.updateInputField();
|
||||
this.accessors.setValue(this._selected.value);
|
||||
}
|
||||
this.inputField.focus();
|
||||
]]>
|
||||
|
@ -557,7 +608,72 @@
|
|||
<body>
|
||||
<![CDATA[
|
||||
try {
|
||||
var newValue = this.stringValue;
|
||||
var nodeValue = null, newValue = null;
|
||||
var boundNode = this.accessors.getBoundNode();
|
||||
var outOfRange = false;
|
||||
if (boundNode && boundNode.hasChildNodes()) {
|
||||
// Since this is a select1, there should normally be just one
|
||||
// child node here. But no guarantee that a select1 generated
|
||||
// the value coming in. So we'll look for text node with
|
||||
// non-whitespace characters to compare with an item's xf:value.
|
||||
// Any other node that we encounter we look to match with an
|
||||
// item's xf:copy. If more than one of either of these exists
|
||||
// in the instance data, we need to generate a xforms-out-of-range
|
||||
// event and style the select1 as out-of-range since by
|
||||
// definition a select1 can not select more than one item.
|
||||
var child = boundNode.firstChild;
|
||||
while (child) {
|
||||
var type = child.nodeType;
|
||||
if (type == Node.TEXT_NODE) {
|
||||
// if child is a text node completely filled with
|
||||
// whitespace let's ignore it and get the next node
|
||||
var string = child.nodeValue;
|
||||
var nonWhitespace = false;
|
||||
if (string) {
|
||||
// this regexp tests whether only whitespace is contained
|
||||
// between the beginning and ending of the string.
|
||||
nonWhitespace = !(/^\s*$/.test(string));
|
||||
}
|
||||
if (nonWhitespace) {
|
||||
if (newValue || nodeValue) {
|
||||
// oh oh! We've already found a selectable node in the
|
||||
// instance data and now we have another. That shouldn't
|
||||
// happen.
|
||||
// XXX generate xforms-out-of-range exception and style
|
||||
// control as out-of-range
|
||||
outOfRange = true;
|
||||
}
|
||||
newValue = string;
|
||||
}
|
||||
} else {
|
||||
// if it's not a text node, we'll assume that we are looking at
|
||||
// a node worth comparing. As such, look for an
|
||||
// item with a copy element that might match this node.
|
||||
if (newValue || nodeValue) {
|
||||
// oh oh! We've already found a selectable node in the
|
||||
// instance data and now we have another. That shouldn't
|
||||
// happen.
|
||||
// XXX generate xforms-out-of-range exception and style
|
||||
// control as out-of-range
|
||||
outOfRange = true;
|
||||
}
|
||||
nodeValue = child;
|
||||
}
|
||||
|
||||
if (child == boundNode.lastChild) {
|
||||
break;
|
||||
}
|
||||
child = child.nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
if (outOfRange) {
|
||||
// can't possibly work, no sense continuing.
|
||||
this.inputField.value = "";
|
||||
this._selected.setActive(false);
|
||||
this._selected = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.selectionOpen || this.accessors.isReadonly()) {
|
||||
this.inputField.setAttribute("readonly", "readonly");
|
||||
|
@ -565,17 +681,35 @@
|
|||
this.inputField.removeAttribute("readonly");
|
||||
}
|
||||
|
||||
if (this._selected) {
|
||||
if (newValue ==
|
||||
this._selected.value) {
|
||||
return true;
|
||||
if (this._selected && !this._selected.isCopyItem) {
|
||||
var envelope = this._getSelectedValue();
|
||||
if (envelope) {
|
||||
var textNode = null;
|
||||
if (envelope.nodeType == Node.ELEMENT_NODE) {
|
||||
textNode = envelope.firstChild;
|
||||
if (newValue == textNode.nodeValue) {
|
||||
// value in instance data already selected. Nothin' left
|
||||
// to do.
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (newValue == contentEnvelope.nodeValue) {
|
||||
// value in instance data already selected. Nothin' left
|
||||
// to do.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
this._selected.setActive(false);
|
||||
this._selected = null;
|
||||
this._lastSelectedItem = null;
|
||||
}
|
||||
|
||||
this.selectItemByValue(newValue);
|
||||
if (newValue) {
|
||||
this.selectItemByValue(newValue);
|
||||
} else if (nodeValue) {
|
||||
this.selectItemByNode(nodeValue);
|
||||
}
|
||||
|
||||
if (this._selected) {
|
||||
this.updateInputField();
|
||||
|
@ -610,7 +744,8 @@
|
|||
item = null;
|
||||
try {
|
||||
if (node.nodeType == document.ELEMENT_NODE &&
|
||||
node.namespaceURI == this.XFORMS_NS && node.localName != "label") {
|
||||
node.namespaceURI == this.XFORMS_NS &&
|
||||
node.localName != "label") {
|
||||
|
||||
item = node.QueryInterface(Components.interfaces.nsIXFormsSelectChild);
|
||||
if (item) {
|
||||
|
@ -635,6 +770,45 @@
|
|||
</body>
|
||||
</method>
|
||||
|
||||
<method name="selectItemByNode">
|
||||
<parameter name="aNode"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
|
||||
// select the copyItem in this select1 whose copyNode equals aNode
|
||||
|
||||
var node = this.firstChild;
|
||||
var item;
|
||||
while (node) {
|
||||
item = null;
|
||||
try {
|
||||
if (node.nodeType == document.ELEMENT_NODE &&
|
||||
node.namespaceURI == this.XFORMS_NS &&
|
||||
node.localName != "label") {
|
||||
|
||||
item = node.QueryInterface(Components.interfaces.nsIXFormsSelectChild);
|
||||
if (item) {
|
||||
item = item.selectItemByNode(aNode);
|
||||
if (item) {
|
||||
if (this._selected) {
|
||||
this._selected.setActive(false);
|
||||
this._selected = null;
|
||||
}
|
||||
this._selected = item.QueryInterface(Components.interfaces.nsIXFormsItemElement);
|
||||
if (this._selected) {
|
||||
this._selected.setActive(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ex) {}
|
||||
node = node.nextSibling;
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="handleBlur">
|
||||
<body>
|
||||
<![CDATA[
|
||||
|
@ -654,12 +828,67 @@
|
|||
return;
|
||||
}
|
||||
|
||||
if (this.selectionOpen && !this._selected) {
|
||||
this.accessors.setValue(this.inputField.value);
|
||||
} else if (this._selected) {
|
||||
if (this._selected) {
|
||||
this.updateInputField();
|
||||
this.accessors.setValue(this._selected.value);
|
||||
}
|
||||
this._handleSelection();
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
// _handleSelection updates the bound node with the value from the
|
||||
// currently selected item's value element or copy element.
|
||||
<method name="_handleSelection">
|
||||
<body>
|
||||
<![CDATA[
|
||||
var boundNode = this.accessors.getBoundNode();
|
||||
if (!boundNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.selectionOpen && !this._selected) {
|
||||
this.accessors.setValue(this.inputField.value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._selected) {
|
||||
// no reason to continue
|
||||
return;
|
||||
}
|
||||
|
||||
if (boundNode.nodeType != boundNode.ELEMENT_NODE) {
|
||||
// if the boundNode type isn't an ELEMENT_NODE, then contentEnvelope
|
||||
// isn't an ELEMENT_NODE (since it is a clone of the bound node).
|
||||
// So if contentEnvelope has a value, it will be the nodeValue.
|
||||
var envelope = this._getSelectedValue();
|
||||
if (envelope) {
|
||||
this.accessors.setValue(envelope.nodeValue);
|
||||
return;
|
||||
}
|
||||
|
||||
// not allowed to copy a node under a non ELEMENT node, so
|
||||
// generating a binding exception per spec.
|
||||
var ev = document.createEvent("Events");
|
||||
ev.initEvent("xforms-binding-exception", true, false);
|
||||
this.dispatchEvent(ev);
|
||||
|
||||
// well, whatever we had selected isn't going to cut it. But the
|
||||
// user did choose to deselect the previous item in favor of this
|
||||
// this item, so we really shouldn't go back to what
|
||||
// was there before. So we'll go to nothing. Make sure bound
|
||||
// node reflects this. Seems to be consistent with what Novell
|
||||
// and formsPlayer does, too.
|
||||
this._selected.setActive(false);
|
||||
this._selected = null;
|
||||
this.inputField.value = "";
|
||||
this.accessors.setValue("");
|
||||
return;
|
||||
}
|
||||
|
||||
var contentEnvelope = this._getSelectedValue();
|
||||
this.accessors.setContent(contentEnvelope);
|
||||
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
|
@ -683,6 +912,63 @@
|
|||
return true;
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="_getSelectedValue">
|
||||
<body>
|
||||
<![CDATA[
|
||||
// The purpose of this function is to return the select1's currently
|
||||
// selected item's value in a contentEnvelope. It achieves this by
|
||||
// cloning the bound node to create the contentEnvelope which will be
|
||||
// returned. If the contentEnvelope is an element node, the contents
|
||||
// of the selected item's value will be inserted as a child of the
|
||||
// contentEnvelope. If it is a textnode, the selected item value will
|
||||
// be put in the contentEnvelope.nodeValue.
|
||||
|
||||
if (!this._selected) {
|
||||
// this will probably only happen if there was an exception
|
||||
// somewhere else first. But no sense continuing below and adding
|
||||
// more exceptions to the console.
|
||||
return null;
|
||||
}
|
||||
|
||||
var boundNode = this.accessors.getBoundNode();
|
||||
if (!boundNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
var contentEnvelope = boundNode.cloneNode(false);
|
||||
if (!contentEnvelope) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (contentEnvelope.nodeType == Node.ELEMENT_NODE) {
|
||||
var contentNode = null;
|
||||
if (this._selected.isCopyItem) {
|
||||
var copyNode = this._selected.copyNode;
|
||||
if (copyNode) {
|
||||
contentNode = copyNode.cloneNode(true);
|
||||
}
|
||||
} else {
|
||||
contentNode = document.createTextNode(this._selected.value);
|
||||
}
|
||||
|
||||
contentEnvelope.appendChild(contentNode);
|
||||
} else {
|
||||
// if the selected item is not a copyItem, then we'll just put the
|
||||
// item's value in the nodeValue for the contentEnvelope. Otherwise
|
||||
// we are stuck trying to stick an element node under a non-element
|
||||
// node and that ainna gonna work.
|
||||
if (!this._selected.isCopyItem) {
|
||||
contentEnvelope.nodeValue = this._selected.value;
|
||||
} else {
|
||||
contentEnvelope = null;
|
||||
}
|
||||
}
|
||||
|
||||
return contentEnvelope;
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
</implementation>
|
||||
</binding>
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ rangeNullInit = XForms Error (25): One or more init() parameters is NaN
|
|||
rangeBeginEndError = XForms Error (26): Begin is higher than end?
|
||||
encodingMemoryError = XForms Error (23): Not enough available memory to encode file %S, size = %S.
|
||||
uploadBoundTypeError = XForms Error (24): Upload element not bound to valid datatype. Must be bound to datatype 'xsd:anyURI', 'xsd:base64Binary', or 'xsd:hexBinary'.
|
||||
copyError = XForms Error (25): A copy element was found whose parent is not an itemset element
|
||||
|
||||
# Warning Messages:
|
||||
warnSOAP = XForms Warning (1): You are using the SOAP post feature, which is an experimental feature! Beware that the functionality might change, and forms may stop working at any time.
|
||||
|
|
Загрузка…
Ссылка в новой задаче