зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #16933 - Implement MutationObserver childList mutations (from MortimerGoro:mutation_children); r=jdm
<!-- Please describe your changes on the following line: --> Implement MutationObserver childList mutations --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [x] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: 323760f47e79b49ef8db4484cca1969bc26b5413 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : d0d805444965d50fc48b8982521415f4ce30c7f8
This commit is contained in:
Родитель
8ab7ae19d1
Коммит
1ae18d00bb
|
@ -29,9 +29,10 @@ pub struct MutationObserver {
|
|||
record_queue: DOMRefCell<Vec<Root<MutationRecord>>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Mutation {
|
||||
Attribute { name: LocalName, namespace: Namespace, old_value: DOMString }
|
||||
pub enum Mutation<'a> {
|
||||
Attribute { name: LocalName, namespace: Namespace, old_value: DOMString },
|
||||
ChildList { added: Option<&'a [&'a Node]>, removed: Option<&'a [&'a Node]>,
|
||||
prev: Option<&'a Node>, next: Option<&'a Node> },
|
||||
}
|
||||
|
||||
#[derive(HeapSizeOf, JSTraceable)]
|
||||
|
@ -143,6 +144,12 @@ impl MutationObserver {
|
|||
interestedObservers.push((Root::from_ref(&*registered.observer),
|
||||
paired_string));
|
||||
}
|
||||
},
|
||||
Mutation::ChildList { .. } => {
|
||||
if !registered.options.child_list {
|
||||
continue;
|
||||
}
|
||||
interestedObservers.push((Root::from_ref(&*registered.observer), None));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -159,6 +166,9 @@ impl MutationObserver {
|
|||
None
|
||||
};
|
||||
MutationRecord::attribute_mutated(target, name, namespace, paired_string.clone())
|
||||
},
|
||||
Mutation::ChildList { ref added, ref removed, ref next, ref prev } => {
|
||||
MutationRecord::child_list_mutated(target, *added, *removed, *next, *prev)
|
||||
}
|
||||
};
|
||||
// Step 4.8
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
use dom::bindings::codegen::Bindings::MutationRecordBinding::MutationRecordBinding;
|
||||
use dom::bindings::codegen::Bindings::MutationRecordBinding::MutationRecordBinding::MutationRecordMethods;
|
||||
use dom::bindings::js::{JS, Root};
|
||||
use dom::bindings::js::{JS, MutNullableJS, Root};
|
||||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||
use dom::bindings::str::DOMString;
|
||||
use dom::node::{Node, window_from_node};
|
||||
|
@ -20,6 +20,10 @@ pub struct MutationRecord {
|
|||
attribute_name: Option<DOMString>,
|
||||
attribute_namespace: Option<DOMString>,
|
||||
old_value: Option<DOMString>,
|
||||
added_nodes: MutNullableJS<NodeList>,
|
||||
removed_nodes: MutNullableJS<NodeList>,
|
||||
next_sibling: Option<JS<Node>>,
|
||||
prev_sibling: Option<JS<Node>>,
|
||||
}
|
||||
|
||||
impl MutationRecord {
|
||||
|
@ -32,15 +36,40 @@ impl MutationRecord {
|
|||
target,
|
||||
Some(DOMString::from(&**attribute_name)),
|
||||
attribute_namespace.map(|n| DOMString::from(&**n)),
|
||||
old_value);
|
||||
old_value,
|
||||
None, None, None, None);
|
||||
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>) -> Root<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));
|
||||
|
||||
reflect_dom_object(box MutationRecord::new_inherited("childList",
|
||||
target,
|
||||
None, None, None,
|
||||
added_nodes.as_ref().map(|list| &**list),
|
||||
removed_nodes.as_ref().map(|list| &**list),
|
||||
next_sibling,
|
||||
prev_sibling),
|
||||
&*window,
|
||||
MutationRecordBinding::Wrap)
|
||||
}
|
||||
|
||||
fn new_inherited(record_type: &str,
|
||||
target: &Node,
|
||||
attribute_name: Option<DOMString>,
|
||||
attribute_namespace: Option<DOMString>,
|
||||
old_value: Option<DOMString>) -> MutationRecord {
|
||||
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),
|
||||
|
@ -48,6 +77,10 @@ impl MutationRecord {
|
|||
attribute_name: attribute_name,
|
||||
attribute_namespace: attribute_namespace,
|
||||
old_value: old_value,
|
||||
added_nodes: MutNullableJS::new(added_nodes),
|
||||
removed_nodes: MutNullableJS::new(removed_nodes),
|
||||
next_sibling: next_sibling.map(JS::from_ref),
|
||||
prev_sibling: prev_sibling.map(JS::from_ref),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,24 +113,28 @@ impl MutationRecordMethods for MutationRecord {
|
|||
|
||||
// https://dom.spec.whatwg.org/#dom-mutationrecord-addednodes
|
||||
fn AddedNodes(&self) -> Root<NodeList> {
|
||||
let window = window_from_node(&*self.target);
|
||||
NodeList::empty(&window)
|
||||
self.added_nodes.or_init(|| {
|
||||
let window = window_from_node(&*self.target);
|
||||
NodeList::empty(&window)
|
||||
})
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-mutationrecord-removednodes
|
||||
fn RemovedNodes(&self) -> Root<NodeList> {
|
||||
let window = window_from_node(&*self.target);
|
||||
NodeList::empty(&window)
|
||||
self.removed_nodes.or_init(|| {
|
||||
let window = window_from_node(&*self.target);
|
||||
NodeList::empty(&window)
|
||||
})
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-mutationrecord-previoussibling
|
||||
fn GetPreviousSibling(&self) -> Option<Root<Node>> {
|
||||
None
|
||||
self.prev_sibling.as_ref().map(|node| Root::from_ref(&**node))
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-mutationrecord-previoussibling
|
||||
fn GetNextSibling(&self) -> Option<Root<Node>> {
|
||||
None
|
||||
self.next_sibling.as_ref().map(|node| Root::from_ref(&**node))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ use dom::htmllinkelement::HTMLLinkElement;
|
|||
use dom::htmlmetaelement::HTMLMetaElement;
|
||||
use dom::htmlstyleelement::HTMLStyleElement;
|
||||
use dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers};
|
||||
use dom::mutationobserver::RegisteredObserver;
|
||||
use dom::mutationobserver::{Mutation, MutationObserver, RegisteredObserver};
|
||||
use dom::nodelist::NodeList;
|
||||
use dom::processinginstruction::ProcessingInstruction;
|
||||
use dom::range::WeakRangeVec;
|
||||
|
@ -1616,18 +1616,27 @@ impl Node {
|
|||
let new_nodes = if let NodeTypeId::DocumentFragment = node.type_id() {
|
||||
// Step 3.
|
||||
new_nodes.extend(node.children().map(|kid| JS::from_ref(&*kid)));
|
||||
// Step 4: mutation observers.
|
||||
// Step 5.
|
||||
// Step 4.
|
||||
for kid in new_nodes.r() {
|
||||
Node::remove(*kid, node, SuppressObserver::Suppressed);
|
||||
}
|
||||
// Step 5.
|
||||
vtable_for(&node).children_changed(&ChildrenMutation::replace_all(new_nodes.r(), &[]));
|
||||
|
||||
let mutation = Mutation::ChildList {
|
||||
added: None,
|
||||
removed: Some(new_nodes.r()),
|
||||
prev: None,
|
||||
next: None,
|
||||
};
|
||||
MutationObserver::queue_a_mutation_record(&node, mutation);
|
||||
|
||||
new_nodes.r()
|
||||
} else {
|
||||
// Step 3.
|
||||
ref_slice(&node)
|
||||
};
|
||||
// Step 6: mutation observers.
|
||||
// Step 6.
|
||||
let previous_sibling = match suppress_observers {
|
||||
SuppressObserver::Unsuppressed => {
|
||||
match child {
|
||||
|
@ -1646,6 +1655,14 @@ impl Node {
|
|||
if let SuppressObserver::Unsuppressed = suppress_observers {
|
||||
vtable_for(&parent).children_changed(
|
||||
&ChildrenMutation::insert(previous_sibling.r(), new_nodes, child));
|
||||
|
||||
let mutation = Mutation::ChildList {
|
||||
added: Some(new_nodes),
|
||||
removed: None,
|
||||
prev: previous_sibling.r(),
|
||||
next: child,
|
||||
};
|
||||
MutationObserver::queue_a_mutation_record(&parent, mutation);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1677,9 +1694,19 @@ impl Node {
|
|||
if let Some(node) = node {
|
||||
Node::insert(node, parent, None, SuppressObserver::Suppressed);
|
||||
}
|
||||
// Step 6: mutation observers.
|
||||
// Step 6.
|
||||
vtable_for(&parent).children_changed(
|
||||
&ChildrenMutation::replace_all(removed_nodes.r(), added_nodes));
|
||||
|
||||
if !removed_nodes.is_empty() || !added_nodes.is_empty() {
|
||||
let mutation = Mutation::ChildList {
|
||||
added: Some(added_nodes),
|
||||
removed: Some(removed_nodes.r()),
|
||||
prev: None,
|
||||
next: None,
|
||||
};
|
||||
MutationObserver::queue_a_mutation_record(&parent, mutation);
|
||||
}
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#concept-node-pre-remove
|
||||
|
@ -1730,6 +1757,15 @@ impl Node {
|
|||
&ChildrenMutation::replace(old_previous_sibling.r(),
|
||||
&Some(&node), &[],
|
||||
old_next_sibling.r()));
|
||||
|
||||
let removed = [node];
|
||||
let mutation = Mutation::ChildList {
|
||||
added: None,
|
||||
removed: Some(&removed),
|
||||
prev: old_previous_sibling.r(),
|
||||
next: old_next_sibling.r(),
|
||||
};
|
||||
MutationObserver::queue_a_mutation_record(&parent, mutation);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2182,6 +2218,14 @@ impl NodeMethods for Node {
|
|||
&ChildrenMutation::replace(previous_sibling.r(),
|
||||
&removed_child, nodes,
|
||||
reference_child));
|
||||
let removed = removed_child.map(|r| [r]);
|
||||
let mutation = Mutation::ChildList {
|
||||
added: Some(nodes),
|
||||
removed: removed.as_ref().map(|r| &r[..]),
|
||||
prev: previous_sibling.r(),
|
||||
next: reference_child,
|
||||
};
|
||||
MutationObserver::queue_a_mutation_record(&self, mutation);
|
||||
|
||||
// Step 15.
|
||||
Ok(Root::from_ref(child))
|
||||
|
|
|
@ -47,6 +47,10 @@ impl NodeList {
|
|||
NodeList::new(window, NodeListType::Simple(iter.map(|r| JS::from_ref(&*r)).collect()))
|
||||
}
|
||||
|
||||
pub fn new_simple_list_slice(window: &Window, slice: &[&Node]) -> Root<NodeList> {
|
||||
NodeList::new(window, NodeListType::Simple(slice.iter().map(|r| JS::from_ref(*r)).collect()))
|
||||
}
|
||||
|
||||
pub fn new_child_list(window: &Window, node: &Node) -> Root<NodeList> {
|
||||
NodeList::new(window, NodeListType::Children(ChildrenList::new(node)))
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче