зеркало из 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"
|
||||
|
||||
interface nsIXFormsControl;
|
||||
|
||||
[uuid(419e780d-4f31-4aa4-bae8-a18099d77bb6)]
|
||||
interface nsIXFormsRepeatElement : nsISupports
|
||||
{
|
||||
|
@ -88,4 +90,20 @@ interface nsIXFormsRepeatElement : nsISupports
|
|||
*/
|
||||
void setCurrentRepeat(in nsIXFormsRepeatElement aCurrentRepeat,
|
||||
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 "nsXFormsMDGEngine.h"
|
||||
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
#include "nsIDOMKeyEvent.h"
|
||||
#include "nsIDOMEventTarget.h"
|
||||
|
@ -106,10 +107,27 @@ nsXFormsControlStub::GetElement(nsIDOMElement **aElement)
|
|||
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
|
||||
nsXFormsControlStub::ResetBoundNode()
|
||||
{
|
||||
// Clear existing bound node, etc.
|
||||
mBoundNode = nsnull;
|
||||
mDependencies.Clear();
|
||||
RemoveIndexListeners();
|
||||
|
||||
if (!mHasParent || !mBindAttrsCount)
|
||||
return NS_OK;
|
||||
|
@ -157,7 +175,7 @@ nsXFormsControlStub::ProcessNodeBinding(const nsString &aBindingAttr,
|
|||
nsIDOMXPathResult **aResult,
|
||||
nsIModelElementPrivate **aModel)
|
||||
{
|
||||
mDependencies.Clear();
|
||||
nsStringArray indexesUsed;
|
||||
|
||||
nsresult rv;
|
||||
rv = nsXFormsUtils::EvaluateNodeBinding(mElement,
|
||||
|
@ -167,12 +185,32 @@ nsXFormsControlStub::ProcessNodeBinding(const nsString &aBindingAttr,
|
|||
aResultType,
|
||||
getter_AddRefs(mModel),
|
||||
aResult,
|
||||
&mDependencies);
|
||||
&mDependencies,
|
||||
&indexesUsed);
|
||||
NS_ENSURE_STATE(mModel);
|
||||
|
||||
mModel->AddFormControl(this);
|
||||
if (aModel)
|
||||
NS_ADDREF(*aModel = mModel);
|
||||
|
||||
if (mModel) {
|
||||
mModel->AddFormControl(this);
|
||||
if (aModel) {
|
||||
NS_ADDREF(*aModel = mModel);
|
||||
if (NS_SUCCEEDED(rv) && indexesUsed.Count()) {
|
||||
// add index listeners on repeat elements
|
||||
nsCOMPtr<nsIDOMDocument> doc;
|
||||
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()
|
||||
{
|
||||
ResetHelpAndHint(PR_FALSE);
|
||||
RemoveIndexListeners();
|
||||
|
||||
if (mModel) {
|
||||
mModel->RemoveFormControl(this);
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
|
||||
#include "nsIModelElementPrivate.h"
|
||||
#include "nsIXFormsControl.h"
|
||||
#include "nsIXFormsRepeatElement.h"
|
||||
#include "nsXFormsStubElement.h"
|
||||
#include "nsXFormsUtils.h"
|
||||
|
||||
|
@ -143,22 +144,27 @@ public:
|
|||
|
||||
protected:
|
||||
/** The nsIXTFXMLVisualWrapper */
|
||||
nsCOMPtr<nsIDOMElement> mElement;
|
||||
nsCOMPtr<nsIDOMElement> mElement;
|
||||
|
||||
/** The node that the control is bound to. */
|
||||
nsCOMPtr<nsIDOMNode> mBoundNode;
|
||||
nsCOMPtr<nsIDOMNode> mBoundNode;
|
||||
|
||||
/** Array of nsIDOMNodes that the control depends on. */
|
||||
nsCOMArray<nsIDOMNode> mDependencies;
|
||||
nsCOMArray<nsIDOMNode> mDependencies;
|
||||
|
||||
/** The model for the control */
|
||||
nsCOMPtr<nsIModelElementPrivate> mModel;
|
||||
nsCOMPtr<nsIModelElementPrivate> mModel;
|
||||
|
||||
/** 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 */
|
||||
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
|
||||
|
@ -219,6 +225,9 @@ protected:
|
|||
* @param aValue - value that the attribute is being changed to.
|
||||
*/
|
||||
void MaybeRemoveFromModel(nsIAtom *aName, const nsAString &aValue);
|
||||
|
||||
/** Removes the index change event listeners */
|
||||
void RemoveIndexListeners();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -232,6 +232,11 @@ protected:
|
|||
* The currently selected repeat (nested repeats)
|
||||
*/
|
||||
nsCOMPtr<nsIXFormsRepeatElement> mCurrentRepeat;
|
||||
|
||||
/**
|
||||
* Array of controls using the repeat-index
|
||||
*/
|
||||
nsCOMArray<nsIXFormsControl> mIndexUsers;
|
||||
|
||||
/**
|
||||
* Retrieves an integer attribute and checks its type.
|
||||
|
@ -369,6 +374,7 @@ NS_IMETHODIMP
|
|||
nsXFormsRepeatElement::OnDestroyed()
|
||||
{
|
||||
mHTMLElement = nsnull;
|
||||
mIndexUsers.Clear();
|
||||
|
||||
return nsXFormsControlStub::OnDestroyed();
|
||||
}
|
||||
|
@ -490,6 +496,9 @@ nsXFormsRepeatElement::SetIndex(PRUint32 *aIndex,
|
|||
// Set current index to new value
|
||||
mCurrentIndex = *aIndex;
|
||||
|
||||
// Inform of index change
|
||||
mParent ? mParent->IndexHasChanged() : IndexHasChanged();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -532,6 +541,42 @@ nsXFormsRepeatElement::SetCurrentRepeat(nsIXFormsRepeatElement *aRepeat,
|
|||
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
|
||||
NS_IMETHODIMP
|
||||
nsXFormsRepeatElement::GetIsParent(PRBool *aIsParent)
|
||||
|
|
|
@ -279,49 +279,64 @@ nsXFormsUtils::GetNodeContext(nsIDOMElement *aElement,
|
|||
*aContextSize = 1;
|
||||
if (aContextPosition)
|
||||
*aContextPosition = 1;
|
||||
|
||||
return FindBindContext(*aBindElement,
|
||||
aOuterBind,
|
||||
aModel,
|
||||
aContextNode);
|
||||
}
|
||||
|
||||
if (aElementFlags & ELEMENT_WITH_MODEL_ATTR) {
|
||||
// CASE 2: Use @model
|
||||
// If bind did not set model, and the element has a model attribute we use this
|
||||
nsAutoString modelId;
|
||||
NS_NAMED_LITERAL_STRING(modelStr, "model");
|
||||
aElement->GetAttribute(modelStr, modelId);
|
||||
|
||||
if (!modelId.IsEmpty()) {
|
||||
nsCOMPtr<nsIDOMElement> modelElement;
|
||||
domDoc->GetElementById(modelId, getter_AddRefs(modelElement));
|
||||
nsCOMPtr<nsIModelElementPrivate> model = do_QueryInterface(modelElement);
|
||||
*aOuterBind = GetParentModel(*aBindElement, aModel);
|
||||
NS_ENSURE_STATE(*aModel);
|
||||
} else {
|
||||
if (aElementFlags & ELEMENT_WITH_MODEL_ATTR) {
|
||||
// CASE 2: Use @model
|
||||
// If bind did not set model, and the element has a model attribute we use this
|
||||
nsAutoString modelId;
|
||||
NS_NAMED_LITERAL_STRING(modelStr, "model");
|
||||
aElement->GetAttribute(modelStr, modelId);
|
||||
|
||||
// No element found, or element not a \<model\> element
|
||||
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;
|
||||
if (!modelId.IsEmpty()) {
|
||||
nsCOMPtr<nsIDOMElement> modelElement;
|
||||
domDoc->GetElementById(modelId, getter_AddRefs(modelElement));
|
||||
nsCOMPtr<nsIModelElementPrivate> model = do_QueryInterface(modelElement);
|
||||
|
||||
// No element found, or element not a \<model\> element
|
||||
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
|
||||
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);
|
||||
// if context node is not set, it's the document element of the model's
|
||||
// default instance
|
||||
if (!*aContextNode) {
|
||||
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;
|
||||
}
|
||||
|
@ -358,7 +373,8 @@ nsXFormsUtils::EvaluateXPath(const nsAString &aExpression,
|
|||
PRUint16 aResultType,
|
||||
PRInt32 aContextPosition,
|
||||
PRInt32 aContextSize,
|
||||
nsCOMArray<nsIDOMNode> *aSet)
|
||||
nsCOMArray<nsIDOMNode> *aSet,
|
||||
nsStringArray *aIndexesUsed)
|
||||
{
|
||||
nsCOMPtr<nsIDOMDocument> doc;
|
||||
aContextNode->GetOwnerDocument(getter_AddRefs(doc));
|
||||
|
@ -397,13 +413,15 @@ nsXFormsUtils::EvaluateXPath(const nsAString &aExpression,
|
|||
nsXFormsXPathParser parser;
|
||||
nsXFormsXPathAnalyzer analyzer(eval, aResolverNode);
|
||||
nsAutoPtr<nsXFormsXPathNode> xNode(parser.Parse(aExpression));
|
||||
|
||||
rv = analyzer.Analyze(aContextNode,
|
||||
xNode,
|
||||
expression,
|
||||
&aExpression,
|
||||
aSet);
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
|
||||
if (aIndexesUsed)
|
||||
*aIndexesUsed = analyzer.IndexesUsed();
|
||||
}
|
||||
CallQueryInterface(supResult, &result); // addrefs
|
||||
}
|
||||
|
@ -421,36 +439,6 @@ nsXFormsUtils::EvaluateXPath(const nsAString &aExpression,
|
|||
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
|
||||
nsXFormsUtils::EvaluateNodeBinding(nsIDOMElement *aElement,
|
||||
PRUint32 aElementFlags,
|
||||
|
@ -459,7 +447,8 @@ nsXFormsUtils::EvaluateNodeBinding(nsIDOMElement *aElement,
|
|||
PRUint16 aResultType,
|
||||
nsIModelElementPrivate **aModel,
|
||||
nsIDOMXPathResult **aResult,
|
||||
nsCOMArray<nsIDOMNode> *aDeps)
|
||||
nsCOMArray<nsIDOMNode> *aDeps,
|
||||
nsStringArray *aIndexesUsed)
|
||||
{
|
||||
if (!aElement || !aModel || !aResult) {
|
||||
return NS_OK;
|
||||
|
@ -484,6 +473,10 @@ nsXFormsUtils::EvaluateNodeBinding(nsIDOMElement *aElement,
|
|||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!contextNode) {
|
||||
return NS_OK; // this will happen if the doc is still loading
|
||||
}
|
||||
|
||||
nsAutoString expr;
|
||||
if (bindElement) {
|
||||
if (!outerBind) {
|
||||
|
@ -507,26 +500,6 @@ nsXFormsUtils::EvaluateNodeBinding(nsIDOMElement *aElement,
|
|||
return NS_OK;
|
||||
|
||||
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,
|
||||
contextSize,
|
||||
contextPosition,
|
||||
aDeps);
|
||||
aDeps,
|
||||
aIndexesUsed);
|
||||
|
||||
res.swap(*aResult); // exchanges ref
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "nsIDOMXPathResult.h"
|
||||
#include "nsIModelElementPrivate.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsVoidArray.h"
|
||||
|
||||
class nsIDOMElement;
|
||||
class nsIXFormsModelElement;
|
||||
|
@ -210,18 +211,9 @@ public:
|
|||
PRUint16 aResultType,
|
||||
nsIModelElementPrivate **aModel,
|
||||
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
|
||||
* nsIXFormsXPathEvaluator from |aContextNode|'s ownerDocument, and calls
|
||||
|
@ -235,7 +227,8 @@ public:
|
|||
PRUint16 aResultType,
|
||||
PRInt32 aContextPosition = 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
|
||||
|
|
|
@ -47,11 +47,9 @@
|
|||
|
||||
MOZ_DECL_CTOR_COUNTER(nsXFormsXPathAnalyzer)
|
||||
|
||||
nsXFormsXPathAnalyzer::nsXFormsXPathAnalyzer(
|
||||
nsIXFormsXPathEvaluator *aEvaluator,
|
||||
nsIDOMNode *aResolver)
|
||||
: mEvaluator(aEvaluator),
|
||||
mResolver(aResolver)
|
||||
nsXFormsXPathAnalyzer::nsXFormsXPathAnalyzer(nsIXFormsXPathEvaluator *aEvaluator,
|
||||
nsIDOMNode *aResolver)
|
||||
: mEvaluator(aEvaluator), mResolver(aResolver)
|
||||
{
|
||||
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("\tIndex: %d - %d\n", aNode->mStartIndex, aNode->mEndIndex);
|
||||
printf("\tCon: %d, Predicate: %d, Literal: %d\n", aNode->mCon, aNode->mPredicate, aNode->mLiteral);
|
||||
printf("\tIsIndex: %d\n", aNode->mIsIndex);
|
||||
#endif
|
||||
|
||||
if (aNode->mEndIndex < 0 || aNode->mStartIndex >= aNode->mEndIndex) {
|
||||
|
@ -176,6 +175,24 @@ nsXFormsXPathAnalyzer::AnalyzeRecursively(nsIDOMNode *aContextNode,
|
|||
rv = result->GetResultType(&type);
|
||||
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
|
||||
if ( type != nsIDOMXPathResult::UNORDERED_NODE_ITERATOR_TYPE
|
||||
&& type != nsIDOMXPathResult::ORDERED_NODE_ITERATOR_TYPE) {
|
||||
|
@ -204,3 +221,9 @@ nsXFormsXPathAnalyzer::AnalyzeRecursively(nsIDOMNode *aContextNode,
|
|||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const nsStringArray&
|
||||
nsXFormsXPathAnalyzer::IndexesUsed() const
|
||||
{
|
||||
return mIndexesUsed;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "nsIDOMNode.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsVoidArray.h"
|
||||
|
||||
/**
|
||||
* This class analyzes an XPath Expression parse tree (nsXFormsXPathNode), and
|
||||
|
@ -58,11 +59,12 @@
|
|||
class nsXFormsXPathAnalyzer {
|
||||
private:
|
||||
nsCOMPtr<nsIXFormsXPathEvaluator> mEvaluator;
|
||||
nsCOMPtr<nsIDOMNode> mResolver;
|
||||
nsCOMPtr<nsIDOMNode> mResolver;
|
||||
|
||||
nsCOMArray<nsIDOMNode> *mCurSet;
|
||||
nsCOMPtr<nsIDOMXPathExpression> mCurExpression;
|
||||
const nsAString *mCurExprString;
|
||||
nsCOMArray<nsIDOMNode> *mCurSet;
|
||||
nsCOMPtr<nsIDOMXPathExpression> mCurExpression;
|
||||
const nsAString *mCurExprString;
|
||||
nsStringArray mIndexesUsed;
|
||||
|
||||
nsresult AnalyzeRecursively(nsIDOMNode *aContextNode,
|
||||
const nsXFormsXPathNode *aNode,
|
||||
|
@ -78,4 +80,6 @@ public:
|
|||
nsIDOMXPathExpression *aExpression,
|
||||
const nsAString *aExprString,
|
||||
nsCOMArray<nsIDOMNode> *aSet);
|
||||
|
||||
const nsStringArray& IndexesUsed() const;
|
||||
};
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
MOZ_DECL_CTOR_COUNTER(nsXFormsXPathNode)
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ public:
|
|||
PRBool mCon;
|
||||
PRBool mPredicate;
|
||||
PRBool mLiteral;
|
||||
PRBool mIsIndex;
|
||||
|
||||
nsXFormsXPathNode(nsXFormsXPathNode* aParent, PRBool aContinue = PR_FALSE);
|
||||
~nsXFormsXPathNode();
|
||||
|
|
|
@ -354,12 +354,13 @@ nsXFormsXPathParser::FilterExpr()
|
|||
void
|
||||
nsXFormsXPathParser::FunctionCall()
|
||||
{
|
||||
if (!mUsesDynamicFunc) {
|
||||
nsDependentSubstring fname = Substring(mScanner.Expression(), mScanner.Offset() + 1, mScanner.Offset() + mScanner.Length() + 1);
|
||||
if (fname.Equals(NS_LITERAL_STRING("now"))) {
|
||||
mUsesDynamicFunc = PR_TRUE;
|
||||
}
|
||||
nsDependentSubstring fname = Substring(mScanner.Expression(),
|
||||
mScanner.Offset() + 1,
|
||||
mScanner.Length());
|
||||
if (!mUsesDynamicFunc && fname.Equals(NS_LITERAL_STRING("now"))) {
|
||||
mUsesDynamicFunc = PR_TRUE;
|
||||
}
|
||||
|
||||
PopToken();
|
||||
PopToken();
|
||||
nsXFormsXPathScanner::XPATHTOKEN t = PeekToken();
|
||||
|
@ -367,18 +368,22 @@ nsXFormsXPathParser::FunctionCall()
|
|||
PRBool con = t == nsXFormsXPathScanner::RPARAN ? PR_FALSE : PR_TRUE;
|
||||
while (con) {
|
||||
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();
|
||||
Expr();
|
||||
if (fname.Equals(NS_LITERAL_STRING("index"))) {
|
||||
c->mIsIndex = PR_TRUE;
|
||||
}
|
||||
PushContext(c);
|
||||
|
||||
t = PeekToken();
|
||||
if (t == nsXFormsXPathScanner::COMMA) {
|
||||
con = (t == nsXFormsXPathScanner::COMMA);
|
||||
if (con) {
|
||||
PopToken(); // Another Argument
|
||||
con = PR_TRUE;
|
||||
} else {
|
||||
con = PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче