mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 15:13:28 +00:00
Change dataset to work directly off DOM element
This commit is contained in:
@@ -16,64 +16,66 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const parser = @import("../netsurf.zig");
|
||||||
const Page = @import("../page.zig").Page;
|
const Page = @import("../page.zig").Page;
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
const DataSet = @This();
|
const DataSet = @This();
|
||||||
|
|
||||||
attributes: std.StringHashMapUnmanaged([]const u8),
|
element: *parser.Element,
|
||||||
|
|
||||||
pub const empty: DataSet = .{
|
|
||||||
.attributes = .empty,
|
|
||||||
};
|
|
||||||
|
|
||||||
const GetResult = union(enum) {
|
const GetResult = union(enum) {
|
||||||
value: []const u8,
|
value: []const u8,
|
||||||
undefined: void,
|
undefined: void,
|
||||||
};
|
};
|
||||||
pub fn named_get(self: *const DataSet, name: []const u8, _: *bool) GetResult {
|
pub fn named_get(self: *const DataSet, name: []const u8, _: *bool, page: *Page) !GetResult {
|
||||||
if (self.attributes.get(name)) |value| {
|
const normalized_name = try normalize(page.call_arena, name);
|
||||||
|
if (try parser.elementGetAttribute(self.element, normalized_name)) |value| {
|
||||||
return .{ .value = value };
|
return .{ .value = value };
|
||||||
}
|
}
|
||||||
return .{ .undefined = {} };
|
return .{ .undefined = {} };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn named_set(self: *DataSet, name: []const u8, value: []const u8, _: *bool, page: *Page) !void {
|
pub fn named_set(self: *DataSet, name: []const u8, value: []const u8, _: *bool, page: *Page) !void {
|
||||||
const arena = page.arena;
|
const normalized_name = try normalize(page.call_arena, name);
|
||||||
const gop = try self.attributes.getOrPut(arena, name);
|
try parser.elementSetAttribute(self.element, normalized_name, value);
|
||||||
errdefer _ = self.attributes.remove(name);
|
|
||||||
|
|
||||||
if (!gop.found_existing) {
|
|
||||||
gop.key_ptr.* = try arena.dupe(u8, name);
|
|
||||||
}
|
|
||||||
gop.value_ptr.* = try arena.dupe(u8, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn named_delete(self: *DataSet, name: []const u8, _: *bool) void {
|
pub fn named_delete(self: *DataSet, name: []const u8, _: *bool, page: *Page) !void {
|
||||||
_ = self.attributes.remove(name);
|
const normalized_name = try normalize(page.call_arena, name);
|
||||||
|
try parser.elementRemoveAttribute(self.element, normalized_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn normalizeName(allocator: Allocator, name: []const u8) ![]const u8 {
|
fn normalize(allocator: Allocator, name: []const u8) ![]const u8 {
|
||||||
std.debug.assert(std.mem.startsWith(u8, name, "data-"));
|
var upper_count: usize = 0;
|
||||||
var owned = try allocator.alloc(u8, name.len - 5);
|
for (name) |c| {
|
||||||
|
if (std.ascii.isUpper(c)) {
|
||||||
var pos: usize = 0;
|
upper_count += 1;
|
||||||
var capitalize = false;
|
|
||||||
for (name[5..]) |c| {
|
|
||||||
if (c == '-') {
|
|
||||||
capitalize = true;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// for every upper-case letter, we'll probably need a dash before it
|
||||||
|
// and we need the 'data-' prefix
|
||||||
|
var normalized = try allocator.alloc(u8, name.len + upper_count + 5);
|
||||||
|
|
||||||
if (capitalize) {
|
@memcpy(normalized[0..5], "data-");
|
||||||
capitalize = false;
|
if (upper_count == 0) {
|
||||||
owned[pos] = std.ascii.toUpper(c);
|
@memcpy(normalized[5..], name);
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pos: usize = 5;
|
||||||
|
for (name) |c| {
|
||||||
|
if (std.ascii.isUpper(c)) {
|
||||||
|
normalized[pos] = '-';
|
||||||
|
pos += 1;
|
||||||
|
normalized[pos] = c + 32;
|
||||||
} else {
|
} else {
|
||||||
owned[pos] = c;
|
normalized[pos] = c;
|
||||||
}
|
}
|
||||||
pos += 1;
|
pos += 1;
|
||||||
}
|
}
|
||||||
return owned[0..pos];
|
return normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
const testing = @import("../../testing.zig");
|
const testing = @import("../../testing.zig");
|
||||||
@@ -88,5 +90,11 @@ test "Browser.HTML.DataSet" {
|
|||||||
.{ "delete el1.dataset.x", "true" },
|
.{ "delete el1.dataset.x", "true" },
|
||||||
.{ "el1.dataset.x", "undefined" },
|
.{ "el1.dataset.x", "undefined" },
|
||||||
.{ "delete el1.dataset.other", "true" }, // yes, this is right
|
.{ "delete el1.dataset.other", "true" }, // yes, this is right
|
||||||
|
|
||||||
|
.{ "let ds1 = el1.dataset", null },
|
||||||
|
.{ "ds1.helloWorld = 'yes'", null },
|
||||||
|
.{ "el1.getAttribute('data-hello-world')", "yes" },
|
||||||
|
.{ "el1.setAttribute('data-this-will-work', 'positive')", null },
|
||||||
|
.{ "ds1.thisWillWork", "positive" },
|
||||||
}, .{});
|
}, .{});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,28 +128,7 @@ pub const HTMLElement = struct {
|
|||||||
if (state.dataset) |*ds| {
|
if (state.dataset) |*ds| {
|
||||||
return ds;
|
return ds;
|
||||||
}
|
}
|
||||||
|
state.dataset = DataSet{ .element = @ptrCast(e) };
|
||||||
// The first time this is called, load the data attributes from the DOM
|
|
||||||
var ds: DataSet = .empty;
|
|
||||||
|
|
||||||
if (try parser.nodeGetAttributes(@ptrCast(e))) |map| {
|
|
||||||
const arena = page.arena;
|
|
||||||
const count = try parser.namedNodeMapGetLength(map);
|
|
||||||
for (0..count) |i| {
|
|
||||||
const attr = try parser.namedNodeMapItem(map, @intCast(i)) orelse continue;
|
|
||||||
const name = try parser.attributeGetName(attr);
|
|
||||||
if (!std.mem.startsWith(u8, name, "data-")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const normalized_name = try DataSet.normalizeName(arena, name);
|
|
||||||
const value = try parser.attributeGetValue(attr) orelse "";
|
|
||||||
// I don't think we need to dupe value, It'll live in libdom for
|
|
||||||
// as long as the page due to the fact that we're using an arena.
|
|
||||||
try ds.attributes.put(arena, normalized_name, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
state.dataset = ds;
|
|
||||||
return &state.dataset.?;
|
return &state.dataset.?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user