mirror of
				https://github.com/lightpanda-io/browser.git
				synced 2025-10-29 15:13:28 +00:00 
			
		
		
		
	Support params for setTimeout and setInterval
This commit is contained in:
		| @@ -20,7 +20,7 @@ const std = @import("std"); | ||||
|  | ||||
| const log = @import("../../log.zig"); | ||||
| const parser = @import("../netsurf.zig"); | ||||
| const Function = @import("../env.zig").Function; | ||||
| const Env = @import("../env.zig").Env; | ||||
| const Page = @import("../page.zig").Page; | ||||
| const Loop = @import("../../runtime/loop.zig").Loop; | ||||
|  | ||||
| @@ -36,6 +36,9 @@ const CSSStyleDeclaration = @import("../cssom/css_style_declaration.zig").CSSSty | ||||
| const Screen = @import("screen.zig").Screen; | ||||
| const Css = @import("../css/css.zig").Css; | ||||
|  | ||||
| const Function = Env.Function; | ||||
| const JsObject = Env.JsObject; | ||||
|  | ||||
| const storage = @import("../storage/storage.zig"); | ||||
|  | ||||
| // https://dom.spec.whatwg.org/#interface-window-extensions | ||||
| @@ -184,13 +187,12 @@ pub const Window = struct { | ||||
|         return page.loop.cancel(kv.value.loop_id); | ||||
|     } | ||||
|  | ||||
|     pub fn _setTimeout(self: *Window, cbk: Function, delay: ?u32, page: *Page) !u32 { | ||||
|         return self.createTimeout(cbk, delay, page, .{}); | ||||
|     pub fn _setTimeout(self: *Window, cbk: Function, delay: ?u32, params: []Env.JsObject, page: *Page) !u32 { | ||||
|         return self.createTimeout(cbk, delay, page, .{ .args = params }); | ||||
|     } | ||||
|  | ||||
|     // TODO handle callback arguments. | ||||
|     pub fn _setInterval(self: *Window, cbk: Function, delay: ?u32, page: *Page) !u32 { | ||||
|         return self.createTimeout(cbk, delay, page, .{ .repeat = true }); | ||||
|     pub fn _setInterval(self: *Window, cbk: Function, delay: ?u32, params: []Env.JsObject, page: *Page) !u32 { | ||||
|         return self.createTimeout(cbk, delay, page, .{ .repeat = true, .args = params }); | ||||
|     } | ||||
|  | ||||
|     pub fn _clearTimeout(self: *Window, id: u32, page: *Page) !void { | ||||
| @@ -230,10 +232,11 @@ pub const Window = struct { | ||||
|     } | ||||
|  | ||||
|     const CreateTimeoutOpts = struct { | ||||
|         args: []Env.JsObject = &.{}, | ||||
|         repeat: bool = false, | ||||
|         animation_frame: bool = false, | ||||
|     }; | ||||
|     fn createTimeout(self: *Window, cbk: Function, delay_: ?u32, page: *Page, comptime opts: CreateTimeoutOpts) !u32 { | ||||
|     fn createTimeout(self: *Window, cbk: Function, delay_: ?u32, page: *Page, opts: CreateTimeoutOpts) !u32 { | ||||
|         const delay = delay_ orelse 0; | ||||
|         if (delay > 5000) { | ||||
|             log.warn(.user_script, "long timeout ignored", .{ .delay = delay, .interval = opts.repeat }); | ||||
| @@ -258,6 +261,15 @@ pub const Window = struct { | ||||
|         } | ||||
|         errdefer _ = self.timers.remove(timer_id); | ||||
|  | ||||
|         const args = opts.args; | ||||
|         var persisted_args: []Env.JsObject = &.{}; | ||||
|         if (args.len > 0) { | ||||
|             persisted_args = try page.arena.alloc(Env.JsObject, args.len); | ||||
|             for (args, persisted_args) |a, *ca| { | ||||
|                 ca.* = try a.persist(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         const delay_ms: u63 = @as(u63, delay) * std.time.ns_per_ms; | ||||
|         const callback = try arena.create(TimerCallback); | ||||
|  | ||||
| @@ -266,6 +278,7 @@ pub const Window = struct { | ||||
|             .loop_id = 0, // we're going to set this to a real value shortly | ||||
|             .window = self, | ||||
|             .timer_id = timer_id, | ||||
|             .args = persisted_args, | ||||
|             .node = .{ .func = TimerCallback.run }, | ||||
|             .repeat = if (opts.repeat) delay_ms else null, | ||||
|             .animation_frame = opts.animation_frame, | ||||
| @@ -344,6 +357,8 @@ const TimerCallback = struct { | ||||
|  | ||||
|     window: *Window, | ||||
|  | ||||
|     args: []Env.JsObject = &.{}, | ||||
|  | ||||
|     fn run(node: *Loop.CallbackNode, repeat_delay: *?u63) void { | ||||
|         const self: *TimerCallback = @fieldParentPtr("node", node); | ||||
|  | ||||
| @@ -353,7 +368,7 @@ const TimerCallback = struct { | ||||
|         if (self.animation_frame) { | ||||
|             call = self.cbk.tryCall(void, .{self.window.performance._now()}, &result); | ||||
|         } else { | ||||
|             call = self.cbk.tryCall(void, .{}, &result); | ||||
|             call = self.cbk.tryCall(void, self.args, &result); | ||||
|         } | ||||
|  | ||||
|         call catch { | ||||
| @@ -427,11 +442,17 @@ test "Browser.HTML.Window" { | ||||
|         .{ "innerWidth", "2" }, | ||||
|     }, .{}); | ||||
|  | ||||
|     // cancelAnimationFrame should be able to cancel a request with the given id | ||||
|     try runner.testCases(&.{ | ||||
|         .{ "let longCall = false;", null }, | ||||
|         .{ "window.setTimeout(() => {longCall = true}, 5001);", null }, | ||||
|         .{ "longCall;", "false" }, | ||||
|  | ||||
|         .{ "let wst = 0;", null }, | ||||
|         .{ "window.setTimeout(() => {wst += 1}, 1)", null }, | ||||
|         .{ "wst", "1" }, | ||||
|  | ||||
|         .{ "window.setTimeout((a, b) => {wst = a + b}, 1, 2, 3)", null }, | ||||
|         .{ "wst", "5" }, | ||||
|     }, .{}); | ||||
|  | ||||
|     // window event target | ||||
|   | ||||
| @@ -1610,13 +1610,28 @@ pub fn Env(comptime State: type, comptime WebApis: type) type { | ||||
|                 const js_this = try js_context.valueToExistingObject(this); | ||||
|  | ||||
|                 const aargs = if (comptime @typeInfo(@TypeOf(args)) == .null) struct {}{} else args; | ||||
|                 const fields = @typeInfo(@TypeOf(aargs)).@"struct".fields; | ||||
|                 var js_args: [fields.len]v8.Value = undefined; | ||||
|                 inline for (fields, 0..) |f, i| { | ||||
|                     js_args[i] = try js_context.zigValueToJs(@field(aargs, f.name)); | ||||
|                 } | ||||
|  | ||||
|                 const result = self.func.castToFunction().call(js_context.v8_context, js_this, &js_args); | ||||
|                 const js_args: []const v8.Value = switch (@typeInfo(@TypeOf(aargs))) { | ||||
|                     .@"struct" => |s| blk: { | ||||
|                         const fields = s.fields; | ||||
|                         var js_args: [fields.len]v8.Value = undefined; | ||||
|                         inline for (fields, 0..) |f, i| { | ||||
|                             js_args[i] = try js_context.zigValueToJs(@field(aargs, f.name)); | ||||
|                         } | ||||
|                         const cargs: [fields.len]v8.Value = js_args; | ||||
|                         break :blk &cargs; | ||||
|                     }, | ||||
|                     .pointer => blk: { | ||||
|                         var values = try js_context.call_arena.alloc(v8.Value, args.len); | ||||
|                         for (args, 0..) |a, i| { | ||||
|                             values[i] = try js_context.zigValueToJs(a); | ||||
|                         } | ||||
|                         break :blk values; | ||||
|                     }, | ||||
|                     else => @compileError("JS Function called with invalid paremter type"), | ||||
|                 }; | ||||
|  | ||||
|                 const result = self.func.castToFunction().call(js_context.v8_context, js_this, js_args); | ||||
|                 if (result == null) { | ||||
|                     return error.JSExecCallback; | ||||
|                 } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Karl Seguin
					Karl Seguin