From 7465f6fb994c453a7b3247f92b9d46fa67032c71 Mon Sep 17 00:00:00 2001 From: "Olli.Pettay%helsinki.fi" Date: Mon, 11 Dec 2006 10:54:09 +0000 Subject: [PATCH] Bug 361501, use 'anonid' attribute inside anonymous content as ID attribute, p=surkov, r=aaronr+me --- extensions/xforms/nsXFormsControlStub.cpp | 19 ++---- extensions/xforms/nsXFormsDispatchElement.cpp | 15 ++--- extensions/xforms/nsXFormsSendElement.cpp | 8 +-- extensions/xforms/nsXFormsSetFocusElement.cpp | 8 +-- extensions/xforms/nsXFormsSetIndexElement.cpp | 13 ++-- extensions/xforms/nsXFormsToggleElement.cpp | 7 +- extensions/xforms/nsXFormsTriggerElement.cpp | 10 ++- extensions/xforms/nsXFormsUtils.cpp | 65 +++++++++++++++---- extensions/xforms/nsXFormsUtils.h | 39 +++++++++-- extensions/xforms/nsXFormsXPathFunctions.cpp | 5 +- 10 files changed, 120 insertions(+), 69 deletions(-) diff --git a/extensions/xforms/nsXFormsControlStub.cpp b/extensions/xforms/nsXFormsControlStub.cpp index a4c44736bfc..866f457e57e 100644 --- a/extensions/xforms/nsXFormsControlStub.cpp +++ b/extensions/xforms/nsXFormsControlStub.cpp @@ -363,35 +363,30 @@ nsXFormsControlStub::ProcessNodeBinding(const nsString &aBindingAttr, if (aModel) NS_ADDREF(*aModel = mModel); + mUsesModelBinding = usesModelBinding; - nsCOMPtr content(do_QueryInterface(mElement)); - NS_ENSURE_STATE(content); - nsCOMPtr doc = content->GetCurrentDoc(); - nsCOMPtr domDoc(do_QueryInterface(doc)); - NS_ENSURE_STATE(domDoc); - - if (NS_SUCCEEDED(rv) && indexesUsed.Count()) { + if (indexesUsed.Count()) { // add index listeners on repeat elements for (PRInt32 i = 0; i < indexesUsed.Count(); ++i) { // Find the repeat element and add |this| as a listener nsCOMPtr repElem; - domDoc->GetElementById(*(indexesUsed[i]), getter_AddRefs(repElem)); + nsXFormsUtils::GetElementByContextId(mElement, *(indexesUsed[i]), + getter_AddRefs(repElem)); nsCOMPtr rep(do_QueryInterface(repElem)); if (!rep) continue; rv = rep->AddIndexUser(this); - if (NS_FAILED(rv)) { - return rv; - } + NS_ENSURE_SUCCESS(rv, rv); + rv = mIndexesUsed.AppendObject(rep); NS_ENSURE_SUCCESS(rv, rv); } } - return rv; + return NS_OK; } NS_IMETHODIMP diff --git a/extensions/xforms/nsXFormsDispatchElement.cpp b/extensions/xforms/nsXFormsDispatchElement.cpp index 1091428335b..9ea05d3443d 100644 --- a/extensions/xforms/nsXFormsDispatchElement.cpp +++ b/extensions/xforms/nsXFormsDispatchElement.cpp @@ -95,18 +95,17 @@ nsXFormsDispatchElement::HandleAction(nsIDOMEvent* aEvent, nsXFormsUtils::GetEventDefaults(name, tmp, bubbles); } - nsCOMPtr doc; - mElement->GetOwnerDocument(getter_AddRefs(doc)); - if (!doc) - return NS_OK; - nsCOMPtr el; - nsXFormsUtils::GetElementById(doc, target, PR_FALSE, mElement, - getter_AddRefs(el)); + nsXFormsUtils::GetElementById(target, PR_FALSE, mElement, getter_AddRefs(el)); if (!el) return NS_OK; - + + nsCOMPtr doc; + mElement->GetOwnerDocument(getter_AddRefs(doc)); nsCOMPtr docEvent = do_QueryInterface(doc); + if (!docEvent) + return NS_OK; + nsCOMPtr event; docEvent->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event)); event->InitEvent(name, bubbles, cancelable); diff --git a/extensions/xforms/nsXFormsSendElement.cpp b/extensions/xforms/nsXFormsSendElement.cpp index c39c425a7b0..eaf8e29803b 100644 --- a/extensions/xforms/nsXFormsSendElement.cpp +++ b/extensions/xforms/nsXFormsSendElement.cpp @@ -64,13 +64,9 @@ nsXFormsSendElement::HandleAction(nsIDOMEvent* aEvent, if (submissionID.IsEmpty()) return NS_OK; - nsCOMPtr doc; - mElement->GetOwnerDocument(getter_AddRefs(doc)); - if (!doc) - return NS_OK; - nsCOMPtr el; - doc->GetElementById(submissionID, getter_AddRefs(el)); + nsXFormsUtils::GetElementByContextId(mElement, submissionID, + getter_AddRefs(el)); if (!el || !nsXFormsUtils::IsXFormsElement(el, submission)) { const PRUnichar *strings[] = { submissionID.get(), submission.get() }; diff --git a/extensions/xforms/nsXFormsSetFocusElement.cpp b/extensions/xforms/nsXFormsSetFocusElement.cpp index a155d90955d..4be503308fe 100644 --- a/extensions/xforms/nsXFormsSetFocusElement.cpp +++ b/extensions/xforms/nsXFormsSetFocusElement.cpp @@ -65,14 +65,8 @@ nsXFormsSetFocusElement::HandleAction(nsIDOMEvent* aEvent, if (control.IsEmpty()) return NS_OK; - nsCOMPtr doc; - mElement->GetOwnerDocument(getter_AddRefs(doc)); - if (!doc) - return NS_OK; - nsCOMPtr el; - nsXFormsUtils::GetElementById(doc, control, PR_TRUE, mElement, - getter_AddRefs(el)); + nsXFormsUtils::GetElementById(control, PR_TRUE, mElement, getter_AddRefs(el)); if (!el) return NS_OK; diff --git a/extensions/xforms/nsXFormsSetIndexElement.cpp b/extensions/xforms/nsXFormsSetIndexElement.cpp index 5075fc5fa39..24220d83688 100644 --- a/extensions/xforms/nsXFormsSetIndexElement.cpp +++ b/extensions/xforms/nsXFormsSetIndexElement.cpp @@ -111,18 +111,17 @@ nsXFormsSetIndexElement::HandleAction(nsIDOMEvent *aEvent, NS_ENSURE_SUCCESS(rv, rv); PRUint32 indexInt = indexDoub < 1 ? 0 : (PRUint32) floor(indexDoub); - // Find the \ with @id == |id| - nsCOMPtr domDoc; - rv = mElement->GetOwnerDocument(getter_AddRefs(domDoc)); - NS_ENSURE_SUCCESS(rv, rv); - #ifdef DEBUG_XF_SETINDEX printf(": Setting index '%s' to '%d'\n", NS_ConvertUTF16toUTF8(id).get(), indexInt); -#endif +#endif + + // Find the \ with @id == |id| nsCOMPtr repeatElem; - rv = domDoc->GetElementById(id, getter_AddRefs(repeatElem)); + nsXFormsUtils::GetElementByContextId(mElement, id, + getter_AddRefs(repeatElem)); + nsCOMPtr repeat = do_QueryInterface(repeatElem); if (!repeat) { const PRUnichar *strings[] = { id.get(), repeatStr.get() }; diff --git a/extensions/xforms/nsXFormsToggleElement.cpp b/extensions/xforms/nsXFormsToggleElement.cpp index 958eb127661..d58f516e937 100644 --- a/extensions/xforms/nsXFormsToggleElement.cpp +++ b/extensions/xforms/nsXFormsToggleElement.cpp @@ -66,14 +66,9 @@ nsXFormsToggleElement::HandleAction(nsIDOMEvent* aEvent, mElement->GetAttribute(caseStr, caseAttr); if (caseAttr.IsEmpty()) return NS_OK; - - nsCOMPtr doc; - mElement->GetOwnerDocument(getter_AddRefs(doc)); - if (!doc) - return NS_OK; nsCOMPtr caseEl; - nsXFormsUtils::GetElementById(doc, caseAttr, PR_TRUE, mElement, + nsXFormsUtils::GetElementById(caseAttr, PR_TRUE, mElement, getter_AddRefs(caseEl)); if (!caseEl) return NS_OK; diff --git a/extensions/xforms/nsXFormsTriggerElement.cpp b/extensions/xforms/nsXFormsTriggerElement.cpp index 67f8a6b4855..385986c29d5 100644 --- a/extensions/xforms/nsXFormsTriggerElement.cpp +++ b/extensions/xforms/nsXFormsTriggerElement.cpp @@ -113,14 +113,12 @@ nsXFormsSubmitElement::HandleDefault(nsIDOMEvent *aEvent, PRBool *aHandled) nsAutoString submissionID; mElement->GetAttribute(submission, submissionID); - nsCOMPtr ownerDoc; - mElement->GetOwnerDocument(getter_AddRefs(ownerDoc)); - NS_ENSURE_STATE(ownerDoc); - nsCOMPtr submissionElement; - ownerDoc->GetElementById(submissionID, getter_AddRefs(submissionElement)); + nsXFormsUtils::GetElementByContextId(mElement, submissionID, + getter_AddRefs(submissionElement)); + nsCOMPtr xfSubmission(do_QueryInterface(submissionElement)); - + if (!xfSubmission) { const PRUnichar *strings[] = { submissionID.get(), submission.get() }; nsXFormsUtils::ReportError(NS_LITERAL_STRING("idRefError"), diff --git a/extensions/xforms/nsXFormsUtils.cpp b/extensions/xforms/nsXFormsUtils.cpp index d9e57ffda1e..ad3550c10d3 100644 --- a/extensions/xforms/nsXFormsUtils.cpp +++ b/extensions/xforms/nsXFormsUtils.cpp @@ -43,6 +43,7 @@ #include "nsIDOMElement.h" #include "nsIDOMNSHTMLElement.h" #include "nsIDocument.h" +#include "nsIDOMDocumentXBL.h" #include "nsINameSpaceManager.h" #include "nsIDOMNodeList.h" #include "nsIDOMXPathEvaluator.h" @@ -312,16 +313,13 @@ nsXFormsUtils::GetNodeContext(nsIDOMElement *aElement, *aContextPosition = 1; // Find correct model element - nsCOMPtr domDoc; - aElement->GetOwnerDocument(getter_AddRefs(domDoc)); - NS_ENSURE_TRUE(domDoc, NS_ERROR_FAILURE); - nsAutoString bindId; NS_NAMED_LITERAL_STRING(bindStr, "bind"); aElement->GetAttribute(bindStr, bindId); if (!bindId.IsEmpty()) { // CASE 1: Use @bind - domDoc->GetElementById(bindId, aBindElement); + GetElementByContextId(aElement, bindId, aBindElement); + if (!IsXFormsElement(*aBindElement, bindStr)) { const PRUnichar *strings[] = { bindId.get(), bindStr.get() }; nsXFormsUtils::ReportError(NS_LITERAL_STRING("idRefError"), @@ -342,9 +340,9 @@ nsXFormsUtils::GetNodeContext(nsIDOMElement *aElement, if (!modelId.IsEmpty()) { nsCOMPtr modelElement; - domDoc->GetElementById(modelId, getter_AddRefs(modelElement)); + GetElementByContextId(aElement, modelId, getter_AddRefs(modelElement)); nsCOMPtr model = do_QueryInterface(modelElement); - + // No element found, or element not a \ element if (!model) { const PRUnichar *strings[] = { modelId.get(), modelStr.get() }; @@ -1798,19 +1796,17 @@ FindRepeatContext(nsIDOMElement *aElement, PRBool aFindContainer) /* static */ nsresult -nsXFormsUtils::GetElementById(nsIDOMDocument *aDoc, - const nsAString &aId, +nsXFormsUtils::GetElementById(const nsAString &aId, const PRBool aOnlyXForms, nsIDOMElement *aCaller, nsIDOMElement **aElement) { NS_ENSURE_TRUE(!aId.IsEmpty(), NS_ERROR_INVALID_ARG); - NS_ENSURE_ARG_POINTER(aDoc); NS_ENSURE_ARG_POINTER(aElement); *aElement = nsnull; nsCOMPtr element; - aDoc->GetElementById(aId, getter_AddRefs(element)); + GetElementByContextId(aCaller, aId, getter_AddRefs(element)); if (!element) return NS_OK; @@ -1894,6 +1890,53 @@ nsXFormsUtils::GetElementById(nsIDOMDocument *aDoc, return NS_OK; } +/* static */ +nsresult +nsXFormsUtils::GetElementByContextId(nsIDOMElement *aRefNode, + const nsAString &aId, + nsIDOMElement **aElement) +{ + NS_ENSURE_ARG(aRefNode); + NS_ENSURE_ARG_POINTER(aElement); + + *aElement = nsnull; + + nsCOMPtr document; + aRefNode->GetOwnerDocument(getter_AddRefs(document)); + + // Even if given element is anonymous node then search element by ID attribute + // of document because anonymous node can inherit attribute from bound node + // that is refID of document. + + nsresult rv = document->GetElementById(aId, aElement); + NS_ENSURE_SUCCESS(rv, rv); + + if (*aElement) + return NS_OK; + + nsCOMPtr xblDoc(do_QueryInterface(document)); + if (!xblDoc) + return NS_OK; + + nsCOMPtr content(do_QueryInterface(aRefNode)); + if (!content) + return NS_OK; + + // Search for the element with the given value in its 'anonid' attribute + // throughout the complete bindings chain. We must ensure that the binding + // parent of currently traversed element is not element itself to avoid an + // infinite loop. + nsIContent *boundContent; + for (boundContent = content->GetBindingParent(); boundContent != nsnull && + boundContent != boundContent->GetBindingParent() && !*aElement; + boundContent = boundContent->GetBindingParent()) { + nsCOMPtr boundElm(do_QueryInterface(boundContent)); + xblDoc->GetAnonymousElementByAttribute(boundElm, NS_LITERAL_STRING("anonid"), + aId, aElement); + } + + return NS_OK; +} /* static */ PRBool diff --git a/extensions/xforms/nsXFormsUtils.h b/extensions/xforms/nsXFormsUtils.h index c3a0ffeff8f..90e69697776 100644 --- a/extensions/xforms/nsXFormsUtils.h +++ b/extensions/xforms/nsXFormsUtils.h @@ -549,21 +549,50 @@ public: static NS_HIDDEN_(PRBool) IsDocumentReadyForBind(nsIDOMElement *aElement); /** - * Retrieve an element by id, handling (cloned) elements inside repeats. + * Search for an element by ID through repeat rows looking for controls in + * addition to looking through the regular DOM. + * + * For example, xf:dispatch dispatches an event to an element with the given + * ID. If the element is in a repeat, you don't want to dispatch the event to + * the element in the DOM since we just end up hiding it and treating it as + * part of the repeat template. So we use nsXFormsUtils::GetElementById to + * dispatch the event to the contol with that id that is in the repeat row + * that has the current focus (well, the repeat row that corresponds to the + * repeat's index). If the element with that ID isn't in a repeat, then it + * picks the element with that ID from the DOM. But you wouldn't want to use + * this call for items that you know can't be inside repeats (like instance or + * submission elements). So for those you should use + * nsXFormsUtils::GetElementByContextId. * - * @param aDoc The document to get element from * @param aId The id of the element * @param aOnlyXForms Only search for XForms elements * @param aCaller The caller (or rather the caller's DOM element), ignored if nsnull * @param aElement The element (or nsnull if not found) */ - static NS_HIDDEN_(nsresult) GetElementById(nsIDOMDocument *aDoc, - const nsAString &aId, + static NS_HIDDEN_(nsresult) GetElementById(const nsAString &aId, const PRBool aOnlyXForms, nsIDOMElement *aCaller, nsIDOMElement **aElement); - + + /** + * Search for an element with the given ID value. First + * nsIDOMDocument::getElementById() is used. If it successful then found + * element is returned. Second, if the given node is inside anonymous content + * then search is performed throughout the complete bindings chain by @anonid + * attribute. + * + * @param aRefNode The node relatively of which search is performed in + * anonymous content + * @param aId The @id/@anonid value to search for + * + * @return aElement The element we found that has its ID/anonid value + * equal to aId + */ + static NS_HIDDEN_(nsresult) GetElementByContextId(nsIDOMElement *aRefNode, + const nsAString &aId, + nsIDOMElement **aElement); + /** * Shows an error dialog for fatal errors. * diff --git a/extensions/xforms/nsXFormsXPathFunctions.cpp b/extensions/xforms/nsXFormsXPathFunctions.cpp index 386712dcec1..bbb55a159d6 100644 --- a/extensions/xforms/nsXFormsXPathFunctions.cpp +++ b/extensions/xforms/nsXFormsXPathFunctions.cpp @@ -166,7 +166,10 @@ nsXFormsXPathFunctions::Index(txIFunctionEvaluationContext *aContext, // aID should be the id of a nsIXFormsRepeatElement nsCOMPtr repeatEle; - nsresult rv = document->GetElementById(aID, getter_AddRefs(repeatEle)); + nsCOMPtr resolverEle(do_QueryInterface(resolverNode)); + nsresult rv = + nsXFormsUtils::GetElementByContextId(resolverEle, aID, + getter_AddRefs(repeatEle)); NS_ENSURE_SUCCESS(rv, rv); // now get the index value from the xforms:repeat.