mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-28 14:43:28 +00:00
Load dynamically added <script> tags
Add a callback to libdom which triggers whenever a script tag is added. Page registers the callback AFTER the HTML is parsed, but before any JS is processed and loads the script tags.
This commit is contained in:
@@ -2133,6 +2133,10 @@ pub inline fn documentCreateAttributeNS(doc: *Document, ns: []const u8, qname: [
|
||||
return attr.?;
|
||||
}
|
||||
|
||||
pub fn documentSetScriptAddedCallback(doc: *Document, ctx: *anyopaque, callback: c.dom_script_added_callback,) void {
|
||||
c._dom_document_set_script_added_callback(doc, ctx, callback);
|
||||
}
|
||||
|
||||
// DocumentHTML
|
||||
pub const DocumentHTML = c.dom_html_document;
|
||||
|
||||
|
||||
@@ -277,6 +277,10 @@ pub const Page = struct {
|
||||
const html_doc = self.window.document;
|
||||
const doc = parser.documentHTMLToDocument(html_doc);
|
||||
|
||||
// we want to be notified of any dynamically added script tags
|
||||
// so that we can load the script
|
||||
parser.documentSetScriptAddedCallback(doc, self, scriptAddedCallback);
|
||||
|
||||
const document_element = (try parser.documentGetDocumentElement(doc)) orelse return error.DocumentElementError;
|
||||
_ = try parser.eventTargetAddEventListener(
|
||||
parser.toEventTarget(parser.Element, document_element),
|
||||
@@ -317,8 +321,12 @@ pub const Page = struct {
|
||||
}
|
||||
|
||||
const e = parser.nodeToElement(next.?);
|
||||
|
||||
const tag = try parser.elementHTMLGetTagType(@as(*parser.ElementHTML, @ptrCast(e)));
|
||||
if (tag != .script) {
|
||||
// ignore non-js script.
|
||||
continue;
|
||||
}
|
||||
|
||||
const script = try Script.init(e) orelse continue;
|
||||
|
||||
// TODO use fetchpriority
|
||||
@@ -348,19 +356,11 @@ pub const Page = struct {
|
||||
// > immediately before the browser continues to parse the
|
||||
// > page.
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#notes
|
||||
try parser.documentHTMLSetCurrentScript(html_doc, @ptrCast(e));
|
||||
self.evalScript(&script) catch |err| {
|
||||
log.err(.page, "eval script error", .{ .err = err });
|
||||
};
|
||||
try parser.documentHTMLSetCurrentScript(html_doc, null);
|
||||
self.evalScript(&script);
|
||||
}
|
||||
|
||||
for (defer_scripts.items) |script| {
|
||||
try parser.documentHTMLSetCurrentScript(html_doc, @ptrCast(script.element));
|
||||
self.evalScript(&script) catch |err| {
|
||||
log.err(.page, "eval script error", .{ .err = err });
|
||||
};
|
||||
try parser.documentHTMLSetCurrentScript(html_doc, null);
|
||||
for (defer_scripts.items) |*script| {
|
||||
self.evalScript(script);
|
||||
}
|
||||
// dispatch DOMContentLoaded before the transition to "complete",
|
||||
// at the point where all subresources apart from async script elements
|
||||
@@ -369,12 +369,8 @@ pub const Page = struct {
|
||||
try HTMLDocument.documentIsLoaded(html_doc, self);
|
||||
|
||||
// eval async scripts.
|
||||
for (async_scripts.items) |script| {
|
||||
try parser.documentHTMLSetCurrentScript(html_doc, @ptrCast(script.element));
|
||||
self.evalScript(&script) catch |err| {
|
||||
log.err(.page, "eval script error", .{ .err = err });
|
||||
};
|
||||
try parser.documentHTMLSetCurrentScript(html_doc, null);
|
||||
for (async_scripts.items) |*script| {
|
||||
self.evalScript(script);
|
||||
}
|
||||
|
||||
try HTMLDocument.documentIsComplete(html_doc, self);
|
||||
@@ -390,10 +386,24 @@ pub const Page = struct {
|
||||
);
|
||||
}
|
||||
|
||||
fn evalScript(self: *Page, script: *const Script) void {
|
||||
self.tryEvalScript(script) catch |err| {
|
||||
log.err(.page, "eval script error", .{ .err = err });
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// evalScript evaluates the src in priority.
|
||||
// if no src is present, we evaluate the text source.
|
||||
// https://html.spec.whatwg.org/multipage/scripting.html#script-processing-model
|
||||
fn evalScript(self: *Page, script: *const Script) !void {
|
||||
fn tryEvalScript(self: *Page, script: *const Script) !void {
|
||||
const html_doc = self.window.document;
|
||||
try parser.documentHTMLSetCurrentScript(html_doc, @ptrCast(script.element));
|
||||
|
||||
defer parser.documentHTMLSetCurrentScript(html_doc, null) catch |err| {
|
||||
log.err(.page, "clear document script", .{.err = err});
|
||||
};
|
||||
|
||||
const src = script.src orelse {
|
||||
// source is inline
|
||||
// TODO handle charset attribute
|
||||
@@ -613,12 +623,6 @@ const Script = struct {
|
||||
};
|
||||
|
||||
fn init(e: *parser.Element) !?Script {
|
||||
// ignore non-script tags
|
||||
const tag = try parser.elementHTMLGetTagType(@as(*parser.ElementHTML, @ptrCast(e)));
|
||||
if (tag != .script) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (try parser.elementGetAttribute(e, "nomodule") != null) {
|
||||
// these scripts should only be loaded if we don't support modules
|
||||
// but since we do support modules, we can just skip them.
|
||||
@@ -707,3 +711,20 @@ fn timestamp() u32 {
|
||||
const ts = std.posix.clock_gettime(std.posix.CLOCK.MONOTONIC) catch unreachable;
|
||||
return @intCast(ts.sec);
|
||||
}
|
||||
|
||||
// A callback from libdom whenever a script tag is added to the DOM.
|
||||
// element is guaranteed to be a script element.
|
||||
// The script tag might not have a src. It might be any attribute, like
|
||||
// `nomodule`, `defer` and `async`. `Script.init` will return null on `nomodule`
|
||||
// so that's handled. And because we're only executing the inline <script> tags
|
||||
// after the document is loaded, it's ok to execute any async and defer scripts
|
||||
// immediately.
|
||||
pub export fn scriptAddedCallback(ctx: ?*anyopaque, element: ?*parser.Element) callconv(.C) void {
|
||||
var script = Script.init(element.?) catch |err| {
|
||||
log.warn(.page, "script added init error", .{.err = err});
|
||||
return;
|
||||
} orelse return;
|
||||
|
||||
const self: *Page = @alignCast(@ptrCast(ctx.?));
|
||||
self.evalScript(&script);
|
||||
}
|
||||
|
||||
2
vendor/netsurf/libdom
vendored
2
vendor/netsurf/libdom
vendored
Submodule vendor/netsurf/libdom updated: b0f4a43147...2576e31b3e
Reference in New Issue
Block a user