From de3f5011bc67bb5159afaf1e8923ed9c1c0ae84d Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Thu, 19 Feb 2026 12:26:04 +0100 Subject: [PATCH] parse style attribute on CSSStyleDeclaration init To reflect the current style attribute, CSSStyleDeclaration now parses it on init. Moreover, this PR synchronizes the element's style attribute with the dynamic changes. --- src/browser/tests/css/stylesheet.html | 51 +++++++++++++++++++ .../webapi/css/CSSStyleDeclaration.zig | 43 ++++++++++++++-- 2 files changed, 91 insertions(+), 3 deletions(-) diff --git a/src/browser/tests/css/stylesheet.html b/src/browser/tests/css/stylesheet.html index abc1ed92..ec14f4fc 100644 --- a/src/browser/tests/css/stylesheet.html +++ b/src/browser/tests/css/stylesheet.html @@ -205,3 +205,54 @@ testing.expectEqual('', style.getPropertyPriority('content')); } + + + + diff --git a/src/browser/webapi/css/CSSStyleDeclaration.zig b/src/browser/webapi/css/CSSStyleDeclaration.zig index 8380b6f3..23b04170 100644 --- a/src/browser/webapi/css/CSSStyleDeclaration.zig +++ b/src/browser/webapi/css/CSSStyleDeclaration.zig @@ -33,10 +33,27 @@ _properties: std.DoublyLinkedList = .{}, _is_computed: bool = false, pub fn init(element: ?*Element, is_computed: bool, page: *Page) !*CSSStyleDeclaration { - return page._factory.create(CSSStyleDeclaration{ + const self = try page._factory.create(CSSStyleDeclaration{ ._element = element, ._is_computed = is_computed, }); + + // Parse the element's existing style attribute into _properties so that + // subsequent JS reads and writes see all CSS properties, not just newly + // added ones. Computed styles have no inline attribute to parse. + if (!is_computed) { + if (element) |el| { + if (el.getAttributeSafe(String.wrap("style"))) |attr_value| { + var it = CssParser.parseDeclarationsList(attr_value); + while (it.next()) |declaration| { + const priority: ?[]const u8 = if (declaration.important) "important" else null; + try self.setPropertyImpl(declaration.name, declaration.value, priority, page); + } + } + } + } + + return self; } pub fn length(self: *const CSSStyleDeclaration) u32 { @@ -76,8 +93,13 @@ pub fn getPropertyPriority(self: *const CSSStyleDeclaration, property_name: []co } pub fn setProperty(self: *CSSStyleDeclaration, property_name: []const u8, value: []const u8, priority_: ?[]const u8, page: *Page) !void { + try self.setPropertyImpl(property_name, value, priority_, page); + try self.syncStyleAttribute(page); +} + +fn setPropertyImpl(self: *CSSStyleDeclaration, property_name: []const u8, value: []const u8, priority_: ?[]const u8, page: *Page) !void { if (value.len == 0) { - _ = try self.removeProperty(property_name, page); + _ = try self.removePropertyImpl(property_name, page); return; } @@ -110,6 +132,12 @@ pub fn setProperty(self: *CSSStyleDeclaration, property_name: []const u8, value: } pub fn removeProperty(self: *CSSStyleDeclaration, property_name: []const u8, page: *Page) ![]const u8 { + const result = try self.removePropertyImpl(property_name, page); + try self.syncStyleAttribute(page); + return result; +} + +fn removePropertyImpl(self: *CSSStyleDeclaration, property_name: []const u8, page: *Page) ![]const u8 { const normalized = normalizePropertyName(property_name, &page.buf); const prop = self.findProperty(normalized) orelse return ""; @@ -121,6 +149,14 @@ pub fn removeProperty(self: *CSSStyleDeclaration, property_name: []const u8, pag return old_value; } +// Serialize current properties back to the element's style attribute so that +// DOM serialization (outerHTML, getAttribute) reflects JS-modified styles. +fn syncStyleAttribute(self: *CSSStyleDeclaration, page: *Page) !void { + const element = self._element orelse return; + const css_text = try self.getCssText(page); + try element.setAttributeSafe(String.wrap("style"), String.wrap(css_text), page); +} + pub fn getFloat(self: *const CSSStyleDeclaration, page: *Page) []const u8 { return self.getPropertyValue("float", page); } @@ -154,8 +190,9 @@ pub fn setCssText(self: *CSSStyleDeclaration, text: []const u8, page: *Page) !vo var it = CssParser.parseDeclarationsList(text); while (it.next()) |declaration| { const priority: ?[]const u8 = if (declaration.important) "important" else null; - try self.setProperty(declaration.name, declaration.value, priority, page); + try self.setPropertyImpl(declaration.name, declaration.value, priority, page); } + try self.syncStyleAttribute(page); } pub fn format(self: *const CSSStyleDeclaration, writer: *std.Io.Writer) !void {