diff --git a/src/browser/Browser.zig b/src/browser/Browser.zig index 16ff2a97..1d3bcbfe 100644 --- a/src/browser/Browser.zig +++ b/src/browser/Browser.zig @@ -108,8 +108,3 @@ pub fn runMessageLoop(self: *const Browser) void { } self.env.runIdleTasks(); } - -const testing = @import("../testing.zig"); -test "Browser" { - try testing.htmlRunner("browser.html", .{}); -} diff --git a/src/browser/EventManager.zig b/src/browser/EventManager.zig index cce80fe9..5efa111b 100644 --- a/src/browser/EventManager.zig +++ b/src/browser/EventManager.zig @@ -92,7 +92,7 @@ pub fn dispatch(self: *EventManager, target: *EventTarget, event: *Event) !void event._target = target; switch (target._type) { .node => |node| try self.dispatchNode(node, event), - .xhr, .window, .abort_signal => { + .xhr, .window, .abort_signal, .media_query_list => { const list = self.lookup.getPtr(@intFromPtr(target)) orelse return; try self.dispatchAll(list, target, event); }, diff --git a/src/browser/js/bridge.zig b/src/browser/js/bridge.zig index 95d2bb29..160abb7b 100644 --- a/src/browser/js/bridge.zig +++ b/src/browser/js/bridge.zig @@ -442,6 +442,7 @@ pub const JsApis = flattenTypes(&.{ @import("../webapi/Crypto.zig"), @import("../webapi/css/CSSStyleDeclaration.zig"), @import("../webapi/css/CSSStyleProperties.zig"), + @import("../webapi/css/MediaQueryList.zig"), @import("../webapi/Document.zig"), @import("../webapi/HTMLDocument.zig"), @import("../webapi/KeyValueList.zig"), diff --git a/src/browser/tests/css/media_query_list.html b/src/browser/tests/css/media_query_list.html new file mode 100644 index 00000000..63cf3c97 --- /dev/null +++ b/src/browser/tests/css/media_query_list.html @@ -0,0 +1,37 @@ + + + + + + + + + + + + + diff --git a/src/browser/tests/page/meta.html b/src/browser/tests/page/meta.html index bf310c41..80647a87 100644 --- a/src/browser/tests/page/meta.html +++ b/src/browser/tests/page/meta.html @@ -37,4 +37,6 @@ testing.expectEqual('string', typeof plainDoc.URL); testing.expectEqual('string', typeof document.readyState); testing.expectEqual('string', typeof plainDoc.readyState); + + testing.expectEqual("[object Intl.DateTimeFormat]", new Intl.DateTimeFormat().toString()); diff --git a/src/browser/webapi/EventTarget.zig b/src/browser/webapi/EventTarget.zig index 45379018..cfb9be4d 100644 --- a/src/browser/webapi/EventTarget.zig +++ b/src/browser/webapi/EventTarget.zig @@ -15,6 +15,7 @@ pub const Type = union(enum) { window: *@import("Window.zig"), xhr: *@import("net/XMLHttpRequestEventTarget.zig"), abort_signal: *@import("AbortSignal.zig"), + media_query_list: *@import("css/MediaQueryList.zig"), }; pub fn dispatchEvent(self: *EventTarget, event: *Event, page: *Page) !bool { @@ -62,6 +63,7 @@ pub fn format(self: *EventTarget, writer: *std.Io.Writer) !void { .window => writer.writeAll(""), .xhr => writer.writeAll(""), .abort_signal => writer.writeAll(""), + .media_query_list => writer.writeAll(""), }; } diff --git a/src/browser/webapi/Location.zig b/src/browser/webapi/Location.zig index 3b9ed58d..0d6bea3b 100644 --- a/src/browser/webapi/Location.zig +++ b/src/browser/webapi/Location.zig @@ -65,7 +65,7 @@ pub const JsApi = struct { pub const hash = bridge.accessor(Location.getHash, null, .{}); pub const pathname = bridge.accessor(Location.getPathname, null, .{}); pub const hostname = bridge.accessor(Location.getHostname, null, .{}); - pub const host = bridge.accessor(URL.getHost, null, .{}); + pub const host = bridge.accessor(Location.getHost, null, .{}); pub const port = bridge.accessor(Location.getPort, null, .{}); pub const origin = bridge.accessor(Location.getOrigin, null, .{}); pub const protocol = bridge.accessor(Location.getProtocol, null, .{}); diff --git a/src/browser/webapi/URL.zig b/src/browser/webapi/URL.zig index 32ca1759..96938403 100644 --- a/src/browser/webapi/URL.zig +++ b/src/browser/webapi/URL.zig @@ -130,41 +130,6 @@ pub fn toString(self: *const URL, page: *const Page) ![:0]const u8 { return buf.written()[0 .. buf.written().len - 1 :0]; } -fn getUserInfo(self: *const URL) ?[]const u8 { - const raw = self._raw; - const scheme_end = std.mem.indexOf(u8, raw, "://") orelse return null; - const authority_start = scheme_end + 3; - - const pos = std.mem.indexOfScalar(u8, raw[authority_start..], '@') orelse return null; - const path_start = std.mem.indexOfScalarPos(u8, raw, authority_start, '/') orelse raw.len; - - const full_pos = authority_start + pos; - if (full_pos < path_start) { - return raw[authority_start..full_pos]; - } - - return null; -} - -fn getHost(self: *const URL) []const u8 { - const raw = self._raw; - const scheme_end = std.mem.indexOf(u8, raw, "://") orelse return ""; - - var authority_start = scheme_end + 3; - if (std.mem.indexOf(u8, raw[authority_start..], "@")) |pos| { - authority_start += pos + 1; - } - - const authority = raw[authority_start..]; - const path_start = std.mem.indexOfAny(u8, authority, "/?#") orelse return authority; - return authority[0..path_start]; -} - -const KnownProtocol = enum { - @"http:", - @"https:", -}; - pub const JsApi = struct { pub const bridge = js.Bridge(URL); diff --git a/src/browser/webapi/Window.zig b/src/browser/webapi/Window.zig index a288e9e5..899a7cfc 100644 --- a/src/browser/webapi/Window.zig +++ b/src/browser/webapi/Window.zig @@ -11,6 +11,7 @@ const Location = @import("Location.zig"); const Fetch = @import("net/Fetch.zig"); const EventTarget = @import("EventTarget.zig"); const ErrorEvent = @import("event/ErrorEvent.zig"); +const MediaQueryList = @import("css/MediaQueryList.zig"); const storage = @import("storage/storage.zig"); const Window = @This(); @@ -135,6 +136,13 @@ pub fn cancelAnimationFrame(self: *Window, id: u32) void { sc.removed = true; } +pub fn matchMedia(_: *const Window, query: []const u8, page: *Page) !*MediaQueryList { + return page._factory.eventTarget(MediaQueryList{ + ._proto = undefined, + ._media = try page.dupeString(query), + }); +} + pub fn btoa(_: *const Window, input: []const u8, page: *Page) ![]const u8 { const encoded_len = std.base64.standard.Encoder.calcSize(input.len); const encoded = try page.call_arena.alloc(u8, encoded_len); @@ -266,6 +274,7 @@ pub const JsApi = struct { pub const clearImmediate = bridge.function(Window.clearImmediate, .{}); pub const requestAnimationFrame = bridge.function(Window.requestAnimationFrame, .{}); pub const cancelAnimationFrame = bridge.function(Window.cancelAnimationFrame, .{}); + pub const matchMedia = bridge.function(Window.matchMedia, .{}); pub const btoa = bridge.function(Window.btoa, .{}); pub const atob = bridge.function(Window.atob, .{}); }; diff --git a/src/browser/webapi/css/MediaQueryList.zig b/src/browser/webapi/css/MediaQueryList.zig new file mode 100644 index 00000000..aec6559f --- /dev/null +++ b/src/browser/webapi/css/MediaQueryList.zig @@ -0,0 +1,44 @@ +// zlint-disable unused-decls +const std = @import("std"); +const js = @import("../../js/js.zig"); +const EventTarget = @import("../EventTarget.zig"); + +const MediaQueryList = @This(); + +_proto: *EventTarget, +_media: []const u8, + +pub fn deinit(self: *MediaQueryList) void { + _ = self; +} + +pub fn asEventTarget(self: *MediaQueryList) *EventTarget { + return self._proto; +} + +pub fn getMedia(self: *const MediaQueryList) []const u8 { + return self._media; +} + +/// Always returns false for dummy implementation +pub fn getMatches(_: *const MediaQueryList) bool { + return false; +} + +pub const JsApi = struct { + pub const bridge = js.Bridge(MediaQueryList); + + pub const Meta = struct { + pub const name = "MediaQueryList"; + pub const prototype_chain = bridge.prototypeChain(); + pub var class_index: u16 = 0; + }; + + pub const media = bridge.accessor(MediaQueryList.getMedia, null, .{}); + pub const matches = bridge.accessor(MediaQueryList.getMatches, null, .{}); +}; + +const testing = @import("../../../testing.zig"); +test "WebApi: MediaQueryList" { + try testing.htmlRunner("css/media_query_list.html", .{}); +}