diff --git a/src/browser/dump.zig b/src/browser/dump.zig
index 2e00ba39..0617b488 100644
--- a/src/browser/dump.zig
+++ b/src/browser/dump.zig
@@ -45,7 +45,7 @@ pub fn root(opts: RootOpts, writer: *std.Io.Writer, page: *Page) !void {
}
}
- return deep(doc.asNode(), .{.strip = opts.strip}, writer);
+ return deep(doc.asNode(), .{ .strip = opts.strip }, writer);
}
pub fn deep(node: *Node, opts: Opts, writer: *std.Io.Writer) error{WriteFailed}!void {
diff --git a/src/browser/js/bridge.zig b/src/browser/js/bridge.zig
index bc380d1a..d4b6b6fe 100644
--- a/src/browser/js/bridge.zig
+++ b/src/browser/js/bridge.zig
@@ -488,9 +488,14 @@ pub const JsApis = flattenTypes(&.{
@import("../webapi/collections.zig"),
@import("../webapi/Console.zig"),
@import("../webapi/Crypto.zig"),
+ @import("../webapi/css/CSSRule.zig"),
+ @import("../webapi/css/CSSRuleList.zig"),
@import("../webapi/css/CSSStyleDeclaration.zig"),
+ @import("../webapi/css/CSSStyleRule.zig"),
+ @import("../webapi/css/CSSStyleSheet.zig"),
@import("../webapi/css/CSSStyleProperties.zig"),
@import("../webapi/css/MediaQueryList.zig"),
+ @import("../webapi/css/StyleSheetList.zig"),
@import("../webapi/Document.zig"),
@import("../webapi/HTMLDocument.zig"),
@import("../webapi/History.zig"),
diff --git a/src/browser/tests/css/stylesheet.html b/src/browser/tests/css/stylesheet.html
new file mode 100644
index 00000000..abc1ed92
--- /dev/null
+++ b/src/browser/tests/css/stylesheet.html
@@ -0,0 +1,207 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/browser/webapi/Document.zig b/src/browser/webapi/Document.zig
index e895bfd4..05223fde 100644
--- a/src/browser/webapi/Document.zig
+++ b/src/browser/webapi/Document.zig
@@ -31,6 +31,7 @@ const NodeFilter = @import("NodeFilter.zig");
const DOMTreeWalker = @import("DOMTreeWalker.zig");
const DOMNodeIterator = @import("DOMNodeIterator.zig");
const DOMImplementation = @import("DOMImplementation.zig");
+const StyleSheetList = @import("css/StyleSheetList.zig");
pub const HTMLDocument = @import("HTMLDocument.zig");
@@ -43,6 +44,7 @@ _ready_state: ReadyState = .loading,
_current_script: ?*Element.Html.Script = null,
_elements_by_id: std.StringHashMapUnmanaged(*Element) = .empty,
_active_element: ?*Element = null,
+_style_sheets: ?*StyleSheetList = null,
pub const Type = union(enum) {
generic,
@@ -225,6 +227,15 @@ pub fn getActiveElement(self: *Document) ?*Element {
return self.getDocumentElement();
}
+pub fn getStyleSheets(self: *Document, page: *Page) !*StyleSheetList {
+ if (self._style_sheets) |sheets| {
+ return sheets;
+ }
+ const sheets = try StyleSheetList.init(page);
+ self._style_sheets = sheets;
+ return sheets;
+}
+
const ReadyState = enum {
loading,
interactive,
@@ -253,7 +264,7 @@ pub const JsApi = struct {
pub const readyState = bridge.accessor(Document.getReadyState, null, .{});
pub const implementation = bridge.accessor(Document.getImplementation, null, .{});
pub const activeElement = bridge.accessor(Document.getActiveElement, null, .{});
-
+ pub const styleSheets = bridge.accessor(Document.getStyleSheets, null, .{});
pub const createElement = bridge.function(Document.createElement, .{});
pub const createElementNS = bridge.function(Document.createElementNS, .{});
pub const createDocumentFragment = bridge.function(Document.createDocumentFragment, .{});
diff --git a/src/browser/webapi/Navigator.zig b/src/browser/webapi/Navigator.zig
index 63b4cfc9..3fa8154f 100644
--- a/src/browser/webapi/Navigator.zig
+++ b/src/browser/webapi/Navigator.zig
@@ -120,4 +120,3 @@ pub const JsApi = struct {
// Methods
pub const javaEnabled = bridge.function(Navigator.javaEnabled, .{});
};
-
diff --git a/src/browser/webapi/Window.zig b/src/browser/webapi/Window.zig
index b65359e4..1607bb79 100644
--- a/src/browser/webapi/Window.zig
+++ b/src/browser/webapi/Window.zig
@@ -243,7 +243,6 @@ pub fn atob(_: *const Window, input: []const u8, page: *Page) ![]const u8 {
return decoded;
}
-
const ScheduleOpts = struct {
repeat: bool,
params: []js.Object,
diff --git a/src/browser/webapi/css/CSSRule.zig b/src/browser/webapi/css/CSSRule.zig
new file mode 100644
index 00000000..dcf41db9
--- /dev/null
+++ b/src/browser/webapi/css/CSSRule.zig
@@ -0,0 +1,90 @@
+const std = @import("std");
+const js = @import("../../js/js.zig");
+const Page = @import("../../Page.zig");
+
+const CSSRule = @This();
+
+pub const Type = enum(u16) {
+ style = 1,
+ charset = 2,
+ import = 3,
+ media = 4,
+ font_face = 5,
+ page = 6,
+ keyframes = 7,
+ keyframe = 8,
+ margin = 9,
+ namespace = 10,
+ counter_style = 11,
+ supports = 12,
+ document = 13,
+ font_feature_values = 14,
+ viewport = 15,
+ region_style = 16,
+};
+
+_type: Type,
+
+pub fn init(rule_type: Type, page: *Page) !*CSSRule {
+ return page._factory.create(CSSRule{
+ ._type = rule_type,
+ });
+}
+
+pub fn getType(self: *const CSSRule) u16 {
+ return @intFromEnum(self._type);
+}
+
+pub fn getCssText(self: *const CSSRule, page: *Page) []const u8 {
+ _ = self;
+ _ = page;
+ return "";
+}
+
+pub fn setCssText(self: *CSSRule, text: []const u8, page: *Page) !void {
+ _ = self;
+ _ = text;
+ _ = page;
+}
+
+pub fn getParentRule(self: *const CSSRule) ?*CSSRule {
+ _ = self;
+ return null;
+}
+
+pub fn getParentStyleSheet(self: *const CSSRule) ?*CSSRule {
+ _ = self;
+ return null;
+}
+
+pub const JsApi = struct {
+ pub const bridge = js.Bridge(CSSRule);
+
+ pub const Meta = struct {
+ pub const name = "CSSRule";
+ pub var class_id: bridge.ClassId = undefined;
+ pub const prototype_chain = bridge.prototypeChain();
+ };
+
+ pub const STYLE_RULE = 1;
+ pub const CHARSET_RULE = 2;
+ pub const IMPORT_RULE = 3;
+ pub const MEDIA_RULE = 4;
+ pub const FONT_FACE_RULE = 5;
+ pub const PAGE_RULE = 6;
+ pub const KEYFRAMES_RULE = 7;
+ pub const KEYFRAME_RULE = 8;
+ pub const MARGIN_RULE = 9;
+ pub const NAMESPACE_RULE = 10;
+ pub const COUNTER_STYLE_RULE = 11;
+ pub const SUPPORTS_RULE = 12;
+ pub const DOCUMENT_RULE = 13;
+ pub const FONT_FEATURE_VALUES_RULE = 14;
+ pub const VIEWPORT_RULE = 15;
+ pub const REGION_STYLE_RULE = 16;
+
+ pub const @"type" = bridge.accessor(CSSRule.getType, null, .{});
+ pub const cssText = bridge.accessor(CSSRule.getCssText, CSSRule.setCssText, .{});
+ pub const parentRule = bridge.accessor(CSSRule.getParentRule, null, .{});
+ pub const parentStyleSheet = bridge.accessor(CSSRule.getParentStyleSheet, null, .{});
+};
diff --git a/src/browser/webapi/css/CSSRuleList.zig b/src/browser/webapi/css/CSSRuleList.zig
new file mode 100644
index 00000000..4a700237
--- /dev/null
+++ b/src/browser/webapi/css/CSSRuleList.zig
@@ -0,0 +1,36 @@
+const std = @import("std");
+const js = @import("../../js/js.zig");
+const Page = @import("../../Page.zig");
+const CSSRule = @import("CSSRule.zig");
+
+const CSSRuleList = @This();
+
+_rules: []*CSSRule = &.{},
+
+pub fn init(page: *Page) !*CSSRuleList {
+ return page._factory.create(CSSRuleList{});
+}
+
+pub fn length(self: *const CSSRuleList) u32 {
+ return @intCast(self._rules.len);
+}
+
+pub fn item(self: *const CSSRuleList, index: usize) ?*CSSRule {
+ if (index >= self._rules.len) {
+ return null;
+ }
+ return self._rules[index];
+}
+
+pub const JsApi = struct {
+ pub const bridge = js.Bridge(CSSRuleList);
+
+ pub const Meta = struct {
+ pub const name = "CSSRuleList";
+ pub const prototype_chain = bridge.prototypeChain();
+ pub var class_id: bridge.ClassId = undefined;
+ };
+
+ pub const length = bridge.accessor(CSSRuleList.length, null, .{});
+ pub const @"[]" = bridge.indexed(CSSRuleList.item, .{ .null_as_undefined = true });
+};
diff --git a/src/browser/webapi/css/CSSStyleDeclaration.zig b/src/browser/webapi/css/CSSStyleDeclaration.zig
index 887a8098..536fa737 100644
--- a/src/browser/webapi/css/CSSStyleDeclaration.zig
+++ b/src/browser/webapi/css/CSSStyleDeclaration.zig
@@ -29,28 +29,6 @@ const CSSStyleDeclaration = @This();
_element: ?*Element = null,
_properties: std.DoublyLinkedList = .{},
-pub const Property = struct {
- _name: String,
- _value: String,
- _important: bool = false,
- _node: std.DoublyLinkedList.Node,
-
- fn fromNodeLink(n: *std.DoublyLinkedList.Node) *Property {
- return @alignCast(@fieldParentPtr("_node", n));
- }
-
- pub fn format(self: *const Property, writer: *std.Io.Writer) !void {
- try self._name.format(writer);
- try writer.writeAll(": ");
- try self._value.format(writer);
-
- if (self._important) {
- try writer.writeAll(" !important");
- }
- try writer.writeByte(';');
- }
-};
-
pub fn init(element: ?*Element, page: *Page) !*CSSStyleDeclaration {
return page._factory.create(CSSStyleDeclaration{
._element = element,
@@ -214,6 +192,28 @@ fn normalizePropertyName(name: []const u8, buf: []u8) []const u8 {
return std.ascii.lowerString(buf, name);
}
+pub const Property = struct {
+ _name: String,
+ _value: String,
+ _important: bool = false,
+ _node: std.DoublyLinkedList.Node,
+
+ fn fromNodeLink(n: *std.DoublyLinkedList.Node) *Property {
+ return @alignCast(@fieldParentPtr("_node", n));
+ }
+
+ pub fn format(self: *const Property, writer: *std.Io.Writer) !void {
+ try self._name.format(writer);
+ try writer.writeAll(": ");
+ try self._value.format(writer);
+
+ if (self._important) {
+ try writer.writeAll(" !important");
+ }
+ try writer.writeByte(';');
+ }
+};
+
pub const JsApi = struct {
pub const bridge = js.Bridge(CSSStyleDeclaration);
diff --git a/src/browser/webapi/css/CSSStyleProperties.zig b/src/browser/webapi/css/CSSStyleProperties.zig
index f595838e..199d1214 100644
--- a/src/browser/webapi/css/CSSStyleProperties.zig
+++ b/src/browser/webapi/css/CSSStyleProperties.zig
@@ -72,7 +72,9 @@ fn isKnownCSSProperty(dash_case: []const u8) bool {
}
fn camelCaseToDashCase(name: []const u8, buf: []u8) []const u8 {
- if (name.len == 0) return name;
+ if (name.len == 0) {
+ return name;
+ }
// Special case: cssFloat -> float
const lower_name = std.ascii.lowerString(buf, name);
diff --git a/src/browser/webapi/css/CSSStyleRule.zig b/src/browser/webapi/css/CSSStyleRule.zig
new file mode 100644
index 00000000..c477621c
--- /dev/null
+++ b/src/browser/webapi/css/CSSStyleRule.zig
@@ -0,0 +1,48 @@
+const std = @import("std");
+const js = @import("../../js/js.zig");
+const Page = @import("../../Page.zig");
+const CSSRule = @import("CSSRule.zig");
+const CSSStyleDeclaration = @import("CSSStyleDeclaration.zig");
+
+const CSSStyleRule = @This();
+
+_proto: *CSSRule,
+_selector_text: []const u8 = "",
+_style: ?*CSSStyleDeclaration = null,
+
+pub fn init(page: *Page) !*CSSStyleRule {
+ const rule = try CSSRule.init(.style, page);
+ return page._factory.create(CSSStyleRule{
+ ._proto = rule,
+ });
+}
+
+pub fn getSelectorText(self: *const CSSStyleRule) []const u8 {
+ return self._selector_text;
+}
+
+pub fn setSelectorText(self: *CSSStyleRule, text: []const u8, page: *Page) !void {
+ self._selector_text = try page.dupeString(text);
+}
+
+pub fn getStyle(self: *CSSStyleRule, page: *Page) !*CSSStyleDeclaration {
+ if (self._style) |style| {
+ return style;
+ }
+ const style = try CSSStyleDeclaration.init(null, page);
+ self._style = style;
+ return style;
+}
+
+pub const JsApi = struct {
+ pub const bridge = js.Bridge(CSSStyleRule);
+
+ pub const Meta = struct {
+ pub const name = "CSSStyleRule";
+ pub const prototype_chain = bridge.prototypeChain(CSSRule);
+ pub var class_id: bridge.ClassId = undefined;
+ };
+
+ pub const selectorText = bridge.accessor(CSSStyleRule.getSelectorText, CSSStyleRule.setSelectorText, .{});
+ pub const style = bridge.accessor(CSSStyleRule.getStyle, null, .{});
+};
diff --git a/src/browser/webapi/css/CSSStyleSheet.zig b/src/browser/webapi/css/CSSStyleSheet.zig
new file mode 100644
index 00000000..a377618d
--- /dev/null
+++ b/src/browser/webapi/css/CSSStyleSheet.zig
@@ -0,0 +1,87 @@
+const std = @import("std");
+const js = @import("../../js/js.zig");
+const Page = @import("../../Page.zig");
+const CSSRuleList = @import("CSSRuleList.zig");
+const CSSRule = @import("CSSRule.zig");
+
+const CSSStyleSheet = @This();
+
+_href: ?[]const u8 = null,
+_title: []const u8 = "",
+_disabled: bool = false,
+_css_rules: ?*CSSRuleList = null,
+_owner_rule: ?*CSSRule = null,
+
+pub fn init(page: *Page) !*CSSStyleSheet {
+ return page._factory.create(CSSStyleSheet{});
+}
+
+pub fn getOwnerNode(self: *const CSSStyleSheet) ?*CSSStyleSheet {
+ _ = self;
+ return null;
+}
+
+pub fn getHref(self: *const CSSStyleSheet) ?[]const u8 {
+ return self._href;
+}
+
+pub fn getTitle(self: *const CSSStyleSheet) []const u8 {
+ return self._title;
+}
+
+pub fn getDisabled(self: *const CSSStyleSheet) bool {
+ return self._disabled;
+}
+
+pub fn setDisabled(self: *CSSStyleSheet, disabled: bool) void {
+ self._disabled = disabled;
+}
+
+pub fn getCssRules(self: *CSSStyleSheet, page: *Page) !*CSSRuleList {
+ if (self._css_rules) |rules| return rules;
+ const rules = try CSSRuleList.init(page);
+ self._css_rules = rules;
+ return rules;
+}
+
+pub fn getOwnerRule(self: *const CSSStyleSheet) ?*CSSRule {
+ return self._owner_rule;
+}
+
+pub fn insertRule(self: *CSSStyleSheet, rule: []const u8, index: u32, page: *Page) !u32 {
+ _ = self;
+ _ = rule;
+ _ = index;
+ _ = page;
+ return 0;
+}
+
+pub fn deleteRule(self: *CSSStyleSheet, index: u32, page: *Page) !void {
+ _ = self;
+ _ = index;
+ _ = page;
+}
+
+pub const JsApi = struct {
+ pub const bridge = js.Bridge(CSSStyleSheet);
+
+ pub const Meta = struct {
+ pub const name = "CSSStyleSheet";
+ pub const prototype_chain = bridge.prototypeChain();
+ pub var class_id: bridge.ClassId = undefined;
+ };
+
+ pub const ownerNode = bridge.accessor(CSSStyleSheet.getOwnerNode, null, .{ .null_as_undefined = true });
+ pub const href = bridge.accessor(CSSStyleSheet.getHref, null, .{ .null_as_undefined = true });
+ pub const title = bridge.accessor(CSSStyleSheet.getTitle, null, .{});
+ pub const disabled = bridge.accessor(CSSStyleSheet.getDisabled, CSSStyleSheet.setDisabled, .{});
+ pub const cssRules = bridge.accessor(CSSStyleSheet.getCssRules, null, .{});
+ pub const ownerRule = bridge.accessor(CSSStyleSheet.getOwnerRule, null, .{ .null_as_undefined = true });
+ pub const insertRule = bridge.function(CSSStyleSheet.insertRule, .{});
+ pub const deleteRule = bridge.function(CSSStyleSheet.deleteRule, .{});
+};
+
+const testing = @import("../../../testing.zig");
+test "WebApi: CSSStyleSheet" {
+ try testing.htmlRunner("css/stylesheet.html", .{});
+}
diff --git a/src/browser/webapi/css/StyleSheetList.zig b/src/browser/webapi/css/StyleSheetList.zig
new file mode 100644
index 00000000..8a019a18
--- /dev/null
+++ b/src/browser/webapi/css/StyleSheetList.zig
@@ -0,0 +1,34 @@
+const std = @import("std");
+const js = @import("../../js/js.zig");
+const Page = @import("../../Page.zig");
+const CSSStyleSheet = @import("CSSStyleSheet.zig");
+
+const StyleSheetList = @This();
+
+_sheets: []*CSSStyleSheet = &.{},
+
+pub fn init(page: *Page) !*StyleSheetList {
+ return page._factory.create(StyleSheetList{});
+}
+
+pub fn length(self: *const StyleSheetList) u32 {
+ return @intCast(self._sheets.len);
+}
+
+pub fn item(self: *const StyleSheetList, index: usize) ?*CSSStyleSheet {
+ if (index >= self._sheets.len) return null;
+ return self._sheets[index];
+}
+
+pub const JsApi = struct {
+ pub const bridge = js.Bridge(StyleSheetList);
+
+ pub const Meta = struct {
+ pub const name = "StyleSheetList";
+ pub const prototype_chain = bridge.prototypeChain();
+ pub var class_id: bridge.ClassId = undefined;
+ };
+
+ pub const length = bridge.accessor(StyleSheetList.length, null, .{});
+ pub const @"[]" = bridge.indexed(StyleSheetList.item, .{ .null_as_undefined = true });
+};
diff --git a/src/browser/webapi/selector/Parser.zig b/src/browser/webapi/selector/Parser.zig
index b97f7c00..a793e7c8 100644
--- a/src/browser/webapi/selector/Parser.zig
+++ b/src/browser/webapi/selector/Parser.zig
@@ -1454,4 +1454,3 @@ test "Selector: Parser.parseNthPattern" {
try testing.expectEqual(" )", parser.input);
}
}
-
diff --git a/src/cdp/domains/log.zig b/src/cdp/domains/log.zig
index 66b8b79f..2eca6847 100644
--- a/src/cdp/domains/log.zig
+++ b/src/cdp/domains/log.zig
@@ -88,7 +88,7 @@ pub fn LogInterceptor(comptime BC: type) type {
self.bc.cdp.sendEvent("Log.entryAdded", .{
.entry = .{
.source = switch (scope) {
- .js, .console => "javascript",
+ .js, .console => "javascript",
.http => "network",
.telemetry, .unknown_prop, .interceptor => unreachable, // filtered out in writer above
else => "other",
diff --git a/src/html5ever/lib.rs b/src/html5ever/lib.rs
index 992b00fd..69f6b399 100644
--- a/src/html5ever/lib.rs
+++ b/src/html5ever/lib.rs
@@ -184,6 +184,7 @@ pub extern "C" fn html5ever_get_memory_usage() -> Memory {
// Streaming parser API
// The Parser type from html5ever implements TendrilSink and supports streaming
pub struct StreamingParser {
+ #[allow(dead_code)]
arena: Box>,
parser: Box,
}