diff options
-rw-r--r-- | components/script/dom/attr.rs | 2 | ||||
-rw-r--r-- | components/script/dom/characterdata.rs | 12 | ||||
-rw-r--r-- | components/script/dom/element.rs | 6 | ||||
-rw-r--r-- | components/script/dom/mutationobserver.rs | 48 | ||||
-rw-r--r-- | components/script/dom/mutationrecord.rs | 59 | ||||
-rw-r--r-- | components/script/dom/webidls/MutationObserver.webidl | 2 | ||||
-rw-r--r-- | tests/wpt/metadata/dom/nodes/MutationObserver-attributes.html.ini | 24 | ||||
-rw-r--r-- | tests/wpt/metadata/dom/nodes/MutationObserver-characterData.html.ini | 48 | ||||
-rw-r--r-- | tests/wpt/metadata/dom/nodes/MutationObserver-takeRecords.html.ini | 9 |
9 files changed, 98 insertions, 112 deletions
diff --git a/components/script/dom/attr.rs b/components/script/dom/attr.rs index 0f6a0b6c96a..333b2ae413e 100644 --- a/components/script/dom/attr.rs +++ b/components/script/dom/attr.rs @@ -185,7 +185,7 @@ impl Attr { let mutation = Mutation::Attribute { name: name.clone(), namespace: namespace.clone(), - old_value: old_value.clone(), + old_value: Some(old_value.clone()), }; MutationObserver::queue_a_mutation_record(owner.upcast::<Node>(), mutation); diff --git a/components/script/dom/characterdata.rs b/components/script/dom/characterdata.rs index ade3060ceb0..ade189739c3 100644 --- a/components/script/dom/characterdata.rs +++ b/components/script/dom/characterdata.rs @@ -17,6 +17,7 @@ use dom::bindings::str::DOMString; use dom::comment::Comment; use dom::document::Document; use dom::element::Element; +use dom::mutationobserver::{Mutation, MutationObserver}; use dom::node::{ChildrenMutation, Node, NodeDamage}; use dom::processinginstruction::ProcessingInstruction; use dom::text::Text; @@ -81,6 +82,14 @@ impl CharacterData { } } } + + // Queue a MutationObserver record before changing the content. + fn queue_mutation_record(&self) { + let mutation = Mutation::CharacterData { + old_value: self.data.borrow().clone(), + }; + MutationObserver::queue_a_mutation_record(self.upcast::<Node>(), mutation); + } } impl CharacterDataMethods for CharacterData { @@ -91,6 +100,7 @@ impl CharacterDataMethods for CharacterData { // https://dom.spec.whatwg.org/#dom-characterdata-data fn SetData(&self, data: DOMString) { + self.queue_mutation_record(); let old_length = self.Length(); let new_length = data.encode_utf16().count() as u32; *self.data.borrow_mut() = data; @@ -193,6 +203,8 @@ impl CharacterDataMethods for CharacterData { } }; // Step 4: Mutation observers. + self.queue_mutation_record(); + // Step 5 to 7. new_data = String::with_capacity( prefix.len() + diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 11b9168eb41..00a2fee7513 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -1163,16 +1163,16 @@ impl Element { pub fn push_attribute(&self, attr: &Attr) { let name = attr.local_name().clone(); let namespace = attr.namespace().clone(); - let value = DOMString::from(&**attr.value()); let mutation = Mutation::Attribute { name: name.clone(), namespace: namespace.clone(), - old_value: value.clone(), + old_value: None, }; MutationObserver::queue_a_mutation_record(&self.node, mutation); if self.get_custom_element_definition().is_some() { + let value = DOMString::from(&**attr.value()); let reaction = CallbackReaction::AttributeChanged(name, None, Some(value), namespace); ScriptThread::enqueue_callback_reaction(self, reaction, None); } @@ -1311,7 +1311,7 @@ impl Element { let mutation = Mutation::Attribute { name: name.clone(), namespace: namespace.clone(), - old_value: old_value.clone(), + old_value: Some(old_value.clone()), }; MutationObserver::queue_a_mutation_record(&self.node, mutation); diff --git a/components/script/dom/mutationobserver.rs b/components/script/dom/mutationobserver.rs index 902f0dcce97..97b4ca36d27 100644 --- a/components/script/dom/mutationobserver.rs +++ b/components/script/dom/mutationobserver.rs @@ -30,7 +30,8 @@ pub struct MutationObserver { } pub enum Mutation<'a> { - Attribute { name: LocalName, namespace: Namespace, old_value: DOMString }, + Attribute { name: LocalName, namespace: Namespace, old_value: Option<DOMString> }, + CharacterData { old_value: DOMString }, ChildList { added: Option<&'a [&'a Node]>, removed: Option<&'a [&'a Node]>, prev: Option<&'a Node>, next: Option<&'a Node> }, } @@ -110,7 +111,8 @@ impl MutationObserver { return; } // Step 1 - let mut interestedObservers: Vec<(DomRoot<MutationObserver>, Option<DOMString>)> = vec![]; + let mut interested_observers: Vec<(DomRoot<MutationObserver>, Option<DOMString>)> = vec![]; + // Step 2 & 3 for node in target.inclusive_ancestors() { for registered in &*node.registered_mutation_observers() { @@ -135,32 +137,52 @@ impl MutationObserver { } // Step 3.1.2 let paired_string = if registered.options.attribute_old_value { + old_value.clone() + } else { + None + }; + // Step 3.1.1 + let idx = interested_observers.iter().position(|&(ref o, _)| + &**o as *const _ == &*registered.observer as *const _); + if let Some(idx) = idx { + interested_observers[idx].1 = paired_string; + } else { + interested_observers.push((DomRoot::from_ref(&*registered.observer), + paired_string)); + } + }, + Mutation::CharacterData { ref old_value } => { + if !registered.options.character_data { + continue; + } + // Step 3.1.2 + let paired_string = if registered.options.character_data_old_value { Some(old_value.clone()) } else { None }; // Step 3.1.1 - let idx = interestedObservers.iter().position(|&(ref o, _)| + let idx = interested_observers.iter().position(|&(ref o, _)| &**o as *const _ == &*registered.observer as *const _); if let Some(idx) = idx { - interestedObservers[idx].1 = paired_string; + interested_observers[idx].1 = paired_string; } else { - interestedObservers.push((DomRoot::from_ref(&*registered.observer), - paired_string)); + interested_observers.push((DomRoot::from_ref(&*registered.observer), + paired_string)); } }, Mutation::ChildList { .. } => { if !registered.options.child_list { continue; } - interestedObservers.push((DomRoot::from_ref(&*registered.observer), None)); + interested_observers.push((DomRoot::from_ref(&*registered.observer), None)); } } } } // Step 4 - for &(ref observer, ref paired_string) in &interestedObservers { + for &(ref observer, ref paired_string) in &interested_observers { // Steps 4.1-4.7 let record = match attr_type { Mutation::Attribute { ref name, ref namespace, .. } => { @@ -171,6 +193,9 @@ impl MutationObserver { }; MutationRecord::attribute_mutated(target, name, namespace, paired_string.clone()) }, + Mutation::CharacterData { .. } => { + MutationRecord::character_data_mutated(target, paired_string.clone()) + } Mutation::ChildList { ref added, ref removed, ref next, ref prev } => { MutationRecord::child_list_mutated(target, *added, *removed, *next, *prev) } @@ -265,4 +290,11 @@ impl MutationObserverMethods for MutationObserver { Ok(()) } + + /// https://dom.spec.whatwg.org/#dom-mutationobserver-takerecords + fn TakeRecords(&self) -> Vec<DomRoot<MutationRecord>> { + let records: Vec<DomRoot<MutationRecord>> = self.record_queue.borrow().clone(); + self.record_queue.borrow_mut().clear(); + records + } } diff --git a/components/script/dom/mutationrecord.rs b/components/script/dom/mutationrecord.rs index dff1a7c0b85..bc41b384a8a 100644 --- a/components/script/dom/mutationrecord.rs +++ b/components/script/dom/mutationrecord.rs @@ -28,10 +28,12 @@ pub struct MutationRecord { impl MutationRecord { #[allow(unrooted_must_root)] - pub fn attribute_mutated(target: &Node, - attribute_name: &LocalName, - attribute_namespace: Option<&Namespace>, - old_value: Option<DOMString>) -> DomRoot<MutationRecord> { + pub fn attribute_mutated( + target: &Node, + attribute_name: &LocalName, + attribute_namespace: Option<&Namespace>, + old_value: Option<DOMString>, + ) -> DomRoot<MutationRecord> { let record = Box::new(MutationRecord::new_inherited( "attributes", target, @@ -43,11 +45,30 @@ impl MutationRecord { reflect_dom_object(record, &*window_from_node(target), MutationRecordBinding::Wrap) } - pub fn child_list_mutated(target: &Node, - added_nodes: Option<&[&Node]>, - removed_nodes: Option<&[&Node]>, - next_sibling: Option<&Node>, - prev_sibling: Option<&Node>) -> DomRoot<MutationRecord> { + pub fn character_data_mutated( + target: &Node, + old_value: Option<DOMString>, + ) -> DomRoot<MutationRecord> { + reflect_dom_object( + Box::new(MutationRecord::new_inherited( + "characterData", + target, + None, None, + old_value, + None, None, None, None + )), + &*window_from_node(target), + MutationRecordBinding::Wrap + ) + } + + pub fn child_list_mutated( + target: &Node, + added_nodes: Option<&[&Node]>, + removed_nodes: Option<&[&Node]>, + next_sibling: Option<&Node>, + prev_sibling: Option<&Node>, + ) -> DomRoot<MutationRecord> { let window = window_from_node(target); let added_nodes = added_nodes.map(|list| NodeList::new_simple_list_slice(&window, list)); let removed_nodes = removed_nodes.map(|list| NodeList::new_simple_list_slice(&window, list)); @@ -67,15 +88,17 @@ impl MutationRecord { ) } - fn new_inherited(record_type: &str, - target: &Node, - attribute_name: Option<DOMString>, - attribute_namespace: Option<DOMString>, - old_value: Option<DOMString>, - added_nodes: Option<&NodeList>, - removed_nodes: Option<&NodeList>, - next_sibling: Option<&Node>, - prev_sibling: Option<&Node>) -> MutationRecord { + fn new_inherited( + record_type: &str, + target: &Node, + attribute_name: Option<DOMString>, + attribute_namespace: Option<DOMString>, + old_value: Option<DOMString>, + added_nodes: Option<&NodeList>, + removed_nodes: Option<&NodeList>, + next_sibling: Option<&Node>, + prev_sibling: Option<&Node>, + ) -> MutationRecord { MutationRecord { reflector_: Reflector::new(), record_type: DOMString::from(record_type), diff --git a/components/script/dom/webidls/MutationObserver.webidl b/components/script/dom/webidls/MutationObserver.webidl index 738c711d8e7..015686c47d9 100644 --- a/components/script/dom/webidls/MutationObserver.webidl +++ b/components/script/dom/webidls/MutationObserver.webidl @@ -12,7 +12,7 @@ interface MutationObserver { [Throws] void observe(Node target, optional MutationObserverInit options); //void disconnect(); - //sequence<MutationRecord> takeRecords(); + sequence<MutationRecord> takeRecords(); }; callback MutationCallback = void (sequence<MutationRecord> mutations, MutationObserver observer); diff --git a/tests/wpt/metadata/dom/nodes/MutationObserver-attributes.html.ini b/tests/wpt/metadata/dom/nodes/MutationObserver-attributes.html.ini index 52a6a920412..a1151d55ada 100644 --- a/tests/wpt/metadata/dom/nodes/MutationObserver-attributes.html.ini +++ b/tests/wpt/metadata/dom/nodes/MutationObserver-attributes.html.ini @@ -1,28 +1,5 @@ [MutationObserver-attributes.html] type: testharness - [attributes Element.id: same value mutation] - expected: FAIL - - [attributes Element.className: new value mutation] - expected: FAIL - - [attributes Element.classList.add: single token addition mutation] - expected: FAIL - - [attributes Element.classList.add: multiple tokens addition mutation] - expected: FAIL - - [attributes Element.setAttribute: classname mutation] - expected: FAIL - - [attributes Element.setAttributeNS: creation mutation] - expected: FAIL - - [attributes Element.setAttributeNS: prefixed attribute creation mutation] - expected: FAIL - - [attributes Element.className: empty string update mutation] - expected: FAIL [attributes/attributeFilter Element.id/Element.className: update mutation] expected: FAIL @@ -32,4 +9,3 @@ [attributeFilter alone Element.id/Element.className: multiple filter update mutation] expected: FAIL - diff --git a/tests/wpt/metadata/dom/nodes/MutationObserver-characterData.html.ini b/tests/wpt/metadata/dom/nodes/MutationObserver-characterData.html.ini index 6e8512d76d9..7bc63c0cfe6 100644 --- a/tests/wpt/metadata/dom/nodes/MutationObserver-characterData.html.ini +++ b/tests/wpt/metadata/dom/nodes/MutationObserver-characterData.html.ini @@ -1,11 +1,6 @@ [MutationObserver-characterData.html] type: testharness expected: TIMEOUT - [characterData Text.data: simple mutation without oldValue] - expected: TIMEOUT - - [characterData Text.data: simple mutation] - expected: TIMEOUT [characterData Text.appendData: simple mutation] expected: TIMEOUT @@ -15,46 +10,3 @@ [characterData Text.appendData: null string mutation] expected: TIMEOUT - - [characterData Text.insertData: simple mutation] - expected: TIMEOUT - - [characterData Text.insertData: empty string mutation] - expected: TIMEOUT - - [characterData Text.insertData: null string mutation] - expected: TIMEOUT - - [characterData Text.deleteData: simple mutation] - expected: TIMEOUT - - [characterData Text.deleteData: empty mutation] - expected: TIMEOUT - - [characterData Text.replaceData: simple mutation] - expected: TIMEOUT - - [characterData Text.replaceData: empty mutation] - expected: TIMEOUT - - [characterData ProcessingInstruction: data mutations] - expected: TIMEOUT - - [characterData Comment: data mutations] - expected: TIMEOUT - - [characterData Range.deleteContents: child and data removal mutation] - expected: TIMEOUT - - [characterData Range.deleteContents: child and data removal mutation (2)] - expected: TIMEOUT - - [characterData Range.extractContents: child and data removal mutation] - expected: TIMEOUT - - [characterData Range.extractContents: child and data removal mutation (2)] - expected: TIMEOUT - - [characterData/characterDataOldValue alone Text.data: simple mutation] - expected: TIMEOUT - diff --git a/tests/wpt/metadata/dom/nodes/MutationObserver-takeRecords.html.ini b/tests/wpt/metadata/dom/nodes/MutationObserver-takeRecords.html.ini index be8b8f2cc8a..a8c6f2f7575 100644 --- a/tests/wpt/metadata/dom/nodes/MutationObserver-takeRecords.html.ini +++ b/tests/wpt/metadata/dom/nodes/MutationObserver-takeRecords.html.ini @@ -1,11 +1,2 @@ [MutationObserver-takeRecords.html] type: testharness - [unreachabled test] - expected: FAIL - - [All records present] - expected: FAIL - - [No more records present] - expected: FAIL - |