aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/script/dom/element.rs5
-rw-r--r--components/script/dom/node.rs97
-rw-r--r--tests/wpt/metadata/MANIFEST.json4
-rw-r--r--tests/wpt/web-platform-tests/dom/nodes/Node-lookupNamespaceURI.html119
4 files changed, 213 insertions, 12 deletions
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index 495a33c9005..30b92f0d49b 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -1121,10 +1121,7 @@ impl<'a> AttributeHandlers for &'a Element {
impl<'a> ElementMethods for &'a Element {
// https://dom.spec.whatwg.org/#dom-element-namespaceuri
fn GetNamespaceURI(self) -> Option<DOMString> {
- match self.namespace {
- ns!("") => None,
- Namespace(ref ns) => Some((**ns).to_owned())
- }
+ Node::namespace_to_string(self.namespace.clone())
}
// https://dom.spec.whatwg.org/#dom-element-localname
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index c5d435d5156..21c427d07b1 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -69,7 +69,7 @@ use std::iter::{FilterMap, Peekable};
use std::mem;
use std::sync::Arc;
use uuid;
-use string_cache::{Atom, QualName};
+use string_cache::{Atom, Namespace, QualName};
//
// The basic Node structure
@@ -1903,6 +1903,79 @@ impl Node {
}
content
}
+
+ pub fn namespace_to_string(namespace: Namespace) -> Option<DOMString> {
+ match namespace {
+ ns!("") => None,
+ Namespace(ref ns) => Some((**ns).to_owned())
+ }
+ }
+
+ // https://dom.spec.whatwg.org/#locate-a-namespace
+ pub fn locate_namespace(node: &Node, prefix: Option<DOMString>) -> Namespace {
+ fn attr_defines_namespace(attr: &Attr,
+ prefix: &Option<Atom>) -> bool {
+ *attr.namespace() == ns!(XMLNS) &&
+ match (attr.prefix(), prefix) {
+ (&Some(ref attr_prefix), &Some(ref prefix)) =>
+ attr_prefix == &atom!("xmlns") &&
+ attr.local_name() == prefix,
+ (&None, &None) => *attr.local_name() == atom!("xmlns"),
+ _ => false
+ }
+ }
+
+ match node.type_id {
+ NodeTypeId::Element(_) => {
+ let element = ElementCast::to_ref(node).unwrap();
+ // Step 1.
+ if *element.namespace() != ns!("") && *element.prefix() == prefix {
+ return element.namespace().clone()
+ }
+
+
+ let prefix_atom = prefix.as_ref().map(|s| Atom::from_slice(s));
+
+ // Step 2.
+ let namespace_attr =
+ element.attrs()
+ .iter()
+ .map(|attr| attr.root())
+ .find(|attr| attr_defines_namespace(attr.r(),
+ &prefix_atom));
+
+ // Steps 2.1-2.
+ if let Some(attr) = namespace_attr {
+ return namespace_from_domstring(Some(attr.Value()));
+ }
+
+ match node.GetParentElement() {
+ // Step 3.
+ None => ns!(""),
+ // Step 4.
+ Some(parent) => Node::locate_namespace(NodeCast::from_ref(parent.r()), prefix)
+ }
+ },
+ NodeTypeId::Document => {
+ match DocumentCast::to_ref(node).unwrap().GetDocumentElement().r() {
+ // Step 1.
+ None => ns!(""),
+ // Step 2.
+ Some(document_element) => {
+ Node::locate_namespace(NodeCast::from_ref(document_element), prefix)
+ }
+ }
+ },
+ NodeTypeId::DocumentType => ns!(""),
+ NodeTypeId::DocumentFragment => ns!(""),
+ _ => match node.GetParentElement() {
+ // Step 1.
+ None => ns!(""),
+ // Step 2.
+ Some(parent) => Node::locate_namespace(NodeCast::from_ref(parent.r()), prefix)
+ }
+ }
+ }
}
impl<'a> NodeMethods for &'a Node {
@@ -2457,15 +2530,23 @@ impl<'a> NodeMethods for &'a Node {
}
// https://dom.spec.whatwg.org/#dom-node-lookupnamespaceuri
- fn LookupNamespaceURI(self, _namespace: Option<DOMString>) -> Option<DOMString> {
- // FIXME (#1826) implement.
- None
- }
+ fn LookupNamespaceURI(self, prefix: Option<DOMString>) -> Option<DOMString> {
+ // Step 1.
+ let prefix = match prefix {
+ Some(ref p) if p.is_empty() => None,
+ pre => pre
+ };
+
+ // Step 2.
+ Node::namespace_to_string(Node::locate_namespace(self, prefix))
+ }
// https://dom.spec.whatwg.org/#dom-node-isdefaultnamespace
- fn IsDefaultNamespace(self, _namespace: Option<DOMString>) -> bool {
- // FIXME (#1826) implement.
- false
+ fn IsDefaultNamespace(self, namespace: Option<DOMString>) -> bool {
+ // Step 1.
+ let namespace = namespace_from_domstring(namespace);
+ // Steps 2 and 3.
+ Node::locate_namespace(self, None) == namespace
}
}
diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json
index 9cc668a4f88..f90ffd4fb39 100644
--- a/tests/wpt/metadata/MANIFEST.json
+++ b/tests/wpt/metadata/MANIFEST.json
@@ -13154,6 +13154,10 @@
"url": "/dom/nodes/Node-lookupPrefix.xhtml"
},
{
+ "path": "dom/nodes/Node-lookupNamespaceURI.html",
+ "url": "/dom/nodes/Node-lookupNamespaceURI.html"
+ },
+ {
"path": "dom/nodes/Node-nodeName.html",
"url": "/dom/nodes/Node-nodeName.html"
},
diff --git a/tests/wpt/web-platform-tests/dom/nodes/Node-lookupNamespaceURI.html b/tests/wpt/web-platform-tests/dom/nodes/Node-lookupNamespaceURI.html
new file mode 100644
index 00000000000..16555f4dc28
--- /dev/null
+++ b/tests/wpt/web-platform-tests/dom/nodes/Node-lookupNamespaceURI.html
@@ -0,0 +1,119 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>LookupNamespaceURI and IsDefaultNamespace tests</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+</head>
+<body>
+<h1>LookupNamespaceURI and IsDefaultNamespace</h1>
+<div id="log"/>
+<script>
+function lookupNamespaceURI(node, prefix, expected, name) {
+ test(function() {
+ assert_equals(node.lookupNamespaceURI(prefix), expected);
+ }, name);
+}
+
+function isDefaultNamespace(node, namespace, expected, name) {
+ test(function() {
+ assert_equals(node.isDefaultNamespace(namespace), expected);
+ }, name);
+}
+
+
+var frag = document.createDocumentFragment();
+lookupNamespaceURI(frag, null, null, 'DocumentFragment should have null namespace');
+lookupNamespaceURI(frag, '', null, 'DocumentFragment should have null namespace');
+lookupNamespaceURI(frag, 'foo', null, 'DocumentFragment should have null namespace');
+lookupNamespaceURI(frag, 'xmlns', null, 'DocumentFragment should have null namespace');
+isDefaultNamespace(frag, null, true, 'DocumentFragment is in default namespace');
+isDefaultNamespace(frag, '', true, 'DocumentFragment is in default namespace');
+isDefaultNamespace(frag, 'foo', false, 'DocumentFragment is in default namespace');
+isDefaultNamespace(frag, 'xmlns', false, 'DocumentFragment is in default namespace');
+
+
+
+var fooElem = document.createElementNS('fooNamespace', 'prefix:elem');
+fooElem.setAttribute('bar', 'value');
+
+lookupNamespaceURI(fooElem, null, null, 'Element should have null namespace');
+lookupNamespaceURI(fooElem, '', null, 'Element should have null namespace');
+lookupNamespaceURI(fooElem, 'fooNamespace', null, 'Element should not have namespace matching prefix with namespaceURI value');
+lookupNamespaceURI(fooElem, 'xmlns', null, 'Element should not have XMLNS namespace');
+lookupNamespaceURI(fooElem, 'prefix', 'fooNamespace', 'Element has namespace URI matching prefix');
+isDefaultNamespace(fooElem, null, true, 'Empty namespace is not default');
+isDefaultNamespace(fooElem, '', true, 'Empty namespace is not default');
+isDefaultNamespace(fooElem, 'fooNamespace', false, 'fooNamespace is not default');
+isDefaultNamespace(fooElem, 'http://www.w3.org/2000/xmlns/', false, 'xmlns namespace is not default');
+
+fooElem.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:bar', 'barURI');
+fooElem.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns', 'bazURI');
+
+lookupNamespaceURI(fooElem, null, 'bazURI', 'Element should have baz namespace');
+lookupNamespaceURI(fooElem, '', 'bazURI', 'Element should have baz namespace');
+lookupNamespaceURI(fooElem, 'prefix', 'fooNamespace', 'Element has namespace URI matching prefix');
+lookupNamespaceURI(fooElem, 'xmlns', null, 'Element does not has namespace with xlmns prefix');
+lookupNamespaceURI(fooElem, 'bar', 'barURI', 'Element has bar namespace');
+
+isDefaultNamespace(fooElem, null, false, 'Empty namespace is not default');
+isDefaultNamespace(fooElem, '', false, 'Empty namespace is not default');
+isDefaultNamespace(fooElem, 'fooNamespace', false, 'fooNamespace is not default');
+isDefaultNamespace(fooElem, 'http://www.w3.org/2000/xmlns/', false, 'xmlns namespace is not default');
+isDefaultNamespace(fooElem, 'barURI', false, 'bar namespace is not default');
+isDefaultNamespace(fooElem, 'bazURI', true, 'baz namespace is default');
+
+var comment = document.createComment('comment');
+fooElem.appendChild(comment);
+
+lookupNamespaceURI(comment, null, 'bazURI', 'Comment should inherit baz namespace');
+lookupNamespaceURI(comment, '', 'bazURI', 'Comment should inherit baz namespace');
+lookupNamespaceURI(comment, 'prefix', 'fooNamespace', 'Comment should inherit namespace URI matching prefix');
+lookupNamespaceURI(comment, 'bar', 'barURI', 'Comment should inherit bar namespace');
+
+isDefaultNamespace(comment, null, false, 'For comment, empty namespace is not default');
+isDefaultNamespace(comment, '', false, 'For comment, empty namespace is not default');
+isDefaultNamespace(comment, 'fooNamespace', false, 'For comment, fooNamespace is not default');
+isDefaultNamespace(comment, 'http://www.w3.org/2000/xmlns/', false, 'For comment, xmlns namespace is not default');
+isDefaultNamespace(comment, 'barURI', false, 'For comment, inherited bar namespace is not default');
+isDefaultNamespace(comment, 'bazURI', true, 'For comment, inherited baz namespace is default');
+
+var fooChild = document.createElementNS('childNamespace', 'childElem');
+fooElem.appendChild(fooChild);
+
+lookupNamespaceURI(fooChild, null, 'childNamespace', 'Child element should inherit baz namespace');
+lookupNamespaceURI(fooChild, '', 'childNamespace', 'Child element should have null namespace');
+lookupNamespaceURI(fooChild, 'xmlns', null, 'Child element should not have XMLNS namespace');
+lookupNamespaceURI(fooChild, 'prefix', 'fooNamespace', 'Child element has namespace URI matching prefix');
+
+isDefaultNamespace(fooChild, null, false, 'Empty namespace is not default for child');
+isDefaultNamespace(fooChild, '', false, 'Empty namespace is not default for child');
+isDefaultNamespace(fooChild, 'fooNamespace', false, 'fooNamespace is not default for child');
+isDefaultNamespace(fooChild, 'http://www.w3.org/2000/xmlns/', false, 'xmlns namespace is not default for child');
+isDefaultNamespace(fooChild, 'barURI', false, 'bar namespace is not default for child');
+isDefaultNamespace(fooChild, 'bazURI', false, 'baz namespace is default for child');
+isDefaultNamespace(fooChild, 'childNamespace', true, 'childNamespace is default for child');
+
+document.documentElement.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:bar', 'barURI');
+document.documentElement.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns', 'bazURI');
+
+lookupNamespaceURI(document, null, 'http://www.w3.org/1999/xhtml', 'Document should have xhtml namespace');
+lookupNamespaceURI(document, '', 'http://www.w3.org/1999/xhtml', 'Document should have xhtml namespace');
+lookupNamespaceURI(document, 'prefix', null, 'Document has no namespace URI matching prefix');
+lookupNamespaceURI(document, 'bar', 'barURI', 'Document has bar namespace');
+
+isDefaultNamespace(document, null, false, 'For document, Empty namespace is not default');
+isDefaultNamespace(document, '', false, 'For document, Empty namespace is not default');
+isDefaultNamespace(document, 'fooNamespace', false, 'For document, fooNamespace is not default');
+isDefaultNamespace(document, 'http://www.w3.org/2000/xmlns/', false, 'For document, xmlns namespace is not default');
+isDefaultNamespace(document, 'barURI', false, 'For document, bar namespace is not default');
+isDefaultNamespace(document, 'bazURI', false, 'For document, baz namespace is not default');
+isDefaultNamespace(document, 'http://www.w3.org/1999/xhtml', true, 'For document, xhtml namespace is default');
+
+var comment = document.createComment('comment');
+document.appendChild(comment);
+lookupNamespaceURI(comment, 'bar', null, 'Comment does not have bar namespace');
+
+</script>
+</body>
+</html>