mirror of
https://github.com/servo/servo.git
synced 2025-07-30 18:50:36 +01:00
Auto merge of #16883 - jdm:mutationobserver, r=jdm
Mutation Observer API Rebased from #16668. - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix (partially) #6633 - [X] There are tests for these changes <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/16883) <!-- Reviewable:end -->
This commit is contained in:
commit
5da0aa9f11
15 changed files with 432 additions and 180 deletions
|
@ -10,6 +10,8 @@ use dom::bindings::js::{LayoutJS, MutNullableJS, Root, RootedReference};
|
||||||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||||
use dom::bindings::str::DOMString;
|
use dom::bindings::str::DOMString;
|
||||||
use dom::element::{AttributeMutation, Element};
|
use dom::element::{AttributeMutation, Element};
|
||||||
|
use dom::mutationobserver::{Mutation, MutationObserver};
|
||||||
|
use dom::node::Node;
|
||||||
use dom::virtualmethods::vtable_for;
|
use dom::virtualmethods::vtable_for;
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
|
@ -170,6 +172,12 @@ impl AttrMethods for Attr {
|
||||||
|
|
||||||
impl Attr {
|
impl Attr {
|
||||||
pub fn set_value(&self, mut value: AttrValue, owner: &Element) {
|
pub fn set_value(&self, mut value: AttrValue, owner: &Element) {
|
||||||
|
let name = self.local_name().clone();
|
||||||
|
let namespace = self.namespace().clone();
|
||||||
|
let old_value = DOMString::from(&**self.value());
|
||||||
|
let mutation = Mutation::Attribute { name, namespace, old_value };
|
||||||
|
MutationObserver::queue_a_mutation_record(owner.upcast::<Node>(), mutation);
|
||||||
|
|
||||||
assert!(Some(owner) == self.owner().r());
|
assert!(Some(owner) == self.owner().r());
|
||||||
owner.will_mutate_attr(self);
|
owner.will_mutate_attr(self);
|
||||||
self.swap_value(&mut value);
|
self.swap_value(&mut value);
|
||||||
|
|
|
@ -63,6 +63,7 @@ use dom::htmltablerowelement::{HTMLTableRowElement, HTMLTableRowElementLayoutHel
|
||||||
use dom::htmltablesectionelement::{HTMLTableSectionElement, HTMLTableSectionElementLayoutHelpers};
|
use dom::htmltablesectionelement::{HTMLTableSectionElement, HTMLTableSectionElementLayoutHelpers};
|
||||||
use dom::htmltemplateelement::HTMLTemplateElement;
|
use dom::htmltemplateelement::HTMLTemplateElement;
|
||||||
use dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers};
|
use dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers};
|
||||||
|
use dom::mutationobserver::{Mutation, MutationObserver};
|
||||||
use dom::namednodemap::NamedNodeMap;
|
use dom::namednodemap::NamedNodeMap;
|
||||||
use dom::node::{CLICK_IN_PROGRESS, ChildrenMutation, LayoutNodeHelpers, Node};
|
use dom::node::{CLICK_IN_PROGRESS, ChildrenMutation, LayoutNodeHelpers, Node};
|
||||||
use dom::node::{NodeDamage, SEQUENTIALLY_FOCUSABLE, UnbindContext};
|
use dom::node::{NodeDamage, SEQUENTIALLY_FOCUSABLE, UnbindContext};
|
||||||
|
@ -1003,6 +1004,12 @@ impl Element {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_attribute(&self, attr: &Attr) {
|
pub fn push_attribute(&self, attr: &Attr) {
|
||||||
|
let name = attr.local_name().clone();
|
||||||
|
let namespace = attr.namespace().clone();
|
||||||
|
let old_value = DOMString::from(&**attr.value());
|
||||||
|
let mutation = Mutation::Attribute { name, namespace, old_value };
|
||||||
|
MutationObserver::queue_a_mutation_record(&self.node, mutation);
|
||||||
|
|
||||||
assert!(attr.GetOwnerElement().r() == Some(self));
|
assert!(attr.GetOwnerElement().r() == Some(self));
|
||||||
self.will_mutate_attr(attr);
|
self.will_mutate_attr(attr);
|
||||||
self.attrs.borrow_mut().push(JS::from_ref(attr));
|
self.attrs.borrow_mut().push(JS::from_ref(attr));
|
||||||
|
@ -1125,13 +1132,18 @@ impl Element {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_first_matching_attribute<F>(&self, find: F) -> Option<Root<Attr>>
|
fn remove_first_matching_attribute<F>(&self, find: F) -> Option<Root<Attr>>
|
||||||
where F: Fn(&Attr) -> bool
|
where F: Fn(&Attr) -> bool {
|
||||||
{
|
|
||||||
let idx = self.attrs.borrow().iter().position(|attr| find(&attr));
|
let idx = self.attrs.borrow().iter().position(|attr| find(&attr));
|
||||||
|
|
||||||
idx.map(|idx| {
|
idx.map(|idx| {
|
||||||
let attr = Root::from_ref(&*(*self.attrs.borrow())[idx]);
|
let attr = Root::from_ref(&*(*self.attrs.borrow())[idx]);
|
||||||
self.will_mutate_attr(&attr);
|
self.will_mutate_attr(&attr);
|
||||||
|
|
||||||
|
let name = attr.local_name().clone();
|
||||||
|
let namespace = attr.namespace().clone();
|
||||||
|
let old_value = DOMString::from(&**attr.value());
|
||||||
|
let mutation = Mutation::Attribute { name, namespace, old_value, };
|
||||||
|
MutationObserver::queue_a_mutation_record(&self.node, mutation);
|
||||||
|
|
||||||
self.attrs.borrow_mut().remove(idx);
|
self.attrs.borrow_mut().remove(idx);
|
||||||
attr.set_owner(None);
|
attr.set_owner(None);
|
||||||
if attr.namespace() == &ns!() {
|
if attr.namespace() == &ns!() {
|
||||||
|
|
|
@ -2,13 +2,22 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use dom::bindings::callback::ExceptionHandling;
|
||||||
|
use dom::bindings::cell::DOMRefCell;
|
||||||
use dom::bindings::codegen::Bindings::MutationObserverBinding;
|
use dom::bindings::codegen::Bindings::MutationObserverBinding;
|
||||||
use dom::bindings::codegen::Bindings::MutationObserverBinding::MutationCallback;
|
use dom::bindings::codegen::Bindings::MutationObserverBinding::MutationCallback;
|
||||||
use dom::bindings::error::Fallible;
|
use dom::bindings::codegen::Bindings::MutationObserverBinding::MutationObserverBinding::MutationObserverMethods;
|
||||||
use dom::bindings::js::Root;
|
use dom::bindings::codegen::Bindings::MutationObserverBinding::MutationObserverInit;
|
||||||
|
use dom::bindings::error::{Error, Fallible};
|
||||||
|
use dom::bindings::js::{JS, Root};
|
||||||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||||
|
use dom::bindings::str::DOMString;
|
||||||
|
use dom::mutationrecord::MutationRecord;
|
||||||
|
use dom::node::Node;
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
|
use html5ever::{Namespace, LocalName};
|
||||||
|
use microtask::Microtask;
|
||||||
use script_thread::ScriptThread;
|
use script_thread::ScriptThread;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
@ -17,6 +26,29 @@ pub struct MutationObserver {
|
||||||
reflector_: Reflector,
|
reflector_: Reflector,
|
||||||
#[ignore_heap_size_of = "can't measure Rc values"]
|
#[ignore_heap_size_of = "can't measure Rc values"]
|
||||||
callback: Rc<MutationCallback>,
|
callback: Rc<MutationCallback>,
|
||||||
|
record_queue: DOMRefCell<Vec<Root<MutationRecord>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Mutation {
|
||||||
|
Attribute { name: LocalName, namespace: Namespace, old_value: DOMString }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(HeapSizeOf, JSTraceable)]
|
||||||
|
pub struct RegisteredObserver {
|
||||||
|
observer: Root<MutationObserver>,
|
||||||
|
options: ObserverOptions,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(HeapSizeOf, JSTraceable)]
|
||||||
|
pub struct ObserverOptions {
|
||||||
|
attribute_old_value: bool,
|
||||||
|
attributes: bool,
|
||||||
|
character_data: bool,
|
||||||
|
character_data_old_value: bool,
|
||||||
|
child_list: bool,
|
||||||
|
subtree: bool,
|
||||||
|
attribute_filter: Vec<DOMString>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MutationObserver {
|
impl MutationObserver {
|
||||||
|
@ -29,6 +61,7 @@ impl MutationObserver {
|
||||||
MutationObserver {
|
MutationObserver {
|
||||||
reflector_: Reflector::new(),
|
reflector_: Reflector::new(),
|
||||||
callback: callback,
|
callback: callback,
|
||||||
|
record_queue: DOMRefCell::new(vec![]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,4 +70,185 @@ impl MutationObserver {
|
||||||
ScriptThread::add_mutation_observer(&*observer);
|
ScriptThread::add_mutation_observer(&*observer);
|
||||||
Ok(observer)
|
Ok(observer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// https://dom.spec.whatwg.org/#queue-a-mutation-observer-compound-microtask
|
||||||
|
pub fn queue_mutation_observer_compound_microtask() {
|
||||||
|
// Step 1
|
||||||
|
if ScriptThread::is_mutation_observer_compound_microtask_queued() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Step 2
|
||||||
|
ScriptThread::set_mutation_observer_compound_microtask_queued(true);
|
||||||
|
// Step 3
|
||||||
|
ScriptThread::enqueue_microtask(Microtask::NotifyMutationObservers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// https://dom.spec.whatwg.org/#notify-mutation-observers
|
||||||
|
pub fn notify_mutation_observers() {
|
||||||
|
// Step 1
|
||||||
|
ScriptThread::set_mutation_observer_compound_microtask_queued(false);
|
||||||
|
// Step 2
|
||||||
|
let notify_list = ScriptThread::get_mutation_observers();
|
||||||
|
// TODO: steps 3-4 (slots)
|
||||||
|
// Step 5
|
||||||
|
for mo in ¬ify_list {
|
||||||
|
let queue: Vec<Root<MutationRecord>> = mo.record_queue.borrow().clone();
|
||||||
|
mo.record_queue.borrow_mut().clear();
|
||||||
|
// TODO: Step 5.3 Remove all transient registered observers whose observer is mo.
|
||||||
|
if !queue.is_empty() {
|
||||||
|
let _ = mo.callback.Call_(&**mo, queue, &**mo, ExceptionHandling::Report);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: Step 6 (slot signals)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// https://dom.spec.whatwg.org/#queueing-a-mutation-record
|
||||||
|
pub fn queue_a_mutation_record(target: &Node, attr_type: Mutation) {
|
||||||
|
// Step 1
|
||||||
|
let mut interestedObservers: Vec<(Root<MutationObserver>, Option<DOMString>)> = vec![];
|
||||||
|
// Step 2 & 3
|
||||||
|
for node in target.inclusive_ancestors() {
|
||||||
|
for registered in &*node.registered_mutation_observers() {
|
||||||
|
if &*node != target && !registered.options.subtree {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
match attr_type {
|
||||||
|
Mutation::Attribute { ref name, ref namespace, ref old_value } => {
|
||||||
|
// Step 3.1
|
||||||
|
if !registered.options.attributes {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if !registered.options.attribute_filter.is_empty() {
|
||||||
|
if *namespace != ns!() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if registered.options.attribute_filter.iter()
|
||||||
|
.find(|s| &**s == &**name).is_some() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Step 3.1.2
|
||||||
|
let paired_string = if registered.options.attribute_old_value {
|
||||||
|
Some(old_value.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
// Step 3.1.1
|
||||||
|
let idx = interestedObservers.iter().position(|&(ref o, _)|
|
||||||
|
&**o as *const _ == &*registered.observer as *const _);
|
||||||
|
if let Some(idx) = idx {
|
||||||
|
interestedObservers[idx].1 = paired_string;
|
||||||
|
} else {
|
||||||
|
interestedObservers.push((Root::from_ref(&*registered.observer),
|
||||||
|
paired_string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4
|
||||||
|
for &(ref observer, ref paired_string) in &interestedObservers {
|
||||||
|
// Steps 4.1-4.7
|
||||||
|
let record = match attr_type {
|
||||||
|
Mutation::Attribute { ref name, ref namespace, .. } => {
|
||||||
|
let namespace = if *namespace != ns!() {
|
||||||
|
Some(namespace)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
MutationRecord::attribute_mutated(target, name, namespace, paired_string.clone())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Step 4.8
|
||||||
|
observer.record_queue.borrow_mut().push(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5
|
||||||
|
MutationObserver::queue_mutation_observer_compound_microtask();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MutationObserverMethods for MutationObserver {
|
||||||
|
/// https://dom.spec.whatwg.org/#dom-mutationobserver-observe
|
||||||
|
fn Observe(&self, target: &Node, options: &MutationObserverInit) -> Fallible<()> {
|
||||||
|
let attribute_filter = options.attributeFilter.clone().unwrap_or(vec![]);
|
||||||
|
let attribute_old_value = options.attributeOldValue.unwrap_or(false);
|
||||||
|
let mut attributes = options.attributes.unwrap_or(false);
|
||||||
|
let mut character_data = options.characterData.unwrap_or(false);
|
||||||
|
let character_data_old_value = options.characterDataOldValue.unwrap_or(false);
|
||||||
|
let child_list = options.childList;
|
||||||
|
let subtree = options.subtree;
|
||||||
|
|
||||||
|
// Step 1
|
||||||
|
if (options.attributeOldValue.is_some() || options.attributeFilter.is_some()) &&
|
||||||
|
options.attributes.is_none() {
|
||||||
|
attributes = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2
|
||||||
|
if options.characterDataOldValue.is_some() && options.characterData.is_none() {
|
||||||
|
character_data = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3
|
||||||
|
if !child_list && !attributes && !character_data {
|
||||||
|
return Err(Error::Type("One of childList, attributes, or characterData must be true".into()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4
|
||||||
|
if attribute_old_value && !attributes {
|
||||||
|
return Err(Error::Type("attributeOldValue is true but attributes is false".into()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5
|
||||||
|
if options.attributeFilter.is_some() && !attributes {
|
||||||
|
return Err(Error::Type("attributeFilter is present but attributes is false".into()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6
|
||||||
|
if character_data_old_value && !character_data {
|
||||||
|
return Err(Error::Type("characterDataOldValue is true but characterData is false".into()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 7
|
||||||
|
let add_new_observer = {
|
||||||
|
let mut replaced = false;
|
||||||
|
for registered in &mut *target.registered_mutation_observers() {
|
||||||
|
if &*registered.observer as *const MutationObserver != self as *const MutationObserver {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// TODO: remove matching transient registered observers
|
||||||
|
registered.options.attribute_old_value = attribute_old_value;
|
||||||
|
registered.options.attributes = attributes;
|
||||||
|
registered.options.character_data = character_data;
|
||||||
|
registered.options.character_data_old_value = character_data_old_value;
|
||||||
|
registered.options.child_list = child_list;
|
||||||
|
registered.options.subtree = subtree;
|
||||||
|
registered.options.attribute_filter = attribute_filter.clone();
|
||||||
|
replaced = true;
|
||||||
|
}
|
||||||
|
!replaced
|
||||||
|
};
|
||||||
|
|
||||||
|
// Step 8
|
||||||
|
if add_new_observer {
|
||||||
|
target.registered_mutation_observers().push(RegisteredObserver {
|
||||||
|
observer: Root::from_ref(self),
|
||||||
|
options: ObserverOptions {
|
||||||
|
attributes,
|
||||||
|
attribute_old_value,
|
||||||
|
character_data,
|
||||||
|
character_data_old_value,
|
||||||
|
subtree,
|
||||||
|
attribute_filter,
|
||||||
|
child_list
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,22 +2,54 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use dom::bindings::codegen::Bindings::MutationRecordBinding::MutationRecordBinding;
|
||||||
use dom::bindings::codegen::Bindings::MutationRecordBinding::MutationRecordBinding::MutationRecordMethods;
|
use dom::bindings::codegen::Bindings::MutationRecordBinding::MutationRecordBinding::MutationRecordMethods;
|
||||||
use dom::bindings::js::{JS, Root};
|
use dom::bindings::js::{JS, Root};
|
||||||
use dom::bindings::reflector::Reflector;
|
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||||
use dom::bindings::str::DOMString;
|
use dom::bindings::str::DOMString;
|
||||||
use dom::node::Node;
|
use dom::node::{Node, window_from_node};
|
||||||
|
use dom::nodelist::NodeList;
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
|
use html5ever::{LocalName, Namespace};
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct MutationRecord {
|
pub struct MutationRecord {
|
||||||
reflector_: Reflector,
|
reflector_: Reflector,
|
||||||
|
|
||||||
//property for record type
|
|
||||||
record_type: DOMString,
|
record_type: DOMString,
|
||||||
|
|
||||||
//property for target node
|
|
||||||
target: JS<Node>,
|
target: JS<Node>,
|
||||||
|
attribute_name: Option<DOMString>,
|
||||||
|
attribute_namespace: Option<DOMString>,
|
||||||
|
old_value: Option<DOMString>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MutationRecord {
|
||||||
|
#[allow(unrooted_must_root)]
|
||||||
|
pub fn attribute_mutated(target: &Node,
|
||||||
|
attribute_name: &LocalName,
|
||||||
|
attribute_namespace: Option<&Namespace>,
|
||||||
|
old_value: Option<DOMString>) -> Root<MutationRecord> {
|
||||||
|
let record = box MutationRecord::new_inherited("attributes",
|
||||||
|
target,
|
||||||
|
Some(DOMString::from(&**attribute_name)),
|
||||||
|
attribute_namespace.map(|n| DOMString::from(&**n)),
|
||||||
|
old_value);
|
||||||
|
reflect_dom_object(record, &*window_from_node(target), MutationRecordBinding::Wrap)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_inherited(record_type: &str,
|
||||||
|
target: &Node,
|
||||||
|
attribute_name: Option<DOMString>,
|
||||||
|
attribute_namespace: Option<DOMString>,
|
||||||
|
old_value: Option<DOMString>) -> MutationRecord {
|
||||||
|
MutationRecord {
|
||||||
|
reflector_: Reflector::new(),
|
||||||
|
record_type: DOMString::from(record_type),
|
||||||
|
target: JS::from_ref(target),
|
||||||
|
attribute_name: attribute_name,
|
||||||
|
attribute_namespace: attribute_namespace,
|
||||||
|
old_value: old_value,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MutationRecordMethods for MutationRecord {
|
impl MutationRecordMethods for MutationRecord {
|
||||||
|
@ -28,7 +60,44 @@ impl MutationRecordMethods for MutationRecord {
|
||||||
|
|
||||||
// https://dom.spec.whatwg.org/#dom-mutationrecord-target
|
// https://dom.spec.whatwg.org/#dom-mutationrecord-target
|
||||||
fn Target(&self) -> Root<Node> {
|
fn Target(&self) -> Root<Node> {
|
||||||
return Root::from_ref(&*self.target);
|
Root::from_ref(&*self.target)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://dom.spec.whatwg.org/#dom-mutationrecord-attributename
|
||||||
|
fn GetAttributeName(&self) -> Option<DOMString> {
|
||||||
|
self.attribute_name.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://dom.spec.whatwg.org/#dom-mutationrecord-attributenamespace
|
||||||
|
fn GetAttributeNamespace(&self) -> Option<DOMString> {
|
||||||
|
self.attribute_namespace.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://dom.spec.whatwg.org/#dom-mutationrecord-oldvalue
|
||||||
|
fn GetOldValue(&self) -> Option<DOMString> {
|
||||||
|
self.old_value.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://dom.spec.whatwg.org/#dom-mutationrecord-addednodes
|
||||||
|
fn AddedNodes(&self) -> Root<NodeList> {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://dom.spec.whatwg.org/#dom-mutationrecord-previoussibling
|
||||||
|
fn GetPreviousSibling(&self) -> Option<Root<Node>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://dom.spec.whatwg.org/#dom-mutationrecord-previoussibling
|
||||||
|
fn GetNextSibling(&self) -> Option<Root<Node>> {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use devtools_traits::NodeInfo;
|
use devtools_traits::NodeInfo;
|
||||||
use document_loader::DocumentLoader;
|
use document_loader::DocumentLoader;
|
||||||
|
use dom::bindings::cell::DOMRefCell;
|
||||||
use dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
|
use dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
|
||||||
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
|
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
|
||||||
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
|
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
|
||||||
|
@ -46,6 +47,7 @@ use dom::htmllinkelement::HTMLLinkElement;
|
||||||
use dom::htmlmetaelement::HTMLMetaElement;
|
use dom::htmlmetaelement::HTMLMetaElement;
|
||||||
use dom::htmlstyleelement::HTMLStyleElement;
|
use dom::htmlstyleelement::HTMLStyleElement;
|
||||||
use dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers};
|
use dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers};
|
||||||
|
use dom::mutationobserver::RegisteredObserver;
|
||||||
use dom::nodelist::NodeList;
|
use dom::nodelist::NodeList;
|
||||||
use dom::processinginstruction::ProcessingInstruction;
|
use dom::processinginstruction::ProcessingInstruction;
|
||||||
use dom::range::WeakRangeVec;
|
use dom::range::WeakRangeVec;
|
||||||
|
@ -72,7 +74,7 @@ use selectors::matching::matches_selector_list;
|
||||||
use selectors::parser::SelectorList;
|
use selectors::parser::SelectorList;
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
use std::cell::{Cell, UnsafeCell};
|
use std::cell::{Cell, UnsafeCell, RefMut};
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
@ -138,6 +140,9 @@ pub struct Node {
|
||||||
/// node is finalized.
|
/// node is finalized.
|
||||||
style_and_layout_data: Cell<Option<OpaqueStyleAndLayoutData>>,
|
style_and_layout_data: Cell<Option<OpaqueStyleAndLayoutData>>,
|
||||||
|
|
||||||
|
/// Registered observers for this node.
|
||||||
|
mutation_observers: DOMRefCell<Vec<RegisteredObserver>>,
|
||||||
|
|
||||||
unique_id: UniqueId,
|
unique_id: UniqueId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,6 +368,11 @@ impl Node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return all registered mutation observers for this node.
|
||||||
|
pub fn registered_mutation_observers(&self) -> RefMut<Vec<RegisteredObserver>> {
|
||||||
|
self.mutation_observers.borrow_mut()
|
||||||
|
}
|
||||||
|
|
||||||
/// Dumps the subtree rooted at this node, for debugging.
|
/// Dumps the subtree rooted at this node, for debugging.
|
||||||
pub fn dump(&self) {
|
pub fn dump(&self) {
|
||||||
self.dump_indent(0);
|
self.dump_indent(0);
|
||||||
|
@ -1411,6 +1421,8 @@ impl Node {
|
||||||
|
|
||||||
style_and_layout_data: Cell::new(None),
|
style_and_layout_data: Cell::new(None),
|
||||||
|
|
||||||
|
mutation_observers: Default::default(),
|
||||||
|
|
||||||
unique_id: UniqueId::new(),
|
unique_id: UniqueId::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
// https://dom.spec.whatwg.org/#mutationobserver
|
// https://dom.spec.whatwg.org/#mutationobserver
|
||||||
[Pref="dom.mutation_observer.enabled", Constructor(MutationCallback callback)]
|
[Pref="dom.mutation_observer.enabled", Constructor(MutationCallback callback)]
|
||||||
interface MutationObserver {
|
interface MutationObserver {
|
||||||
//void observe(Node target, optional MutationObserverInit options);
|
[Throws]
|
||||||
|
void observe(Node target, optional MutationObserverInit options);
|
||||||
//void disconnect();
|
//void disconnect();
|
||||||
//sequence<MutationRecord> takeRecords();
|
//sequence<MutationRecord> takeRecords();
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,13 +12,13 @@ interface MutationRecord {
|
||||||
readonly attribute DOMString type;
|
readonly attribute DOMString type;
|
||||||
[SameObject]
|
[SameObject]
|
||||||
readonly attribute Node target;
|
readonly attribute Node target;
|
||||||
//[SameObject]
|
[SameObject]
|
||||||
//readonly attribute NodeList addedNodes;
|
readonly attribute NodeList addedNodes;
|
||||||
//[SameObject]
|
[SameObject]
|
||||||
//readonly attribute NodeList removedNodes;
|
readonly attribute NodeList removedNodes;
|
||||||
//readonly attribute Node? previousSibling;
|
readonly attribute Node? previousSibling;
|
||||||
//readonly attribute Node? nextSibling;
|
readonly attribute Node? nextSibling;
|
||||||
//readonly attribute DOMString? attributeName;
|
readonly attribute DOMString? attributeName;
|
||||||
//readonly attribute DOMString? attributeNamespace;
|
readonly attribute DOMString? attributeNamespace;
|
||||||
//readonly attribute DOMString? oldValue;
|
readonly attribute DOMString? oldValue;
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,6 +11,7 @@ use dom::bindings::cell::DOMRefCell;
|
||||||
use dom::bindings::codegen::Bindings::PromiseBinding::PromiseJobCallback;
|
use dom::bindings::codegen::Bindings::PromiseBinding::PromiseJobCallback;
|
||||||
use dom::bindings::js::Root;
|
use dom::bindings::js::Root;
|
||||||
use dom::globalscope::GlobalScope;
|
use dom::globalscope::GlobalScope;
|
||||||
|
use dom::mutationobserver::MutationObserver;
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
@ -28,6 +29,7 @@ pub struct MicrotaskQueue {
|
||||||
#[derive(JSTraceable, HeapSizeOf)]
|
#[derive(JSTraceable, HeapSizeOf)]
|
||||||
pub enum Microtask {
|
pub enum Microtask {
|
||||||
Promise(EnqueuedPromiseCallback),
|
Promise(EnqueuedPromiseCallback),
|
||||||
|
NotifyMutationObservers,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A promise callback scheduled to run during the next microtask checkpoint (#4283).
|
/// A promise callback scheduled to run during the next microtask checkpoint (#4283).
|
||||||
|
@ -71,6 +73,9 @@ impl MicrotaskQueue {
|
||||||
let _ = job.callback.Call_(&*target, ExceptionHandling::Report);
|
let _ = job.callback.Call_(&*target, ExceptionHandling::Report);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Microtask::NotifyMutationObservers => {
|
||||||
|
MutationObserver::notify_mutation_observers();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -481,6 +481,9 @@ pub struct ScriptThread {
|
||||||
|
|
||||||
microtask_queue: MicrotaskQueue,
|
microtask_queue: MicrotaskQueue,
|
||||||
|
|
||||||
|
/// Microtask Queue for adding support for mutation observer microtasks
|
||||||
|
mutation_observer_compound_microtask_queued: Cell<bool>,
|
||||||
|
|
||||||
/// The unit of related similar-origin browsing contexts' list of MutationObserver objects
|
/// The unit of related similar-origin browsing contexts' list of MutationObserver objects
|
||||||
mutation_observers: DOMRefCell<Vec<JS<MutationObserver>>>,
|
mutation_observers: DOMRefCell<Vec<JS<MutationObserver>>>,
|
||||||
|
|
||||||
|
@ -589,6 +592,20 @@ impl ScriptThread {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_mutation_observer_compound_microtask_queued(value: bool) {
|
||||||
|
SCRIPT_THREAD_ROOT.with(|root| {
|
||||||
|
let script_thread = unsafe { &*root.get().unwrap() };
|
||||||
|
script_thread.mutation_observer_compound_microtask_queued.set(value);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_mutation_observer_compound_microtask_queued() -> bool {
|
||||||
|
SCRIPT_THREAD_ROOT.with(|root| {
|
||||||
|
let script_thread = unsafe { &*root.get().unwrap() };
|
||||||
|
return script_thread.mutation_observer_compound_microtask_queued.get();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_mutation_observer(observer: &MutationObserver) {
|
pub fn add_mutation_observer(observer: &MutationObserver) {
|
||||||
SCRIPT_THREAD_ROOT.with(|root| {
|
SCRIPT_THREAD_ROOT.with(|root| {
|
||||||
let script_thread = unsafe { &*root.get().unwrap() };
|
let script_thread = unsafe { &*root.get().unwrap() };
|
||||||
|
@ -598,6 +615,13 @@ impl ScriptThread {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_mutation_observers() -> Vec<Root<MutationObserver>> {
|
||||||
|
SCRIPT_THREAD_ROOT.with(|root| {
|
||||||
|
let script_thread = unsafe { &*root.get().unwrap() };
|
||||||
|
script_thread.mutation_observers.borrow().iter().map(|o| Root::from_ref(&**o)).collect()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn mark_document_with_no_blocked_loads(doc: &Document) {
|
pub fn mark_document_with_no_blocked_loads(doc: &Document) {
|
||||||
SCRIPT_THREAD_ROOT.with(|root| {
|
SCRIPT_THREAD_ROOT.with(|root| {
|
||||||
let script_thread = unsafe { &*root.get().unwrap() };
|
let script_thread = unsafe { &*root.get().unwrap() };
|
||||||
|
@ -750,6 +774,8 @@ impl ScriptThread {
|
||||||
|
|
||||||
microtask_queue: MicrotaskQueue::default(),
|
microtask_queue: MicrotaskQueue::default(),
|
||||||
|
|
||||||
|
mutation_observer_compound_microtask_queued: Default::default(),
|
||||||
|
|
||||||
mutation_observers: Default::default(),
|
mutation_observers: Default::default(),
|
||||||
|
|
||||||
layout_to_constellation_chan: state.layout_to_constellation_chan,
|
layout_to_constellation_chan: state.layout_to_constellation_chan,
|
||||||
|
|
|
@ -30,13 +30,13 @@ macro_rules! sizeof_checker (
|
||||||
|
|
||||||
// Update the sizes here
|
// Update the sizes here
|
||||||
sizeof_checker!(size_event_target, EventTarget, 40);
|
sizeof_checker!(size_event_target, EventTarget, 40);
|
||||||
sizeof_checker!(size_node, Node, 152);
|
sizeof_checker!(size_node, Node, 184);
|
||||||
sizeof_checker!(size_element, Element, 320);
|
sizeof_checker!(size_element, Element, 352);
|
||||||
sizeof_checker!(size_htmlelement, HTMLElement, 336);
|
sizeof_checker!(size_htmlelement, HTMLElement, 368);
|
||||||
sizeof_checker!(size_div, HTMLDivElement, 336);
|
sizeof_checker!(size_div, HTMLDivElement, 368);
|
||||||
sizeof_checker!(size_span, HTMLSpanElement, 336);
|
sizeof_checker!(size_span, HTMLSpanElement, 368);
|
||||||
sizeof_checker!(size_text, Text, 184);
|
sizeof_checker!(size_text, Text, 216);
|
||||||
sizeof_checker!(size_characterdata, CharacterData, 184);
|
sizeof_checker!(size_characterdata, CharacterData, 216);
|
||||||
sizeof_checker!(size_servothreadsafelayoutnode, ServoThreadSafeLayoutNode, 16);
|
sizeof_checker!(size_servothreadsafelayoutnode, ServoThreadSafeLayoutNode, 16);
|
||||||
|
|
||||||
// We use these types in the parallel traversal. They should stay pointer-sized.
|
// We use these types in the parallel traversal. They should stay pointer-sized.
|
||||||
|
|
|
@ -1,114 +1,27 @@
|
||||||
[MutationObserver-attributes.html]
|
[MutationObserver-attributes.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
[attributes Element.id: update, no oldValue, mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.id: update mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.id: empty string update mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.id: same value mutation]
|
[attributes Element.id: same value mutation]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[attributes Element.unknown: IDL attribute no mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes HTMLInputElement.type: type update mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.className: new value mutation]
|
[attributes Element.className: new value mutation]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[attributes Element.className: empty string update mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.className: same value mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.className: same multiple values mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.classList.add: single token addition mutation]
|
[attributes Element.classList.add: single token addition mutation]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[attributes Element.classList.add: multiple tokens addition mutation]
|
[attributes Element.classList.add: multiple tokens addition mutation]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[attributes Element.classList.add: syntax err/no mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.classList.add: invalid character/no mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.classList.add: same value mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.classList.remove: single token removal mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.classList.remove: multiple tokens removal mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.classList.remove: missing token removal mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.classList.toggle: token removal mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.classList.toggle: token addition mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.classList.toggle: forced token removal mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.classList.toggle: forced missing token removal no mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.classList.toggle: forced existing token addition no mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.classList.toggle: forced token addition mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.attributes.value: update mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.attributes.value: same id mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.setAttribute: id mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.setAttribute: same class mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.setAttribute: classname mutation]
|
[attributes Element.setAttribute: classname mutation]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[attributes Element.removeAttribute: removal mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.removeAttribute: removal no mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[childList HTMLInputElement.removeAttribute: type removal mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.setAttributeNS: creation mutation]
|
[attributes Element.setAttributeNS: creation mutation]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[attributes Element.setAttributeNS: prefixed attribute creation mutation]
|
[attributes Element.setAttributeNS: prefixed attribute creation mutation]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[attributes Element.removeAttributeNS: removal mutation]
|
[attributes Element.className: empty string update mutation]
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.removeAttributeNS: removal no mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributes Element.removeAttributeNS: prefixed attribute removal no mutation]
|
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[attributes/attributeFilter Element.id/Element.className: update mutation]
|
[attributes/attributeFilter Element.id/Element.className: update mutation]
|
||||||
|
@ -117,12 +30,6 @@
|
||||||
[attributes/attributeFilter Element.id/Element.className: multiple filter update mutation]
|
[attributes/attributeFilter Element.id/Element.className: multiple filter update mutation]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[attributeOldValue alone Element.id: update mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[attributeFilter alone Element.id/Element.className: multiple filter update mutation]
|
[attributeFilter alone Element.id/Element.className: multiple filter update mutation]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[childList false: no childList mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -1,59 +1,60 @@
|
||||||
[MutationObserver-characterData.html]
|
[MutationObserver-characterData.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
|
expected: TIMEOUT
|
||||||
[characterData Text.data: simple mutation without oldValue]
|
[characterData Text.data: simple mutation without oldValue]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[characterData Text.data: simple mutation]
|
[characterData Text.data: simple mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[characterData Text.appendData: simple mutation]
|
[characterData Text.appendData: simple mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[characterData Text.appendData: empty string mutation]
|
[characterData Text.appendData: empty string mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[characterData Text.appendData: null string mutation]
|
[characterData Text.appendData: null string mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[characterData Text.insertData: simple mutation]
|
[characterData Text.insertData: simple mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[characterData Text.insertData: empty string mutation]
|
[characterData Text.insertData: empty string mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[characterData Text.insertData: null string mutation]
|
[characterData Text.insertData: null string mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[characterData Text.deleteData: simple mutation]
|
[characterData Text.deleteData: simple mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[characterData Text.deleteData: empty mutation]
|
[characterData Text.deleteData: empty mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[characterData Text.replaceData: simple mutation]
|
[characterData Text.replaceData: simple mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[characterData Text.replaceData: empty mutation]
|
[characterData Text.replaceData: empty mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[characterData ProcessingInstruction: data mutations]
|
[characterData ProcessingInstruction: data mutations]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[characterData Comment: data mutations]
|
[characterData Comment: data mutations]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[characterData Range.deleteContents: child and data removal mutation]
|
[characterData Range.deleteContents: child and data removal mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[characterData Range.deleteContents: child and data removal mutation (2)]
|
[characterData Range.deleteContents: child and data removal mutation (2)]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[characterData Range.extractContents: child and data removal mutation]
|
[characterData Range.extractContents: child and data removal mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[characterData Range.extractContents: child and data removal mutation (2)]
|
[characterData Range.extractContents: child and data removal mutation (2)]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[characterData/characterDataOldValue alone Text.data: simple mutation]
|
[characterData/characterDataOldValue alone Text.data: simple mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
|
|
|
@ -1,95 +1,90 @@
|
||||||
[MutationObserver-childList.html]
|
[MutationObserver-childList.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
[childList Node.nodeValue: no mutation]
|
expected: TIMEOUT
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[childList Node.textContent: replace content mutation]
|
[childList Node.textContent: replace content mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Node.textContent: no previous content mutation]
|
[childList Node.textContent: no previous content mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Node.textContent: textContent no mutation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[childList Node.textContent: empty string mutation]
|
[childList Node.textContent: empty string mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Node.normalize mutation]
|
[childList Node.normalize mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Node.normalize mutations]
|
[childList Node.normalize mutations]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Node.insertBefore: addition mutation]
|
[childList Node.insertBefore: addition mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Node.insertBefore: removal mutation]
|
[childList Node.insertBefore: removal mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Node.insertBefore: removal and addition mutations]
|
[childList Node.insertBefore: removal and addition mutations]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Node.insertBefore: fragment addition mutations]
|
[childList Node.insertBefore: fragment addition mutations]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Node.insertBefore: fragment removal mutations]
|
[childList Node.insertBefore: fragment removal mutations]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Node.insertBefore: last child addition mutation]
|
[childList Node.insertBefore: last child addition mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Node.appendChild: addition mutation]
|
[childList Node.appendChild: addition mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Node.appendChild: removal mutation]
|
[childList Node.appendChild: removal mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Node.appendChild: removal and addition mutations]
|
[childList Node.appendChild: removal and addition mutations]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Node.appendChild: fragment addition mutations]
|
[childList Node.appendChild: fragment addition mutations]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Node.appendChild: fragment removal mutations]
|
[childList Node.appendChild: fragment removal mutations]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Node.appendChild: addition outside document tree mutation]
|
[childList Node.appendChild: addition outside document tree mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Node.replaceChild: replacement mutation]
|
[childList Node.replaceChild: replacement mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Node.replaceChild: removal mutation]
|
[childList Node.replaceChild: removal mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Node.replaceChild: internal replacement mutation]
|
[childList Node.replaceChild: internal replacement mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Node.removeChild: removal mutation]
|
[childList Node.removeChild: removal mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Range.deleteContents: child removal mutation]
|
[childList Range.deleteContents: child removal mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Range.deleteContents: child and data removal mutation]
|
[childList Range.deleteContents: child and data removal mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Range.extractContents: child removal mutation]
|
[childList Range.extractContents: child removal mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Range.extractContents: child and data removal mutation]
|
[childList Range.extractContents: child and data removal mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Range.insertNode: child insertion mutation]
|
[childList Range.insertNode: child insertion mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Range.insertNode: children insertion mutation]
|
[childList Range.insertNode: children insertion mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Range.surroundContents: children removal and addition mutation]
|
[childList Range.surroundContents: children removal and addition mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[childList Node.replaceChild: self internal replacement mutation]
|
[childList Node.replaceChild: self internal replacement mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
[MutationObserver-inner-outer.html]
|
[MutationObserver-inner-outer.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
|
expected: TIMEOUT
|
||||||
[innerHTML mutation]
|
[innerHTML mutation]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[innerHTML with 2 children mutation]
|
[innerHTML with 2 children mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[outerHTML mutation]
|
[outerHTML mutation]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
|
|
|
@ -2,3 +2,4 @@
|
||||||
type: testharness
|
type: testharness
|
||||||
[Adopting a node should make it same-origin-domain.]
|
[Adopting a node should make it same-origin-domain.]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue