mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-22 04:34:44 +00:00
Merge pull request #1602 from lightpanda-io/css-delcaration
parse style attribute on CSSStyleDeclaration init
This commit is contained in:
@@ -205,3 +205,54 @@
|
|||||||
testing.expectEqual('', style.getPropertyPriority('content'));
|
testing.expectEqual('', style.getPropertyPriority('content'));
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script id="CSSStyleDeclaration_style_syncs_to_attribute">
|
||||||
|
{
|
||||||
|
// JS style modifications must be reflected in getAttribute.
|
||||||
|
const div = document.createElement('div');
|
||||||
|
|
||||||
|
// Named property assignment (element.style.X = ...)
|
||||||
|
div.style.opacity = '0';
|
||||||
|
testing.expectEqual('opacity: 0;', div.getAttribute('style'));
|
||||||
|
|
||||||
|
// Update existing property
|
||||||
|
div.style.opacity = '1';
|
||||||
|
testing.expectEqual('opacity: 1;', div.getAttribute('style'));
|
||||||
|
|
||||||
|
// Add a second property
|
||||||
|
div.style.color = 'red';
|
||||||
|
testing.expectTrue(div.getAttribute('style').includes('opacity: 1'));
|
||||||
|
testing.expectTrue(div.getAttribute('style').includes('color: red'));
|
||||||
|
|
||||||
|
// removeProperty syncs back
|
||||||
|
div.style.removeProperty('opacity');
|
||||||
|
testing.expectTrue(!div.getAttribute('style').includes('opacity'));
|
||||||
|
testing.expectTrue(div.getAttribute('style').includes('color: red'));
|
||||||
|
|
||||||
|
// setCssText syncs back
|
||||||
|
div.style.cssText = 'filter: blur(0px)';
|
||||||
|
testing.expectEqual('filter: blur(0px);', div.getAttribute('style'));
|
||||||
|
|
||||||
|
// setCssText with empty string clears attribute
|
||||||
|
div.style.cssText = '';
|
||||||
|
testing.expectEqual('', div.getAttribute('style'));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="CSSStyleDeclaration_outerHTML_reflects_style_changes">
|
||||||
|
{
|
||||||
|
// outerHTML must reflect JS-modified styles (regression test for
|
||||||
|
// DOM serialization reading stale HTML-parsed attribute values).
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.setAttribute('style', 'filter:blur(10px);opacity:0');
|
||||||
|
|
||||||
|
div.style.filter = 'blur(0px)';
|
||||||
|
div.style.opacity = '1';
|
||||||
|
|
||||||
|
const html = div.outerHTML;
|
||||||
|
testing.expectTrue(html.includes('filter: blur(0px)'));
|
||||||
|
testing.expectTrue(html.includes('opacity: 1'));
|
||||||
|
testing.expectTrue(!html.includes('blur(10px)'));
|
||||||
|
testing.expectTrue(!html.includes('opacity:0'));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -33,10 +33,26 @@ _properties: std.DoublyLinkedList = .{},
|
|||||||
_is_computed: bool = false,
|
_is_computed: bool = false,
|
||||||
|
|
||||||
pub fn init(element: ?*Element, is_computed: bool, page: *Page) !*CSSStyleDeclaration {
|
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,
|
._element = element,
|
||||||
._is_computed = is_computed,
|
._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(comptime .wrap("style"))) |attr_value| {
|
||||||
|
var it = CssParser.parseDeclarationsList(attr_value);
|
||||||
|
while (it.next()) |declaration| {
|
||||||
|
try self.setPropertyImpl(declaration.name, declaration.value, declaration.important, page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn length(self: *const CSSStyleDeclaration) u32 {
|
pub fn length(self: *const CSSStyleDeclaration) u32 {
|
||||||
@@ -76,15 +92,8 @@ 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 {
|
pub fn setProperty(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);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const normalized = normalizePropertyName(property_name, &page.buf);
|
|
||||||
const priority = priority_ orelse "";
|
|
||||||
|
|
||||||
// Validate priority
|
// Validate priority
|
||||||
|
const priority = priority_ orelse "";
|
||||||
const important = if (priority.len > 0) blk: {
|
const important = if (priority.len > 0) blk: {
|
||||||
if (!std.ascii.eqlIgnoreCase(priority, "important")) {
|
if (!std.ascii.eqlIgnoreCase(priority, "important")) {
|
||||||
return;
|
return;
|
||||||
@@ -92,6 +101,19 @@ pub fn setProperty(self: *CSSStyleDeclaration, property_name: []const u8, value:
|
|||||||
break :blk true;
|
break :blk true;
|
||||||
} else false;
|
} else false;
|
||||||
|
|
||||||
|
try self.setPropertyImpl(property_name, value, important, page);
|
||||||
|
|
||||||
|
try self.syncStyleAttribute(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setPropertyImpl(self: *CSSStyleDeclaration, property_name: []const u8, value: []const u8, important: bool, page: *Page) !void {
|
||||||
|
if (value.len == 0) {
|
||||||
|
_ = try self.removePropertyImpl(property_name, page);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalized = normalizePropertyName(property_name, &page.buf);
|
||||||
|
|
||||||
// Find existing property
|
// Find existing property
|
||||||
if (self.findProperty(normalized)) |existing| {
|
if (self.findProperty(normalized)) |existing| {
|
||||||
existing._value = try String.init(page.arena, value, .{});
|
existing._value = try String.init(page.arena, value, .{});
|
||||||
@@ -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 {
|
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 normalized = normalizePropertyName(property_name, &page.buf);
|
||||||
const prop = self.findProperty(normalized) orelse return "";
|
const prop = self.findProperty(normalized) orelse return "";
|
||||||
|
|
||||||
@@ -121,12 +149,21 @@ pub fn removeProperty(self: *CSSStyleDeclaration, property_name: []const u8, pag
|
|||||||
return old_value;
|
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(comptime .wrap("style"), .wrap(css_text), page);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn getFloat(self: *const CSSStyleDeclaration, page: *Page) []const u8 {
|
pub fn getFloat(self: *const CSSStyleDeclaration, page: *Page) []const u8 {
|
||||||
return self.getPropertyValue("float", page);
|
return self.getPropertyValue("float", page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setFloat(self: *CSSStyleDeclaration, value_: ?[]const u8, page: *Page) !void {
|
pub fn setFloat(self: *CSSStyleDeclaration, value_: ?[]const u8, page: *Page) !void {
|
||||||
return self.setProperty("float", value_ orelse "", null, page);
|
try self.setPropertyImpl("float", value_ orelse "", false, page);
|
||||||
|
try self.syncStyleAttribute(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getCssText(self: *const CSSStyleDeclaration, page: *Page) ![]const u8 {
|
pub fn getCssText(self: *const CSSStyleDeclaration, page: *Page) ![]const u8 {
|
||||||
@@ -153,9 +190,9 @@ pub fn setCssText(self: *CSSStyleDeclaration, text: []const u8, page: *Page) !vo
|
|||||||
// Parse and set new properties
|
// Parse and set new properties
|
||||||
var it = CssParser.parseDeclarationsList(text);
|
var it = CssParser.parseDeclarationsList(text);
|
||||||
while (it.next()) |declaration| {
|
while (it.next()) |declaration| {
|
||||||
const priority: ?[]const u8 = if (declaration.important) "important" else null;
|
try self.setPropertyImpl(declaration.name, declaration.value, declaration.important, page);
|
||||||
try self.setProperty(declaration.name, declaration.value, priority, page);
|
|
||||||
}
|
}
|
||||||
|
try self.syncStyleAttribute(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format(self: *const CSSStyleDeclaration, writer: *std.Io.Writer) !void {
|
pub fn format(self: *const CSSStyleDeclaration, writer: *std.Io.Writer) !void {
|
||||||
|
|||||||
Reference in New Issue
Block a user