@@ -36,8 +36,8 @@ const Walker = @import("../dom/walker.zig").WalkerChildren;
3636pub const MutationObserver = struct {
3737 page : * Page ,
3838 cbk : Env.Function ,
39- connected : bool ,
4039 scheduled : bool ,
40+ observers : std .ArrayListUnmanaged (* Observer ),
4141
4242 // List of records which were observed. When the call scope ends, we need to
4343 // execute our callback with it.
@@ -48,8 +48,8 @@ pub const MutationObserver = struct {
4848 .cbk = cbk ,
4949 .page = page ,
5050 .observed = .{},
51- .connected = true ,
5251 .scheduled = false ,
52+ .observers = .empty ,
5353 };
5454 }
5555
@@ -68,39 +68,41 @@ pub const MutationObserver = struct {
6868 .event_node = .{ .id = self .cbk .id , .func = Observer .handle },
6969 };
7070
71+ try self .observers .append (arena , observer );
72+
7173 // register node's events
7274 if (options .childList or options .subtree ) {
73- _ = try parser .eventTargetAddEventListener (
75+ observer . dom_node_inserted_listener = try parser .eventTargetAddEventListener (
7476 parser .toEventTarget (parser .Node , node ),
7577 "DOMNodeInserted" ,
7678 & observer .event_node ,
7779 false ,
7880 );
79- _ = try parser .eventTargetAddEventListener (
81+ observer . dom_node_removed_listener = try parser .eventTargetAddEventListener (
8082 parser .toEventTarget (parser .Node , node ),
8183 "DOMNodeRemoved" ,
8284 & observer .event_node ,
8385 false ,
8486 );
8587 }
8688 if (options .attr ()) {
87- _ = try parser .eventTargetAddEventListener (
89+ observer . dom_node_attribute_modified_listener = try parser .eventTargetAddEventListener (
8890 parser .toEventTarget (parser .Node , node ),
8991 "DOMAttrModified" ,
9092 & observer .event_node ,
9193 false ,
9294 );
9395 }
9496 if (options .cdata ()) {
95- _ = try parser .eventTargetAddEventListener (
97+ observer . dom_cdata_modified_listener = try parser .eventTargetAddEventListener (
9698 parser .toEventTarget (parser .Node , node ),
9799 "DOMCharacterDataModified" ,
98100 & observer .event_node ,
99101 false ,
100102 );
101103 }
102104 if (options .subtree ) {
103- _ = try parser .eventTargetAddEventListener (
105+ observer . dom_subtree_modified_listener = try parser .eventTargetAddEventListener (
104106 parser .toEventTarget (parser .Node , node ),
105107 "DOMSubtreeModified" ,
106108 & observer .event_node ,
@@ -111,10 +113,6 @@ pub const MutationObserver = struct {
111113
112114 fn callback (ctx : * anyopaque ) ? u32 {
113115 const self : * MutationObserver = @ptrCast (@alignCast (ctx ));
114- if (self .connected == false ) {
115- self .scheduled = true ;
116- return null ;
117- }
118116 self .scheduled = false ;
119117
120118 const records = self .observed .items ;
@@ -125,7 +123,7 @@ pub const MutationObserver = struct {
125123 defer self .observed .clearRetainingCapacity ();
126124
127125 var result : Env.Function.Result = undefined ;
128- self .cbk .tryCall (void , .{records }, & result ) catch {
126+ self .cbk .tryCallWithThis (void , self , .{records }, & result ) catch {
129127 log .debug (.user_script , "callback error" , .{
130128 .err = result .exception ,
131129 .stack = result .stack ,
@@ -135,9 +133,55 @@ pub const MutationObserver = struct {
135133 return null ;
136134 }
137135
138- // TODO
139136 pub fn _disconnect (self : * MutationObserver ) ! void {
140- self .connected = false ;
137+ for (self .observers .items ) | observer | {
138+ const event_target = parser .toEventTarget (parser .Node , observer .node );
139+ if (observer .dom_node_inserted_listener ) | listener | {
140+ try parser .eventTargetRemoveEventListener (
141+ event_target ,
142+ "DOMNodeInserted" ,
143+ listener ,
144+ false ,
145+ );
146+ }
147+
148+ if (observer .dom_node_removed_listener ) | listener | {
149+ try parser .eventTargetRemoveEventListener (
150+ event_target ,
151+ "DOMNodeRemoved" ,
152+ listener ,
153+ false ,
154+ );
155+ }
156+
157+ if (observer .dom_node_attribute_modified_listener ) | listener | {
158+ try parser .eventTargetRemoveEventListener (
159+ event_target ,
160+ "DOMAttrModified" ,
161+ listener ,
162+ false ,
163+ );
164+ }
165+
166+ if (observer .dom_cdata_modified_listener ) | listener | {
167+ try parser .eventTargetRemoveEventListener (
168+ event_target ,
169+ "DOMCharacterDataModified" ,
170+ listener ,
171+ false ,
172+ );
173+ }
174+
175+ if (observer .dom_subtree_modified_listener ) | listener | {
176+ try parser .eventTargetRemoveEventListener (
177+ event_target ,
178+ "DOMSubtreeModified" ,
179+ listener ,
180+ false ,
181+ );
182+ }
183+ }
184+ self .observers .clearRetainingCapacity ();
141185 }
142186
143187 // TODO
@@ -222,6 +266,12 @@ const Observer = struct {
222266
223267 event_node : parser.EventNode ,
224268
269+ dom_node_inserted_listener : ? * parser.EventListener = null ,
270+ dom_node_removed_listener : ? * parser.EventListener = null ,
271+ dom_node_attribute_modified_listener : ? * parser.EventListener = null ,
272+ dom_cdata_modified_listener : ? * parser.EventListener = null ,
273+ dom_subtree_modified_listener : ? * parser.EventListener = null ,
274+
225275 fn appliesTo (
226276 self : * const Observer ,
227277 target : * parser.Node ,
0 commit comments