diff options
author | bors-servo <metajack+bors@gmail.com> | 2015-07-10 06:44:25 -0600 |
---|---|---|
committer | bors-servo <metajack+bors@gmail.com> | 2015-07-10 06:44:25 -0600 |
commit | 52e857dd7b9b083d691efab088aeba80888c61ff (patch) | |
tree | 77c449b1fecb01d4938800e6fbe525eebdd24125 | |
parent | 314483a97f29a7e75c46a6e7ffb580bbc5f0ad9b (diff) | |
parent | 326b2a7161892f739f525338ee2813d7aa620e2f (diff) | |
download | servo-52e857dd7b9b083d691efab088aeba80888c61ff.tar.gz servo-52e857dd7b9b083d691efab088aeba80888c61ff.zip |
Auto merge of #6561 - dzbarsky:namespace, r=Ms2ger
Implement Node#isDefaultNamespace and Node#lookupNamespaceURI (fixes #1826)
<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/6561)
<!-- Reviewable:end -->
-rw-r--r-- | components/script/dom/element.rs | 5 | ||||
-rw-r--r-- | components/script/dom/node.rs | 97 | ||||
-rw-r--r-- | tests/wpt/metadata/MANIFEST.json | 4 | ||||
-rw-r--r-- | tests/wpt/web-platform-tests/dom/nodes/Node-lookupNamespaceURI.html | 119 |
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> |