mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 23:23:28 +00:00
Merge pull request #975 from lightpanda-io/dynamic_script
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
zig-test / zig build dev (push) Has been cancelled
zig-test / browser fetch (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
zig-test / zig build dev (push) Has been cancelled
zig-test / browser fetch (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
Support dynamic scripts which are added to the DOM before src is set
This commit is contained in:
@@ -143,32 +143,7 @@ pub fn addFromElement(self: *ScriptManager, element: *parser.Element) !void {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
var onload: ?Script.Callback = null;
|
|
||||||
var onerror: ?Script.Callback = null;
|
|
||||||
|
|
||||||
const page = self.page;
|
const page = self.page;
|
||||||
if (page.getNodeState(@ptrCast(element))) |se| {
|
|
||||||
// if the script has a node state, then it was dynamically added and thus
|
|
||||||
// the onload/onerror were saved in the state (if there are any)
|
|
||||||
if (se.onload) |function| {
|
|
||||||
onload = .{ .function = function };
|
|
||||||
}
|
|
||||||
if (se.onerror) |function| {
|
|
||||||
onerror = .{ .function = function };
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// if the script has no node state, then it could still be dynamically
|
|
||||||
// added (could have been dynamically added, but no attributes were set
|
|
||||||
// which required a node state to be created) or it could be a inline
|
|
||||||
// <script>.
|
|
||||||
if (try parser.elementGetAttribute(element, "onload")) |string| {
|
|
||||||
onload = .{ .string = string };
|
|
||||||
}
|
|
||||||
if (try parser.elementGetAttribute(element, "onerror")) |string| {
|
|
||||||
onerror = .{ .string = string };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var source: Script.Source = undefined;
|
var source: Script.Source = undefined;
|
||||||
var remote_url: ?[:0]const u8 = null;
|
var remote_url: ?[:0]const u8 = null;
|
||||||
if (try parser.elementGetAttribute(element, "src")) |src| {
|
if (try parser.elementGetAttribute(element, "src")) |src| {
|
||||||
@@ -184,8 +159,6 @@ pub fn addFromElement(self: *ScriptManager, element: *parser.Element) !void {
|
|||||||
|
|
||||||
var script = Script{
|
var script = Script{
|
||||||
.kind = kind,
|
.kind = kind,
|
||||||
.onload = onload,
|
|
||||||
.onerror = onerror,
|
|
||||||
.element = element,
|
.element = element,
|
||||||
.source = source,
|
.source = source,
|
||||||
.url = remote_url orelse page.url.raw,
|
.url = remote_url orelse page.url.raw,
|
||||||
@@ -558,8 +531,6 @@ const Script = struct {
|
|||||||
is_async: bool,
|
is_async: bool,
|
||||||
is_defer: bool,
|
is_defer: bool,
|
||||||
source: Source,
|
source: Source,
|
||||||
onload: ?Callback,
|
|
||||||
onerror: ?Callback,
|
|
||||||
element: *parser.Element,
|
element: *parser.Element,
|
||||||
|
|
||||||
const Kind = enum {
|
const Kind = enum {
|
||||||
@@ -644,7 +615,7 @@ const Script = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn executeCallback(self: *const Script, comptime typ: []const u8, page: *Page) void {
|
fn executeCallback(self: *const Script, comptime typ: []const u8, page: *Page) void {
|
||||||
const callback = @field(self, typ) orelse return;
|
const callback = self.getCallback(typ, page) orelse return;
|
||||||
|
|
||||||
switch (callback) {
|
switch (callback) {
|
||||||
.string => |str| {
|
.string => |str| {
|
||||||
@@ -687,6 +658,23 @@ const Script = struct {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn getCallback(self: *const Script, comptime typ: []const u8, page: *Page) ?Callback {
|
||||||
|
const element = self.element;
|
||||||
|
// first we check if there was an el.onload set directly on the
|
||||||
|
// element in JavaScript (if so, it'd be stored in the node state)
|
||||||
|
if (page.getNodeState(@ptrCast(element))) |se| {
|
||||||
|
if (@field(se, typ)) |function| {
|
||||||
|
return .{ .function = function };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if we have no node state, or if the node state has no onload/onerror
|
||||||
|
// then check for the onload/onerror attribute
|
||||||
|
if (parser.elementGetAttribute(element, typ) catch null) |string| {
|
||||||
|
return .{ .string = string };
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const BufferPool = struct {
|
const BufferPool = struct {
|
||||||
|
|||||||
@@ -262,7 +262,6 @@ pub const EventHandler = struct {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const callback = (try listener.callback(target)) orelse return null;
|
const callback = (try listener.callback(target)) orelse return null;
|
||||||
|
|
||||||
if (signal) |s| {
|
if (signal) |s| {
|
||||||
|
|||||||
@@ -862,12 +862,23 @@ pub const HTMLScriptElement = struct {
|
|||||||
) orelse "";
|
) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_src(self: *parser.Script, v: []const u8) !void {
|
pub fn set_src(self: *parser.Script, v: []const u8, page: *Page) !void {
|
||||||
return try parser.elementSetAttribute(
|
try parser.elementSetAttribute(
|
||||||
parser.scriptToElt(self),
|
parser.scriptToElt(self),
|
||||||
"src",
|
"src",
|
||||||
v,
|
v,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (try Node.get_isConnected(@alignCast(@ptrCast(self)))) {
|
||||||
|
// There are sites which do set the src AFTER appending the script
|
||||||
|
// tag to the document:
|
||||||
|
// const s = document.createElement('script');
|
||||||
|
// document.getElementsByTagName('body')[0].appendChild(s);
|
||||||
|
// s.src = '...';
|
||||||
|
// This should load the script.
|
||||||
|
// addFromElement protects against double execution.
|
||||||
|
try page.script_manager.addFromElement(@alignCast(@ptrCast(self)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_type(self: *parser.Script) !?[]const u8 {
|
pub fn get_type(self: *parser.Script) !?[]const u8 {
|
||||||
@@ -878,7 +889,7 @@ pub const HTMLScriptElement = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_type(self: *parser.Script, v: []const u8) !void {
|
pub fn set_type(self: *parser.Script, v: []const u8) !void {
|
||||||
return try parser.elementSetAttribute(
|
try parser.elementSetAttribute(
|
||||||
parser.scriptToElt(self),
|
parser.scriptToElt(self),
|
||||||
"type",
|
"type",
|
||||||
v,
|
v,
|
||||||
@@ -893,7 +904,7 @@ pub const HTMLScriptElement = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_text(self: *parser.Script, v: []const u8) !void {
|
pub fn set_text(self: *parser.Script, v: []const u8) !void {
|
||||||
return try parser.elementSetAttribute(
|
try parser.elementSetAttribute(
|
||||||
parser.scriptToElt(self),
|
parser.scriptToElt(self),
|
||||||
"text",
|
"text",
|
||||||
v,
|
v,
|
||||||
@@ -908,7 +919,7 @@ pub const HTMLScriptElement = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_integrity(self: *parser.Script, v: []const u8) !void {
|
pub fn set_integrity(self: *parser.Script, v: []const u8) !void {
|
||||||
return try parser.elementSetAttribute(
|
try parser.elementSetAttribute(
|
||||||
parser.scriptToElt(self),
|
parser.scriptToElt(self),
|
||||||
"integrity",
|
"integrity",
|
||||||
v,
|
v,
|
||||||
|
|||||||
@@ -1110,13 +1110,22 @@ fn timestamp() u32 {
|
|||||||
// so that's handled. And because we're only executing the inline <script> tags
|
// 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
|
// after the document is loaded, it's ok to execute any async and defer scripts
|
||||||
// immediately.
|
// immediately.
|
||||||
pub export fn scriptAddedCallback(ctx: ?*anyopaque, element: ?*parser.Element) callconv(.C) void {
|
pub export fn scriptAddedCallback(ctx: ?*anyopaque, element: ?*parser.Element) callconv(.c) void {
|
||||||
const self: *Page = @alignCast(@ptrCast(ctx.?));
|
const self: *Page = @alignCast(@ptrCast(ctx.?));
|
||||||
|
|
||||||
if (self.delayed_navigation) {
|
if (self.delayed_navigation) {
|
||||||
// if we're planning on navigating to another page, don't run this script
|
// if we're planning on navigating to another page, don't run this script
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It's posisble for a script to be dynamically added without a src.
|
||||||
|
// const s = document.createElement('script');
|
||||||
|
// document.getElementsByTagName('body')[0].appendChild(s);
|
||||||
|
// The src can be set after. We handle that in HTMLScriptElement.set_src,
|
||||||
|
// but it's important we don't pass such elements to the script_manager
|
||||||
|
// here, else the script_manager will flag it as already-processed.
|
||||||
|
_ = parser.elementGetAttribute(element.?, "src") catch return orelse return;
|
||||||
|
|
||||||
self.script_manager.addFromElement(element.?) catch |err| {
|
self.script_manager.addFromElement(element.?) catch |err| {
|
||||||
log.warn(.browser, "dynamic script", .{ .err = err });
|
log.warn(.browser, "dynamic script", .{ .err = err });
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user