mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-22 12:44:43 +00:00
Merge pull request #1389 from lightpanda-io/nikneym/image-src-dispatch
`Image` & `Style`: Dispatch `load` event
This commit is contained in:
@@ -41,8 +41,10 @@ const Parser = @import("parser/Parser.zig");
|
||||
const URL = @import("URL.zig");
|
||||
const Node = @import("webapi/Node.zig");
|
||||
const Event = @import("webapi/Event.zig");
|
||||
const EventTarget = @import("webapi/EventTarget.zig");
|
||||
const CData = @import("webapi/CData.zig");
|
||||
const Element = @import("webapi/Element.zig");
|
||||
const HtmlElement = @import("webapi/element/Html.zig");
|
||||
const Window = @import("webapi/Window.zig");
|
||||
const Location = @import("webapi/Location.zig");
|
||||
const Document = @import("webapi/Document.zig");
|
||||
@@ -124,6 +126,10 @@ _element_assigned_slots: Element.AssignedSlotLookup = .{},
|
||||
/// ```
|
||||
_element_attr_listeners: GlobalEventHandlersLookup = .{},
|
||||
|
||||
/// `load` events that'll be fired before window's `load` event.
|
||||
/// A call to `documentIsComplete` (which calls `_documentIsComplete`) resets it.
|
||||
_to_load: std.ArrayList(*Element) = .{},
|
||||
|
||||
_script_manager: ScriptManager,
|
||||
|
||||
// List of active MutationObservers
|
||||
@@ -335,6 +341,8 @@ fn reset(self: *Page, comptime initializing: bool) !void {
|
||||
|
||||
self._element_attr_listeners = .{};
|
||||
|
||||
self._to_load = .{};
|
||||
|
||||
self._notified_network_idle = .init;
|
||||
self._notified_network_almost_idle = .init;
|
||||
|
||||
@@ -690,15 +698,34 @@ pub fn documentIsComplete(self: *Page) void {
|
||||
fn _documentIsComplete(self: *Page) !void {
|
||||
self.document._ready_state = .complete;
|
||||
|
||||
// dispatch window.load event
|
||||
const event = try Event.initTrusted("load", .{}, self);
|
||||
// this event is weird, it's dispatched directly on the window, but
|
||||
// with the document as the target
|
||||
|
||||
var ls: JS.Local.Scope = undefined;
|
||||
self.js.localScope(&ls);
|
||||
defer ls.deinit();
|
||||
|
||||
// Dispatch `_to_load` events before window.load.
|
||||
for (self._to_load.items) |element| {
|
||||
const maybe_inline_listener = self.getAttrListener(element, .onload);
|
||||
|
||||
try self._event_manager.dispatchWithFunction(
|
||||
element.asEventTarget(),
|
||||
event,
|
||||
ls.toLocal(maybe_inline_listener),
|
||||
.{ .context = "Page dispatch load events" },
|
||||
);
|
||||
|
||||
if (comptime IS_DEBUG) {
|
||||
log.debug(.page, "load event for element", .{ .element = element });
|
||||
}
|
||||
}
|
||||
|
||||
// `_to_load` can be cleaned here.
|
||||
self._to_load.clearAndFree(self.arena);
|
||||
|
||||
// Dispatch window.load event.
|
||||
// This event is weird, it's dispatched directly on the window, but
|
||||
// with the document as the target.
|
||||
event._target = self.document.asEventTarget();
|
||||
try self._event_manager.dispatchWithFunction(
|
||||
self.window.asEventTarget(),
|
||||
|
||||
@@ -97,3 +97,62 @@
|
||||
testing.expectEqual('lazy', img.getAttribute('loading'));
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="load-trigger-event">
|
||||
{
|
||||
const img = document.createElement("img");
|
||||
let count = 0;
|
||||
img.addEventListener("load", ({ bubbles, cancelBubble, cancelable, composed, isTrusted, target }) => {
|
||||
testing.expectEqual(true, count < 3);
|
||||
count++;
|
||||
|
||||
testing.expectEqual(false, bubbles);
|
||||
testing.expectEqual(false, cancelBubble);
|
||||
testing.expectEqual(false, cancelable);
|
||||
testing.expectEqual(false, composed);
|
||||
testing.expectEqual(true, isTrusted);
|
||||
testing.expectEqual(img, target);
|
||||
});
|
||||
|
||||
for (let i = 0; i < 3; i++) {
|
||||
img.src = "https://cdn.lightpanda.io/website/assets/images/docs/hn.png";
|
||||
testing.expectEqual("https://cdn.lightpanda.io/website/assets/images/docs/hn.png", img.src);
|
||||
}
|
||||
|
||||
// Make sure count is incremented asynchronously.
|
||||
testing.expectEqual(0, count);
|
||||
}
|
||||
</script>
|
||||
|
||||
<img
|
||||
id="inline-img"
|
||||
src="https://cdn.lightpanda.io/website/assets/images/docs/hn.png"
|
||||
onload="(() => testing.expectEqual(true, true))()"
|
||||
/>
|
||||
|
||||
<script id="inline-on-load">
|
||||
{
|
||||
const img = document.getElementById("inline-img");
|
||||
testing.expectEqual(true, img.onload instanceof Function);
|
||||
// Also call inline to double check.
|
||||
img.onload();
|
||||
|
||||
// Make sure ones attached with `addEventListener` also executed.
|
||||
testing.async(async () => {
|
||||
const result = await new Promise(resolve => {
|
||||
img.addEventListener("load", ({ bubbles, cancelBubble, cancelable, composed, isTrusted, target }) => {
|
||||
testing.expectEqual(false, bubbles);
|
||||
testing.expectEqual(false, cancelBubble);
|
||||
testing.expectEqual(false, cancelable);
|
||||
testing.expectEqual(false, composed);
|
||||
testing.expectEqual(true, isTrusted);
|
||||
testing.expectEqual(img, target);
|
||||
|
||||
return resolve(true);
|
||||
});
|
||||
});
|
||||
|
||||
testing.expectEqual(true, result);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -5,6 +5,10 @@ const URL = @import("../../../URL.zig");
|
||||
const Node = @import("../../Node.zig");
|
||||
const Element = @import("../../Element.zig");
|
||||
const HtmlElement = @import("../Html.zig");
|
||||
const Event = @import("../../Event.zig");
|
||||
const log = @import("../../../../log.zig");
|
||||
|
||||
const IS_DEBUG = @import("builtin").mode == .Debug;
|
||||
|
||||
const Image = @This();
|
||||
_proto: *HtmlElement,
|
||||
@@ -115,6 +119,19 @@ pub const JsApi = struct {
|
||||
pub const loading = bridge.accessor(Image.getLoading, Image.setLoading, .{});
|
||||
};
|
||||
|
||||
pub const Build = struct {
|
||||
pub fn created(node: *Node, page: *Page) !void {
|
||||
const self = node.as(Image);
|
||||
const image = self.asElement();
|
||||
// Exit if src not set.
|
||||
// TODO: We might want to check if src point to valid image.
|
||||
_ = image.getAttributeSafe(comptime .wrap("src")) orelse return;
|
||||
|
||||
// Push to `_to_load` to dispatch load event just before window load event.
|
||||
return page._to_load.append(page.arena, image);
|
||||
}
|
||||
};
|
||||
|
||||
const testing = @import("../../../../testing.zig");
|
||||
test "WebApi: HTML.Image" {
|
||||
try testing.htmlRunner("element/html/image.html", .{});
|
||||
|
||||
@@ -96,6 +96,15 @@ pub const JsApi = struct {
|
||||
pub const sheet = bridge.accessor(Style.getSheet, null, .{});
|
||||
};
|
||||
|
||||
pub const Build = struct {
|
||||
pub fn created(node: *Node, page: *Page) !void {
|
||||
const self = node.as(Style);
|
||||
const style = self.asElement();
|
||||
// Push to `_to_load` to dispatch load event just before window load event.
|
||||
return page._to_load.append(page.arena, style);
|
||||
}
|
||||
};
|
||||
|
||||
const testing = @import("../../../../testing.zig");
|
||||
test "WebApi: Style" {
|
||||
try testing.htmlRunner("element/html/style.html", .{});
|
||||
|
||||
Reference in New Issue
Block a user