mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-28 14:43:28 +00:00
Merge pull request #840 from lightpanda-io/xhr_readystatechange
Some checks failed
e2e-test / zig build release (push) Has been cancelled
zig-test / zig build dev (push) Has been cancelled
zig-test / zig test (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 / browser fetch (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
nightly build / build-linux-x86_64 (push) Has been cancelled
nightly build / build-linux-aarch64 (push) Has been cancelled
nightly build / build-macos-aarch64 (push) Has been cancelled
nightly build / build-macos-x86_64 (push) Has been cancelled
wpt / web platform tests json output (push) Has been cancelled
wpt / perf-fmt (push) Has been cancelled
Some checks failed
e2e-test / zig build release (push) Has been cancelled
zig-test / zig build dev (push) Has been cancelled
zig-test / zig test (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 / browser fetch (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
nightly build / build-linux-x86_64 (push) Has been cancelled
nightly build / build-linux-aarch64 (push) Has been cancelled
nightly build / build-macos-aarch64 (push) Has been cancelled
nightly build / build-macos-x86_64 (push) Has been cancelled
wpt / web platform tests json output (push) Has been cancelled
wpt / perf-fmt (push) Has been cancelled
Add readystate change event to XHR
This commit is contained in:
@@ -23,10 +23,12 @@ const Page = @import("../page.zig").Page;
|
||||
const EventHandler = @import("../events/event.zig").EventHandler;
|
||||
|
||||
const DOMException = @import("exceptions.zig").DOMException;
|
||||
const Nod = @import("node.zig");
|
||||
const nod = @import("node.zig");
|
||||
|
||||
// EventTarget interfaces
|
||||
pub const Union = Nod.Union;
|
||||
pub const Union = union(enum) {
|
||||
node: nod.Union,
|
||||
xhr: *@import("../xhr/xhr.zig").XMLHttpRequest,
|
||||
};
|
||||
|
||||
// EventTarget implementation
|
||||
pub const EventTarget = struct {
|
||||
@@ -39,18 +41,22 @@ pub const EventTarget = struct {
|
||||
// The window is a common non-node target, but it's easy to handle as
|
||||
// its a singleton.
|
||||
if (@intFromPtr(et) == @intFromPtr(&page.window.base)) {
|
||||
return .{ .Window = &page.window };
|
||||
return .{ .node = .{ .Window = &page.window } };
|
||||
}
|
||||
|
||||
// AbortSignal is another non-node target. It has a distinct usage though
|
||||
// so we hijack the event internal type to identity if.
|
||||
switch (try parser.eventGetInternalType(e)) {
|
||||
.abort_signal => {
|
||||
return .{ .AbortSignal = @fieldParentPtr("proto", @as(*parser.EventTargetTBase, @ptrCast(et))) };
|
||||
return .{ .node = .{ .AbortSignal = @fieldParentPtr("proto", @as(*parser.EventTargetTBase, @ptrCast(et))) } };
|
||||
},
|
||||
.xhr_event => {
|
||||
const XMLHttpRequestEventTarget = @import("../xhr/event_target.zig").XMLHttpRequestEventTarget;
|
||||
const base: *XMLHttpRequestEventTarget = @fieldParentPtr("base", @as(*parser.EventTargetTBase, @ptrCast(et)));
|
||||
return .{ .xhr = @fieldParentPtr("proto", base) };
|
||||
},
|
||||
else => {
|
||||
// some of these probably need to be special-cased like abort_signal
|
||||
return Nod.Node.toInterface(@as(*parser.Node, @ptrCast(et)));
|
||||
return .{ .node = try nod.Node.toInterface(@as(*parser.Node, @ptrCast(et))) };
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ pub const Event = struct {
|
||||
|
||||
pub fn toInterface(evt: *parser.Event) !Union {
|
||||
return switch (try parser.eventGetInternalType(evt)) {
|
||||
.event, .abort_signal => .{ .Event = evt },
|
||||
.event, .abort_signal, .xhr_event => .{ .Event = evt },
|
||||
.custom_event => .{ .CustomEvent = @as(*CustomEvent, @ptrCast(evt)).* },
|
||||
.progress_event => .{ .ProgressEvent = @as(*ProgressEvent, @ptrCast(evt)).* },
|
||||
.mouse_event => .{ .MouseEvent = @as(*parser.MouseEvent, @ptrCast(evt)) },
|
||||
|
||||
@@ -527,6 +527,7 @@ pub const EventType = enum(u8) {
|
||||
mouse_event = 3,
|
||||
error_event = 4,
|
||||
abort_signal = 5,
|
||||
xhr_event = 6,
|
||||
};
|
||||
|
||||
pub const MutationEvent = c.dom_mutation_event;
|
||||
|
||||
@@ -1017,7 +1017,7 @@ const Script = struct {
|
||||
|
||||
const src: []const u8 = blk: {
|
||||
const s = self.src orelse break :blk page.url.raw;
|
||||
break :blk try URL.stitch(page.arena, s, page.url.raw, .{.alloc = .if_needed});
|
||||
break :blk try URL.stitch(page.arena, s, page.url.raw, .{ .alloc = .if_needed });
|
||||
};
|
||||
|
||||
// if self.src is null, then this is an inline script, and it should
|
||||
|
||||
@@ -39,6 +39,7 @@ pub const XMLHttpRequestEventTarget = struct {
|
||||
onload_cbk: ?Function = null,
|
||||
ontimeout_cbk: ?Function = null,
|
||||
onloadend_cbk: ?Function = null,
|
||||
onreadystatechange_cbk: ?Function = null,
|
||||
|
||||
fn register(
|
||||
self: *XMLHttpRequestEventTarget,
|
||||
@@ -86,6 +87,9 @@ pub const XMLHttpRequestEventTarget = struct {
|
||||
pub fn get_onloadend(self: *XMLHttpRequestEventTarget) ?Function {
|
||||
return self.onloadend_cbk;
|
||||
}
|
||||
pub fn get_onreadystatechange(self: *XMLHttpRequestEventTarget) ?Function {
|
||||
return self.onreadystatechange_cbk;
|
||||
}
|
||||
|
||||
pub fn set_onloadstart(self: *XMLHttpRequestEventTarget, listener: EventHandler.Listener, page: *Page) !void {
|
||||
if (self.onloadstart_cbk) |cbk| try self.unregister("loadstart", cbk.id);
|
||||
@@ -111,4 +115,8 @@ pub const XMLHttpRequestEventTarget = struct {
|
||||
if (self.onloadend_cbk) |cbk| try self.unregister("loadend", cbk.id);
|
||||
self.onloadend_cbk = try self.register(page.arena, "loadend", listener);
|
||||
}
|
||||
pub fn set_onreadystatechange(self: *XMLHttpRequestEventTarget, listener: EventHandler.Listener, page: *Page) !void {
|
||||
if (self.onreadystatechange_cbk) |cbk| try self.unregister("readystatechange", cbk.id);
|
||||
self.onreadystatechange_cbk = try self.register(page.arena, "readystatechange", listener);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -138,6 +138,13 @@ pub const XMLHttpRequest = struct {
|
||||
done = 4,
|
||||
};
|
||||
|
||||
// class attributes
|
||||
pub const _UNSENT = @intFromEnum(State.unsent);
|
||||
pub const _OPENED = @intFromEnum(State.opened);
|
||||
pub const _HEADERS_RECEIVED = @intFromEnum(State.headers_received);
|
||||
pub const _LOADING = @intFromEnum(State.loading);
|
||||
pub const _DONE = @intFromEnum(State.done);
|
||||
|
||||
// https://xhr.spec.whatwg.org/#response-type
|
||||
const ResponseType = enum {
|
||||
Empty,
|
||||
@@ -360,6 +367,8 @@ pub const XMLHttpRequest = struct {
|
||||
// We can we defer event destroy once the event is dispatched.
|
||||
defer parser.eventDestroy(evt);
|
||||
|
||||
try parser.eventSetInternalType(evt, .xhr_event);
|
||||
|
||||
try parser.eventInit(evt, typ, .{ .bubbles = true, .cancelable = true });
|
||||
_ = try parser.eventTargetDispatchEvent(@as(*parser.EventTarget, @ptrCast(self)), evt);
|
||||
}
|
||||
@@ -579,11 +588,27 @@ pub const XMLHttpRequest = struct {
|
||||
}
|
||||
|
||||
fn onErr(self: *XMLHttpRequest, err: anyerror) void {
|
||||
self.state = .done;
|
||||
self.send_flag = false;
|
||||
self.dispatchEvt("readystatechange");
|
||||
self.dispatchProgressEvent("error", .{});
|
||||
self.dispatchProgressEvent("loadend", .{});
|
||||
|
||||
// capture the state before we change it
|
||||
const s = self.state;
|
||||
|
||||
const is_abort = err == DOMError.Abort;
|
||||
|
||||
if (is_abort) {
|
||||
self.state = .unsent;
|
||||
} else {
|
||||
self.state = .done;
|
||||
self.dispatchEvt("error");
|
||||
}
|
||||
|
||||
if (s != .done or s != .unsent) {
|
||||
self.dispatchEvt("readystatechange");
|
||||
if (is_abort) {
|
||||
self.dispatchProgressEvent("abort", .{});
|
||||
}
|
||||
self.dispatchProgressEvent("loadend", .{});
|
||||
}
|
||||
|
||||
const level: log.Level = if (err == DOMError.Abort) .debug else .err;
|
||||
log.log(.http, level, "error", .{
|
||||
@@ -922,4 +947,26 @@ test "Browser.XHR.XMLHttpRequest" {
|
||||
// So the url has been retrieved.
|
||||
.{ "status", "200" },
|
||||
}, .{});
|
||||
|
||||
try runner.testCases(&.{
|
||||
.{ "const req6 = new XMLHttpRequest()", null },
|
||||
.{
|
||||
\\ var readyStates = [];
|
||||
\\ var currentTarget = null;
|
||||
\\ req6.onreadystatechange = (e) => {
|
||||
\\ currentTarget = e.currentTarget;
|
||||
\\ readyStates.push(req6.readyState);
|
||||
\\ }
|
||||
,
|
||||
null,
|
||||
},
|
||||
.{ "req6.open('GET', 'https://127.0.0.1:9581/xhr')", null },
|
||||
.{ "req6.send()", null },
|
||||
.{ "readyStates.length", "4" },
|
||||
.{ "readyStates[0] === XMLHttpRequest.OPENED", "true" },
|
||||
.{ "readyStates[1] === XMLHttpRequest.HEADERS_RECEIVED", "true" },
|
||||
.{ "readyStates[2] === XMLHttpRequest.LOADING", "true" },
|
||||
.{ "readyStates[3] === XMLHttpRequest.DONE", "true" },
|
||||
.{ "currentTarget == req6", "true" },
|
||||
}, .{});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user