mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-02-04 06:23:45 +00:00
prefer attributeChange to run side-effects
This should give more consistent results than using `setSrc`.
This commit is contained in:
@@ -162,15 +162,50 @@ pub const JsApi = struct {
|
|||||||
pub const loading = bridge.accessor(Image.getLoading, Image.setLoading, .{});
|
pub const loading = bridge.accessor(Image.getLoading, Image.setLoading, .{});
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Parameters passed to scheduler for "load" events.
|
/// Argument passed to `dispatchLoadEvent`.
|
||||||
const CallbackParams = struct { page: *Page, element: *Element };
|
const CallbackParams = struct { page: *Page, element: *Element };
|
||||||
|
|
||||||
|
/// Callback passed to `Scheduler` to execute load listeners.
|
||||||
|
fn dispatchLoadEvent(raw: *anyopaque) !?u32 {
|
||||||
|
const _args: *CallbackParams = @ptrCast(@alignCast(raw));
|
||||||
|
const _page = _args.page;
|
||||||
|
defer _page._factory.destroy(_args);
|
||||||
|
|
||||||
|
const _element = _args.element;
|
||||||
|
const _img = _element.as(Image);
|
||||||
|
const event_target = _element.asEventTarget();
|
||||||
|
const event = try Event.initTrusted("load", .{}, _page);
|
||||||
|
|
||||||
|
// If onload provided, dispatch with it.
|
||||||
|
if (_img._on_load) |_on_load| {
|
||||||
|
var ls: js.Local.Scope = undefined;
|
||||||
|
_page.js.localScope(&ls);
|
||||||
|
defer ls.deinit();
|
||||||
|
|
||||||
|
try _page._event_manager.dispatchWithFunction(
|
||||||
|
event_target,
|
||||||
|
event,
|
||||||
|
_on_load.local(&ls.local),
|
||||||
|
.{ .context = "Image.onload" },
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dispatch to addEventListener listeners.
|
||||||
|
try _page._event_manager.dispatch(event_target, event);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
pub const Build = struct {
|
pub const Build = struct {
|
||||||
pub fn created(node: *Node, page: *Page) !void {
|
pub fn created(node: *Node, page: *Page) !void {
|
||||||
const self = node.as(Image);
|
const self = node.as(Image);
|
||||||
const image = self.asElement();
|
const image = self.asElement();
|
||||||
// Exit if src not set. We might want to check if src point to valid image.
|
// Exit if src not set. We might want to check if src point to valid image.
|
||||||
_ = image.getAttributeSafe("src") orelse return;
|
const src = image.getAttributeSafe("src") orelse return;
|
||||||
|
// We can at least check if this is a valid URL.
|
||||||
|
if (!URL.isCompleteHTTPUrl(src)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Set `onload` if provided.
|
// Set `onload` if provided.
|
||||||
blk: {
|
blk: {
|
||||||
@@ -202,37 +237,7 @@ pub const Build = struct {
|
|||||||
// quite easier, which might be the reason.
|
// quite easier, which might be the reason.
|
||||||
return page.scheduler.add(
|
return page.scheduler.add(
|
||||||
args,
|
args,
|
||||||
struct {
|
dispatchLoadEvent,
|
||||||
fn wrap(raw: *anyopaque) anyerror!?u32 {
|
|
||||||
const _args: *CallbackParams = @ptrCast(@alignCast(raw));
|
|
||||||
const _page = _args.page;
|
|
||||||
defer _page._factory.destroy(_args);
|
|
||||||
|
|
||||||
const _element = _args.element;
|
|
||||||
const _img = _element.as(Image);
|
|
||||||
const event_target = _element.asEventTarget();
|
|
||||||
const event = try Event.initTrusted("load", .{}, _page);
|
|
||||||
|
|
||||||
// If onload provided, dispatch with it.
|
|
||||||
if (_img._on_load) |_on_load| {
|
|
||||||
var ls: js.Local.Scope = undefined;
|
|
||||||
_page.js.localScope(&ls);
|
|
||||||
defer ls.deinit();
|
|
||||||
|
|
||||||
try _page._event_manager.dispatchWithFunction(
|
|
||||||
event_target,
|
|
||||||
event,
|
|
||||||
_on_load.local(&ls.local),
|
|
||||||
.{ .context = "Image.onload" },
|
|
||||||
);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dispatch to addEventListener listeners.
|
|
||||||
try _page._event_manager.dispatch(event_target, event);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}.wrap,
|
|
||||||
25,
|
25,
|
||||||
.{
|
.{
|
||||||
.low_priority = false,
|
.low_priority = false,
|
||||||
@@ -240,6 +245,39 @@ pub const Build = struct {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn attributeChange(
|
||||||
|
element: *Element,
|
||||||
|
attr_name: []const u8,
|
||||||
|
attr_value: []const u8,
|
||||||
|
page: *Page,
|
||||||
|
) !void {
|
||||||
|
const self = element.as(Image);
|
||||||
|
const image = self.asElement();
|
||||||
|
|
||||||
|
const src_changed_and_valid = std.mem.eql(u8, attr_name, "src") and
|
||||||
|
URL.isCompleteHTTPUrl(attr_value);
|
||||||
|
|
||||||
|
if (src_changed_and_valid) {
|
||||||
|
// Have to do this since `Scheduler` only allow passing a single arg.
|
||||||
|
const args = try page._factory.create(CallbackParams{
|
||||||
|
.page = page,
|
||||||
|
.element = image,
|
||||||
|
});
|
||||||
|
errdefer page._factory.destroy(args);
|
||||||
|
|
||||||
|
// We don't actually fetch the media, here we fake the load call.
|
||||||
|
try page.scheduler.add(
|
||||||
|
args,
|
||||||
|
dispatchLoadEvent,
|
||||||
|
25,
|
||||||
|
.{
|
||||||
|
.low_priority = false,
|
||||||
|
.name = "Image.Build.attributeChange",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const testing = @import("../../../../testing.zig");
|
const testing = @import("../../../../testing.zig");
|
||||||
|
|||||||
Reference in New Issue
Block a user