/src/serenity/Userland/Libraries/LibWeb/DOM/MutationObserver.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2022, Luke Wilde <lukew@serenityos.org> |
3 | | * Copyright (c) 2022, Andreas Kling <kling@serenityos.org> |
4 | | * |
5 | | * SPDX-License-Identifier: BSD-2-Clause |
6 | | */ |
7 | | |
8 | | #pragma once |
9 | | |
10 | | #include <AK/RefCounted.h> |
11 | | #include <LibJS/Heap/Handle.h> |
12 | | #include <LibWeb/DOM/MutationRecord.h> |
13 | | #include <LibWeb/WebIDL/CallbackType.h> |
14 | | #include <LibWeb/WebIDL/ExceptionOr.h> |
15 | | |
16 | | namespace Web::DOM { |
17 | | |
18 | | // https://dom.spec.whatwg.org/#dictdef-mutationobserverinit |
19 | | struct MutationObserverInit { |
20 | | bool child_list { false }; |
21 | | Optional<bool> attributes; |
22 | | Optional<bool> character_data; |
23 | | bool subtree { false }; |
24 | | Optional<bool> attribute_old_value; |
25 | | Optional<bool> character_data_old_value; |
26 | | Optional<Vector<String>> attribute_filter; |
27 | | }; |
28 | | |
29 | | // https://dom.spec.whatwg.org/#mutationobserver |
30 | | class MutationObserver final : public Bindings::PlatformObject { |
31 | | WEB_PLATFORM_OBJECT(MutationObserver, Bindings::PlatformObject); |
32 | | JS_DECLARE_ALLOCATOR(MutationObserver); |
33 | | |
34 | | public: |
35 | | static WebIDL::ExceptionOr<JS::NonnullGCPtr<MutationObserver>> construct_impl(JS::Realm&, JS::GCPtr<WebIDL::CallbackType>); |
36 | | virtual ~MutationObserver() override; |
37 | | |
38 | | WebIDL::ExceptionOr<void> observe(Node& target, MutationObserverInit options = {}); |
39 | | void disconnect(); |
40 | | Vector<JS::Handle<MutationRecord>> take_records(); |
41 | | |
42 | 0 | Vector<WeakPtr<Node>>& node_list() { return m_node_list; } |
43 | 0 | Vector<WeakPtr<Node>> const& node_list() const { return m_node_list; } |
44 | | |
45 | 0 | WebIDL::CallbackType& callback() { return *m_callback; } |
46 | | |
47 | | void enqueue_record(Badge<Node>, JS::NonnullGCPtr<MutationRecord> mutation_record) |
48 | 0 | { |
49 | 0 | m_record_queue.append(*mutation_record); |
50 | 0 | } |
51 | | |
52 | | private: |
53 | | MutationObserver(JS::Realm&, JS::GCPtr<WebIDL::CallbackType>); |
54 | | |
55 | | virtual void initialize(JS::Realm&) override; |
56 | | virtual void visit_edges(Cell::Visitor&) override; |
57 | | |
58 | | // https://dom.spec.whatwg.org/#concept-mo-callback |
59 | | JS::GCPtr<WebIDL::CallbackType> m_callback; |
60 | | |
61 | | // https://dom.spec.whatwg.org/#mutationobserver-node-list |
62 | | // NOTE: These are weak, per https://dom.spec.whatwg.org/#garbage-collection |
63 | | // Registered observers in a node’s registered observer list have a weak reference to the node. |
64 | | Vector<WeakPtr<Node>> m_node_list; |
65 | | |
66 | | // https://dom.spec.whatwg.org/#concept-mo-queue |
67 | | Vector<JS::NonnullGCPtr<MutationRecord>> m_record_queue; |
68 | | }; |
69 | | |
70 | | // https://dom.spec.whatwg.org/#registered-observer |
71 | | class RegisteredObserver : public JS::Cell { |
72 | | JS_CELL(RegisteredObserver, JS::Cell); |
73 | | |
74 | | public: |
75 | | static JS::NonnullGCPtr<RegisteredObserver> create(MutationObserver&, MutationObserverInit const&); |
76 | | virtual ~RegisteredObserver() override; |
77 | | |
78 | 0 | JS::NonnullGCPtr<MutationObserver> observer() const { return m_observer; } |
79 | | |
80 | 0 | MutationObserverInit const& options() const { return m_options; } |
81 | 0 | void set_options(MutationObserverInit options) { m_options = move(options); } |
82 | | |
83 | | protected: |
84 | | RegisteredObserver(MutationObserver& observer, MutationObserverInit const& options); |
85 | | |
86 | | virtual void visit_edges(Cell::Visitor&) override; |
87 | | |
88 | | private: |
89 | | JS::NonnullGCPtr<MutationObserver> m_observer; |
90 | | MutationObserverInit m_options; |
91 | | }; |
92 | | |
93 | | // https://dom.spec.whatwg.org/#transient-registered-observer |
94 | | class TransientRegisteredObserver final : public RegisteredObserver { |
95 | | JS_CELL(TransientRegisteredObserver, RegisteredObserver); |
96 | | JS_DECLARE_ALLOCATOR(TransientRegisteredObserver); |
97 | | |
98 | | public: |
99 | | static JS::NonnullGCPtr<TransientRegisteredObserver> create(MutationObserver&, MutationObserverInit const&, RegisteredObserver& source); |
100 | | virtual ~TransientRegisteredObserver() override; |
101 | | |
102 | 0 | JS::NonnullGCPtr<RegisteredObserver> source() const { return m_source; } |
103 | | |
104 | | private: |
105 | | TransientRegisteredObserver(MutationObserver& observer, MutationObserverInit const& options, RegisteredObserver& source); |
106 | | |
107 | | virtual void visit_edges(Cell::Visitor&) override; |
108 | | |
109 | | JS::NonnullGCPtr<RegisteredObserver> m_source; |
110 | | }; |
111 | | |
112 | | } |