mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 07:03:29 +00:00
Use correct 'this' on MutationObserver callback
Add support for MutationObserver.disconnect
This commit is contained in:
@@ -36,8 +36,8 @@ const Walker = @import("../dom/walker.zig").WalkerChildren;
|
|||||||
pub const MutationObserver = struct {
|
pub const MutationObserver = struct {
|
||||||
page: *Page,
|
page: *Page,
|
||||||
cbk: Env.Function,
|
cbk: Env.Function,
|
||||||
connected: bool,
|
|
||||||
scheduled: bool,
|
scheduled: bool,
|
||||||
|
observers: std.ArrayListUnmanaged(*Observer),
|
||||||
|
|
||||||
// List of records which were observed. When the call scope ends, we need to
|
// List of records which were observed. When the call scope ends, we need to
|
||||||
// execute our callback with it.
|
// execute our callback with it.
|
||||||
@@ -48,8 +48,8 @@ pub const MutationObserver = struct {
|
|||||||
.cbk = cbk,
|
.cbk = cbk,
|
||||||
.page = page,
|
.page = page,
|
||||||
.observed = .{},
|
.observed = .{},
|
||||||
.connected = true,
|
|
||||||
.scheduled = false,
|
.scheduled = false,
|
||||||
|
.observers = .empty,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,15 +68,17 @@ pub const MutationObserver = struct {
|
|||||||
.event_node = .{ .id = self.cbk.id, .func = Observer.handle },
|
.event_node = .{ .id = self.cbk.id, .func = Observer.handle },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
try self.observers.append(arena, observer);
|
||||||
|
|
||||||
// register node's events
|
// register node's events
|
||||||
if (options.childList or options.subtree) {
|
if (options.childList or options.subtree) {
|
||||||
_ = try parser.eventTargetAddEventListener(
|
observer.dom_node_inserted_listener = try parser.eventTargetAddEventListener(
|
||||||
parser.toEventTarget(parser.Node, node),
|
parser.toEventTarget(parser.Node, node),
|
||||||
"DOMNodeInserted",
|
"DOMNodeInserted",
|
||||||
&observer.event_node,
|
&observer.event_node,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
_ = try parser.eventTargetAddEventListener(
|
observer.dom_node_removed_listener = try parser.eventTargetAddEventListener(
|
||||||
parser.toEventTarget(parser.Node, node),
|
parser.toEventTarget(parser.Node, node),
|
||||||
"DOMNodeRemoved",
|
"DOMNodeRemoved",
|
||||||
&observer.event_node,
|
&observer.event_node,
|
||||||
@@ -84,7 +86,7 @@ pub const MutationObserver = struct {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (options.attr()) {
|
if (options.attr()) {
|
||||||
_ = try parser.eventTargetAddEventListener(
|
observer.dom_node_attribute_modified_listener = try parser.eventTargetAddEventListener(
|
||||||
parser.toEventTarget(parser.Node, node),
|
parser.toEventTarget(parser.Node, node),
|
||||||
"DOMAttrModified",
|
"DOMAttrModified",
|
||||||
&observer.event_node,
|
&observer.event_node,
|
||||||
@@ -92,7 +94,7 @@ pub const MutationObserver = struct {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (options.cdata()) {
|
if (options.cdata()) {
|
||||||
_ = try parser.eventTargetAddEventListener(
|
observer.dom_cdata_modified_listener = try parser.eventTargetAddEventListener(
|
||||||
parser.toEventTarget(parser.Node, node),
|
parser.toEventTarget(parser.Node, node),
|
||||||
"DOMCharacterDataModified",
|
"DOMCharacterDataModified",
|
||||||
&observer.event_node,
|
&observer.event_node,
|
||||||
@@ -100,7 +102,7 @@ pub const MutationObserver = struct {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (options.subtree) {
|
if (options.subtree) {
|
||||||
_ = try parser.eventTargetAddEventListener(
|
observer.dom_subtree_modified_listener = try parser.eventTargetAddEventListener(
|
||||||
parser.toEventTarget(parser.Node, node),
|
parser.toEventTarget(parser.Node, node),
|
||||||
"DOMSubtreeModified",
|
"DOMSubtreeModified",
|
||||||
&observer.event_node,
|
&observer.event_node,
|
||||||
@@ -111,10 +113,6 @@ pub const MutationObserver = struct {
|
|||||||
|
|
||||||
fn callback(ctx: *anyopaque) ?u32 {
|
fn callback(ctx: *anyopaque) ?u32 {
|
||||||
const self: *MutationObserver = @ptrCast(@alignCast(ctx));
|
const self: *MutationObserver = @ptrCast(@alignCast(ctx));
|
||||||
if (self.connected == false) {
|
|
||||||
self.scheduled = true;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
self.scheduled = false;
|
self.scheduled = false;
|
||||||
|
|
||||||
const records = self.observed.items;
|
const records = self.observed.items;
|
||||||
@@ -125,7 +123,7 @@ pub const MutationObserver = struct {
|
|||||||
defer self.observed.clearRetainingCapacity();
|
defer self.observed.clearRetainingCapacity();
|
||||||
|
|
||||||
var result: Env.Function.Result = undefined;
|
var result: Env.Function.Result = undefined;
|
||||||
self.cbk.tryCall(void, .{records}, &result) catch {
|
self.cbk.tryCallWithThis(void, self, .{records}, &result) catch {
|
||||||
log.debug(.user_script, "callback error", .{
|
log.debug(.user_script, "callback error", .{
|
||||||
.err = result.exception,
|
.err = result.exception,
|
||||||
.stack = result.stack,
|
.stack = result.stack,
|
||||||
@@ -135,9 +133,55 @@ pub const MutationObserver = struct {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
|
||||||
pub fn _disconnect(self: *MutationObserver) !void {
|
pub fn _disconnect(self: *MutationObserver) !void {
|
||||||
self.connected = false;
|
for (self.observers.items) |observer| {
|
||||||
|
const event_target = parser.toEventTarget(parser.Node, observer.node);
|
||||||
|
if (observer.dom_node_inserted_listener) |listener| {
|
||||||
|
try parser.eventTargetRemoveEventListener(
|
||||||
|
event_target,
|
||||||
|
"DOMNodeInserted",
|
||||||
|
listener,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (observer.dom_node_removed_listener) |listener| {
|
||||||
|
try parser.eventTargetRemoveEventListener(
|
||||||
|
event_target,
|
||||||
|
"DOMNodeRemoved",
|
||||||
|
listener,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (observer.dom_node_attribute_modified_listener) |listener| {
|
||||||
|
try parser.eventTargetRemoveEventListener(
|
||||||
|
event_target,
|
||||||
|
"DOMAttrModified",
|
||||||
|
listener,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (observer.dom_cdata_modified_listener) |listener| {
|
||||||
|
try parser.eventTargetRemoveEventListener(
|
||||||
|
event_target,
|
||||||
|
"DOMCharacterDataModified",
|
||||||
|
listener,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (observer.dom_subtree_modified_listener) |listener| {
|
||||||
|
try parser.eventTargetRemoveEventListener(
|
||||||
|
event_target,
|
||||||
|
"DOMSubtreeModified",
|
||||||
|
listener,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.observers.clearRetainingCapacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
@@ -222,6 +266,12 @@ const Observer = struct {
|
|||||||
|
|
||||||
event_node: parser.EventNode,
|
event_node: parser.EventNode,
|
||||||
|
|
||||||
|
dom_node_inserted_listener: ?*parser.EventListener = null,
|
||||||
|
dom_node_removed_listener: ?*parser.EventListener = null,
|
||||||
|
dom_node_attribute_modified_listener: ?*parser.EventListener = null,
|
||||||
|
dom_cdata_modified_listener: ?*parser.EventListener = null,
|
||||||
|
dom_subtree_modified_listener: ?*parser.EventListener = null,
|
||||||
|
|
||||||
fn appliesTo(
|
fn appliesTo(
|
||||||
self: *const Observer,
|
self: *const Observer,
|
||||||
target: *parser.Node,
|
target: *parser.Node,
|
||||||
|
|||||||
@@ -11,15 +11,19 @@
|
|||||||
|
|
||||||
var nb = 0;
|
var nb = 0;
|
||||||
var mrs;
|
var mrs;
|
||||||
new MutationObserver((mu) => {
|
let cb_this1;
|
||||||
|
let mu1 = new MutationObserver(function(mu) {
|
||||||
mrs = mu;
|
mrs = mu;
|
||||||
nb++;
|
nb++;
|
||||||
}).observe(document.firstElementChild, { attributes: true, attributeOldValue: true });
|
cb_this1 = this;
|
||||||
|
});
|
||||||
|
mu1.observe(document.firstElementChild, { attributes: true, attributeOldValue: true });
|
||||||
document.firstElementChild.setAttribute("foo", "bar");
|
document.firstElementChild.setAttribute("foo", "bar");
|
||||||
document.firstElementChild.firstChild.setAttribute("foo", "bar");
|
document.firstElementChild.firstChild.setAttribute("foo", "bar");
|
||||||
|
|
||||||
testing.eventually(() => {
|
testing.eventually(() => {
|
||||||
testing.expectEqual(1, nb);
|
testing.expectEqual(1, nb);
|
||||||
|
testing.expectEqual(cb_this1, mu1);
|
||||||
testing.expectEqual('attributes', mrs[0].type);
|
testing.expectEqual('attributes', mrs[0].type);
|
||||||
testing.expectEqual(document.firstElementChild, mrs[0].target);
|
testing.expectEqual(document.firstElementChild, mrs[0].target);
|
||||||
testing.expectEqual('bar', mrs[0].target.getAttribute('foo'));
|
testing.expectEqual('bar', mrs[0].target.getAttribute('foo'));
|
||||||
@@ -30,14 +34,17 @@
|
|||||||
var nb2 = 0;
|
var nb2 = 0;
|
||||||
var mrs2;
|
var mrs2;
|
||||||
var node1 = $('#p1').firstChild;
|
var node1 = $('#p1').firstChild;
|
||||||
new MutationObserver((mu) => {
|
let mu2 = new MutationObserver((mu) => {
|
||||||
mrs2 = mu;
|
mrs2 = mu;
|
||||||
nb2++;
|
nb2++;
|
||||||
}).observe(node1, { characterData: true, characterDataOldValue: true });
|
cb_this2 = this;
|
||||||
|
})
|
||||||
|
mu2.observe(node1, { characterData: true, characterDataOldValue: true });
|
||||||
node1.data = "foo";
|
node1.data = "foo";
|
||||||
|
|
||||||
testing.eventually(() => {
|
testing.eventually(() => {
|
||||||
testing.expectEqual(1, nb2);
|
testing.expectEqual(1, nb2);
|
||||||
|
testing.expectEqual(window, cb_this2);
|
||||||
testing.expectEqual('characterData', mrs2[0].type);
|
testing.expectEqual('characterData', mrs2[0].type);
|
||||||
testing.expectEqual(node1, mrs2[0].target);
|
testing.expectEqual(node1, mrs2[0].target);
|
||||||
testing.expectEqual('foo', mrs2[0].target.data);
|
testing.expectEqual('foo', mrs2[0].target.data);
|
||||||
|
|||||||
Reference in New Issue
Block a user