Skip to content

Commit b6341c1

Browse files
authored
Merge pull request #892 from lightpanda-io/set_timeout_params
Support params for setTimeout and setInterval
2 parents 08487b0 + cd540df commit b6341c1

File tree

2 files changed

+51
-15
lines changed

2 files changed

+51
-15
lines changed

src/browser/html/window.zig

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const std = @import("std");
2020

2121
const log = @import("../../log.zig");
2222
const parser = @import("../netsurf.zig");
23-
const Function = @import("../env.zig").Function;
23+
const Env = @import("../env.zig").Env;
2424
const Page = @import("../page.zig").Page;
2525
const Loop = @import("../../runtime/loop.zig").Loop;
2626

@@ -36,6 +36,9 @@ const CSSStyleDeclaration = @import("../cssom/css_style_declaration.zig").CSSSty
3636
const Screen = @import("screen.zig").Screen;
3737
const Css = @import("../css/css.zig").Css;
3838

39+
const Function = Env.Function;
40+
const JsObject = Env.JsObject;
41+
3942
const storage = @import("../storage/storage.zig");
4043

4144
// https://dom.spec.whatwg.org/#interface-window-extensions
@@ -184,13 +187,12 @@ pub const Window = struct {
184187
return page.loop.cancel(kv.value.loop_id);
185188
}
186189

187-
pub fn _setTimeout(self: *Window, cbk: Function, delay: ?u32, page: *Page) !u32 {
188-
return self.createTimeout(cbk, delay, page, .{});
190+
pub fn _setTimeout(self: *Window, cbk: Function, delay: ?u32, params: []Env.JsObject, page: *Page) !u32 {
191+
return self.createTimeout(cbk, delay, page, .{ .args = params });
189192
}
190193

191-
// TODO handle callback arguments.
192-
pub fn _setInterval(self: *Window, cbk: Function, delay: ?u32, page: *Page) !u32 {
193-
return self.createTimeout(cbk, delay, page, .{ .repeat = true });
194+
pub fn _setInterval(self: *Window, cbk: Function, delay: ?u32, params: []Env.JsObject, page: *Page) !u32 {
195+
return self.createTimeout(cbk, delay, page, .{ .repeat = true, .args = params });
194196
}
195197

196198
pub fn _clearTimeout(self: *Window, id: u32, page: *Page) !void {
@@ -230,10 +232,11 @@ pub const Window = struct {
230232
}
231233

232234
const CreateTimeoutOpts = struct {
235+
args: []Env.JsObject = &.{},
233236
repeat: bool = false,
234237
animation_frame: bool = false,
235238
};
236-
fn createTimeout(self: *Window, cbk: Function, delay_: ?u32, page: *Page, comptime opts: CreateTimeoutOpts) !u32 {
239+
fn createTimeout(self: *Window, cbk: Function, delay_: ?u32, page: *Page, opts: CreateTimeoutOpts) !u32 {
237240
const delay = delay_ orelse 0;
238241
if (delay > 5000) {
239242
log.warn(.user_script, "long timeout ignored", .{ .delay = delay, .interval = opts.repeat });
@@ -258,6 +261,15 @@ pub const Window = struct {
258261
}
259262
errdefer _ = self.timers.remove(timer_id);
260263

264+
const args = opts.args;
265+
var persisted_args: []Env.JsObject = &.{};
266+
if (args.len > 0) {
267+
persisted_args = try page.arena.alloc(Env.JsObject, args.len);
268+
for (args, persisted_args) |a, *ca| {
269+
ca.* = try a.persist();
270+
}
271+
}
272+
261273
const delay_ms: u63 = @as(u63, delay) * std.time.ns_per_ms;
262274
const callback = try arena.create(TimerCallback);
263275

@@ -266,6 +278,7 @@ pub const Window = struct {
266278
.loop_id = 0, // we're going to set this to a real value shortly
267279
.window = self,
268280
.timer_id = timer_id,
281+
.args = persisted_args,
269282
.node = .{ .func = TimerCallback.run },
270283
.repeat = if (opts.repeat) delay_ms else null,
271284
.animation_frame = opts.animation_frame,
@@ -344,6 +357,8 @@ const TimerCallback = struct {
344357

345358
window: *Window,
346359

360+
args: []Env.JsObject = &.{},
361+
347362
fn run(node: *Loop.CallbackNode, repeat_delay: *?u63) void {
348363
const self: *TimerCallback = @fieldParentPtr("node", node);
349364

@@ -353,7 +368,7 @@ const TimerCallback = struct {
353368
if (self.animation_frame) {
354369
call = self.cbk.tryCall(void, .{self.window.performance._now()}, &result);
355370
} else {
356-
call = self.cbk.tryCall(void, .{}, &result);
371+
call = self.cbk.tryCall(void, self.args, &result);
357372
}
358373

359374
call catch {
@@ -427,11 +442,17 @@ test "Browser.HTML.Window" {
427442
.{ "innerWidth", "2" },
428443
}, .{});
429444

430-
// cancelAnimationFrame should be able to cancel a request with the given id
431445
try runner.testCases(&.{
432446
.{ "let longCall = false;", null },
433447
.{ "window.setTimeout(() => {longCall = true}, 5001);", null },
434448
.{ "longCall;", "false" },
449+
450+
.{ "let wst = 0;", null },
451+
.{ "window.setTimeout(() => {wst += 1}, 1)", null },
452+
.{ "wst", "1" },
453+
454+
.{ "window.setTimeout((a, b) => {wst = a + b}, 1, 2, 3)", null },
455+
.{ "wst", "5" },
435456
}, .{});
436457

437458
// window event target

src/runtime/js.zig

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1766,13 +1766,28 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
17661766
const js_this = try js_context.valueToExistingObject(this);
17671767

17681768
const aargs = if (comptime @typeInfo(@TypeOf(args)) == .null) struct {}{} else args;
1769-
const fields = @typeInfo(@TypeOf(aargs)).@"struct".fields;
1770-
var js_args: [fields.len]v8.Value = undefined;
1771-
inline for (fields, 0..) |f, i| {
1772-
js_args[i] = try js_context.zigValueToJs(@field(aargs, f.name));
1773-
}
17741769

1775-
const result = self.func.castToFunction().call(js_context.v8_context, js_this, &js_args);
1770+
const js_args: []const v8.Value = switch (@typeInfo(@TypeOf(aargs))) {
1771+
.@"struct" => |s| blk: {
1772+
const fields = s.fields;
1773+
var js_args: [fields.len]v8.Value = undefined;
1774+
inline for (fields, 0..) |f, i| {
1775+
js_args[i] = try js_context.zigValueToJs(@field(aargs, f.name));
1776+
}
1777+
const cargs: [fields.len]v8.Value = js_args;
1778+
break :blk &cargs;
1779+
},
1780+
.pointer => blk: {
1781+
var values = try js_context.call_arena.alloc(v8.Value, args.len);
1782+
for (args, 0..) |a, i| {
1783+
values[i] = try js_context.zigValueToJs(a);
1784+
}
1785+
break :blk values;
1786+
},
1787+
else => @compileError("JS Function called with invalid paremter type"),
1788+
};
1789+
1790+
const result = self.func.castToFunction().call(js_context.v8_context, js_this, js_args);
17761791
if (result == null) {
17771792
return error.JSExecCallback;
17781793
}

0 commit comments

Comments
 (0)