diff --git a/src/browser/webapi/Document.zig b/src/browser/webapi/Document.zig index 5abf6624f..1295b7966 100644 --- a/src/browser/webapi/Document.zig +++ b/src/browser/webapi/Document.zig @@ -303,7 +303,18 @@ pub fn setDomain(self: *Document, value: []const u8) !void { try doc_frame.js.setOrigin(key); } -pub fn getCookie(_: *Document, frame: *Frame) ![]const u8 { +// A cookie-averse document (no browsing context: createHTMLDocument, +// DOMParser, XHR documents) reads cookies as the empty string and ignores +// writes. +fn isCookieAverse(self: *const Document, frame: *const Frame) bool { + const doc_frame = self._frame orelse return true; + return doc_frame.document != self and frame.document != self; +} + +pub fn getCookie(self: *Document, frame: *Frame) ![]const u8 { + if (self.isCookieAverse(frame)) { + return ""; + } var buf: std.ArrayList(u8) = .empty; try frame._session.cookie_jar.forRequest(frame.url, buf.writer(frame.local_arena), .{ .is_http = false, @@ -312,7 +323,10 @@ pub fn getCookie(_: *Document, frame: *Frame) ![]const u8 { return buf.items; } -pub fn setCookie(_: *Document, cookie_str: []const u8, frame: *Frame) ![]const u8 { +pub fn setCookie(self: *Document, cookie_str: []const u8, frame: *Frame) ![]const u8 { + if (self.isCookieAverse(frame)) { + return cookie_str; + } // we use the cookie jar's allocator to parse the cookie because it // outlives the frame's arena. const Cookie = @import("storage/Cookie.zig"); diff --git a/src/browser/webapi/element/Html.zig b/src/browser/webapi/element/Html.zig index 2817e196b..be30988ea 100644 --- a/src/browser/webapi/element/Html.zig +++ b/src/browser/webapi/element/Html.zig @@ -372,6 +372,17 @@ pub fn setTranslate(self: *HtmlElement, translate: bool, frame: *Frame) !void { try self.asElement().setAttributeSafe(comptime .wrap("translate"), .wrap(if (translate) "yes" else "no"), frame); } +// accessKeyLabel: the UA-assigned shortcut for a valid (single character) +// accesskey, or the empty string. We report an Alt+ chord like Chromium. +pub fn getAccessKeyLabel(self: *HtmlElement, frame: *Frame) ![]const u8 { + const value = self.asElement().getAttributeSafe(comptime .wrap("accesskey")) orelse return ""; + const codepoints = std.unicode.utf8CountCodepoints(value) catch return ""; + if (codepoints != 1) { + return ""; + } + return std.fmt.allocPrint(frame.call_arena, "Alt+{s}", .{value}); +} + pub fn getPopover(self: *HtmlElement) ?[]const u8 { const s = popover.getState(self.asElement()) orelse return null; return @tagName(s); @@ -1735,6 +1746,7 @@ pub const JsApi = struct { pub const dir = bridge.accessor(HtmlElement.getDir, HtmlElement.setDir, .{ .ce_reactions = true }); pub const hidden = bridge.accessor(HtmlElement.getHidden, HtmlElement.setHidden, .{ .ce_reactions = true }); pub const translate = bridge.accessor(HtmlElement.getTranslate, HtmlElement.setTranslate, .{ .ce_reactions = true }); + pub const accessKeyLabel = bridge.accessor(HtmlElement.getAccessKeyLabel, null, .{}); pub const popover = bridge.accessor(HtmlElement.getPopover, HtmlElement.setPopover, .{ .ce_reactions = true }); pub const showPopover = bridge.function(HtmlElement.showPopover, .{}); pub const hidePopover = bridge.function(HtmlElement.hidePopover, .{});