From 81e8fa73b3aa9b3e00704684c8ff0524671c0859 Mon Sep 17 00:00:00 2001 From: "bzbarsky%mit.edu" Date: Thu, 14 Sep 2006 04:29:02 +0000 Subject: [PATCH] Implement GetElementsByAttributeNS. Bug 239976, patch by Joerg Bornemann , r+sr=bzbarsky --- content/base/src/nsDocument.cpp | 12 +-- content/base/src/nsGenericElement.cpp | 12 +-- content/test/unit/test_nodelist.js | 110 +++++++++++++++++++++ content/xul/content/src/nsXULElement.cpp | 30 ++++++ content/xul/document/src/nsXULDocument.cpp | 33 ++++++- dom/public/idl/xul/nsIDOMXULDocument.idl | 6 +- dom/public/idl/xul/nsIDOMXULElement.idl | 6 +- 7 files changed, 190 insertions(+), 19 deletions(-) diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index d2aa39b60f7..05d8e955030 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -2759,8 +2759,6 @@ nsDocument::GetElementsByTagNameNS(const nsAString& aNamespaceURI, { PRInt32 nameSpaceId = kNameSpaceID_Wildcard; - nsContentList *list = nsnull; - if (!aNamespaceURI.EqualsLiteral("*")) { nsresult rv = nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI, @@ -2768,13 +2766,11 @@ nsDocument::GetElementsByTagNameNS(const nsAString& aNamespaceURI, NS_ENSURE_SUCCESS(rv, rv); } - if (!list) { - nsCOMPtr nameAtom = do_GetAtom(aLocalName); - NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY); + nsCOMPtr nameAtom = do_GetAtom(aLocalName); + NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY); - list = NS_GetContentList(this, nameAtom, nameSpaceId).get(); - NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY); - } + nsContentList *list = NS_GetContentList(this, nameAtom, nameSpaceId).get(); + NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY); // transfer ref to aReturn *aReturn = list; diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp index 6973f753f23..4abe8b1c89d 100644 --- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -1639,8 +1639,6 @@ nsGenericElement::GetElementsByTagNameNS(const nsAString& aNamespaceURI, { PRInt32 nameSpaceId = kNameSpaceID_Wildcard; - nsContentList *list = nsnull; - if (!aNamespaceURI.EqualsLiteral("*")) { nsresult rv = nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI, @@ -1648,13 +1646,11 @@ nsGenericElement::GetElementsByTagNameNS(const nsAString& aNamespaceURI, NS_ENSURE_SUCCESS(rv, rv); } - if (!list) { - nsCOMPtr nameAtom = do_GetAtom(aLocalName); - NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY); + nsCOMPtr nameAtom = do_GetAtom(aLocalName); + NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY); - list = NS_GetContentList(this, nameAtom, nameSpaceId).get(); - NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY); - } + nsContentList *list = NS_GetContentList(this, nameAtom, nameSpaceId).get(); + NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY); // transfer ref to aReturn *aReturn = list; diff --git a/content/test/unit/test_nodelist.js b/content/test/unit/test_nodelist.js index 1a40c494d9b..cd238545330 100644 --- a/content/test/unit/test_nodelist.js +++ b/content/test/unit/test_nodelist.js @@ -10,6 +10,7 @@ function run_test() test_getElementsByTagName(); test_getElementsByTagNameNS(); test_getElementsByAttribute(); + test_getElementsByAttributeNS(); // What else should we test? // XXXbz we need more tests here to test liveness! @@ -282,3 +283,112 @@ function test_getElementsByAttribute() do_check_eq(root.getElementsByAttribute("foo:foo", "baz").length, 0); } + +function test_getElementsByAttributeNS() +{ + var doc = ParseFile("nodelist_data_2.xul"); + var root = doc.documentElement; + + // Sadly, DOMParser can't create XULDocument objects. But at least we have a + // XULElement! + + do_check_true(root instanceof nsIDOMXULElement); + + // Check that getElementsByAttributeNS returns a nodelist. + do_check_true(root.getElementsByAttributeNS("*", "*", "*") instanceof + nsIDOMNodeList); + + var master1 = doc.getElementById("master1"); + var master2 = doc.getElementById("master2"); + var master3 = doc.getElementById("master3"); + var external = doc.getElementById("external"); + + do_check_true(master1 instanceof nsIDOMXULElement); + do_check_true(master2 instanceof nsIDOMXULElement); + do_check_true(master3 instanceof nsIDOMXULElement); + do_check_true(external instanceof nsIDOMXULElement); + + // Test wildcard namespace + do_check_eq(root.getElementsByAttributeNS("*", "foo", "foo").length, + 38); + do_check_eq(master1.getElementsByAttributeNS("*", "foo", "foo").length, + 11); + do_check_eq(master2.getElementsByAttributeNS("*", "foo", "foo").length, + 10); + do_check_eq(master3.getElementsByAttributeNS("*", "foo", "foo").length, + 11); + + do_check_eq(root.getElementsByAttributeNS("*", "foo", "bar").length, + 16); + do_check_eq(master1.getElementsByAttributeNS("*", "foo", "bar").length, + 4); + do_check_eq(master2.getElementsByAttributeNS("*", "foo", "bar").length, + 5); + do_check_eq(master3.getElementsByAttributeNS("*", "foo", "bar").length, + 4); + + do_check_eq(root.getElementsByAttributeNS("*", "bar", "bar").length, + 21); + do_check_eq(master1.getElementsByAttributeNS("*", "bar", "bar").length, + 6); + do_check_eq(master2.getElementsByAttributeNS("*", "bar", "bar").length, + 6); + do_check_eq(master3.getElementsByAttributeNS("*", "bar", "bar").length, + 6); + + do_check_eq(root.getElementsByAttributeNS("*", "foo", "*").length, + 54); + do_check_eq(master1.getElementsByAttributeNS("*", "foo", "*").length, + 15); + do_check_eq(master2.getElementsByAttributeNS("*", "foo", "*").length, + 15); + do_check_eq(master3.getElementsByAttributeNS("*", "foo", "*").length, + 15); + + // Test null namespace. This should be the same as getElementsByAttribute. + do_check_eq(root.getElementsByAttributeNS("", "foo", "foo").length, + root.getElementsByAttribute("foo", "foo").length); + do_check_eq(master1.getElementsByAttributeNS("", "foo", "foo").length, + master1.getElementsByAttribute("foo", "foo").length); + do_check_eq(master2.getElementsByAttributeNS("", "foo", "foo").length, + master2.getElementsByAttribute("foo", "foo").length); + do_check_eq(master3.getElementsByAttributeNS("", "foo", "foo").length, + master3.getElementsByAttribute("foo", "foo").length); + + // Test namespace "foo" + do_check_eq(root.getElementsByAttributeNS("foo", "foo", "foo").length, + 24); + do_check_eq(master1.getElementsByAttributeNS("foo", "foo", "foo").length, + 7); + do_check_eq(master2.getElementsByAttributeNS("foo", "foo", "foo").length, + 6); + do_check_eq(master3.getElementsByAttributeNS("foo", "foo", "foo").length, + 7); + + do_check_eq(root.getElementsByAttributeNS("foo", "foo", "bar").length, + 9); + do_check_eq(master1.getElementsByAttributeNS("foo", "foo", "bar").length, + 2); + do_check_eq(master2.getElementsByAttributeNS("foo", "foo", "bar").length, + 3); + do_check_eq(master3.getElementsByAttributeNS("foo", "foo", "bar").length, + 2); + + do_check_eq(root.getElementsByAttributeNS("foo", "bar", "foo").length, + 7); + do_check_eq(master1.getElementsByAttributeNS("foo", "bar", "foo").length, + 2); + do_check_eq(master2.getElementsByAttributeNS("foo", "bar", "foo").length, + 2); + do_check_eq(master3.getElementsByAttributeNS("foo", "bar", "foo").length, + 2); + + do_check_eq(root.getElementsByAttributeNS("foo", "bar", "bar").length, + 14); + do_check_eq(master1.getElementsByAttributeNS("foo", "bar", "bar").length, + 4); + do_check_eq(master2.getElementsByAttributeNS("foo", "bar", "bar").length, + 4); + do_check_eq(master3.getElementsByAttributeNS("foo", "bar", "bar").length, + 4); +} diff --git a/content/xul/content/src/nsXULElement.cpp b/content/xul/content/src/nsXULElement.cpp index 5c5dc7f6230..663ccc780d4 100644 --- a/content/xul/content/src/nsXULElement.cpp +++ b/content/xul/content/src/nsXULElement.cpp @@ -516,6 +516,36 @@ nsXULElement::GetElementsByAttribute(const nsAString& aAttribute, return NS_OK; } +NS_IMETHODIMP +nsXULElement::GetElementsByAttributeNS(const nsAString& aNamespaceURI, + const nsAString& aAttribute, + const nsAString& aValue, + nsIDOMNodeList** aReturn) +{ + nsCOMPtr attrAtom(do_GetAtom(aAttribute)); + NS_ENSURE_TRUE(attrAtom, NS_ERROR_OUT_OF_MEMORY); + + PRInt32 nameSpaceId = kNameSpaceID_Wildcard; + if (!aNamespaceURI.EqualsLiteral("*")) { + nsresult rv = + nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI, + nameSpaceId); + NS_ENSURE_SUCCESS(rv, rv); + } + + nsContentList *list = + new nsContentList(this, + nsXULDocument::MatchAttribute, + aValue, + PR_TRUE, + attrAtom, + nameSpaceId); + NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY); + + NS_ADDREF(*aReturn = list); + return NS_OK; +} + //---------------------------------------------------------------------- // nsIXMLContent interface diff --git a/content/xul/document/src/nsXULDocument.cpp b/content/xul/document/src/nsXULDocument.cpp index d3d23a5ebf7..ba874080611 100644 --- a/content/xul/document/src/nsXULDocument.cpp +++ b/content/xul/document/src/nsXULDocument.cpp @@ -1150,6 +1150,34 @@ nsXULDocument::GetElementsByAttribute(const nsAString& aAttribute, return NS_OK; } +NS_IMETHODIMP +nsXULDocument::GetElementsByAttributeNS(const nsAString& aNamespaceURI, + const nsAString& aAttribute, + const nsAString& aValue, + nsIDOMNodeList** aReturn) +{ + nsCOMPtr attrAtom(do_GetAtom(aAttribute)); + NS_ENSURE_TRUE(attrAtom, NS_ERROR_OUT_OF_MEMORY); + + PRInt32 nameSpaceId = kNameSpaceID_Wildcard; + if (!aNamespaceURI.EqualsLiteral("*")) { + nsresult rv = + nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI, + nameSpaceId); + NS_ENSURE_SUCCESS(rv, rv); + } + + nsContentList *list = new nsContentList(this, + MatchAttribute, + aValue, + PR_TRUE, + attrAtom, + nameSpaceId); + NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY); + + NS_ADDREF(*aReturn = list); + return NS_OK; +} NS_IMETHODIMP nsXULDocument::Persist(const nsAString& aID, @@ -2005,7 +2033,8 @@ nsXULDocument::MatchAttribute(nsIContent* aContent, { NS_PRECONDITION(aContent, "Must have content node to work with!"); - if (aNamespaceID != kNameSpaceID_Unknown) { + if (aNamespaceID != kNameSpaceID_Unknown && + aNamespaceID != kNameSpaceID_Wildcard) { return aAttrValue.EqualsLiteral("*") ? aContent->HasAttr(aNamespaceID, aAttrName) : aContent->AttrValueIs(aNamespaceID, aAttrName, aAttrValue, @@ -2020,6 +2049,8 @@ nsXULDocument::MatchAttribute(nsIContent* aContent, PRBool nameMatch; if (name->IsAtom()) { nameMatch = name->Atom() == aAttrName; + } else if (aNamespaceID == kNameSpaceID_Wildcard) { + nameMatch = name->NodeInfo()->Equals(aAttrName); } else { nameMatch = name->NodeInfo()->QualifiedNameEquals(aAttrName); } diff --git a/dom/public/idl/xul/nsIDOMXULDocument.idl b/dom/public/idl/xul/nsIDOMXULDocument.idl index e7a86489c9d..46da2faa03a 100644 --- a/dom/public/idl/xul/nsIDOMXULDocument.idl +++ b/dom/public/idl/xul/nsIDOMXULDocument.idl @@ -42,7 +42,7 @@ interface nsIDOMXULCommandDispatcher; interface nsIObserver; -[scriptable, uuid(a521baa9-0745-453a-9049-03c1a2241378)] +[scriptable, uuid(9816241b-2a20-44ff-903b-575f40c0ecc5)] interface nsIDOMXULDocument : nsISupports { attribute nsIDOMNode popupNode; @@ -66,6 +66,10 @@ interface nsIDOMXULDocument : nsISupports nsIDOMNodeList getElementsByAttribute(in DOMString name, in DOMString value); + nsIDOMNodeList getElementsByAttributeNS(in DOMString namespaceURI, + in DOMString name, + in DOMString value); + void addBroadcastListenerFor(in nsIDOMElement broadcaster, in nsIDOMElement observer, in DOMString attr); diff --git a/dom/public/idl/xul/nsIDOMXULElement.idl b/dom/public/idl/xul/nsIDOMXULElement.idl index d26c9325ed0..7f7b2a401df 100644 --- a/dom/public/idl/xul/nsIDOMXULElement.idl +++ b/dom/public/idl/xul/nsIDOMXULElement.idl @@ -46,7 +46,7 @@ interface nsIControllers; interface nsIBoxObject; -[scriptable, uuid(0574ed81-c088-11d2-96ed-00104b7b7deb)] +[scriptable, uuid(2261a45f-0a8f-401a-8e90-8da0d26cf9e3)] interface nsIDOMXULElement : nsIDOMElement { attribute DOMString id; @@ -116,4 +116,8 @@ interface nsIDOMXULElement : nsIDOMElement nsIDOMNodeList getElementsByAttribute(in DOMString name, in DOMString value); + + nsIDOMNodeList getElementsByAttributeNS(in DOMString namespaceURI, + in DOMString name, + in DOMString value); };