aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/script/dom/attr.rs2
-rw-r--r--components/script/dom/characterdata.rs12
-rw-r--r--components/script/dom/element.rs6
-rw-r--r--components/script/dom/mutationobserver.rs48
-rw-r--r--components/script/dom/mutationrecord.rs59
-rw-r--r--components/script/dom/webidls/MutationObserver.webidl2
-rw-r--r--tests/wpt/metadata/dom/nodes/MutationObserver-attributes.html.ini24
-rw-r--r--tests/wpt/metadata/dom/nodes/MutationObserver-characterData.html.ini48
-rw-r--r--tests/wpt/metadata/dom/nodes/MutationObserver-takeRecords.html.ini9
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
-