aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathieu Hordesseaux <mathieu@adopteunmec.com>2015-12-23 17:21:45 +0100
committerMathieu Hordesseaux <mathieu@adopteunmec.com>2016-01-28 12:35:44 +0100
commit322b120f8a17876cb97b6d734cfde4f68a04c5cd (patch)
tree00dc3c08ec5d9b248e70db036b66a5987f0be06a
parentbc44ae679f0d4a01194777c56e09a48fbebea1ad (diff)
downloadservo-322b120f8a17876cb97b6d734cfde4f68a04c5cd.tar.gz
servo-322b120f8a17876cb97b6d734cfde4f68a04c5cd.zip
Implement SetNamedItem, SetNamedItemNS, SetAttributeNode and SetAttributeNodeNS
-rw-r--r--components/script/dom/attr.rs10
-rw-r--r--components/script/dom/element.rs64
-rw-r--r--components/script/dom/namednodemap.rs11
-rw-r--r--components/script/dom/webidls/Element.webidl5
-rw-r--r--components/script/dom/webidls/NamedNodeMap.webidl8
-rw-r--r--tests/wpt/metadata/dom/interfaces.html.ini24
-rw-r--r--tests/wpt/metadata/dom/nodes/attributes.html.ini15
-rw-r--r--tests/wpt/metadata/html/dom/interfaces.html.ini13
-rw-r--r--tests/wpt/metadata/html/dom/reflection-misc.html.ini1
-rw-r--r--tests/wpt/metadata/html/semantics/interfaces.html.ini1
-rw-r--r--tests/wpt/web-platform-tests/dom/nodes/attributes.html20
11 files changed, 105 insertions, 67 deletions
diff --git a/components/script/dom/attr.rs b/components/script/dom/attr.rs
index 34cb8537c86..ec7b999f5b9 100644
--- a/components/script/dom/attr.rs
+++ b/components/script/dom/attr.rs
@@ -193,16 +193,12 @@ impl Attr {
pub fn set_owner(&self, owner: Option<&Element>) {
let ns = &self.identifier.namespace;
match (self.owner().r(), owner) {
- (None, Some(new)) => {
- // Already in the list of attributes of new owner.
- assert!(new.get_attribute(&ns, &self.identifier.local_name) ==
- Some(Root::from_ref(self)))
- }
(Some(old), None) => {
// Already gone from the list of attributes of old owner.
- assert!(old.get_attribute(&ns, &self.identifier.local_name).is_none())
+ assert!(old.get_attribute(&ns, &self.identifier.local_name).r() != Some(self))
}
- (old, new) => assert!(old == new),
+ (Some(old), Some(new)) => assert!(old == new),
+ _ => {},
}
self.owner.set(owner);
}
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index 4fcdea83dcf..66cad82dbb8 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -863,9 +863,7 @@ impl Element {
name: Atom,
namespace: Namespace,
prefix: Option<Atom>) {
- self.will_mutate_attr();
let window = window_from_node(self);
- let in_empty_ns = namespace == ns!();
let attr = Attr::new(&window,
local_name,
value,
@@ -873,9 +871,15 @@ impl Element {
namespace,
prefix,
Some(self));
- self.attrs.borrow_mut().push(JS::from_rooted(&attr));
- if in_empty_ns {
- vtable_for(self.upcast()).attribute_mutated(&attr, AttributeMutation::Set(None));
+ self.push_attribute(&attr);
+ }
+
+ pub fn push_attribute(&self, attr: &Attr) {
+ assert!(attr.GetOwnerElement().r() == Some(self));
+ self.will_mutate_attr();
+ self.attrs.borrow_mut().push(JS::from_ref(attr));
+ if attr.namespace() == &ns!() {
+ vtable_for(self.upcast()).attribute_mutated(attr, AttributeMutation::Set(None));
}
}
@@ -1269,6 +1273,56 @@ impl ElementMethods for Element {
Ok(())
}
+ // https://dom.spec.whatwg.org/#dom-element-setattributenode
+ fn SetAttributeNode(&self, attr: &Attr) -> Fallible<Option<Root<Attr>>> {
+ // Step 1.
+ if let Some(owner) = attr.GetOwnerElement() {
+ if &*owner != self {
+ return Err(Error::InUseAttribute);
+ }
+ }
+
+ // Step 2.
+ let position = self.attrs.borrow().iter().position(|old_attr| {
+ attr.namespace() == old_attr.namespace() && attr.local_name() == old_attr.local_name()
+ });
+
+ if let Some(position) = position {
+
+ let old_attr = Root::from_ref(&*self.attrs.borrow()[position]);
+
+ // Step 3.
+ if old_attr.r() == attr {
+ return Ok(Some(Root::from_ref(attr)));
+ }
+
+ // Step 4.
+ self.will_mutate_attr();
+ attr.set_owner(Some(self));
+ self.attrs.borrow_mut()[position] = JS::from_ref(attr);
+ old_attr.set_owner(None);
+ if attr.namespace() == &ns!() {
+ vtable_for(self.upcast()).attribute_mutated(
+ &attr, AttributeMutation::Set(Some(&old_attr.value())));
+ }
+
+ // Step 6.
+ Ok(Some(old_attr))
+ } else {
+ // Step 5.
+ attr.set_owner(Some(self));
+ self.push_attribute(attr);
+
+ // Step 6.
+ Ok(None)
+ }
+ }
+
+ // https://dom.spec.whatwg.org/#dom-element-setattributenodens
+ fn SetAttributeNodeNS(&self, attr: &Attr) -> Fallible<Option<Root<Attr>>> {
+ self.SetAttributeNode(attr)
+ }
+
// https://dom.spec.whatwg.org/#dom-element-removeattribute
fn RemoveAttribute(&self, name: DOMString) {
let name = self.parsed_name(name);
diff --git a/components/script/dom/namednodemap.rs b/components/script/dom/namednodemap.rs
index 0bb7f438c8e..ca564f04e00 100644
--- a/components/script/dom/namednodemap.rs
+++ b/components/script/dom/namednodemap.rs
@@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::attr::Attr;
+use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
use dom::bindings::codegen::Bindings::NamedNodeMapBinding;
use dom::bindings::codegen::Bindings::NamedNodeMapBinding::NamedNodeMapMethods;
use dom::bindings::error::{Error, Fallible};
@@ -58,6 +59,16 @@ impl NamedNodeMapMethods for NamedNodeMap {
self.owner.get_attribute(&ns, &Atom::from(&*local_name))
}
+ // https://dom.spec.whatwg.org/#dom-namednodemap-setnameditem
+ fn SetNamedItem(&self, attr: &Attr) -> Fallible<Option<Root<Attr>>> {
+ self.owner.SetAttributeNode(attr)
+ }
+
+ // https://dom.spec.whatwg.org/#dom-namednodemap-setnameditemns
+ fn SetNamedItemNS(&self, attr: &Attr) -> Fallible<Option<Root<Attr>>> {
+ self.SetNamedItem(attr)
+ }
+
// https://dom.spec.whatwg.org/#dom-namednodemap-removenameditem
fn RemoveNamedItem(&self, name: DOMString) -> Fallible<Root<Attr>> {
let name = self.owner.parsed_name(name);
diff --git a/components/script/dom/webidls/Element.webidl b/components/script/dom/webidls/Element.webidl
index 2e3deb6adb0..1a9b74bb9f2 100644
--- a/components/script/dom/webidls/Element.webidl
+++ b/components/script/dom/webidls/Element.webidl
@@ -50,6 +50,11 @@ interface Element : Node {
boolean hasAttribute(DOMString name);
boolean hasAttributeNS(DOMString? namespace, DOMString localName);
+ [Throws]
+ Attr? setAttributeNode(Attr attr);
+ [Throws]
+ Attr? setAttributeNodeNS(Attr attr);
+
[Pure, Throws]
Element? closest(DOMString selectors);
diff --git a/components/script/dom/webidls/NamedNodeMap.webidl b/components/script/dom/webidls/NamedNodeMap.webidl
index 235de06a802..581c8dc7e89 100644
--- a/components/script/dom/webidls/NamedNodeMap.webidl
+++ b/components/script/dom/webidls/NamedNodeMap.webidl
@@ -13,10 +13,10 @@ interface NamedNodeMap {
getter Attr? getNamedItem(DOMString name);
[Pure]
Attr? getNamedItemNS(DOMString? namespace, DOMString localName);
- //[Throws]
- //Attr? setNamedItem(Attr attr);
- //[Throws]
- //Attr? setNamedItemNS(Attr attr);
+ [Throws]
+ Attr? setNamedItem(Attr attr);
+ [Throws]
+ Attr? setNamedItemNS(Attr attr);
[Throws]
Attr removeNamedItem(DOMString name);
[Throws]
diff --git a/tests/wpt/metadata/dom/interfaces.html.ini b/tests/wpt/metadata/dom/interfaces.html.ini
index 0a7aab7b33b..837106ef25f 100644
--- a/tests/wpt/metadata/dom/interfaces.html.ini
+++ b/tests/wpt/metadata/dom/interfaces.html.ini
@@ -108,12 +108,6 @@
[Element interface: operation hasAttributes()]
expected: FAIL
- [Element interface: operation setAttributeNode(Attr)]
- expected: FAIL
-
- [Element interface: operation setAttributeNodeNS(Attr)]
- expected: FAIL
-
[Element interface: operation removeAttributeNode(Attr)]
expected: FAIL
@@ -126,18 +120,6 @@
[Element interface: element must inherit property "hasAttributes" with the proper type (7)]
expected: FAIL
- [Element interface: element must inherit property "setAttributeNode" with the proper type (19)]
- expected: FAIL
-
- [Element interface: calling setAttributeNode(Attr) on element with too few arguments must throw TypeError]
- expected: FAIL
-
- [Element interface: element must inherit property "setAttributeNodeNS" with the proper type (20)]
- expected: FAIL
-
- [Element interface: calling setAttributeNodeNS(Attr) on element with too few arguments must throw TypeError]
- expected: FAIL
-
[Element interface: element must inherit property "removeAttributeNode" with the proper type (21)]
expected: FAIL
@@ -156,12 +138,6 @@
[Element interface: calling queryAll(DOMString) on element with too few arguments must throw TypeError]
expected: FAIL
- [NamedNodeMap interface: operation setNamedItem(Attr)]
- expected: FAIL
-
- [NamedNodeMap interface: operation setNamedItemNS(Attr)]
- expected: FAIL
-
[Range interface: stringifier]
expected: FAIL
diff --git a/tests/wpt/metadata/dom/nodes/attributes.html.ini b/tests/wpt/metadata/dom/nodes/attributes.html.ini
index 709c462e36f..88db1baa145 100644
--- a/tests/wpt/metadata/dom/nodes/attributes.html.ini
+++ b/tests/wpt/metadata/dom/nodes/attributes.html.ini
@@ -1,17 +1,8 @@
[attributes.html]
type: testharness
- [Basic functionality of setAttributeNode]
- expected: FAIL
-
[Basic functionality of removeAttributeNode]
expected: FAIL
- [setAttributeNode on bound attribute should throw InUseAttributeError]
- expected: FAIL
-
- [Basic functionality of setAttributeNodeNS]
- expected: FAIL
-
[getAttributeNames tests]
expected: FAIL
@@ -27,12 +18,6 @@
[Own property correctness with two namespaced attributes with the same name-with-prefix]
expected: FAIL
- [setAttributeNode, if it fires mutation events, should fire one with the new node when resetting an existing attribute (outer shell)]
- expected: FAIL
-
- [setAttributeNode called with an Attr that has the same name as an existing one should not change attribute order]
- expected: FAIL
-
[Own property names should only include all-lowercase qualified names for an HTML element in an HTML document]
expected: FAIL
diff --git a/tests/wpt/metadata/html/dom/interfaces.html.ini b/tests/wpt/metadata/html/dom/interfaces.html.ini
index 02806e334df..ee818164602 100644
--- a/tests/wpt/metadata/html/dom/interfaces.html.ini
+++ b/tests/wpt/metadata/html/dom/interfaces.html.ini
@@ -2013,18 +2013,6 @@
[Element interface: document.createElement("noscript") must inherit property "hasAttributes" with the proper type (7)]
expected: FAIL
- [Element interface: document.createElement("noscript") must inherit property "setAttributeNode" with the proper type (19)]
- expected: FAIL
-
- [Element interface: calling setAttributeNode(Attr) on document.createElement("noscript") with too few arguments must throw TypeError]
- expected: FAIL
-
- [Element interface: document.createElement("noscript") must inherit property "setAttributeNodeNS" with the proper type (20)]
- expected: FAIL
-
- [Element interface: calling setAttributeNodeNS(Attr) on document.createElement("noscript") with too few arguments must throw TypeError]
- expected: FAIL
-
[Element interface: document.createElement("noscript") must inherit property "removeAttributeNode" with the proper type (21)]
expected: FAIL
@@ -9101,3 +9089,4 @@
[WebSocket interface: new WebSocket("ws://foo") must inherit property "extensions" with the proper type (10)]
expected: FAIL
+
diff --git a/tests/wpt/metadata/html/dom/reflection-misc.html.ini b/tests/wpt/metadata/html/dom/reflection-misc.html.ini
index 1f073b67a59..048c7bb3b18 100644
--- a/tests/wpt/metadata/html/dom/reflection-misc.html.ini
+++ b/tests/wpt/metadata/html/dom/reflection-misc.html.ini
@@ -12998,3 +12998,4 @@
[dialog.itemId: IDL set to object "test-valueOf" followed by IDL get]
expected: FAIL
+
diff --git a/tests/wpt/metadata/html/semantics/interfaces.html.ini b/tests/wpt/metadata/html/semantics/interfaces.html.ini
index 76f2cd96b22..19feaad44c3 100644
--- a/tests/wpt/metadata/html/semantics/interfaces.html.ini
+++ b/tests/wpt/metadata/html/semantics/interfaces.html.ini
@@ -59,3 +59,4 @@
[Interfaces for RTC]
expected: FAIL
+
diff --git a/tests/wpt/web-platform-tests/dom/nodes/attributes.html b/tests/wpt/web-platform-tests/dom/nodes/attributes.html
index e331389ff85..76a501c37ca 100644
--- a/tests/wpt/web-platform-tests/dom/nodes/attributes.html
+++ b/tests/wpt/web-platform-tests/dom/nodes/attributes.html
@@ -447,6 +447,26 @@ test(function() {
}, "Basic functionality of setAttributeNodeNS")
test(function() {
+ var el = document.createElement("div");
+ var other = document.createElement("div");
+ attr = document.createAttribute("foo");
+ assert_equals(el.setAttributeNode(attr), null);
+ assert_equals(attr.ownerElement, el);
+ assert_throws("INUSE_ATTRIBUTE_ERR",
+ function() { other.setAttributeNode(attr) },
+ "Attribute already associated with el")
+}, "If attr’s element is neither null nor element, throw an InUseAttributeError.");
+
+test(function() {
+ var el = document.createElement("div");
+ attr = document.createAttribute("foo");
+ assert_equals(el.setAttributeNode(attr), null);
+ el.setAttribute("bar", "qux");
+ assert_equals(el.setAttributeNode(attr), attr);
+ assert_equals(el.attributes[0], attr);
+}, "Replacing an attr by itself");
+
+test(function() {
var el = document.createElement("div")
el.setAttribute("foo", "bar")
var attrNode = el.getAttributeNode("foo");