-
-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement mutation observers #6633
Comments
cc @nox |
Colour me interested. Why do you think mutation observers are the way to go for DOM ranges? |
Note that these aren't the DOM mutation observers, just an internal servo thing that lets ranges register a callback for when the document changes. It's similar to nsIMutationObserver in Gecko. |
That sounds confusingly named, in that case :) |
True it could use a different name. MutationWatcher or something. |
I'm not sure how that PR helps here. There's not really a great way for nodes to know that they're the start or end of some range. |
I made |
That's a lot of storage. I think it's better to store that Vec on the document itself, that's basically what I'm doing in #6639 |
With a Vec on the document itself, children_changed() could still be used in the VirtualMethods implementation of Node to update any range associated to the context object, or actually the insert methods and friends could do it themselves too, couldn't they? Why the indirection with this MutationObserver thing? |
I can see children_changed being used for some of the notifications, but I'm not sure how you'd handle some other cases. For example, there are steps to run when calling CharacterData#replaceData, or Node#normalize. As for the MutationObserver thing... One thing to keep in mind is that NodeIterator also defines "removing steps" (https://dom.spec.whatwg.org/#nodeiterator). Having played around with it some I think the MutationObserver abstraction isn't necessary yet and just makes things more complicated for now so I'm tempted to drop it. |
I'm on the Range part. |
This depends on #4283 |
#1980 also covers this. We should close one of them. |
Question regarding test cases : We have completed the initial steps and we are now moving to the subsequent steps. |
I expect that the existing tests should provide enough coverage; my only worry is if they also require features that your project will not implement. It would be useful to create a simple test case that only uses the features that you are implementing in your project; it can live in tests/wpt/mozilla/tests/mozilla/. |
Hi, I am implementing the subsequent steps of the Mutation Observer API as described here: https://github.com/servo/servo/wiki/Mutation-observer-project I am stuck at the step 3 of the notify mutation observers algorithm. I am not sure how to get the "copy of unit of related similar-origin browsing contexts' signal slot list. " This is what I have implemented in the impl MicrotaskQueue of microtask.rs file so far: /// https://dom.spec.whatwg.org/#notify-mutation-observers
/// Notify Mutation Observers.
pub fn notifyMutationObservers() {
SCRIPT_THREAD_ROOT.with(|root| {
let script_thread = unsafe { &*root.get().unwrap() };
// Step 1
script_thread.mutation_observer_compound_microtask_queued.borrow_mut() = false;
// Step 2
let notifyList = script_thread.mutation_observers.borrow_mut();
// Step 3
let signalList = ""; // Stuck;
// Step 4
// ??
});
} Can you please point us in the right direction? Thanks. |
Servo doesn't implement anything related to slots, so you can leave |
While implementing the MutationObserver.observe method, In steps 3-6 it says that we need to throw a TypeError, but I could not find any specification for 'TypeError'. |
Unfortunately we don't implement step 1 of those APIs in Servo yet, or that would have been a good idea! Throwing exceptions occurs automatically when returning an Err value from DOM APIs, but also requires that the WebIDL method be marked |
Hi, I am trying to implement the subsequent steps of the Mutation Observer API as described here: https://github.com/servo/servo/wiki/Mutation-observer-project. I am a bit confused regarding - make changing/appending/removing/replacing an attribute queue a mutation record via Attr::set_value, Element::push_attribute, and Element::remove_first_matching_attribute. In order to change or append or remove or replace an attribute, I am unsure if I need to modify the existing methods like setAttribute or removeAttribute as seen in the element.rs file? Or I need to implement any such related methods in some other file? Can you please help me? Thanks! |
The algorithms at https://dom.spec.whatwg.org/#concept-element-attributes-change all involve queuing a mutation record as the first step before actually modifying the element's attribute. You'll want to modify the existing methods to add that behaviour, since they are the fundamental building blocks that other APIs like setAttribute and removeAttribute are built upon. Does that make sense? |
@srivassumit Oh, tough luck. In other words, the field type of 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);
})
} |
@srivassumit For your observe method, I'm actually quite surprised that you need to mutate the |
@KiChjang For the Observe Method this is my code: /// https://dom.spec.whatwg.org/#dom-mutationobserver-observe
/// MutationObserver.observe method
fn Observe(&self, target: &Node, options: &MutationObserverInit) -> Fallible<()> {
// Step 1: If either options’ attributeOldValue or attributeFilter is present and
// options’ attributes is omitted, set options’ attributes to true.
if (options.attributeOldValue.is_some() || options.attributeFilter.is_some()) && options.attributes.is_none() {
options.borrow_mut().attributes = Some(true);
}
// Step2: If options’ characterDataOldValue is present and options’ characterData is omitted,
// set options’ characterData to true.
if options.characterDataOldValue.is_some() && options.characterData.is_some() {
options.borrow_mut().characterData = Some(true);
}
// Step3: If none of options’ childList, attributes, and characterData is true, throw a TypeError.
if !options.childList && !options.attributes.unwrap() && !options.characterData.unwrap() {
return Err(Error::Type("childList, attributes, and characterData not true".to_owned()));
}
// Step4: If options’ attributeOldValue is true and options’ attributes is false, throw a TypeError.
if options.attributeOldValue.unwrap() && !options.attributes.unwrap() {
return Err(Error::Type("attributeOldValue is true but attributes is false".to_owned()));
}
// Step5: If options’ attributeFilter is present and options’ attributes is false, throw a TypeError.
if options.attributeFilter.is_some() && !options.attributes.unwrap() {
return Err(Error::Type("attributeFilter is present but attributes is false".to_owned()));
}
// Step6: If options’ characterDataOldValue is true and options’ characterData is false, throw a TypeError.
if options.characterDataOldValue.unwrap() && !options.characterData.unwrap() {
return Err(Error::Type("characterDataOldValue is true but characterData is false".to_owned()));
}
// TODO: Step 7
// TODO: Step 8
Ok(())
} the same error is there for both of the following lines: I was trying to set the value for attributes using this first: |
Unfortunately, you cannot mutate the value of |
Hi, In the step 7 of MutationObserver's observe,
So, here, the list of registered observers will be from the node.rs: How do I determine the transient registered observer. As per my understanding, I need to check if the source of the 'registered observer' exists in this vector. But how do I obtain the source? Correct me if I am wrong. Also, the following statement confuses me -
How do I obtain a registered observer's observer? |
The link in the spec for registered observer points out that a registered observer's observer is just the As for the transient observers, just leave a TODO like |
Hi, I have some doubts in the usage of traits. I have encountered issues related to it at 2 places -
and in this as well :
Can you point me in the right direction w.r.t traits? Thanks! |
For the second, you want: |
Hello Josh, I am trying to iterate over node’s list of registered observers ( for Step 3 of Queuing a mutation record) . The following is my code: pub fn queue_a_mutation_record(target: &Node,attr_type: Mutation) {
//https://dom.spec.whatwg.org/#queueing-a-mutation-record
// Step 1 :Let interested observers be an initially empty set of MutationObserver objects optionally paired with a string
let mut interestedObservers: Vec<Root<MutationObserver>> = vec![];
let mut pairedStrings: Vec<DOMString> = vec![];
// Step 2: Let nodes be the inclusive ancestors of target.
let mut nodes: Vec<Root<Node>> = vec![];
for ancestor in target.inclusive_ancestors() {
nodes.push(ancestor);
}
// Step 3: For each node in nodes
for node in &nodes {
for registered_observer in node.registered_mutation_observers_for_type().borrow_mut().iter() {
}
}
} I tried using the above approach by writing On compilation, I get the following error
Even on replacing node with target ( just to check if target works) by replacing line Compiler shows the following error:
Please let us know on how to approach this problem. Thank you. |
You wrote |
Although it sounds like maybe your |
Hi, Is there any way to access the registered's options (MutationObserverInit) via the MutationObserver object? I thought I will need it for this step -
Thanks! |
I recommend adding members to MutationObserver that you initialize to the values present in the MutationObserverInit argument in the constructor. |
(they will need to be wrapped in Cell or DOMRefCell types to allow mutating them later) |
Hi, There is no MutationObserverInit argument in the constructor currently and if we add it, it shoots an error in the Bindings file:
Should we create another overridden constructor which also has MutationObserverInit argument? Or what way should we follow? |
Hi Josh, My enum is pub enum Mutation {
Attribute { name: Atom, namespace: Namespace, oldValue: DOMString, newValue: DOMString}
} Since I need name and namespace of Attribute of Mutation enum which is passed as an argument to my function , I tried using the match function like (http://rustbyexample.com/custom_types/enum.html) My function is //Queuing a mutation record
pub fn queue_a_mutation_record(target: &Node, attr_type: Mutation) {
// Step 1
let mut interestedObservers: Vec<Root<MutationObserver>> = vec![];
let mut pairedStrings: Vec<DOMString> = vec![];
// Step 2
let mut nodes: Vec<Root<Node>> = vec![];
for ancestor in target.inclusive_ancestors() {
nodes.push(ancestor);
}
// Step 3
for node in &nodes {
for registered_observer in node.registered_mutation_observers_for_type().borrow().iter() {
//let bool condition1 = (node!=target);
}
}
// Step 4
for observer in &interestedObservers {
//Step 4.1
let mut record= MutationRecord::new(target);
//Step 4.2
match attr_type {
Mutation::Attribute {name,namespace,oldValue,newValue} => { let mut given_name = name;let mut given_namespace = namespace;
},
}
}
} On compilation I get
(similar errors for namespace,oldValue and newValue). I tried including #[derive(Clone,Copy)] before my mutation and the following code impl Copy for Mutation {}
impl Clone for Mutation { fn clone(&self) -> Self { *self } } Compiler still throws
Please let us know on how to reference name and namespace of attr_type ( function argument). |
I'm very confused why you have pub enum Mutation {
Attribute { name: Atom, namespace: Namespace, oldValue: DOMString, newValue: DOMString}
} Can |
Hi, In Step 3 of Queuing a mutation record , type is supposed to be compared with "attributes", "characterData" and "childList". |
The "type" in the spec is equivalent to matching against the enum that we're using. To avoid the errors about partially moved values, you will want to use |
As for the question about MutationObserverInit, my mistake. I guess you will want sensible defaults for the new members in the constructor, and then set them to the real values in MutationObserver::Observe. |
Mutation observer API <!-- Please describe your changes on the following line: --> This contains the changes for the subsequent steps of Implementing the Mutation Observer API as described in the [Mutation Observer Project](https://github.com/servo/servo/wiki/Mutation-observer-project): --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [ ] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #6633 (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. --> <!-- 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/16668) <!-- Reviewable:end -->
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 -->
@jdm just want to make sure what's the status of this issue - it seems that effectively almost all of the listed work in https://github.com/servo/servo/wiki/Mutation-observer-project is done (I tried to go over them and mark done items, excuse the crude format), mostly by #16883? It seems that what's left is:
Asking because we planned to take this on as a team as a part of our university thesis project |
cc @taki-jaro |
@Xanewok Signal slots are part of a standard that we don't implement, so those can be ignored. We're also missing character data notifications, and all of the failing tests that are named MutationObserver. |
We have implemented mutation observers. If anything is missing or not working, we should open new issues for those items. |
I've started some patches for this.
The text was updated successfully, but these errors were encountered: