зеркало из https://github.com/mozilla/pjs.git
Let controls using index() listen for changes to repeat indexes. Bug 289534, r=smaug+doronr, a=mkaply, NPOTB
This commit is contained in:
Родитель
2d9c8da55d
Коммит
c553b66916
|
@ -43,6 +43,8 @@
|
||||||
|
|
||||||
#include "nsISupports.idl"
|
#include "nsISupports.idl"
|
||||||
|
|
||||||
|
interface nsIXFormsControl;
|
||||||
|
|
||||||
[uuid(419e780d-4f31-4aa4-bae8-a18099d77bb6)]
|
[uuid(419e780d-4f31-4aa4-bae8-a18099d77bb6)]
|
||||||
interface nsIXFormsRepeatElement : nsISupports
|
interface nsIXFormsRepeatElement : nsISupports
|
||||||
{
|
{
|
||||||
|
@ -88,4 +90,20 @@ interface nsIXFormsRepeatElement : nsISupports
|
||||||
*/
|
*/
|
||||||
void setCurrentRepeat(in nsIXFormsRepeatElement aCurrentRepeat,
|
void setCurrentRepeat(in nsIXFormsRepeatElement aCurrentRepeat,
|
||||||
in unsigned long aIndex);
|
in unsigned long aIndex);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add user of repeat-index. The control will have Bind() and Refresh()
|
||||||
|
* called on it, when the index changes.
|
||||||
|
*/
|
||||||
|
void addIndexUser(in nsIXFormsControl aControl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove user of repeat-index.
|
||||||
|
*/
|
||||||
|
void removeIndexUser(in nsIXFormsControl aControl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Informs repeat-index users of index change.
|
||||||
|
*/
|
||||||
|
void indexHasChanged();
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "nsXFormsControlStub.h"
|
#include "nsXFormsControlStub.h"
|
||||||
#include "nsXFormsMDGEngine.h"
|
#include "nsXFormsMDGEngine.h"
|
||||||
|
|
||||||
|
#include "nsIDOMDocument.h"
|
||||||
#include "nsIDOMEvent.h"
|
#include "nsIDOMEvent.h"
|
||||||
#include "nsIDOMKeyEvent.h"
|
#include "nsIDOMKeyEvent.h"
|
||||||
#include "nsIDOMEventTarget.h"
|
#include "nsIDOMEventTarget.h"
|
||||||
|
@ -106,10 +107,27 @@ nsXFormsControlStub::GetElement(nsIDOMElement **aElement)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsXFormsControlStub::RemoveIndexListeners()
|
||||||
|
{
|
||||||
|
if (!mIndexesUsed.Count())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (PRInt32 i = 0; i < mIndexesUsed.Count(); ++i) {
|
||||||
|
nsCOMPtr<nsIXFormsRepeatElement> rep = mIndexesUsed[i];
|
||||||
|
rep->RemoveIndexUser(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
mIndexesUsed.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsXFormsControlStub::ResetBoundNode()
|
nsXFormsControlStub::ResetBoundNode()
|
||||||
{
|
{
|
||||||
|
// Clear existing bound node, etc.
|
||||||
mBoundNode = nsnull;
|
mBoundNode = nsnull;
|
||||||
|
mDependencies.Clear();
|
||||||
|
RemoveIndexListeners();
|
||||||
|
|
||||||
if (!mHasParent || !mBindAttrsCount)
|
if (!mHasParent || !mBindAttrsCount)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -157,7 +175,7 @@ nsXFormsControlStub::ProcessNodeBinding(const nsString &aBindingAttr,
|
||||||
nsIDOMXPathResult **aResult,
|
nsIDOMXPathResult **aResult,
|
||||||
nsIModelElementPrivate **aModel)
|
nsIModelElementPrivate **aModel)
|
||||||
{
|
{
|
||||||
mDependencies.Clear();
|
nsStringArray indexesUsed;
|
||||||
|
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
rv = nsXFormsUtils::EvaluateNodeBinding(mElement,
|
rv = nsXFormsUtils::EvaluateNodeBinding(mElement,
|
||||||
|
@ -167,12 +185,32 @@ nsXFormsControlStub::ProcessNodeBinding(const nsString &aBindingAttr,
|
||||||
aResultType,
|
aResultType,
|
||||||
getter_AddRefs(mModel),
|
getter_AddRefs(mModel),
|
||||||
aResult,
|
aResult,
|
||||||
&mDependencies);
|
&mDependencies,
|
||||||
|
&indexesUsed);
|
||||||
|
NS_ENSURE_STATE(mModel);
|
||||||
|
|
||||||
|
mModel->AddFormControl(this);
|
||||||
|
if (aModel)
|
||||||
|
NS_ADDREF(*aModel = mModel);
|
||||||
|
|
||||||
if (mModel) {
|
if (NS_SUCCEEDED(rv) && indexesUsed.Count()) {
|
||||||
mModel->AddFormControl(this);
|
// add index listeners on repeat elements
|
||||||
if (aModel) {
|
nsCOMPtr<nsIDOMDocument> doc;
|
||||||
NS_ADDREF(*aModel = mModel);
|
mElement->GetOwnerDocument(getter_AddRefs(doc));
|
||||||
|
NS_ENSURE_STATE(doc);
|
||||||
|
|
||||||
|
for (PRInt32 i = 0; i < indexesUsed.Count(); ++i) {
|
||||||
|
// Find the repeat element and add |this| as a listener
|
||||||
|
nsCOMPtr<nsIDOMElement> repElem;
|
||||||
|
doc->GetElementById(*(indexesUsed[i]), getter_AddRefs(repElem));
|
||||||
|
nsCOMPtr<nsIXFormsRepeatElement> rep(do_QueryInterface(repElem));
|
||||||
|
NS_ENSURE_STATE(rep);
|
||||||
|
rv = rep->AddIndexUser(this);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
rv = mIndexesUsed.AppendObject(rep);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,6 +352,7 @@ NS_IMETHODIMP
|
||||||
nsXFormsControlStub::OnDestroyed()
|
nsXFormsControlStub::OnDestroyed()
|
||||||
{
|
{
|
||||||
ResetHelpAndHint(PR_FALSE);
|
ResetHelpAndHint(PR_FALSE);
|
||||||
|
RemoveIndexListeners();
|
||||||
|
|
||||||
if (mModel) {
|
if (mModel) {
|
||||||
mModel->RemoveFormControl(this);
|
mModel->RemoveFormControl(this);
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
|
|
||||||
#include "nsIModelElementPrivate.h"
|
#include "nsIModelElementPrivate.h"
|
||||||
#include "nsIXFormsControl.h"
|
#include "nsIXFormsControl.h"
|
||||||
|
#include "nsIXFormsRepeatElement.h"
|
||||||
#include "nsXFormsStubElement.h"
|
#include "nsXFormsStubElement.h"
|
||||||
#include "nsXFormsUtils.h"
|
#include "nsXFormsUtils.h"
|
||||||
|
|
||||||
|
@ -143,22 +144,27 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** The nsIXTFXMLVisualWrapper */
|
/** The nsIXTFXMLVisualWrapper */
|
||||||
nsCOMPtr<nsIDOMElement> mElement;
|
nsCOMPtr<nsIDOMElement> mElement;
|
||||||
|
|
||||||
/** The node that the control is bound to. */
|
/** The node that the control is bound to. */
|
||||||
nsCOMPtr<nsIDOMNode> mBoundNode;
|
nsCOMPtr<nsIDOMNode> mBoundNode;
|
||||||
|
|
||||||
/** Array of nsIDOMNodes that the control depends on. */
|
/** Array of nsIDOMNodes that the control depends on. */
|
||||||
nsCOMArray<nsIDOMNode> mDependencies;
|
nsCOMArray<nsIDOMNode> mDependencies;
|
||||||
|
|
||||||
/** The model for the control */
|
/** The model for the control */
|
||||||
nsCOMPtr<nsIModelElementPrivate> mModel;
|
nsCOMPtr<nsIModelElementPrivate> mModel;
|
||||||
|
|
||||||
/** This event listener is used to create xforms-hint and xforms-help events. */
|
/** This event listener is used to create xforms-hint and xforms-help events. */
|
||||||
nsCOMPtr<nsIDOMEventListener> mEventListener;
|
nsCOMPtr<nsIDOMEventListener> mEventListener;
|
||||||
|
|
||||||
/** State that tells whether control has a parent or not */
|
/** State that tells whether control has a parent or not */
|
||||||
PRBool mHasParent;
|
PRBool mHasParent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of repeat-elements of which the control uses repeat-index.
|
||||||
|
*/
|
||||||
|
nsCOMArray<nsIXFormsRepeatElement> mIndexesUsed;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to keep track of whether this control has any single node binding
|
* Used to keep track of whether this control has any single node binding
|
||||||
|
@ -219,6 +225,9 @@ protected:
|
||||||
* @param aValue - value that the attribute is being changed to.
|
* @param aValue - value that the attribute is being changed to.
|
||||||
*/
|
*/
|
||||||
void MaybeRemoveFromModel(nsIAtom *aName, const nsAString &aValue);
|
void MaybeRemoveFromModel(nsIAtom *aName, const nsAString &aValue);
|
||||||
|
|
||||||
|
/** Removes the index change event listeners */
|
||||||
|
void RemoveIndexListeners();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -232,6 +232,11 @@ protected:
|
||||||
* The currently selected repeat (nested repeats)
|
* The currently selected repeat (nested repeats)
|
||||||
*/
|
*/
|
||||||
nsCOMPtr<nsIXFormsRepeatElement> mCurrentRepeat;
|
nsCOMPtr<nsIXFormsRepeatElement> mCurrentRepeat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of controls using the repeat-index
|
||||||
|
*/
|
||||||
|
nsCOMArray<nsIXFormsControl> mIndexUsers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves an integer attribute and checks its type.
|
* Retrieves an integer attribute and checks its type.
|
||||||
|
@ -369,6 +374,7 @@ NS_IMETHODIMP
|
||||||
nsXFormsRepeatElement::OnDestroyed()
|
nsXFormsRepeatElement::OnDestroyed()
|
||||||
{
|
{
|
||||||
mHTMLElement = nsnull;
|
mHTMLElement = nsnull;
|
||||||
|
mIndexUsers.Clear();
|
||||||
|
|
||||||
return nsXFormsControlStub::OnDestroyed();
|
return nsXFormsControlStub::OnDestroyed();
|
||||||
}
|
}
|
||||||
|
@ -490,6 +496,9 @@ nsXFormsRepeatElement::SetIndex(PRUint32 *aIndex,
|
||||||
// Set current index to new value
|
// Set current index to new value
|
||||||
mCurrentIndex = *aIndex;
|
mCurrentIndex = *aIndex;
|
||||||
|
|
||||||
|
// Inform of index change
|
||||||
|
mParent ? mParent->IndexHasChanged() : IndexHasChanged();
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -532,6 +541,42 @@ nsXFormsRepeatElement::SetCurrentRepeat(nsIXFormsRepeatElement *aRepeat,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsXFormsRepeatElement::AddIndexUser(nsIXFormsControl *aControl)
|
||||||
|
{
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
if (mIndexUsers.IndexOf(aControl) == -1 && !mIndexUsers.AppendObject(aControl))
|
||||||
|
rv = NS_ERROR_FAILURE;
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsXFormsRepeatElement::RemoveIndexUser(nsIXFormsControl *aControl)
|
||||||
|
{
|
||||||
|
return mIndexUsers.RemoveObject(aControl) ? NS_OK : NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsXFormsRepeatElement::IndexHasChanged()
|
||||||
|
{
|
||||||
|
///
|
||||||
|
/// @bug We need to handle \<bind\> elements too (XXX)
|
||||||
|
|
||||||
|
// copy the index array, as index users might add/remove themselves when
|
||||||
|
// they are rebound and refreshed().
|
||||||
|
nsCOMArray<nsIXFormsControl> indexes(mIndexUsers);
|
||||||
|
|
||||||
|
for (PRInt32 i = 0; i < indexes.Count(); ++i) {
|
||||||
|
nsCOMPtr<nsIXFormsControl> control = indexes[i];
|
||||||
|
control->Bind();
|
||||||
|
control->Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
// NB: CloneNode() assumes that this always succeeds
|
// NB: CloneNode() assumes that this always succeeds
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsXFormsRepeatElement::GetIsParent(PRBool *aIsParent)
|
nsXFormsRepeatElement::GetIsParent(PRBool *aIsParent)
|
||||||
|
|
|
@ -279,49 +279,64 @@ nsXFormsUtils::GetNodeContext(nsIDOMElement *aElement,
|
||||||
*aContextSize = 1;
|
*aContextSize = 1;
|
||||||
if (aContextPosition)
|
if (aContextPosition)
|
||||||
*aContextPosition = 1;
|
*aContextPosition = 1;
|
||||||
|
|
||||||
return FindBindContext(*aBindElement,
|
|
||||||
aOuterBind,
|
|
||||||
aModel,
|
|
||||||
aContextNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aElementFlags & ELEMENT_WITH_MODEL_ATTR) {
|
*aOuterBind = GetParentModel(*aBindElement, aModel);
|
||||||
// CASE 2: Use @model
|
NS_ENSURE_STATE(*aModel);
|
||||||
// If bind did not set model, and the element has a model attribute we use this
|
} else {
|
||||||
nsAutoString modelId;
|
if (aElementFlags & ELEMENT_WITH_MODEL_ATTR) {
|
||||||
NS_NAMED_LITERAL_STRING(modelStr, "model");
|
// CASE 2: Use @model
|
||||||
aElement->GetAttribute(modelStr, modelId);
|
// If bind did not set model, and the element has a model attribute we use this
|
||||||
|
nsAutoString modelId;
|
||||||
if (!modelId.IsEmpty()) {
|
NS_NAMED_LITERAL_STRING(modelStr, "model");
|
||||||
nsCOMPtr<nsIDOMElement> modelElement;
|
aElement->GetAttribute(modelStr, modelId);
|
||||||
domDoc->GetElementById(modelId, getter_AddRefs(modelElement));
|
|
||||||
nsCOMPtr<nsIModelElementPrivate> model = do_QueryInterface(modelElement);
|
|
||||||
|
|
||||||
// No element found, or element not a \<model\> element
|
if (!modelId.IsEmpty()) {
|
||||||
if (!model) {
|
nsCOMPtr<nsIDOMElement> modelElement;
|
||||||
const PRUnichar *strings[] = { modelId.get(), modelStr.get() };
|
domDoc->GetElementById(modelId, getter_AddRefs(modelElement));
|
||||||
nsXFormsUtils::ReportError(NS_LITERAL_STRING("idRefError"),
|
nsCOMPtr<nsIModelElementPrivate> model = do_QueryInterface(modelElement);
|
||||||
strings, 2, aElement, aElement);
|
|
||||||
nsXFormsUtils::DispatchEvent(aElement, eEvent_BindingException);
|
// No element found, or element not a \<model\> element
|
||||||
return NS_ERROR_FAILURE;
|
if (!model) {
|
||||||
|
const PRUnichar *strings[] = { modelId.get(), modelStr.get() };
|
||||||
|
nsXFormsUtils::ReportError(NS_LITERAL_STRING("idRefError"),
|
||||||
|
strings, 2, aElement, aElement);
|
||||||
|
nsXFormsUtils::DispatchEvent(aElement, eEvent_BindingException);
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_ADDREF(*aModel = model);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_ADDREF(*aModel = model);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Search for a parent setting context for us
|
||||||
|
nsresult rv = FindParentContext(aElement,
|
||||||
|
aModel,
|
||||||
|
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.
|
||||||
|
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search for a parent setting context for us
|
// if context node is not set, it's the document element of the model's
|
||||||
nsresult rv = FindParentContext(aElement,
|
// default instance
|
||||||
aModel,
|
if (!*aContextNode) {
|
||||||
aContextNode,
|
nsCOMPtr<nsIXFormsModelElement> modelInt = do_QueryInterface(*aModel);
|
||||||
aContextPosition,
|
NS_ENSURE_STATE(modelInt);
|
||||||
aContextSize);
|
|
||||||
// CASE 3/4: Use parent's model / first model in document.
|
nsCOMPtr<nsIDOMDocument> instanceDoc;
|
||||||
// If FindParentContext() does not find a parent context but |aModel| is not
|
modelInt->GetInstanceDocument(NS_LITERAL_STRING(""),
|
||||||
// set, it sets the model to the first model in the document.
|
getter_AddRefs(instanceDoc));
|
||||||
|
NS_ENSURE_STATE(instanceDoc);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
nsIDOMElement* docElement;
|
||||||
|
instanceDoc->GetDocumentElement(&docElement); // addrefs
|
||||||
|
NS_ENSURE_STATE(docElement);
|
||||||
|
*aContextNode = docElement; // addref'ed above
|
||||||
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -358,7 +373,8 @@ nsXFormsUtils::EvaluateXPath(const nsAString &aExpression,
|
||||||
PRUint16 aResultType,
|
PRUint16 aResultType,
|
||||||
PRInt32 aContextPosition,
|
PRInt32 aContextPosition,
|
||||||
PRInt32 aContextSize,
|
PRInt32 aContextSize,
|
||||||
nsCOMArray<nsIDOMNode> *aSet)
|
nsCOMArray<nsIDOMNode> *aSet,
|
||||||
|
nsStringArray *aIndexesUsed)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIDOMDocument> doc;
|
nsCOMPtr<nsIDOMDocument> doc;
|
||||||
aContextNode->GetOwnerDocument(getter_AddRefs(doc));
|
aContextNode->GetOwnerDocument(getter_AddRefs(doc));
|
||||||
|
@ -397,13 +413,15 @@ nsXFormsUtils::EvaluateXPath(const nsAString &aExpression,
|
||||||
nsXFormsXPathParser parser;
|
nsXFormsXPathParser parser;
|
||||||
nsXFormsXPathAnalyzer analyzer(eval, aResolverNode);
|
nsXFormsXPathAnalyzer analyzer(eval, aResolverNode);
|
||||||
nsAutoPtr<nsXFormsXPathNode> xNode(parser.Parse(aExpression));
|
nsAutoPtr<nsXFormsXPathNode> xNode(parser.Parse(aExpression));
|
||||||
|
|
||||||
rv = analyzer.Analyze(aContextNode,
|
rv = analyzer.Analyze(aContextNode,
|
||||||
xNode,
|
xNode,
|
||||||
expression,
|
expression,
|
||||||
&aExpression,
|
&aExpression,
|
||||||
aSet);
|
aSet);
|
||||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||||
|
|
||||||
|
if (aIndexesUsed)
|
||||||
|
*aIndexesUsed = analyzer.IndexesUsed();
|
||||||
}
|
}
|
||||||
CallQueryInterface(supResult, &result); // addrefs
|
CallQueryInterface(supResult, &result); // addrefs
|
||||||
}
|
}
|
||||||
|
@ -421,36 +439,6 @@ nsXFormsUtils::EvaluateXPath(const nsAString &aExpression,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ nsresult
|
|
||||||
nsXFormsUtils::FindBindContext(nsIDOMElement *aBindElement,
|
|
||||||
PRBool *aOuterBind,
|
|
||||||
nsIModelElementPrivate **aModel,
|
|
||||||
nsIDOMNode **aContextNode)
|
|
||||||
{
|
|
||||||
NS_ENSURE_ARG_POINTER(aContextNode);
|
|
||||||
*aContextNode = nsnull;
|
|
||||||
|
|
||||||
// 1) Find the model for the bind
|
|
||||||
*aOuterBind = GetParentModel(aBindElement, aModel);
|
|
||||||
NS_ENSURE_STATE(*aModel);
|
|
||||||
|
|
||||||
// 2) Find the context node
|
|
||||||
nsCOMPtr<nsIXFormsModelElement> modelInt = do_QueryInterface(*aModel);
|
|
||||||
NS_ENSURE_STATE(modelInt);
|
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMDocument> instanceDoc;
|
|
||||||
modelInt->GetInstanceDocument(NS_LITERAL_STRING(""),
|
|
||||||
getter_AddRefs(instanceDoc));
|
|
||||||
NS_ENSURE_STATE(instanceDoc);
|
|
||||||
|
|
||||||
nsIDOMElement* docElement;
|
|
||||||
instanceDoc->GetDocumentElement(&docElement); // addrefs
|
|
||||||
NS_ENSURE_STATE(docElement);
|
|
||||||
*aContextNode = docElement; // addref'ed above
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */ nsresult
|
/* static */ nsresult
|
||||||
nsXFormsUtils::EvaluateNodeBinding(nsIDOMElement *aElement,
|
nsXFormsUtils::EvaluateNodeBinding(nsIDOMElement *aElement,
|
||||||
PRUint32 aElementFlags,
|
PRUint32 aElementFlags,
|
||||||
|
@ -459,7 +447,8 @@ nsXFormsUtils::EvaluateNodeBinding(nsIDOMElement *aElement,
|
||||||
PRUint16 aResultType,
|
PRUint16 aResultType,
|
||||||
nsIModelElementPrivate **aModel,
|
nsIModelElementPrivate **aModel,
|
||||||
nsIDOMXPathResult **aResult,
|
nsIDOMXPathResult **aResult,
|
||||||
nsCOMArray<nsIDOMNode> *aDeps)
|
nsCOMArray<nsIDOMNode> *aDeps,
|
||||||
|
nsStringArray *aIndexesUsed)
|
||||||
{
|
{
|
||||||
if (!aElement || !aModel || !aResult) {
|
if (!aElement || !aModel || !aResult) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -484,6 +473,10 @@ nsXFormsUtils::EvaluateNodeBinding(nsIDOMElement *aElement,
|
||||||
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
if (!contextNode) {
|
||||||
|
return NS_OK; // this will happen if the doc is still loading
|
||||||
|
}
|
||||||
|
|
||||||
nsAutoString expr;
|
nsAutoString expr;
|
||||||
if (bindElement) {
|
if (bindElement) {
|
||||||
if (!outerBind) {
|
if (!outerBind) {
|
||||||
|
@ -507,26 +500,6 @@ nsXFormsUtils::EvaluateNodeBinding(nsIDOMElement *aElement,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
||||||
expr.Assign(aDefaultRef);
|
expr.Assign(aDefaultRef);
|
||||||
}
|
|
||||||
|
|
||||||
if (!contextNode) {
|
|
||||||
nsCOMPtr<nsIDOMDocument> instanceDoc;
|
|
||||||
nsCOMPtr<nsIXFormsModelElement> model = do_QueryInterface(*aModel);
|
|
||||||
|
|
||||||
NS_ENSURE_STATE(model); // The referenced model is not actually a model element, or does not exist.
|
|
||||||
|
|
||||||
model->GetInstanceDocument(NS_LITERAL_STRING(""),
|
|
||||||
getter_AddRefs(instanceDoc));
|
|
||||||
|
|
||||||
NS_ENSURE_STATE(instanceDoc);
|
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMElement> docElement;
|
|
||||||
instanceDoc->GetDocumentElement(getter_AddRefs(docElement));
|
|
||||||
contextNode = docElement;
|
|
||||||
|
|
||||||
if (!contextNode) {
|
|
||||||
return NS_OK; // this will happen if the doc is still loading
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -537,7 +510,8 @@ nsXFormsUtils::EvaluateNodeBinding(nsIDOMElement *aElement,
|
||||||
aResultType,
|
aResultType,
|
||||||
contextSize,
|
contextSize,
|
||||||
contextPosition,
|
contextPosition,
|
||||||
aDeps);
|
aDeps,
|
||||||
|
aIndexesUsed);
|
||||||
|
|
||||||
res.swap(*aResult); // exchanges ref
|
res.swap(*aResult); // exchanges ref
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
#include "nsIDOMXPathResult.h"
|
#include "nsIDOMXPathResult.h"
|
||||||
#include "nsIModelElementPrivate.h"
|
#include "nsIModelElementPrivate.h"
|
||||||
#include "nsIScriptError.h"
|
#include "nsIScriptError.h"
|
||||||
|
#include "nsVoidArray.h"
|
||||||
|
|
||||||
class nsIDOMElement;
|
class nsIDOMElement;
|
||||||
class nsIXFormsModelElement;
|
class nsIXFormsModelElement;
|
||||||
|
@ -210,18 +211,9 @@ public:
|
||||||
PRUint16 aResultType,
|
PRUint16 aResultType,
|
||||||
nsIModelElementPrivate **aModel,
|
nsIModelElementPrivate **aModel,
|
||||||
nsIDOMXPathResult **aResult,
|
nsIDOMXPathResult **aResult,
|
||||||
nsCOMArray<nsIDOMNode> *aDeps = nsnull);
|
nsCOMArray<nsIDOMNode> *aDeps = nsnull,
|
||||||
|
nsStringArray *aIndexesUsed = nsnull);
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a bind element |aBindElement|, find the model and the context node
|
|
||||||
* for it. |aOuterBind| tells whether the bind element is an outermost bind.
|
|
||||||
*/
|
|
||||||
static NS_HIDDEN_(nsresult)
|
|
||||||
FindBindContext(nsIDOMElement *aBindElement,
|
|
||||||
PRBool *aOuterBind,
|
|
||||||
nsIModelElementPrivate **aModel,
|
|
||||||
nsIDOMNode **aContextNode);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience method for doing XPath evaluations. This gets a
|
* Convenience method for doing XPath evaluations. This gets a
|
||||||
* nsIXFormsXPathEvaluator from |aContextNode|'s ownerDocument, and calls
|
* nsIXFormsXPathEvaluator from |aContextNode|'s ownerDocument, and calls
|
||||||
|
@ -235,7 +227,8 @@ public:
|
||||||
PRUint16 aResultType,
|
PRUint16 aResultType,
|
||||||
PRInt32 aContextPosition = 1,
|
PRInt32 aContextPosition = 1,
|
||||||
PRInt32 aContextSize = 1,
|
PRInt32 aContextSize = 1,
|
||||||
nsCOMArray<nsIDOMNode> *aSet = nsnull);
|
nsCOMArray<nsIDOMNode> *aSet = nsnull,
|
||||||
|
nsStringArray *aIndexesUsed = nsnull);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a node in the instance data, get its string value according
|
* Given a node in the instance data, get its string value according
|
||||||
|
|
|
@ -47,11 +47,9 @@
|
||||||
|
|
||||||
MOZ_DECL_CTOR_COUNTER(nsXFormsXPathAnalyzer)
|
MOZ_DECL_CTOR_COUNTER(nsXFormsXPathAnalyzer)
|
||||||
|
|
||||||
nsXFormsXPathAnalyzer::nsXFormsXPathAnalyzer(
|
nsXFormsXPathAnalyzer::nsXFormsXPathAnalyzer(nsIXFormsXPathEvaluator *aEvaluator,
|
||||||
nsIXFormsXPathEvaluator *aEvaluator,
|
nsIDOMNode *aResolver)
|
||||||
nsIDOMNode *aResolver)
|
: mEvaluator(aEvaluator), mResolver(aResolver)
|
||||||
: mEvaluator(aEvaluator),
|
|
||||||
mResolver(aResolver)
|
|
||||||
{
|
{
|
||||||
MOZ_COUNT_CTOR(nsXFormsXPathAnalyzer);
|
MOZ_COUNT_CTOR(nsXFormsXPathAnalyzer);
|
||||||
}
|
}
|
||||||
|
@ -119,6 +117,7 @@ nsXFormsXPathAnalyzer::AnalyzeRecursively(nsIDOMNode *aContextNode,
|
||||||
printf("\tChild: %p, Sibling: %p\n", (void*) aNode->mChild, (void*) aNode->mSibling);
|
printf("\tChild: %p, Sibling: %p\n", (void*) aNode->mChild, (void*) aNode->mSibling);
|
||||||
printf("\tIndex: %d - %d\n", aNode->mStartIndex, aNode->mEndIndex);
|
printf("\tIndex: %d - %d\n", aNode->mStartIndex, aNode->mEndIndex);
|
||||||
printf("\tCon: %d, Predicate: %d, Literal: %d\n", aNode->mCon, aNode->mPredicate, aNode->mLiteral);
|
printf("\tCon: %d, Predicate: %d, Literal: %d\n", aNode->mCon, aNode->mPredicate, aNode->mLiteral);
|
||||||
|
printf("\tIsIndex: %d\n", aNode->mIsIndex);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (aNode->mEndIndex < 0 || aNode->mStartIndex >= aNode->mEndIndex) {
|
if (aNode->mEndIndex < 0 || aNode->mStartIndex >= aNode->mEndIndex) {
|
||||||
|
@ -176,6 +175,24 @@ nsXFormsXPathAnalyzer::AnalyzeRecursively(nsIDOMNode *aContextNode,
|
||||||
rv = result->GetResultType(&type);
|
rv = result->GetResultType(&type);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
if (aNode->mIsIndex) {
|
||||||
|
// Extract index parameter, xp is "index(parameter)"
|
||||||
|
const PRUint32 indexSize = sizeof("index(") - 1;
|
||||||
|
nsDependentSubstring indexExpr = Substring(xp,
|
||||||
|
indexSize,
|
||||||
|
xp.Length() - indexSize - 1); // remove final ')' too
|
||||||
|
nsCOMPtr<nsIDOMXPathResult> stringRes;
|
||||||
|
rv = mEvaluator->Evaluate(indexExpr, aContextNode, mResolver,
|
||||||
|
nsIDOMXPathResult::STRING_TYPE,
|
||||||
|
nsnull, getter_AddRefs(stringRes));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
nsAutoString indexId;
|
||||||
|
rv = stringRes->GetStringValue(indexId);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
mIndexesUsed.AppendString(indexId);
|
||||||
|
}
|
||||||
|
|
||||||
// We are only interested in nodes
|
// We are only interested in nodes
|
||||||
if ( type != nsIDOMXPathResult::UNORDERED_NODE_ITERATOR_TYPE
|
if ( type != nsIDOMXPathResult::UNORDERED_NODE_ITERATOR_TYPE
|
||||||
&& type != nsIDOMXPathResult::ORDERED_NODE_ITERATOR_TYPE) {
|
&& type != nsIDOMXPathResult::ORDERED_NODE_ITERATOR_TYPE) {
|
||||||
|
@ -204,3 +221,9 @@ nsXFormsXPathAnalyzer::AnalyzeRecursively(nsIDOMNode *aContextNode,
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const nsStringArray&
|
||||||
|
nsXFormsXPathAnalyzer::IndexesUsed() const
|
||||||
|
{
|
||||||
|
return mIndexesUsed;
|
||||||
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
#include "nsIDOMNode.h"
|
#include "nsIDOMNode.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
|
#include "nsVoidArray.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class analyzes an XPath Expression parse tree (nsXFormsXPathNode), and
|
* This class analyzes an XPath Expression parse tree (nsXFormsXPathNode), and
|
||||||
|
@ -58,11 +59,12 @@
|
||||||
class nsXFormsXPathAnalyzer {
|
class nsXFormsXPathAnalyzer {
|
||||||
private:
|
private:
|
||||||
nsCOMPtr<nsIXFormsXPathEvaluator> mEvaluator;
|
nsCOMPtr<nsIXFormsXPathEvaluator> mEvaluator;
|
||||||
nsCOMPtr<nsIDOMNode> mResolver;
|
nsCOMPtr<nsIDOMNode> mResolver;
|
||||||
|
|
||||||
nsCOMArray<nsIDOMNode> *mCurSet;
|
nsCOMArray<nsIDOMNode> *mCurSet;
|
||||||
nsCOMPtr<nsIDOMXPathExpression> mCurExpression;
|
nsCOMPtr<nsIDOMXPathExpression> mCurExpression;
|
||||||
const nsAString *mCurExprString;
|
const nsAString *mCurExprString;
|
||||||
|
nsStringArray mIndexesUsed;
|
||||||
|
|
||||||
nsresult AnalyzeRecursively(nsIDOMNode *aContextNode,
|
nsresult AnalyzeRecursively(nsIDOMNode *aContextNode,
|
||||||
const nsXFormsXPathNode *aNode,
|
const nsXFormsXPathNode *aNode,
|
||||||
|
@ -78,4 +80,6 @@ public:
|
||||||
nsIDOMXPathExpression *aExpression,
|
nsIDOMXPathExpression *aExpression,
|
||||||
const nsAString *aExprString,
|
const nsAString *aExprString,
|
||||||
nsCOMArray<nsIDOMNode> *aSet);
|
nsCOMArray<nsIDOMNode> *aSet);
|
||||||
|
|
||||||
|
const nsStringArray& IndexesUsed() const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
MOZ_DECL_CTOR_COUNTER(nsXFormsXPathNode)
|
MOZ_DECL_CTOR_COUNTER(nsXFormsXPathNode)
|
||||||
|
|
||||||
nsXFormsXPathNode::nsXFormsXPathNode(nsXFormsXPathNode* aParent, PRBool aContinue)
|
nsXFormsXPathNode::nsXFormsXPathNode(nsXFormsXPathNode* aParent, PRBool aContinue)
|
||||||
: mChild(nsnull), mEndIndex(-100), mCon(aContinue)
|
: mChild(nsnull), mEndIndex(-100), mCon(aContinue), mIsIndex(PR_FALSE)
|
||||||
{
|
{
|
||||||
MOZ_COUNT_CTOR(nsXFormsXPathNode);
|
MOZ_COUNT_CTOR(nsXFormsXPathNode);
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@ public:
|
||||||
PRBool mCon;
|
PRBool mCon;
|
||||||
PRBool mPredicate;
|
PRBool mPredicate;
|
||||||
PRBool mLiteral;
|
PRBool mLiteral;
|
||||||
|
PRBool mIsIndex;
|
||||||
|
|
||||||
nsXFormsXPathNode(nsXFormsXPathNode* aParent, PRBool aContinue = PR_FALSE);
|
nsXFormsXPathNode(nsXFormsXPathNode* aParent, PRBool aContinue = PR_FALSE);
|
||||||
~nsXFormsXPathNode();
|
~nsXFormsXPathNode();
|
||||||
|
|
|
@ -354,12 +354,13 @@ nsXFormsXPathParser::FilterExpr()
|
||||||
void
|
void
|
||||||
nsXFormsXPathParser::FunctionCall()
|
nsXFormsXPathParser::FunctionCall()
|
||||||
{
|
{
|
||||||
if (!mUsesDynamicFunc) {
|
nsDependentSubstring fname = Substring(mScanner.Expression(),
|
||||||
nsDependentSubstring fname = Substring(mScanner.Expression(), mScanner.Offset() + 1, mScanner.Offset() + mScanner.Length() + 1);
|
mScanner.Offset() + 1,
|
||||||
if (fname.Equals(NS_LITERAL_STRING("now"))) {
|
mScanner.Length());
|
||||||
mUsesDynamicFunc = PR_TRUE;
|
if (!mUsesDynamicFunc && fname.Equals(NS_LITERAL_STRING("now"))) {
|
||||||
}
|
mUsesDynamicFunc = PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
PopToken();
|
PopToken();
|
||||||
PopToken();
|
PopToken();
|
||||||
nsXFormsXPathScanner::XPATHTOKEN t = PeekToken();
|
nsXFormsXPathScanner::XPATHTOKEN t = PeekToken();
|
||||||
|
@ -367,18 +368,22 @@ nsXFormsXPathParser::FunctionCall()
|
||||||
PRBool con = t == nsXFormsXPathScanner::RPARAN ? PR_FALSE : PR_TRUE;
|
PRBool con = t == nsXFormsXPathScanner::RPARAN ? PR_FALSE : PR_TRUE;
|
||||||
while (con) {
|
while (con) {
|
||||||
if (t == nsXFormsXPathScanner::XPATHEOF) {
|
if (t == nsXFormsXPathScanner::XPATHEOF) {
|
||||||
XPathCompilerException("Expected ) got EOF", mScanner.Expression(), mScanner.Offset(), mScanner.Length());
|
XPathCompilerException("Expected ) got EOF",
|
||||||
|
mScanner.Expression(),
|
||||||
|
mScanner.Offset(),
|
||||||
|
mScanner.Length());
|
||||||
}
|
}
|
||||||
nsXFormsXPathNode* c = JustContext();
|
nsXFormsXPathNode* c = JustContext();
|
||||||
Expr();
|
Expr();
|
||||||
|
if (fname.Equals(NS_LITERAL_STRING("index"))) {
|
||||||
|
c->mIsIndex = PR_TRUE;
|
||||||
|
}
|
||||||
PushContext(c);
|
PushContext(c);
|
||||||
|
|
||||||
t = PeekToken();
|
t = PeekToken();
|
||||||
if (t == nsXFormsXPathScanner::COMMA) {
|
con = (t == nsXFormsXPathScanner::COMMA);
|
||||||
|
if (con) {
|
||||||
PopToken(); // Another Argument
|
PopToken(); // Another Argument
|
||||||
con = PR_TRUE;
|
|
||||||
} else {
|
|
||||||
con = PR_FALSE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче