[XForms] Handle references to id attributes inside repeats. Bug 302513, r=smaug+doronr
This commit is contained in:
Родитель
9b7260746c
Коммит
b4402c8920
|
@ -44,6 +44,7 @@
|
|||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIXFormsControl;
|
||||
interface nsIDOMNode;
|
||||
|
||||
[uuid(419e780d-4f31-4aa4-bae8-a18099d77bb6)]
|
||||
interface nsIXFormsRepeatElement : nsISupports
|
||||
|
@ -91,6 +92,13 @@ interface nsIXFormsRepeatElement : nsISupports
|
|||
void setCurrentRepeat(in nsIXFormsRepeatElement aCurrentRepeat,
|
||||
in unsigned long aIndex);
|
||||
|
||||
/**
|
||||
* Get currently selected repeat row
|
||||
*
|
||||
* @return The current repeat row
|
||||
*/
|
||||
nsIDOMNode getCurrentRepeatRow();
|
||||
|
||||
/**
|
||||
* Add user of repeat-index. The control will have Bind() and Refresh()
|
||||
* called on it, when the index changes.
|
||||
|
|
|
@ -101,7 +101,8 @@ nsXFormsDispatchElement::HandleAction(nsIDOMEvent* aEvent,
|
|||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMElement> el;
|
||||
doc->GetElementById(target, getter_AddRefs(el));
|
||||
nsXFormsUtils::GetElementById(doc, target, PR_FALSE, mElement,
|
||||
getter_AddRefs(el));
|
||||
if (!el)
|
||||
return NS_OK;
|
||||
|
||||
|
|
|
@ -546,6 +546,25 @@ nsXFormsRepeatElement::SetCurrentRepeat(nsIXFormsRepeatElement *aRepeat,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsRepeatElement::GetCurrentRepeatRow(nsIDOMNode **aRow)
|
||||
{
|
||||
if (mCurrentRepeat) {
|
||||
// nested repeats
|
||||
return mCurrentRepeat->GetCurrentRepeatRow(aRow);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMNodeList> children;
|
||||
NS_ENSURE_STATE(mHTMLElement);
|
||||
mHTMLElement->GetChildNodes(getter_AddRefs(children));
|
||||
NS_ENSURE_STATE(children);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> child;
|
||||
children->Item(mCurrentIndex - 1, // Indexes are 1-based, the DOM is 0-based
|
||||
getter_AddRefs(child));
|
||||
NS_IF_ADDREF(*aRow = child);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsRepeatElement::AddIndexUser(nsIXFormsControl *aControl)
|
||||
|
@ -917,11 +936,6 @@ nsXFormsRepeatElement::CloneNode(nsIDOMNode *aSrc,
|
|||
}
|
||||
}
|
||||
|
||||
// Remove @id, if there
|
||||
nsCOMPtr<nsIDOMElement> targElem(do_QueryInterface(*aTarget));
|
||||
if (targElem)
|
||||
targElem->RemoveAttribute(NS_LITERAL_STRING("id"));
|
||||
|
||||
// Clone children of aSrc
|
||||
nsCOMPtr<nsIDOMNode> tmp;
|
||||
nsCOMPtr<nsIDOMNodeList> childNodes;
|
||||
|
|
|
@ -71,10 +71,10 @@ nsXFormsSetFocusElement::HandleAction(nsIDOMEvent* aEvent,
|
|||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMElement> el;
|
||||
doc->GetElementById(control, getter_AddRefs(el));
|
||||
nsXFormsUtils::GetElementById(doc, control, PR_TRUE, mElement,
|
||||
getter_AddRefs(el));
|
||||
if (!el)
|
||||
return NS_OK;
|
||||
//XXX Should we check the type of the element?
|
||||
|
||||
return nsXFormsUtils::DispatchEvent(el, eEvent_Focus);
|
||||
}
|
||||
|
|
|
@ -62,7 +62,8 @@ nsXFormsToggleElement::HandleAction(nsIDOMEvent* aEvent,
|
|||
return NS_OK;
|
||||
|
||||
nsAutoString caseAttr;
|
||||
mElement->GetAttribute(NS_LITERAL_STRING("case"), caseAttr);
|
||||
NS_NAMED_LITERAL_STRING(caseStr, "case");
|
||||
mElement->GetAttribute(caseStr, caseAttr);
|
||||
if (caseAttr.IsEmpty())
|
||||
return NS_OK;
|
||||
|
||||
|
@ -72,11 +73,12 @@ nsXFormsToggleElement::HandleAction(nsIDOMEvent* aEvent,
|
|||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMElement> caseEl;
|
||||
doc->GetElementById(caseAttr, getter_AddRefs(caseEl));
|
||||
nsXFormsUtils::GetElementById(doc, caseAttr, PR_TRUE, mElement,
|
||||
getter_AddRefs(caseEl));
|
||||
if (!caseEl)
|
||||
return NS_OK;
|
||||
|
||||
if (!nsXFormsUtils::IsXFormsElement(caseEl, NS_LITERAL_STRING("case")))
|
||||
|
||||
if (!nsXFormsUtils::IsXFormsElement(caseEl, caseStr))
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> parent;
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#include "nsIContent.h"
|
||||
#include "nsIAttribute.h"
|
||||
#include "nsXFormsAtoms.h"
|
||||
#include "nsIXFormsRepeatElement.h"
|
||||
|
||||
#include "nsIXFormsContextControl.h"
|
||||
#include "nsIDOMDocumentEvent.h"
|
||||
|
@ -1413,3 +1414,136 @@ nsXFormsUtils::IsDocumentReadyForBind(nsIDOMDocument *aDocument)
|
|||
return test ? PR_TRUE : PR_FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the repeat context for an element: Returns a parent repeat or
|
||||
* contextcontainer (depending on |aFindContainer|).
|
||||
*
|
||||
* @param aElement The element to retrieve context for
|
||||
* @param aFindContainer find true: "contextcontainer", false: "repeat"
|
||||
* @return The repeat or contextcontainer node
|
||||
*/
|
||||
already_AddRefed<nsIDOMNode>
|
||||
FindRepeatContext(nsIDOMElement *aElement, PRBool aFindContainer)
|
||||
{
|
||||
nsIDOMNode *result = nsnull;
|
||||
|
||||
// XXX Possibly use mRepeatState functionality from nsXFormsDelegateStub to
|
||||
// save running up the tree?
|
||||
nsCOMPtr<nsIDOMNode> context, temp;
|
||||
aElement->GetParentNode(getter_AddRefs(context));
|
||||
nsresult rv;
|
||||
while (context) {
|
||||
if (nsXFormsUtils::IsXFormsElement(context,
|
||||
aFindContainer ?
|
||||
NS_LITERAL_STRING("contextcontainer") :
|
||||
NS_LITERAL_STRING("repeat"))) {
|
||||
break;
|
||||
}
|
||||
temp.swap(context);
|
||||
rv = temp->GetParentNode(getter_AddRefs(context));
|
||||
}
|
||||
if (context && NS_SUCCEEDED(rv)) {
|
||||
NS_ADDREF(result = context);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
nsXFormsUtils::GetElementById(nsIDOMDocument *aDoc,
|
||||
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<nsIDOMElement> element;
|
||||
aDoc->GetElementById(aId, getter_AddRefs(element));
|
||||
if (!element)
|
||||
return NS_OK;
|
||||
|
||||
// Check whether the element is inside a repeat. If it is, find the cloned
|
||||
// element for the currently selected row.
|
||||
nsCOMPtr<nsIDOMNode> repeat = FindRepeatContext(element, PR_FALSE);
|
||||
if (!repeat) {
|
||||
// Element not inside a repeat, just return the element (eventually
|
||||
// checking for XForms namespace)
|
||||
if (aOnlyXForms) {
|
||||
nsAutoString ns;
|
||||
element->GetNamespaceURI(ns);
|
||||
if (!ns.EqualsLiteral(NS_NAMESPACE_XFORMS)) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
NS_ADDREF(*aElement = element);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Check whether the caller is inside a repeat
|
||||
nsCOMPtr<nsIDOMNode> repeatRow;
|
||||
if (aCaller) {
|
||||
repeatRow = FindRepeatContext(aCaller, PR_TRUE);
|
||||
}
|
||||
|
||||
if (!repeatRow) {
|
||||
// aCaller was either not set or not inside a repeat, used currently
|
||||
// focused row of the element's repeat
|
||||
nsCOMPtr<nsIXFormsRepeatElement> repeatInt(do_QueryInterface(repeat));
|
||||
NS_ENSURE_STATE(repeatInt);
|
||||
repeatInt->GetCurrentRepeatRow(getter_AddRefs(repeatRow));
|
||||
NS_ASSERTION(repeatRow, "huh? No currently selected repeat row?");
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMElement> rowElement(do_QueryInterface(repeatRow));
|
||||
NS_ENSURE_STATE(rowElement);
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> repeatDoc;
|
||||
rowElement->GetOwnerDocument(getter_AddRefs(repeatDoc));
|
||||
|
||||
nsCOMPtr<nsIDOMNodeList> descendants;
|
||||
nsresult rv;
|
||||
rv = rowElement->GetElementsByTagNameNS(aOnlyXForms ?
|
||||
NS_LITERAL_STRING(NS_NAMESPACE_XFORMS) :
|
||||
NS_LITERAL_STRING("*"),
|
||||
NS_LITERAL_STRING("*"),
|
||||
getter_AddRefs(descendants));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_STATE(descendants);
|
||||
PRUint32 elements;
|
||||
descendants->GetLength(&elements);
|
||||
if (!elements) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRUint32 i;
|
||||
PRUint16 type;
|
||||
nsAutoString idVal;
|
||||
nsCOMPtr<nsIDOMNode> childNode;
|
||||
for (i = 0; i < elements; ++i) {
|
||||
descendants->Item(i, getter_AddRefs(childNode));
|
||||
childNode->GetNodeType(&type);
|
||||
if (type == nsIDOMNode::ELEMENT_NODE) {
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(childNode));
|
||||
NS_ASSERTION(content, "An ELEMENT_NODE not implementing nsIContent?!");
|
||||
rv = content->GetAttr(kNameSpaceID_None, content->GetIDAttributeName(),
|
||||
idVal);
|
||||
if (rv == NS_CONTENT_ATTR_HAS_VALUE && idVal.Equals(aId)) {
|
||||
element = do_QueryInterface(childNode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i == elements) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_ENSURE_STATE(element);
|
||||
NS_ADDREF(*aElement = element);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -422,6 +422,21 @@ public:
|
|||
*/
|
||||
static NS_HIDDEN_(PRBool) IsDocumentReadyForBind(nsIDOMDocument *aDocument);
|
||||
|
||||
/**
|
||||
* Retrieve an element by id, handling (cloned) elements inside repeats.
|
||||
*
|
||||
* @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,
|
||||
const PRBool aOnlyXForms,
|
||||
nsIDOMElement *aCaller,
|
||||
nsIDOMElement **aElement);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче