mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 21:57:35 +00:00
LibWeb: Introduce Mutation{Record,Observer} and observer microtasks
This commit is contained in:
parent
116a7b74fe
commit
c9ba5531e0
15 changed files with 531 additions and 0 deletions
|
@ -6,11 +6,15 @@
|
|||
*/
|
||||
|
||||
#include <LibJS/Module.h>
|
||||
#include <LibJS/Runtime/Array.h>
|
||||
#include <LibJS/Runtime/Environment.h>
|
||||
#include <LibJS/Runtime/FinalizationRegistry.h>
|
||||
#include <LibJS/Runtime/NativeFunction.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
#include <LibWeb/Bindings/IDLAbstractOperations.h>
|
||||
#include <LibWeb/Bindings/MainThreadVM.h>
|
||||
#include <LibWeb/Bindings/MutationObserverWrapper.h>
|
||||
#include <LibWeb/Bindings/MutationRecordWrapper.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/HTML/PromiseRejectionEvent.h>
|
||||
#include <LibWeb/HTML/Scripting/ClassicScript.h>
|
||||
|
@ -286,4 +290,74 @@ JS::VM& main_thread_vm()
|
|||
return *vm;
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#queue-a-mutation-observer-compound-microtask
|
||||
void queue_mutation_observer_microtask(DOM::Document& document)
|
||||
{
|
||||
// FIXME: Is this the correct VM?
|
||||
auto& vm = main_thread_vm();
|
||||
auto& custom_data = verify_cast<WebEngineCustomData>(*vm.custom_data());
|
||||
|
||||
// 1. If the surrounding agent’s mutation observer microtask queued is true, then return.
|
||||
if (custom_data.mutation_observer_microtask_queued)
|
||||
return;
|
||||
|
||||
// 2. Set the surrounding agent’s mutation observer microtask queued to true.
|
||||
custom_data.mutation_observer_microtask_queued = true;
|
||||
|
||||
// 3. Queue a microtask to notify mutation observers.
|
||||
// NOTE: This uses the implied document concept. In the case of mutation observers, it is always done in a node context, so document should be that node's document.
|
||||
// FIXME: Is it safe to pass custom_data through?
|
||||
HTML::queue_a_microtask(&document, [&custom_data]() {
|
||||
// 1. Set the surrounding agent’s mutation observer microtask queued to false.
|
||||
custom_data.mutation_observer_microtask_queued = false;
|
||||
|
||||
// 2. Let notifySet be a clone of the surrounding agent’s mutation observers.
|
||||
auto notify_set = custom_data.mutation_observers;
|
||||
|
||||
// FIXME: 3. Let signalSet be a clone of the surrounding agent’s signal slots.
|
||||
|
||||
// FIXME: 4. Empty the surrounding agent’s signal slots.
|
||||
|
||||
// 5. For each mo of notifySet:
|
||||
for (auto& mutation_observer : notify_set) {
|
||||
// 1. Let records be a clone of mo’s record queue.
|
||||
// 2. Empty mo’s record queue.
|
||||
auto records = mutation_observer.take_records();
|
||||
|
||||
// 3. For each node of mo’s node list, remove all transient registered observers whose observer is mo from node’s registered observer list.
|
||||
for (auto& node : mutation_observer.node_list()) {
|
||||
// FIXME: Is this correct?
|
||||
if (node.is_null())
|
||||
continue;
|
||||
|
||||
node->registered_observers_list().remove_all_matching([&mutation_observer](DOM::RegisteredObserver& registered_observer) {
|
||||
return is<DOM::TransientRegisteredObserver>(registered_observer) && static_cast<DOM::TransientRegisteredObserver&>(registered_observer).observer.ptr() == &mutation_observer;
|
||||
});
|
||||
}
|
||||
|
||||
// 4. If records is not empty, then invoke mo’s callback with « records, mo », and mo. If this throws an exception, catch it, and report the exception.
|
||||
if (!records.is_empty()) {
|
||||
auto& callback = mutation_observer.callback();
|
||||
auto& global_object = callback.callback_context.global_object();
|
||||
|
||||
auto* wrapped_records = MUST(JS::Array::create(global_object, 0));
|
||||
for (size_t i = 0; i < records.size(); ++i) {
|
||||
auto& record = records.at(i);
|
||||
auto* wrapped_record = Bindings::wrap(global_object, record);
|
||||
auto property_index = JS::PropertyKey { i };
|
||||
MUST(wrapped_records->create_data_property(property_index, wrapped_record));
|
||||
}
|
||||
|
||||
auto* wrapped_mutation_observer = Bindings::wrap(global_object, mutation_observer);
|
||||
|
||||
auto result = IDL::invoke_callback(callback, wrapped_mutation_observer, wrapped_records, wrapped_mutation_observer);
|
||||
if (result.is_abrupt())
|
||||
HTML::report_exception(result);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: 6. For each slot of signalSet, fire an event named slotchange, with its bubbles attribute set to true, at slot.
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/NonnullRefPtrVector.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Runtime/JobCallback.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
#include <LibWeb/DOM/MutationObserver.h>
|
||||
#include <LibWeb/HTML/EventLoop/EventLoop.h>
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
@ -18,6 +20,15 @@ struct WebEngineCustomData final : public JS::VM::CustomData {
|
|||
virtual ~WebEngineCustomData() override = default;
|
||||
|
||||
HTML::EventLoop event_loop;
|
||||
|
||||
// FIXME: These should only be on similar-origin window agents, but we don't currently differentiate agent types.
|
||||
|
||||
// https://dom.spec.whatwg.org/#mutation-observer-compound-microtask-queued-flag
|
||||
bool mutation_observer_microtask_queued { false };
|
||||
|
||||
// https://dom.spec.whatwg.org/#mutation-observer-list
|
||||
// FIXME: This should be a set.
|
||||
NonnullRefPtrVector<DOM::MutationObserver> mutation_observers;
|
||||
};
|
||||
|
||||
struct WebEngineCustomJobCallbackData final : public JS::JobCallback::CustomData {
|
||||
|
@ -35,5 +46,6 @@ struct WebEngineCustomJobCallbackData final : public JS::JobCallback::CustomData
|
|||
|
||||
HTML::ClassicScript* active_script();
|
||||
JS::VM& main_thread_vm();
|
||||
void queue_mutation_observer_microtask(DOM::Document&);
|
||||
|
||||
}
|
||||
|
|
|
@ -254,6 +254,10 @@
|
|||
#include <LibWeb/Bindings/MessageEventPrototype.h>
|
||||
#include <LibWeb/Bindings/MouseEventConstructor.h>
|
||||
#include <LibWeb/Bindings/MouseEventPrototype.h>
|
||||
#include <LibWeb/Bindings/MutationObserverConstructor.h>
|
||||
#include <LibWeb/Bindings/MutationObserverPrototype.h>
|
||||
#include <LibWeb/Bindings/MutationRecordConstructor.h>
|
||||
#include <LibWeb/Bindings/MutationRecordPrototype.h>
|
||||
#include <LibWeb/Bindings/NavigatorConstructor.h>
|
||||
#include <LibWeb/Bindings/NavigatorPrototype.h>
|
||||
#include <LibWeb/Bindings/NodeConstructor.h>
|
||||
|
@ -492,6 +496,8 @@
|
|||
ADD_WINDOW_OBJECT_INTERFACE(MessageChannel) \
|
||||
ADD_WINDOW_OBJECT_INTERFACE(MessageEvent) \
|
||||
ADD_WINDOW_OBJECT_INTERFACE(MouseEvent) \
|
||||
ADD_WINDOW_OBJECT_INTERFACE(MutationObserver) \
|
||||
ADD_WINDOW_OBJECT_INTERFACE(MutationRecord) \
|
||||
ADD_WINDOW_OBJECT_INTERFACE(Navigator) \
|
||||
ADD_WINDOW_OBJECT_INTERFACE(Node) \
|
||||
ADD_WINDOW_OBJECT_INTERFACE(NodeIterator) \
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue