@@ -36,8 +36,8 @@ const Walker = @import("../dom/walker.zig").WalkerChildren;
36
36
pub const MutationObserver = struct {
37
37
page : * Page ,
38
38
cbk : Env.Function ,
39
- connected : bool ,
40
39
scheduled : bool ,
40
+ observers : std .ArrayListUnmanaged (* Observer ),
41
41
42
42
// List of records which were observed. When the call scope ends, we need to
43
43
// execute our callback with it.
@@ -48,8 +48,8 @@ pub const MutationObserver = struct {
48
48
.cbk = cbk ,
49
49
.page = page ,
50
50
.observed = .{},
51
- .connected = true ,
52
51
.scheduled = false ,
52
+ .observers = .empty ,
53
53
};
54
54
}
55
55
@@ -68,39 +68,41 @@ pub const MutationObserver = struct {
68
68
.event_node = .{ .id = self .cbk .id , .func = Observer .handle },
69
69
};
70
70
71
+ try self .observers .append (arena , observer );
72
+
71
73
// register node's events
72
74
if (options .childList or options .subtree ) {
73
- _ = try parser .eventTargetAddEventListener (
75
+ observer . dom_node_inserted_listener = try parser .eventTargetAddEventListener (
74
76
parser .toEventTarget (parser .Node , node ),
75
77
"DOMNodeInserted" ,
76
78
& observer .event_node ,
77
79
false ,
78
80
);
79
- _ = try parser .eventTargetAddEventListener (
81
+ observer . dom_node_removed_listener = try parser .eventTargetAddEventListener (
80
82
parser .toEventTarget (parser .Node , node ),
81
83
"DOMNodeRemoved" ,
82
84
& observer .event_node ,
83
85
false ,
84
86
);
85
87
}
86
88
if (options .attr ()) {
87
- _ = try parser .eventTargetAddEventListener (
89
+ observer . dom_node_attribute_modified_listener = try parser .eventTargetAddEventListener (
88
90
parser .toEventTarget (parser .Node , node ),
89
91
"DOMAttrModified" ,
90
92
& observer .event_node ,
91
93
false ,
92
94
);
93
95
}
94
96
if (options .cdata ()) {
95
- _ = try parser .eventTargetAddEventListener (
97
+ observer . dom_cdata_modified_listener = try parser .eventTargetAddEventListener (
96
98
parser .toEventTarget (parser .Node , node ),
97
99
"DOMCharacterDataModified" ,
98
100
& observer .event_node ,
99
101
false ,
100
102
);
101
103
}
102
104
if (options .subtree ) {
103
- _ = try parser .eventTargetAddEventListener (
105
+ observer . dom_subtree_modified_listener = try parser .eventTargetAddEventListener (
104
106
parser .toEventTarget (parser .Node , node ),
105
107
"DOMSubtreeModified" ,
106
108
& observer .event_node ,
@@ -111,10 +113,6 @@ pub const MutationObserver = struct {
111
113
112
114
fn callback (ctx : * anyopaque ) ? u32 {
113
115
const self : * MutationObserver = @ptrCast (@alignCast (ctx ));
114
- if (self .connected == false ) {
115
- self .scheduled = true ;
116
- return null ;
117
- }
118
116
self .scheduled = false ;
119
117
120
118
const records = self .observed .items ;
@@ -125,7 +123,7 @@ pub const MutationObserver = struct {
125
123
defer self .observed .clearRetainingCapacity ();
126
124
127
125
var result : Env.Function.Result = undefined ;
128
- self .cbk .tryCall (void , .{records }, & result ) catch {
126
+ self .cbk .tryCallWithThis (void , self , .{records }, & result ) catch {
129
127
log .debug (.user_script , "callback error" , .{
130
128
.err = result .exception ,
131
129
.stack = result .stack ,
@@ -135,9 +133,55 @@ pub const MutationObserver = struct {
135
133
return null ;
136
134
}
137
135
138
- // TODO
139
136
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 ();
141
185
}
142
186
143
187
// TODO
@@ -222,6 +266,12 @@ const Observer = struct {
222
266
223
267
event_node : parser.EventNode ,
224
268
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
+
225
275
fn appliesTo (
226
276
self : * const Observer ,
227
277
target : * parser.Node ,
0 commit comments