mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-12-15 15:58:57 +00:00
Add keys/values/entries/forEach/toString to DOMTokenList
This commit is contained in:
@@ -684,7 +684,7 @@ const Script = struct {
|
||||
fn errorCallback(ctx: *anyopaque, err: anyerror) void {
|
||||
const self: *Script = @ptrCast(@alignCast(ctx));
|
||||
log.warn(.http, "script fetch error", .{
|
||||
.err = err ,
|
||||
.err = err,
|
||||
.req = self.url,
|
||||
.mode = self.mode,
|
||||
.kind = self.kind,
|
||||
|
||||
@@ -288,6 +288,7 @@ pub const Iterator = struct {
|
||||
|
||||
const Opts = struct {
|
||||
async: bool = false,
|
||||
null_as_undefined: bool = false,
|
||||
};
|
||||
|
||||
fn init(comptime T: type, comptime struct_or_func: anytype, comptime opts: Opts) Iterator {
|
||||
|
||||
@@ -332,3 +332,272 @@
|
||||
testing.expectEqual('a c e b f', div.className);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=toString>
|
||||
{
|
||||
const div = document.createElement('div');
|
||||
div.className = 'foo bar baz';
|
||||
|
||||
testing.expectEqual('foo bar baz', div.classList.toString());
|
||||
|
||||
div.className = '';
|
||||
testing.expectEqual('', div.classList.toString());
|
||||
|
||||
div.className = ' alpha beta ';
|
||||
testing.expectEqual(' alpha beta ', div.classList.toString());
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=keys_iterator>
|
||||
{
|
||||
const div = document.createElement('div');
|
||||
div.className = 'one two three';
|
||||
|
||||
const keys = [];
|
||||
const iter = div.classList.keys();
|
||||
|
||||
let result = iter.next();
|
||||
testing.expectEqual(false, result.done);
|
||||
testing.expectEqual(0, result.value);
|
||||
keys.push(result.value);
|
||||
|
||||
result = iter.next();
|
||||
testing.expectEqual(false, result.done);
|
||||
testing.expectEqual(1, result.value);
|
||||
keys.push(result.value);
|
||||
|
||||
result = iter.next();
|
||||
testing.expectEqual(false, result.done);
|
||||
testing.expectEqual(2, result.value);
|
||||
keys.push(result.value);
|
||||
|
||||
result = iter.next();
|
||||
testing.expectEqual(true, result.done);
|
||||
testing.expectEqual(undefined, result.value);
|
||||
|
||||
testing.expectEqual([0, 1, 2], keys);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=keys_for_of>
|
||||
{
|
||||
const div = document.createElement('div');
|
||||
div.className = 'alpha beta gamma';
|
||||
|
||||
const keys = [];
|
||||
for (const key of div.classList.keys()) {
|
||||
keys.push(key);
|
||||
}
|
||||
testing.expectEqual([0, 1, 2], keys);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=values_iterator>
|
||||
{
|
||||
const div = document.createElement('div');
|
||||
div.className = 'red green blue';
|
||||
|
||||
const values = [];
|
||||
const iter = div.classList.values();
|
||||
|
||||
let result = iter.next();
|
||||
testing.expectEqual(false, result.done);
|
||||
testing.expectEqual('red', result.value);
|
||||
values.push(result.value);
|
||||
|
||||
result = iter.next();
|
||||
testing.expectEqual(false, result.done);
|
||||
testing.expectEqual('green', result.value);
|
||||
values.push(result.value);
|
||||
|
||||
result = iter.next();
|
||||
testing.expectEqual(false, result.done);
|
||||
testing.expectEqual('blue', result.value);
|
||||
values.push(result.value);
|
||||
|
||||
result = iter.next();
|
||||
testing.expectEqual(true, result.done);
|
||||
testing.expectEqual(undefined, result.value);
|
||||
|
||||
testing.expectEqual(['red', 'green', 'blue'], values);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=values_for_of>
|
||||
{
|
||||
const div = document.createElement('div');
|
||||
div.className = 'x y z';
|
||||
|
||||
const values = [];
|
||||
for (const value of div.classList.values()) {
|
||||
values.push(value);
|
||||
}
|
||||
testing.expectEqual(['x', 'y', 'z'], values);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=entries_iterator>
|
||||
{
|
||||
const div = document.createElement('div');
|
||||
div.className = 'first second third';
|
||||
|
||||
const entries = [];
|
||||
const iter = div.classList.entries();
|
||||
|
||||
let result = iter.next();
|
||||
testing.expectEqual(false, result.done);
|
||||
testing.expectEqual([0, 'first'], result.value);
|
||||
entries.push(result.value);
|
||||
|
||||
result = iter.next();
|
||||
testing.expectEqual(false, result.done);
|
||||
testing.expectEqual([1, 'second'], result.value);
|
||||
entries.push(result.value);
|
||||
|
||||
result = iter.next();
|
||||
testing.expectEqual(false, result.done);
|
||||
testing.expectEqual([2, 'third'], result.value);
|
||||
entries.push(result.value);
|
||||
|
||||
result = iter.next();
|
||||
testing.expectEqual(true, result.done);
|
||||
testing.expectEqual(undefined, result.value);
|
||||
|
||||
testing.expectEqual([[0, 'first'], [1, 'second'], [2, 'third']], entries);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=entries_for_of>
|
||||
{
|
||||
const div = document.createElement('div');
|
||||
div.className = 'a b c';
|
||||
|
||||
const entries = [];
|
||||
for (const entry of div.classList.entries()) {
|
||||
entries.push(entry);
|
||||
}
|
||||
testing.expectEqual([[0, 'a'], [1, 'b'], [2, 'c']], entries);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=forEach_basic>
|
||||
{
|
||||
const div = document.createElement('div');
|
||||
div.className = 'red green blue';
|
||||
|
||||
const values = [];
|
||||
const indices = [];
|
||||
const lists = [];
|
||||
|
||||
div.classList.forEach((value, index, list) => {
|
||||
values.push(value);
|
||||
indices.push(index);
|
||||
lists.push(list);
|
||||
});
|
||||
|
||||
testing.expectEqual(['red', 'green', 'blue'], values);
|
||||
testing.expectEqual([0, 1, 2], indices);
|
||||
testing.expectEqual(3, lists.length);
|
||||
testing.expectEqual(div.classList, lists[0]);
|
||||
testing.expectEqual(div.classList, lists[1]);
|
||||
testing.expectEqual(div.classList, lists[2]);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=forEach_with_this>
|
||||
{
|
||||
const div = document.createElement('div');
|
||||
div.className = 'one two';
|
||||
|
||||
const context = { count: 0 };
|
||||
|
||||
div.classList.forEach(function(value) {
|
||||
this.count++;
|
||||
}, context);
|
||||
|
||||
testing.expectEqual(2, context.count);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=forEach_empty_list>
|
||||
{
|
||||
const div = document.createElement('div');
|
||||
div.className = '';
|
||||
|
||||
let callCount = 0;
|
||||
div.classList.forEach(() => {
|
||||
callCount++;
|
||||
});
|
||||
|
||||
testing.expectEqual(0, callCount);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=forEach_duplicates>
|
||||
{
|
||||
const div = document.createElement('div');
|
||||
div.className = 'foo foo bar';
|
||||
|
||||
const values = [];
|
||||
div.classList.forEach((value) => {
|
||||
values.push(value);
|
||||
});
|
||||
|
||||
testing.expectEqual(['foo', 'bar'], values);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=iterators_empty_list>
|
||||
{
|
||||
const div = document.createElement('div');
|
||||
div.className = '';
|
||||
|
||||
const keys = [...div.classList.keys()];
|
||||
testing.expectEqual([], keys);
|
||||
|
||||
const values = [...div.classList.values()];
|
||||
testing.expectEqual([], values);
|
||||
|
||||
const entries = [...div.classList.entries()];
|
||||
testing.expectEqual([], entries);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=iterators_with_duplicates>
|
||||
{
|
||||
const div = document.createElement('div');
|
||||
div.className = 'alpha alpha beta alpha';
|
||||
|
||||
const values = [...div.classList.values()];
|
||||
testing.expectEqual(['alpha', 'beta'], values);
|
||||
|
||||
const entries = [...div.classList.entries()];
|
||||
testing.expectEqual([[0, 'alpha'], [1, 'beta']], entries);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=iterator_live_behavior>
|
||||
{
|
||||
const div = document.createElement('div');
|
||||
div.className = 'one two three';
|
||||
|
||||
const iter = div.classList.values();
|
||||
|
||||
let result = iter.next();
|
||||
testing.expectEqual('one', result.value);
|
||||
|
||||
div.classList.add('four');
|
||||
|
||||
result = iter.next();
|
||||
testing.expectEqual('two', result.value);
|
||||
|
||||
result = iter.next();
|
||||
testing.expectEqual('three', result.value);
|
||||
|
||||
result = iter.next();
|
||||
testing.expectEqual('four', result.value);
|
||||
|
||||
result = iter.next();
|
||||
testing.expectEqual(true, result.done);
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -34,6 +34,8 @@ pub fn registerTypes() []const type {
|
||||
@import("collections/HTMLAllCollection.zig").Iterator,
|
||||
HTMLOptionsCollection,
|
||||
DOMTokenList,
|
||||
DOMTokenList.Iterator,
|
||||
DOMTokenList.KeyIterator,
|
||||
DOMTokenList.ValueIterator,
|
||||
DOMTokenList.EntryIterator,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -17,11 +17,12 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
const log = @import("../../../log.zig");
|
||||
const js = @import("../../js/js.zig");
|
||||
|
||||
const Page = @import("../../Page.zig");
|
||||
const Element = @import("../Element.zig");
|
||||
const GenericIterator = @import("iterator.zig").Entry;
|
||||
const Page = @import("../../Page.zig");
|
||||
|
||||
pub const DOMTokenList = @This();
|
||||
|
||||
@@ -32,6 +33,10 @@ pub const DOMTokenList = @This();
|
||||
_element: *Element,
|
||||
_attribute_name: []const u8,
|
||||
|
||||
pub const KeyIterator = GenericIterator(Iterator, "0");
|
||||
pub const ValueIterator = GenericIterator(Iterator, "1");
|
||||
pub const EntryIterator = GenericIterator(Iterator, null);
|
||||
|
||||
const Lookup = std.StringArrayHashMapUnmanaged(void);
|
||||
|
||||
const WHITESPACE = " \t\n\r\x0C";
|
||||
@@ -158,21 +163,40 @@ pub fn setValue(self: *DOMTokenList, value: []const u8, page: *Page) !void {
|
||||
try self._element.setAttribute(self._attribute_name, value, page);
|
||||
}
|
||||
|
||||
pub fn iterator(self: *const DOMTokenList, page: *Page) !*Iterator {
|
||||
return Iterator.init(.{ .list = self }, page);
|
||||
pub fn keys(self: *DOMTokenList, page: *Page) !*KeyIterator {
|
||||
return .init(.{ .list = self }, page);
|
||||
}
|
||||
|
||||
pub const Iterator = GenericIterator(struct {
|
||||
index: usize = 0,
|
||||
list: *const DOMTokenList,
|
||||
pub fn values(self: *DOMTokenList, page: *Page) !*ValueIterator {
|
||||
return .init(.{ .list = self }, page);
|
||||
}
|
||||
|
||||
// TODO: the underlying list.iten is very inefficient!
|
||||
pub fn next(self: *@This(), page: *Page) !?[]const u8 {
|
||||
const index = self.index;
|
||||
self.index = index + 1;
|
||||
return self.list.item(index, page);
|
||||
pub fn entries(self: *DOMTokenList, page: *Page) !*EntryIterator {
|
||||
return .init(.{ .list = self }, page);
|
||||
}
|
||||
|
||||
pub fn forEach(self: *DOMTokenList, cb_: js.Function, js_this_: ?js.Object, page: *Page) !void {
|
||||
const cb = if (js_this_) |js_this| try cb_.withThis(js_this) else cb_;
|
||||
|
||||
const allocator = page.call_arena;
|
||||
|
||||
var i: i32 = 0;
|
||||
var seen: std.StringArrayHashMapUnmanaged(void) = .empty;
|
||||
|
||||
var it = std.mem.tokenizeAny(u8, self.getValue(), WHITESPACE);
|
||||
while (it.next()) |token| {
|
||||
const gop = try seen.getOrPut(allocator, token);
|
||||
if (gop.found_existing) {
|
||||
continue;
|
||||
}
|
||||
var result: js.Function.Result = undefined;
|
||||
cb.tryCall(void, .{ token, i, self }, &result) catch {
|
||||
log.debug(.js, "forEach callback", .{ .err = result.exception, .stack = result.stack, .source = "DOMTokenList" });
|
||||
return;
|
||||
};
|
||||
i += 1;
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
|
||||
fn getTokens(self: *const DOMTokenList, page: *Page) !Lookup {
|
||||
const value = self.getValue();
|
||||
@@ -205,6 +229,20 @@ fn updateAttribute(self: *DOMTokenList, tokens: Lookup, page: *Page) !void {
|
||||
try self._element.setAttribute(self._attribute_name, joined, page);
|
||||
}
|
||||
|
||||
const Iterator = struct {
|
||||
index: u32 = 0,
|
||||
list: *DOMTokenList,
|
||||
|
||||
const Entry = struct { u32, []const u8 };
|
||||
|
||||
pub fn next(self: *Iterator, page: *Page) !?Entry {
|
||||
const index = self.index;
|
||||
const node = try self.list.item(index, page) orelse return null;
|
||||
self.index = index + 1;
|
||||
return .{ index, node };
|
||||
}
|
||||
};
|
||||
|
||||
pub const JsApi = struct {
|
||||
pub const bridge = js.Bridge(DOMTokenList);
|
||||
|
||||
@@ -229,6 +267,11 @@ pub const JsApi = struct {
|
||||
pub const toggle = bridge.function(DOMTokenList.toggle, .{ .dom_exception = true });
|
||||
pub const replace = bridge.function(DOMTokenList.replace, .{ .dom_exception = true });
|
||||
pub const value = bridge.accessor(DOMTokenList.getValue, DOMTokenList.setValue, .{});
|
||||
pub const symbol_iterator = bridge.iterator(DOMTokenList.iterator, .{});
|
||||
pub const toString = bridge.function(DOMTokenList.getValue, .{});
|
||||
pub const keys = bridge.function(DOMTokenList.keys, .{});
|
||||
pub const values = bridge.function(DOMTokenList.values, .{});
|
||||
pub const entries = bridge.function(DOMTokenList.entries, .{});
|
||||
pub const symbol_iterator = bridge.iterator(DOMTokenList.values, .{});
|
||||
pub const forEach = bridge.function(DOMTokenList.forEach, .{});
|
||||
pub const @"[]" = bridge.indexed(DOMTokenList.item, .{ .null_as_undefined = true });
|
||||
};
|
||||
|
||||
@@ -21,11 +21,6 @@ const js = @import("../../js/js.zig");
|
||||
const Page = @import("../../Page.zig");
|
||||
|
||||
pub fn Entry(comptime Inner: type, comptime field: ?[]const u8) type {
|
||||
// const InnerStruct = switch (@typeInfo(Inner)) {
|
||||
// .@"struct" => Inner,
|
||||
// .pointer => |ptr| ptr.child,
|
||||
// else => @compileError("invalid iterator type"),
|
||||
// };
|
||||
const InnerStruct = Inner;
|
||||
const R = reflect(InnerStruct, field);
|
||||
|
||||
@@ -68,7 +63,7 @@ pub fn Entry(comptime Inner: type, comptime field: ?[]const u8) type {
|
||||
pub var class_id: bridge.ClassId = undefined;
|
||||
};
|
||||
|
||||
pub const next = bridge.function(Self.next, .{});
|
||||
pub const next = bridge.function(Self.next, .{ .null_as_undefined = true });
|
||||
pub const symbol_iterator = bridge.iterator(Self, .{});
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user