Skip to content

Commit ec92f11

Browse files
committed
Change dataset to work directly off DOM element
1 parent 2aa5eb8 commit ec92f11

File tree

2 files changed

+41
-54
lines changed

2 files changed

+41
-54
lines changed

src/browser/html/DataSet.zig

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,64 +16,66 @@
1616
// You should have received a copy of the GNU Affero General Public License
1717
// along with this program. If not, see <https://www.gnu.org/licenses/>.
1818
const std = @import("std");
19+
const parser = @import("../netsurf.zig");
1920
const Page = @import("../page.zig").Page;
21+
2022
const Allocator = std.mem.Allocator;
2123

2224
const DataSet = @This();
2325

24-
attributes: std.StringHashMapUnmanaged([]const u8),
25-
26-
pub const empty: DataSet = .{
27-
.attributes = .empty,
28-
};
26+
element: *parser.Element,
2927

3028
const GetResult = union(enum) {
3129
value: []const u8,
3230
undefined: void,
3331
};
34-
pub fn named_get(self: *const DataSet, name: []const u8, _: *bool) GetResult {
35-
if (self.attributes.get(name)) |value| {
32+
pub fn named_get(self: *const DataSet, name: []const u8, _: *bool, page: *Page) !GetResult {
33+
const normalized_name = try normalize(page.call_arena, name);
34+
if (try parser.elementGetAttribute(self.element, normalized_name)) |value| {
3635
return .{ .value = value };
3736
}
3837
return .{ .undefined = {} };
3938
}
4039

4140
pub fn named_set(self: *DataSet, name: []const u8, value: []const u8, _: *bool, page: *Page) !void {
42-
const arena = page.arena;
43-
const gop = try self.attributes.getOrPut(arena, name);
44-
errdefer _ = self.attributes.remove(name);
45-
46-
if (!gop.found_existing) {
47-
gop.key_ptr.* = try arena.dupe(u8, name);
48-
}
49-
gop.value_ptr.* = try arena.dupe(u8, value);
41+
const normalized_name = try normalize(page.call_arena, name);
42+
try parser.elementSetAttribute(self.element, normalized_name, value);
5043
}
5144

52-
pub fn named_delete(self: *DataSet, name: []const u8, _: *bool) void {
53-
_ = self.attributes.remove(name);
45+
pub fn named_delete(self: *DataSet, name: []const u8, _: *bool, page: *Page) !void {
46+
const normalized_name = try normalize(page.call_arena, name);
47+
try parser.elementRemoveAttribute(self.element, normalized_name);
5448
}
5549

56-
pub fn normalizeName(allocator: Allocator, name: []const u8) ![]const u8 {
57-
std.debug.assert(std.mem.startsWith(u8, name, "data-"));
58-
var owned = try allocator.alloc(u8, name.len - 5);
59-
60-
var pos: usize = 0;
61-
var capitalize = false;
62-
for (name[5..]) |c| {
63-
if (c == '-') {
64-
capitalize = true;
65-
continue;
50+
fn normalize(allocator: Allocator, name: []const u8) ![]const u8 {
51+
var upper_count: usize = 0;
52+
for (name) |c| {
53+
if (std.ascii.isUpper(c)) {
54+
upper_count += 1;
6655
}
56+
}
57+
// for every upper-case letter, we'll probably need a dash before it
58+
// and we need the 'data-' prefix
59+
var normalized = try allocator.alloc(u8, name.len + upper_count + 5);
6760

68-
if (capitalize) {
69-
capitalize = false;
70-
owned[pos] = std.ascii.toUpper(c);
61+
@memcpy(normalized[0..5], "data-");
62+
if (upper_count == 0) {
63+
@memcpy(normalized[5..], name);
64+
return normalized;
65+
}
66+
67+
var pos: usize = 5;
68+
for (name) |c| {
69+
if (std.ascii.isUpper(c)) {
70+
normalized[pos] = '-';
71+
pos += 1;
72+
normalized[pos] = c + 32;
7173
} else {
72-
owned[pos] = c;
74+
normalized[pos] = c;
7375
}
7476
pos += 1;
7577
}
76-
return owned[0..pos];
78+
return normalized;
7779
}
7880

7981
const testing = @import("../../testing.zig");
@@ -88,5 +90,11 @@ test "Browser.HTML.DataSet" {
8890
.{ "delete el1.dataset.x", "true" },
8991
.{ "el1.dataset.x", "undefined" },
9092
.{ "delete el1.dataset.other", "true" }, // yes, this is right
93+
94+
.{ "let ds1 = el1.dataset", null },
95+
.{ "ds1.helloWorld = 'yes'", null },
96+
.{ "el1.getAttribute('data-hello-world')", "yes" },
97+
.{ "el1.setAttribute('data-this-will-work', 'positive')", null },
98+
.{ "ds1.thisWillWork", "positive" },
9199
}, .{});
92100
}

src/browser/html/elements.zig

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -128,28 +128,7 @@ pub const HTMLElement = struct {
128128
if (state.dataset) |*ds| {
129129
return ds;
130130
}
131-
132-
// The first time this is called, load the data attributes from the DOM
133-
var ds: DataSet = .empty;
134-
135-
if (try parser.nodeGetAttributes(@ptrCast(e))) |map| {
136-
const arena = page.arena;
137-
const count = try parser.namedNodeMapGetLength(map);
138-
for (0..count) |i| {
139-
const attr = try parser.namedNodeMapItem(map, @intCast(i)) orelse continue;
140-
const name = try parser.attributeGetName(attr);
141-
if (!std.mem.startsWith(u8, name, "data-")) {
142-
continue;
143-
}
144-
const normalized_name = try DataSet.normalizeName(arena, name);
145-
const value = try parser.attributeGetValue(attr) orelse "";
146-
// I don't think we need to dupe value, It'll live in libdom for
147-
// as long as the page due to the fact that we're using an arena.
148-
try ds.attributes.put(arena, normalized_name, value);
149-
}
150-
}
151-
152-
state.dataset = ds;
131+
state.dataset = DataSet{ .element = @ptrCast(e) };
153132
return &state.dataset.?;
154133
}
155134

0 commit comments

Comments
 (0)