[XForms] Handle references to id attributes inside repeats. Bug 302513, r=smaug+doronr

This commit is contained in:
allan%beaufour.dk 2005-08-23 11:00:50 +00:00
Родитель 9b7260746c
Коммит b4402c8920
7 изменённых файлов: 186 добавлений и 12 удалений

Просмотреть файл

@ -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