mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-12-16 08:18:59 +00:00
add some skeleton implementations for various CSS WebAPIs
This commit is contained in:
@@ -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 {
|
pub fn deep(node: *Node, opts: Opts, writer: *std.Io.Writer) error{WriteFailed}!void {
|
||||||
|
|||||||
@@ -488,9 +488,14 @@ pub const JsApis = flattenTypes(&.{
|
|||||||
@import("../webapi/collections.zig"),
|
@import("../webapi/collections.zig"),
|
||||||
@import("../webapi/Console.zig"),
|
@import("../webapi/Console.zig"),
|
||||||
@import("../webapi/Crypto.zig"),
|
@import("../webapi/Crypto.zig"),
|
||||||
|
@import("../webapi/css/CSSRule.zig"),
|
||||||
|
@import("../webapi/css/CSSRuleList.zig"),
|
||||||
@import("../webapi/css/CSSStyleDeclaration.zig"),
|
@import("../webapi/css/CSSStyleDeclaration.zig"),
|
||||||
|
@import("../webapi/css/CSSStyleRule.zig"),
|
||||||
|
@import("../webapi/css/CSSStyleSheet.zig"),
|
||||||
@import("../webapi/css/CSSStyleProperties.zig"),
|
@import("../webapi/css/CSSStyleProperties.zig"),
|
||||||
@import("../webapi/css/MediaQueryList.zig"),
|
@import("../webapi/css/MediaQueryList.zig"),
|
||||||
|
@import("../webapi/css/StyleSheetList.zig"),
|
||||||
@import("../webapi/Document.zig"),
|
@import("../webapi/Document.zig"),
|
||||||
@import("../webapi/HTMLDocument.zig"),
|
@import("../webapi/HTMLDocument.zig"),
|
||||||
@import("../webapi/History.zig"),
|
@import("../webapi/History.zig"),
|
||||||
|
|||||||
207
src/browser/tests/css/stylesheet.html
Normal file
207
src/browser/tests/css/stylesheet.html
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<script src="../testing.js"></script>
|
||||||
|
|
||||||
|
<script id="document_styleSheets">
|
||||||
|
{
|
||||||
|
const sheets = document.styleSheets;
|
||||||
|
testing.expectTrue(sheets !== null);
|
||||||
|
testing.expectEqual(0, sheets.length);
|
||||||
|
|
||||||
|
// Should return same instance
|
||||||
|
const sheets2 = document.styleSheets;
|
||||||
|
testing.expectTrue(sheets === sheets2);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="CSSStyleSheet_basic">
|
||||||
|
{
|
||||||
|
const sheets = document.styleSheets;
|
||||||
|
testing.expectEqual('StyleSheetList', sheets.constructor.name);
|
||||||
|
|
||||||
|
// Test indexed access on empty list
|
||||||
|
testing.expectEqual(undefined, sheets[0]);
|
||||||
|
testing.expectEqual(undefined, sheets[99]);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="CSSStyleDeclaration_setCssText_basic">
|
||||||
|
{
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const style = div.style;
|
||||||
|
|
||||||
|
// Set single property
|
||||||
|
style.cssText = 'color: red';
|
||||||
|
testing.expectEqual('red', style.getPropertyValue('color'));
|
||||||
|
testing.expectEqual(1, style.length);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="CSSStyleDeclaration_setCssText_multiple">
|
||||||
|
{
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const style = div.style;
|
||||||
|
|
||||||
|
// Set multiple properties
|
||||||
|
style.cssText = 'color: red; background: blue; margin: 10px';
|
||||||
|
testing.expectEqual('red', style.getPropertyValue('color'));
|
||||||
|
testing.expectEqual('blue', style.getPropertyValue('background'));
|
||||||
|
testing.expectEqual('10px', style.getPropertyValue('margin'));
|
||||||
|
testing.expectEqual(3, style.length);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="CSSStyleDeclaration_setCssText_important">
|
||||||
|
{
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const style = div.style;
|
||||||
|
|
||||||
|
// Set property with !important
|
||||||
|
style.cssText = 'color: red !important';
|
||||||
|
testing.expectEqual('red', style.getPropertyValue('color'));
|
||||||
|
testing.expectEqual('important', style.getPropertyPriority('color'));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="CSSStyleDeclaration_setCssText_important_multiple">
|
||||||
|
{
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const style = div.style;
|
||||||
|
|
||||||
|
// Mix of important and non-important
|
||||||
|
style.cssText = 'color: red !important; background: blue; margin: 10px !important';
|
||||||
|
testing.expectEqual('important', style.getPropertyPriority('color'));
|
||||||
|
testing.expectEqual('', style.getPropertyPriority('background'));
|
||||||
|
testing.expectEqual('important', style.getPropertyPriority('margin'));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="CSSStyleDeclaration_setCssText_whitespace">
|
||||||
|
{
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const style = div.style;
|
||||||
|
|
||||||
|
// Test whitespace handling
|
||||||
|
style.cssText = ' color : red ; background : blue ';
|
||||||
|
testing.expectEqual('red', style.getPropertyValue('color'));
|
||||||
|
testing.expectEqual('blue', style.getPropertyValue('background'));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="CSSStyleDeclaration_setCssText_trailing_semicolon">
|
||||||
|
{
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const style = div.style;
|
||||||
|
|
||||||
|
// Trailing semicolon should be handled
|
||||||
|
style.cssText = 'color: red;';
|
||||||
|
testing.expectEqual('red', style.getPropertyValue('color'));
|
||||||
|
testing.expectEqual(1, style.length);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="CSSStyleDeclaration_setCssText_no_semicolon">
|
||||||
|
{
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const style = div.style;
|
||||||
|
|
||||||
|
// Single property without semicolon
|
||||||
|
style.cssText = 'color: red';
|
||||||
|
testing.expectEqual('red', style.getPropertyValue('color'));
|
||||||
|
testing.expectEqual(1, style.length);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="CSSStyleDeclaration_setCssText_empty_declarations">
|
||||||
|
{
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const style = div.style;
|
||||||
|
|
||||||
|
// Multiple semicolons should be ignored
|
||||||
|
style.cssText = 'color: red;;; background: blue';
|
||||||
|
testing.expectEqual('red', style.getPropertyValue('color'));
|
||||||
|
testing.expectEqual('blue', style.getPropertyValue('background'));
|
||||||
|
testing.expectEqual(2, style.length);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="CSSStyleDeclaration_setCssText_replace">
|
||||||
|
{
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const style = div.style;
|
||||||
|
|
||||||
|
// Set initial properties
|
||||||
|
style.cssText = 'color: red; background: blue';
|
||||||
|
testing.expectEqual(2, style.length);
|
||||||
|
|
||||||
|
// Replace with new properties
|
||||||
|
style.cssText = 'margin: 10px';
|
||||||
|
testing.expectEqual('', style.getPropertyValue('color'));
|
||||||
|
testing.expectEqual('', style.getPropertyValue('background'));
|
||||||
|
testing.expectEqual('10px', style.getPropertyValue('margin'));
|
||||||
|
testing.expectEqual(1, style.length);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="CSSStyleDeclaration_setCssText_clear">
|
||||||
|
{
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const style = div.style;
|
||||||
|
|
||||||
|
style.cssText = 'color: red; background: blue';
|
||||||
|
testing.expectEqual(2, style.length);
|
||||||
|
|
||||||
|
// Clear all properties
|
||||||
|
style.cssText = '';
|
||||||
|
testing.expectEqual(0, style.length);
|
||||||
|
testing.expectEqual('', style.getPropertyValue('color'));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="CSSStyleDeclaration_setCssText_colon_in_value">
|
||||||
|
{
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const style = div.style;
|
||||||
|
|
||||||
|
// URL value with colon
|
||||||
|
style.cssText = 'background: url(http://example.com/image.png)';
|
||||||
|
testing.expectEqual('url(http://example.com/image.png)', style.getPropertyValue('background'));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="CSSStyleDeclaration_setCssText_important_whitespace">
|
||||||
|
{
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const style = div.style;
|
||||||
|
|
||||||
|
// Various whitespace around !important
|
||||||
|
style.cssText = 'color: red!important';
|
||||||
|
testing.expectEqual('important', style.getPropertyPriority('color'));
|
||||||
|
|
||||||
|
style.cssText = 'color: red ! important';
|
||||||
|
testing.expectEqual('important', style.getPropertyPriority('color'));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="CSSStyleDeclaration_setCssText_case_insensitive_property">
|
||||||
|
{
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const style = div.style;
|
||||||
|
|
||||||
|
// Property names should be normalized to lowercase
|
||||||
|
style.cssText = 'COLOR: red; BACKGROUND: blue';
|
||||||
|
testing.expectEqual('red', style.getPropertyValue('color'));
|
||||||
|
testing.expectEqual('blue', style.getPropertyValue('background'));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="CSSStyleDeclaration_setCssText_exclamation_not_important">
|
||||||
|
{
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const style = div.style;
|
||||||
|
|
||||||
|
// Exclamation mark without "important" should be kept in value
|
||||||
|
style.cssText = 'content: "hello!"';
|
||||||
|
testing.expectEqual('"hello!"', style.getPropertyValue('content'));
|
||||||
|
testing.expectEqual('', style.getPropertyPriority('content'));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -31,6 +31,7 @@ const NodeFilter = @import("NodeFilter.zig");
|
|||||||
const DOMTreeWalker = @import("DOMTreeWalker.zig");
|
const DOMTreeWalker = @import("DOMTreeWalker.zig");
|
||||||
const DOMNodeIterator = @import("DOMNodeIterator.zig");
|
const DOMNodeIterator = @import("DOMNodeIterator.zig");
|
||||||
const DOMImplementation = @import("DOMImplementation.zig");
|
const DOMImplementation = @import("DOMImplementation.zig");
|
||||||
|
const StyleSheetList = @import("css/StyleSheetList.zig");
|
||||||
|
|
||||||
pub const HTMLDocument = @import("HTMLDocument.zig");
|
pub const HTMLDocument = @import("HTMLDocument.zig");
|
||||||
|
|
||||||
@@ -43,6 +44,7 @@ _ready_state: ReadyState = .loading,
|
|||||||
_current_script: ?*Element.Html.Script = null,
|
_current_script: ?*Element.Html.Script = null,
|
||||||
_elements_by_id: std.StringHashMapUnmanaged(*Element) = .empty,
|
_elements_by_id: std.StringHashMapUnmanaged(*Element) = .empty,
|
||||||
_active_element: ?*Element = null,
|
_active_element: ?*Element = null,
|
||||||
|
_style_sheets: ?*StyleSheetList = null,
|
||||||
|
|
||||||
pub const Type = union(enum) {
|
pub const Type = union(enum) {
|
||||||
generic,
|
generic,
|
||||||
@@ -225,6 +227,15 @@ pub fn getActiveElement(self: *Document) ?*Element {
|
|||||||
return self.getDocumentElement();
|
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 {
|
const ReadyState = enum {
|
||||||
loading,
|
loading,
|
||||||
interactive,
|
interactive,
|
||||||
@@ -253,7 +264,7 @@ pub const JsApi = struct {
|
|||||||
pub const readyState = bridge.accessor(Document.getReadyState, null, .{});
|
pub const readyState = bridge.accessor(Document.getReadyState, null, .{});
|
||||||
pub const implementation = bridge.accessor(Document.getImplementation, null, .{});
|
pub const implementation = bridge.accessor(Document.getImplementation, null, .{});
|
||||||
pub const activeElement = bridge.accessor(Document.getActiveElement, 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 createElement = bridge.function(Document.createElement, .{});
|
||||||
pub const createElementNS = bridge.function(Document.createElementNS, .{});
|
pub const createElementNS = bridge.function(Document.createElementNS, .{});
|
||||||
pub const createDocumentFragment = bridge.function(Document.createDocumentFragment, .{});
|
pub const createDocumentFragment = bridge.function(Document.createDocumentFragment, .{});
|
||||||
|
|||||||
@@ -120,4 +120,3 @@ pub const JsApi = struct {
|
|||||||
// Methods
|
// Methods
|
||||||
pub const javaEnabled = bridge.function(Navigator.javaEnabled, .{});
|
pub const javaEnabled = bridge.function(Navigator.javaEnabled, .{});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -243,7 +243,6 @@ pub fn atob(_: *const Window, input: []const u8, page: *Page) ![]const u8 {
|
|||||||
return decoded;
|
return decoded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const ScheduleOpts = struct {
|
const ScheduleOpts = struct {
|
||||||
repeat: bool,
|
repeat: bool,
|
||||||
params: []js.Object,
|
params: []js.Object,
|
||||||
|
|||||||
90
src/browser/webapi/css/CSSRule.zig
Normal file
90
src/browser/webapi/css/CSSRule.zig
Normal file
@@ -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, .{});
|
||||||
|
};
|
||||||
36
src/browser/webapi/css/CSSRuleList.zig
Normal file
36
src/browser/webapi/css/CSSRuleList.zig
Normal file
@@ -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 });
|
||||||
|
};
|
||||||
@@ -29,28 +29,6 @@ const CSSStyleDeclaration = @This();
|
|||||||
_element: ?*Element = null,
|
_element: ?*Element = null,
|
||||||
_properties: std.DoublyLinkedList = .{},
|
_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 {
|
pub fn init(element: ?*Element, page: *Page) !*CSSStyleDeclaration {
|
||||||
return page._factory.create(CSSStyleDeclaration{
|
return page._factory.create(CSSStyleDeclaration{
|
||||||
._element = element,
|
._element = element,
|
||||||
@@ -214,6 +192,28 @@ fn normalizePropertyName(name: []const u8, buf: []u8) []const u8 {
|
|||||||
return std.ascii.lowerString(buf, name);
|
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 JsApi = struct {
|
||||||
pub const bridge = js.Bridge(CSSStyleDeclaration);
|
pub const bridge = js.Bridge(CSSStyleDeclaration);
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,9 @@ fn isKnownCSSProperty(dash_case: []const u8) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn camelCaseToDashCase(name: []const u8, buf: []u8) []const u8 {
|
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
|
// Special case: cssFloat -> float
|
||||||
const lower_name = std.ascii.lowerString(buf, name);
|
const lower_name = std.ascii.lowerString(buf, name);
|
||||||
|
|||||||
48
src/browser/webapi/css/CSSStyleRule.zig
Normal file
48
src/browser/webapi/css/CSSStyleRule.zig
Normal file
@@ -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, .{});
|
||||||
|
};
|
||||||
87
src/browser/webapi/css/CSSStyleSheet.zig
Normal file
87
src/browser/webapi/css/CSSStyleSheet.zig
Normal file
@@ -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", .{});
|
||||||
|
}
|
||||||
34
src/browser/webapi/css/StyleSheetList.zig
Normal file
34
src/browser/webapi/css/StyleSheetList.zig
Normal file
@@ -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 });
|
||||||
|
};
|
||||||
@@ -1454,4 +1454,3 @@ test "Selector: Parser.parseNthPattern" {
|
|||||||
try testing.expectEqual(" )", parser.input);
|
try testing.expectEqual(" )", parser.input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ pub fn LogInterceptor(comptime BC: type) type {
|
|||||||
self.bc.cdp.sendEvent("Log.entryAdded", .{
|
self.bc.cdp.sendEvent("Log.entryAdded", .{
|
||||||
.entry = .{
|
.entry = .{
|
||||||
.source = switch (scope) {
|
.source = switch (scope) {
|
||||||
.js, .console => "javascript",
|
.js, .console => "javascript",
|
||||||
.http => "network",
|
.http => "network",
|
||||||
.telemetry, .unknown_prop, .interceptor => unreachable, // filtered out in writer above
|
.telemetry, .unknown_prop, .interceptor => unreachable, // filtered out in writer above
|
||||||
else => "other",
|
else => "other",
|
||||||
|
|||||||
@@ -184,6 +184,7 @@ pub extern "C" fn html5ever_get_memory_usage() -> Memory {
|
|||||||
// Streaming parser API
|
// Streaming parser API
|
||||||
// The Parser type from html5ever implements TendrilSink and supports streaming
|
// The Parser type from html5ever implements TendrilSink and supports streaming
|
||||||
pub struct StreamingParser {
|
pub struct StreamingParser {
|
||||||
|
#[allow(dead_code)]
|
||||||
arena: Box<typed_arena::Arena<sink::ElementData>>,
|
arena: Box<typed_arena::Arena<sink::ElementData>>,
|
||||||
parser: Box<dyn std::any::Any>,
|
parser: Box<dyn std::any::Any>,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user