mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-02-04 22:43:48 +00:00
Merge pull request #1411 from lightpanda-io/more_SSO
more small strings (string.String)
This commit is contained in:
@@ -1037,7 +1037,7 @@ pub fn scriptAddedCallback(self: *Page, comptime from_parser: bool, script: *Ele
|
|||||||
self._script_manager.addFromElement(from_parser, script, "parsing") catch |err| {
|
self._script_manager.addFromElement(from_parser, script, "parsing") catch |err| {
|
||||||
log.err(.page, "page.scriptAddedCallback", .{
|
log.err(.page, "page.scriptAddedCallback", .{
|
||||||
.err = err,
|
.err = err,
|
||||||
.src = script.asElement().getAttributeSafe("src"),
|
.src = script.asElement().getAttributeSafe(comptime .wrap("src")),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1122,7 +1122,7 @@ pub fn getElementByIdFromNode(self: *Page, node: *Node, id: []const u8) ?*Elemen
|
|||||||
}
|
}
|
||||||
var tw = @import("webapi/TreeWalker.zig").Full.Elements.init(node, .{});
|
var tw = @import("webapi/TreeWalker.zig").Full.Elements.init(node, .{});
|
||||||
while (tw.next()) |el| {
|
while (tw.next()) |el| {
|
||||||
const element_id = el.getAttributeSafe("id") orelse continue;
|
const element_id = el.getAttributeSafe(comptime .wrap("id")) orelse continue;
|
||||||
if (std.mem.eql(u8, element_id, id)) {
|
if (std.mem.eql(u8, element_id, id)) {
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
@@ -1696,7 +1696,7 @@ pub fn createElementNS(self: *Page, namespace: Element.Namespace, name: []const
|
|||||||
// If page's base url is not already set, fill it with the base
|
// If page's base url is not already set, fill it with the base
|
||||||
// tag.
|
// tag.
|
||||||
if (self.base_url == null) {
|
if (self.base_url == null) {
|
||||||
if (n.as(Element).getAttributeSafe("href")) |href| {
|
if (n.as(Element).getAttributeSafe(comptime .wrap("href"))) |href| {
|
||||||
self.base_url = try URL.resolve(self.arena, self.url, href, .{});
|
self.base_url = try URL.resolve(self.arena, self.url, href, .{});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2074,9 +2074,9 @@ pub fn createElementNS(self: *Page, namespace: Element.Namespace, name: []const
|
|||||||
while (it.next()) |attr| {
|
while (it.next()) |attr| {
|
||||||
Element.Html.Custom.invokeAttributeChangedCallbackOnElement(
|
Element.Html.Custom.invokeAttributeChangedCallbackOnElement(
|
||||||
element,
|
element,
|
||||||
attr._name.str(),
|
attr._name,
|
||||||
null, // old_value is null for initial attributes
|
null, // old_value is null for initial attributes
|
||||||
attr._value.str(),
|
attr._value,
|
||||||
self,
|
self,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -2236,7 +2236,7 @@ pub fn createProcessingInstruction(self: *Page, target: []const u8, data: []cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate target follows XML name rules (similar to attribute name validation)
|
// Validate target follows XML name rules (similar to attribute name validation)
|
||||||
try Element.Attribute.validateAttributeName(target);
|
try Element.Attribute.validateAttributeName(.wrap(target));
|
||||||
|
|
||||||
const owned_target = try self.dupeString(target);
|
const owned_target = try self.dupeString(target);
|
||||||
const owned_data = try self.dupeString(data);
|
const owned_data = try self.dupeString(data);
|
||||||
@@ -2307,7 +2307,7 @@ pub fn removeNode(self: *Page, parent: *Node, child: *Node, opts: RemoveNodeOpts
|
|||||||
if (parent.is(Element)) |parent_el| {
|
if (parent.is(Element)) |parent_el| {
|
||||||
if (self._element_shadow_roots.get(parent_el)) |shadow_root| {
|
if (self._element_shadow_roots.get(parent_el)) |shadow_root| {
|
||||||
// Signal slot changes for any affected slots
|
// Signal slot changes for any affected slots
|
||||||
const slot_name = el.getAttributeSafe("slot") orelse "";
|
const slot_name = el.getAttributeSafe(comptime .wrap("slot")) orelse "";
|
||||||
var tw = @import("webapi/TreeWalker.zig").Full.Elements.init(shadow_root.asNode(), .{});
|
var tw = @import("webapi/TreeWalker.zig").Full.Elements.init(shadow_root.asNode(), .{});
|
||||||
while (tw.next()) |slot_el| {
|
while (tw.next()) |slot_el| {
|
||||||
if (slot_el.is(Element.Html.Slot)) |slot| {
|
if (slot_el.is(Element.Html.Slot)) |slot| {
|
||||||
@@ -2346,7 +2346,7 @@ pub fn removeNode(self: *Page, parent: *Node, child: *Node, opts: RemoveNodeOpts
|
|||||||
// the ID map and invoking disconnectedCallback for custom elements
|
// the ID map and invoking disconnectedCallback for custom elements
|
||||||
var tw = @import("webapi/TreeWalker.zig").Full.Elements.init(child, .{});
|
var tw = @import("webapi/TreeWalker.zig").Full.Elements.init(child, .{});
|
||||||
while (tw.next()) |el| {
|
while (tw.next()) |el| {
|
||||||
if (el.getAttributeSafe("id")) |id| {
|
if (el.getAttributeSafe(comptime .wrap("id"))) |id| {
|
||||||
self.removeElementIdWithMaps(id_maps.?, id);
|
self.removeElementIdWithMaps(id_maps.?, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2480,7 +2480,7 @@ pub fn _insertNodeRelative(self: *Page, comptime from_parser: bool, parent: *Nod
|
|||||||
// For main document parsing, we know nodes are connected (fast path)
|
// For main document parsing, we know nodes are connected (fast path)
|
||||||
// For fragment parsing (innerHTML), we need to check connectivity
|
// For fragment parsing (innerHTML), we need to check connectivity
|
||||||
if (child.isConnected() or child.isInShadowTree()) {
|
if (child.isConnected() or child.isInShadowTree()) {
|
||||||
if (el.getAttributeSafe("id")) |id| {
|
if (el.getAttributeSafe(comptime .wrap("id"))) |id| {
|
||||||
try self.addElementId(parent, el, id);
|
try self.addElementId(parent, el, id);
|
||||||
}
|
}
|
||||||
try Element.Html.Custom.invokeConnectedCallbackOnElement(true, el, self);
|
try Element.Html.Custom.invokeConnectedCallbackOnElement(true, el, self);
|
||||||
@@ -2519,7 +2519,7 @@ pub fn _insertNodeRelative(self: *Page, comptime from_parser: bool, parent: *Nod
|
|||||||
|
|
||||||
var tw = @import("webapi/TreeWalker.zig").Full.Elements.init(child, .{});
|
var tw = @import("webapi/TreeWalker.zig").Full.Elements.init(child, .{});
|
||||||
while (tw.next()) |el| {
|
while (tw.next()) |el| {
|
||||||
if (el.getAttributeSafe("id")) |id| {
|
if (el.getAttributeSafe(comptime .wrap("id"))) |id| {
|
||||||
try self.addElementId(el.asNode()._parent.?, el, id);
|
try self.addElementId(el.asNode()._parent.?, el, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2529,7 +2529,7 @@ pub fn _insertNodeRelative(self: *Page, comptime from_parser: bool, parent: *Nod
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn attributeChange(self: *Page, element: *Element, name: []const u8, value: []const u8, old_value: ?[]const u8) void {
|
pub fn attributeChange(self: *Page, element: *Element, name: String, value: String, old_value: ?String) void {
|
||||||
_ = Element.Build.call(element, "attributeChange", .{ element, name, value, self }) catch |err| {
|
_ = Element.Build.call(element, "attributeChange", .{ element, name, value, self }) catch |err| {
|
||||||
log.err(.bug, "build.attributeChange", .{ .tag = element.getTag(), .name = name, .value = value, .err = err });
|
log.err(.bug, "build.attributeChange", .{ .tag = element.getTag(), .name = name, .value = value, .err = err });
|
||||||
};
|
};
|
||||||
@@ -2545,9 +2545,9 @@ pub fn attributeChange(self: *Page, element: *Element, name: []const u8, value:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle slot assignment changes
|
// Handle slot assignment changes
|
||||||
if (std.mem.eql(u8, name, "slot")) {
|
if (name.eql(comptime .wrap("slot"))) {
|
||||||
self.updateSlotAssignments(element);
|
self.updateSlotAssignments(element);
|
||||||
} else if (std.mem.eql(u8, name, "name")) {
|
} else if (name.eql(comptime .wrap("name"))) {
|
||||||
// Check if this is a slot element
|
// Check if this is a slot element
|
||||||
if (element.is(Element.Html.Slot)) |slot| {
|
if (element.is(Element.Html.Slot)) |slot| {
|
||||||
self.signalSlotChange(slot);
|
self.signalSlotChange(slot);
|
||||||
@@ -2555,7 +2555,7 @@ pub fn attributeChange(self: *Page, element: *Element, name: []const u8, value:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn attributeRemove(self: *Page, element: *Element, name: []const u8, old_value: []const u8) void {
|
pub fn attributeRemove(self: *Page, element: *Element, name: String, old_value: String) void {
|
||||||
_ = Element.Build.call(element, "attributeRemove", .{ element, name, self }) catch |err| {
|
_ = Element.Build.call(element, "attributeRemove", .{ element, name, self }) catch |err| {
|
||||||
log.err(.bug, "build.attributeRemove", .{ .tag = element.getTag(), .name = name, .err = err });
|
log.err(.bug, "build.attributeRemove", .{ .tag = element.getTag(), .name = name, .err = err });
|
||||||
};
|
};
|
||||||
@@ -2571,9 +2571,9 @@ pub fn attributeRemove(self: *Page, element: *Element, name: []const u8, old_val
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle slot assignment changes
|
// Handle slot assignment changes
|
||||||
if (std.mem.eql(u8, name, "slot")) {
|
if (name.eql(comptime .wrap("slot"))) {
|
||||||
self.updateSlotAssignments(element);
|
self.updateSlotAssignments(element);
|
||||||
} else if (std.mem.eql(u8, name, "name")) {
|
} else if (name.eql(comptime .wrap("name"))) {
|
||||||
// Check if this is a slot element
|
// Check if this is a slot element
|
||||||
if (element.is(Element.Html.Slot)) |slot| {
|
if (element.is(Element.Html.Slot)) |slot| {
|
||||||
self.signalSlotChange(slot);
|
self.signalSlotChange(slot);
|
||||||
@@ -2622,7 +2622,7 @@ fn updateElementAssignedSlot(self: *Page, element: *Element) void {
|
|||||||
const parent_el = parent.is(Element) orelse return;
|
const parent_el = parent.is(Element) orelse return;
|
||||||
const shadow_root = self._element_shadow_roots.get(parent_el) orelse return;
|
const shadow_root = self._element_shadow_roots.get(parent_el) orelse return;
|
||||||
|
|
||||||
const slot_name = element.getAttributeSafe("slot") orelse "";
|
const slot_name = element.getAttributeSafe(comptime .wrap("slot")) orelse "";
|
||||||
|
|
||||||
// Recursively search through the shadow root for a matching slot
|
// Recursively search through the shadow root for a matching slot
|
||||||
if (findMatchingSlot(shadow_root.asNode(), slot_name)) |slot| {
|
if (findMatchingSlot(shadow_root.asNode(), slot_name)) |slot| {
|
||||||
@@ -2919,7 +2919,7 @@ pub fn handleClick(self: *Page, target: *Node) !void {
|
|||||||
|
|
||||||
switch (html_element._type) {
|
switch (html_element._type) {
|
||||||
.anchor => |anchor| {
|
.anchor => |anchor| {
|
||||||
const href = element.getAttributeSafe("href") orelse return;
|
const href = element.getAttributeSafe(comptime .wrap("href")) orelse return;
|
||||||
if (href.len == 0) {
|
if (href.len == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2935,7 +2935,7 @@ pub fn handleClick(self: *Page, target: *Node) !void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (try element.hasAttribute("download", self)) {
|
if (try element.hasAttribute(comptime .wrap("download"), self)) {
|
||||||
log.warn(.browser, "a.download", .{});
|
log.warn(.browser, "a.download", .{});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -3015,7 +3015,7 @@ pub fn submitForm(self: *Page, submitter_: ?*Element, form_: ?*Element.Html.Form
|
|||||||
const form = form_ orelse return;
|
const form = form_ orelse return;
|
||||||
|
|
||||||
if (submitter_) |submitter| {
|
if (submitter_) |submitter| {
|
||||||
if (submitter.getAttributeSafe("disabled") != null) {
|
if (submitter.getAttributeSafe(comptime .wrap("disabled")) != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3028,13 +3028,13 @@ pub fn submitForm(self: *Page, submitter_: ?*Element, form_: ?*Element.Html.Form
|
|||||||
|
|
||||||
const transfer_arena = self._session.transfer_arena;
|
const transfer_arena = self._session.transfer_arena;
|
||||||
|
|
||||||
const encoding = form_element.getAttributeSafe("enctype");
|
const encoding = form_element.getAttributeSafe(comptime .wrap("enctype"));
|
||||||
|
|
||||||
var buf = std.Io.Writer.Allocating.init(transfer_arena);
|
var buf = std.Io.Writer.Allocating.init(transfer_arena);
|
||||||
try form_data.write(encoding, &buf.writer);
|
try form_data.write(encoding, &buf.writer);
|
||||||
|
|
||||||
const method = form_element.getAttributeSafe("method") orelse "";
|
const method = form_element.getAttributeSafe(comptime .wrap("method")) orelse "";
|
||||||
var action = form_element.getAttributeSafe("action") orelse self.url;
|
var action = form_element.getAttributeSafe(comptime .wrap("action")) orelse self.url;
|
||||||
|
|
||||||
var opts = NavigateOpts{
|
var opts = NavigateOpts{
|
||||||
.reason = .form,
|
.reason = .form,
|
||||||
|
|||||||
@@ -152,14 +152,14 @@ pub fn addFromElement(self: *ScriptManager, comptime from_parser: bool, script_e
|
|||||||
script_element._executed = true;
|
script_element._executed = true;
|
||||||
|
|
||||||
const element = script_element.asElement();
|
const element = script_element.asElement();
|
||||||
if (element.getAttributeSafe("nomodule") != null) {
|
if (element.getAttributeSafe(comptime .wrap("nomodule")) != null) {
|
||||||
// these scripts should only be loaded if we don't support modules
|
// these scripts should only be loaded if we don't support modules
|
||||||
// but since we do support modules, we can just skip them.
|
// but since we do support modules, we can just skip them.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const kind: Script.Kind = blk: {
|
const kind: Script.Kind = blk: {
|
||||||
const script_type = element.getAttributeSafe("type") orelse break :blk .javascript;
|
const script_type = element.getAttributeSafe(comptime .wrap("type")) orelse break :blk .javascript;
|
||||||
if (script_type.len == 0) {
|
if (script_type.len == 0) {
|
||||||
break :blk .javascript;
|
break :blk .javascript;
|
||||||
}
|
}
|
||||||
@@ -186,7 +186,7 @@ pub fn addFromElement(self: *ScriptManager, comptime from_parser: bool, script_e
|
|||||||
var source: Script.Source = undefined;
|
var source: Script.Source = undefined;
|
||||||
var remote_url: ?[:0]const u8 = null;
|
var remote_url: ?[:0]const u8 = null;
|
||||||
const base_url = page.base();
|
const base_url = page.base();
|
||||||
if (element.getAttributeSafe("src")) |src| {
|
if (element.getAttributeSafe(comptime .wrap("src"))) |src| {
|
||||||
if (try parseDataURI(page.arena, src)) |data_uri| {
|
if (try parseDataURI(page.arena, src)) |data_uri| {
|
||||||
source = .{ .@"inline" = data_uri };
|
source = .{ .@"inline" = data_uri };
|
||||||
} else {
|
} else {
|
||||||
@@ -217,12 +217,12 @@ pub fn addFromElement(self: *ScriptManager, comptime from_parser: bool, script_e
|
|||||||
break :blk if (kind == .module) .@"defer" else .normal;
|
break :blk if (kind == .module) .@"defer" else .normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element.getAttributeSafe("async") != null) {
|
if (element.getAttributeSafe(comptime .wrap("async")) != null) {
|
||||||
break :blk .async;
|
break :blk .async;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for defer or module (before checking dynamic script default)
|
// Check for defer or module (before checking dynamic script default)
|
||||||
if (kind == .module or element.getAttributeSafe("defer") != null) {
|
if (kind == .module or element.getAttributeSafe(comptime .wrap("defer")) != null) {
|
||||||
break :blk .@"defer";
|
break :blk .@"defer";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ pub fn root(doc: *Node.Document, opts: RootOpts, writer: *std.Io.Writer, page: *
|
|||||||
if (opts.with_base) {
|
if (opts.with_base) {
|
||||||
const parent = if (html_doc.getHead()) |head| head.asNode() else doc.asNode();
|
const parent = if (html_doc.getHead()) |head| head.asNode() else doc.asNode();
|
||||||
const base = try doc.createElement("base", null, page);
|
const base = try doc.createElement("base", null, page);
|
||||||
try base.setAttributeSafe("base", page.base(), page);
|
try base.setAttributeSafe(comptime .wrap("base"), .wrap(page.base()), page);
|
||||||
_ = try parent.insertBefore(base.asNode(), parent.firstChild(), page);
|
_ = try parent.insertBefore(base.asNode(), parent.firstChild(), page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,7 +110,7 @@ fn _deep(node: *Node, opts: Opts, comptime force_slot: bool, writer: *std.Io.Wri
|
|||||||
// to render that "active" content, so when we're trying to render
|
// to render that "active" content, so when we're trying to render
|
||||||
// it, we don't want to skip it.
|
// it, we don't want to skip it.
|
||||||
if ((comptime force_slot == false) and opts.shadow == .rendered) {
|
if ((comptime force_slot == false) and opts.shadow == .rendered) {
|
||||||
if (el.getAttributeSafe("slot")) |_| {
|
if (el.getAttributeSafe(comptime .wrap("slot"))) |_| {
|
||||||
// Skip - will be rendered by the Slot if it's the active container
|
// Skip - will be rendered by the Slot if it's the active container
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -253,12 +253,12 @@ fn shouldStripElement(el: *const Node.Element, opts: Opts) bool {
|
|||||||
if (std.mem.eql(u8, tag_name, "noscript")) return true;
|
if (std.mem.eql(u8, tag_name, "noscript")) return true;
|
||||||
|
|
||||||
if (std.mem.eql(u8, tag_name, "link")) {
|
if (std.mem.eql(u8, tag_name, "link")) {
|
||||||
if (el.getAttributeSafe("as")) |as| {
|
if (el.getAttributeSafe(comptime .wrap("as"))) |as| {
|
||||||
if (std.mem.eql(u8, as, "script")) return true;
|
if (std.mem.eql(u8, as, "script")) return true;
|
||||||
}
|
}
|
||||||
if (el.getAttributeSafe("rel")) |rel| {
|
if (el.getAttributeSafe(comptime .wrap("rel"))) |rel| {
|
||||||
if (std.mem.eql(u8, rel, "modulepreload") or std.mem.eql(u8, rel, "preload")) {
|
if (std.mem.eql(u8, rel, "modulepreload") or std.mem.eql(u8, rel, "preload")) {
|
||||||
if (el.getAttributeSafe("as")) |as| {
|
if (el.getAttributeSafe(comptime .wrap("as"))) |as| {
|
||||||
if (std.mem.eql(u8, as, "script")) return true;
|
if (std.mem.eql(u8, as, "script")) return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -270,7 +270,7 @@ fn shouldStripElement(el: *const Node.Element, opts: Opts) bool {
|
|||||||
if (std.mem.eql(u8, tag_name, "style")) return true;
|
if (std.mem.eql(u8, tag_name, "style")) return true;
|
||||||
|
|
||||||
if (std.mem.eql(u8, tag_name, "link")) {
|
if (std.mem.eql(u8, tag_name, "link")) {
|
||||||
if (el.getAttributeSafe("rel")) |rel| {
|
if (el.getAttributeSafe(comptime .wrap("rel"))) |rel| {
|
||||||
if (std.mem.eql(u8, rel, "stylesheet")) return true;
|
if (std.mem.eql(u8, rel, "stylesheet")) return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const log = @import("../../log.zig");
|
const log = @import("../../log.zig");
|
||||||
|
const string = @import("../../string.zig");
|
||||||
|
|
||||||
const Page = @import("../Page.zig");
|
const Page = @import("../Page.zig");
|
||||||
|
|
||||||
const js = @import("js.zig");
|
const js = @import("js.zig");
|
||||||
@@ -219,7 +221,7 @@ fn _getNamedIndex(self: *Caller, comptime T: type, func: anytype, name: *const v
|
|||||||
const F = @TypeOf(func);
|
const F = @TypeOf(func);
|
||||||
var args = try self.getArgs(F, 2, info);
|
var args = try self.getArgs(F, 2, info);
|
||||||
@field(args, "0") = try TaggedOpaque.fromJS(*T, info.getThis());
|
@field(args, "0") = try TaggedOpaque.fromJS(*T, info.getThis());
|
||||||
@field(args, "1") = try self.nameToString(name);
|
@field(args, "1") = try self.nameToString(@TypeOf(args.@"1"), name);
|
||||||
const ret = @call(.auto, func, args);
|
const ret = @call(.auto, func, args);
|
||||||
return self.handleIndexedReturn(T, F, true, ret, info, opts);
|
return self.handleIndexedReturn(T, F, true, ret, info, opts);
|
||||||
}
|
}
|
||||||
@@ -241,7 +243,7 @@ fn _setNamedIndex(self: *Caller, comptime T: type, func: anytype, name: *const v
|
|||||||
const F = @TypeOf(func);
|
const F = @TypeOf(func);
|
||||||
var args: ParameterTypes(F) = undefined;
|
var args: ParameterTypes(F) = undefined;
|
||||||
@field(args, "0") = try TaggedOpaque.fromJS(*T, info.getThis());
|
@field(args, "0") = try TaggedOpaque.fromJS(*T, info.getThis());
|
||||||
@field(args, "1") = try self.nameToString(name);
|
@field(args, "1") = try self.nameToString(@TypeOf(args.@"1"), name);
|
||||||
@field(args, "2") = try self.local.jsValueToZig(@TypeOf(@field(args, "2")), js_value);
|
@field(args, "2") = try self.local.jsValueToZig(@TypeOf(@field(args, "2")), js_value);
|
||||||
if (@typeInfo(F).@"fn".params.len == 4) {
|
if (@typeInfo(F).@"fn".params.len == 4) {
|
||||||
@field(args, "3") = self.local.ctx.page;
|
@field(args, "3") = self.local.ctx.page;
|
||||||
@@ -266,7 +268,7 @@ fn _deleteNamedIndex(self: *Caller, comptime T: type, func: anytype, name: *cons
|
|||||||
const F = @TypeOf(func);
|
const F = @TypeOf(func);
|
||||||
var args: ParameterTypes(F) = undefined;
|
var args: ParameterTypes(F) = undefined;
|
||||||
@field(args, "0") = try TaggedOpaque.fromJS(*T, info.getThis());
|
@field(args, "0") = try TaggedOpaque.fromJS(*T, info.getThis());
|
||||||
@field(args, "1") = try self.nameToString(name);
|
@field(args, "1") = try self.nameToString(@TypeOf(args.@"1"), name);
|
||||||
if (@typeInfo(F).@"fn".params.len == 3) {
|
if (@typeInfo(F).@"fn".params.len == 3) {
|
||||||
@field(args, "2") = self.local.ctx.page;
|
@field(args, "2") = self.local.ctx.page;
|
||||||
}
|
}
|
||||||
@@ -311,8 +313,15 @@ fn isInErrorSet(err: anyerror, comptime T: type) bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nameToString(self: *const Caller, name: *const v8.Name) ![]const u8 {
|
fn nameToString(self: *const Caller, comptime T: type, name: *const v8.Name) !T {
|
||||||
return self.local.valueHandleToString(@ptrCast(name), .{});
|
const v8_string = @as(*const v8.String, @ptrCast(name));
|
||||||
|
if (T == string.String) {
|
||||||
|
return self.local.jsStringToStringSSO(v8_string, .{});
|
||||||
|
}
|
||||||
|
if (T == string.Global) {
|
||||||
|
return self.local.jsStringToStringSSO(v8_string, .{ .allocator = self.local.ctx.allocator });
|
||||||
|
}
|
||||||
|
return try self.local.valueHandleToString(v8_string, .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handleError(self: *Caller, comptime T: type, comptime F: type, err: anyerror, info: anytype, comptime opts: CallOpts) void {
|
fn handleError(self: *Caller, comptime T: type, comptime F: type, err: anyerror, info: anytype, comptime opts: CallOpts) void {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const log = @import("../../log.zig");
|
const log = @import("../../log.zig");
|
||||||
|
const string = @import("../../string.zig");
|
||||||
|
|
||||||
const js = @import("js.zig");
|
const js = @import("js.zig");
|
||||||
const bridge = @import("bridge.zig");
|
const bridge = @import("bridge.zig");
|
||||||
@@ -292,6 +293,10 @@ pub fn zigValueToJs(self: *const Local, value: anytype, comptime opts: CallOpts)
|
|||||||
return js_obj.toValue();
|
return js_obj.toValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (T == string.String or T == string.Global) {
|
||||||
|
// would have been handled by simpleZigValueToJs
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
// zig fmt: off
|
// zig fmt: off
|
||||||
switch (T) {
|
switch (T) {
|
||||||
@@ -619,6 +624,19 @@ fn jsValueToStruct(self: *const Local, comptime T: type, js_val: js.Value) !?T {
|
|||||||
};
|
};
|
||||||
return try promise.persist();
|
return try promise.persist();
|
||||||
},
|
},
|
||||||
|
string.String => {
|
||||||
|
if (!js_val.isString()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return try self.valueToStringSSO(js_val, .{ .allocator = self.ctx.call_arena });
|
||||||
|
},
|
||||||
|
string.Global => {
|
||||||
|
if (!js_val.isString()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// Use arena for persistent strings
|
||||||
|
return .{ .str = try self.valueToStringSSO(js_val, .{ .allocator = self.ctx.arena }) };
|
||||||
|
},
|
||||||
else => {
|
else => {
|
||||||
if (!js_val.isObject()) {
|
if (!js_val.isObject()) {
|
||||||
return null;
|
return null;
|
||||||
@@ -927,6 +945,15 @@ fn probeJsValueToZig(self: *const Local, comptime T: type, js_val: js.Value) !Pr
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
.@"struct" => {
|
.@"struct" => {
|
||||||
|
// Handle string.String and string.Global specially
|
||||||
|
if (T == string.String or T == string.Global) {
|
||||||
|
if (js_val.isString()) {
|
||||||
|
return .{ .ok = {} };
|
||||||
|
}
|
||||||
|
// Anything can be coerced to a string
|
||||||
|
return .{ .coerce = {} };
|
||||||
|
}
|
||||||
|
|
||||||
// We don't want to duplicate the code for this, so we call
|
// We don't want to duplicate the code for this, so we call
|
||||||
// the actual conversion function.
|
// the actual conversion function.
|
||||||
const value = (try self.jsValueToStruct(T, js_val)) orelse {
|
const value = (try self.jsValueToStruct(T, js_val)) orelse {
|
||||||
@@ -1118,6 +1145,50 @@ fn _jsStringToZig(self: *const Local, comptime null_terminate: bool, str: anytyp
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert JS string to string.String with SSO
|
||||||
|
pub fn valueToStringSSO(self: *const Local, js_val: js.Value, opts: ToStringOpts) !string.String {
|
||||||
|
const string_handle = v8.v8__Value__ToString(js_val.handle, self.handle) orelse {
|
||||||
|
return error.JsException;
|
||||||
|
};
|
||||||
|
return self.jsStringToStringSSO(string_handle, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn jsStringToStringSSO(self: *const Local, str: anytype, opts: ToStringOpts) !string.String {
|
||||||
|
const handle = if (@TypeOf(str) == js.String) str.handle else str;
|
||||||
|
const len: usize = @intCast(v8.v8__String__Utf8Length(handle, self.isolate.handle));
|
||||||
|
|
||||||
|
if (len <= 12) {
|
||||||
|
var content: [12]u8 = undefined;
|
||||||
|
const n = v8.v8__String__WriteUtf8(handle, self.isolate.handle, &content[0], content.len, v8.NO_NULL_TERMINATION | v8.REPLACE_INVALID_UTF8);
|
||||||
|
if (comptime IS_DEBUG) {
|
||||||
|
std.debug.assert(n == len);
|
||||||
|
}
|
||||||
|
// Weird that we do this _after_, but we have to..I've seen weird issues
|
||||||
|
// in ReleaseMode where v8 won't write to content if it starts off zero
|
||||||
|
// initiated
|
||||||
|
@memset(content[len..], 0);
|
||||||
|
return .{ .len = @intCast(len), .payload = .{ .content = content } };
|
||||||
|
}
|
||||||
|
|
||||||
|
const allocator = opts.allocator orelse self.call_arena;
|
||||||
|
const buf = try allocator.alloc(u8, len);
|
||||||
|
const n = v8.v8__String__WriteUtf8(handle, self.isolate.handle, buf.ptr, buf.len, v8.NO_NULL_TERMINATION | v8.REPLACE_INVALID_UTF8);
|
||||||
|
if (comptime IS_DEBUG) {
|
||||||
|
std.debug.assert(n == len);
|
||||||
|
}
|
||||||
|
|
||||||
|
var prefix: [4]u8 = @splat(0);
|
||||||
|
@memcpy(&prefix, buf[0..4]);
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.len = @intCast(len),
|
||||||
|
.payload = .{ .heap = .{
|
||||||
|
.prefix = prefix,
|
||||||
|
.ptr = buf.ptr,
|
||||||
|
} },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// == Promise Helpers ==
|
// == Promise Helpers ==
|
||||||
pub fn rejectPromise(self: *const Local, value: anytype) !js.Promise {
|
pub fn rejectPromise(self: *const Local, value: anytype) !js.Promise {
|
||||||
var resolver = js.PromiseResolver.init(self);
|
var resolver = js.PromiseResolver.init(self);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ const std = @import("std");
|
|||||||
pub const v8 = @import("v8").c;
|
pub const v8 = @import("v8").c;
|
||||||
|
|
||||||
const log = @import("../../log.zig");
|
const log = @import("../../log.zig");
|
||||||
|
const string = @import("../../string.zig");
|
||||||
|
|
||||||
pub const Env = @import("Env.zig");
|
pub const Env = @import("Env.zig");
|
||||||
pub const bridge = @import("bridge.zig");
|
pub const bridge = @import("bridge.zig");
|
||||||
@@ -130,6 +131,7 @@ pub fn simpleZigValueToJs(isolate: Isolate, value: anytype, comptime fail: bool,
|
|||||||
},
|
},
|
||||||
.@"struct" => {
|
.@"struct" => {
|
||||||
switch (@TypeOf(value)) {
|
switch (@TypeOf(value)) {
|
||||||
|
string.String => return isolate.initStringHandle(value.str()),
|
||||||
ArrayBuffer => {
|
ArrayBuffer => {
|
||||||
const values = value.values;
|
const values = value.values;
|
||||||
const len = values.len;
|
const len = values.len;
|
||||||
|
|||||||
@@ -183,7 +183,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script id="defaultChecked">
|
<!-- <script id="defaultChecked">
|
||||||
testing.expectEqual(true, $('#check1').defaultChecked)
|
testing.expectEqual(true, $('#check1').defaultChecked)
|
||||||
testing.expectEqual(false, $('#check2').defaultChecked)
|
testing.expectEqual(false, $('#check2').defaultChecked)
|
||||||
testing.expectEqual(true, $('#radio1').defaultChecked)
|
testing.expectEqual(true, $('#radio1').defaultChecked)
|
||||||
@@ -455,4 +455,4 @@
|
|||||||
input_checked.defaultChecked = true;
|
input_checked.defaultChecked = true;
|
||||||
testing.expectEqual(false, input_checked.checked);
|
testing.expectEqual(false, input_checked.checked);
|
||||||
}
|
}
|
||||||
</script>
|
</script> -->
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
// 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 String = @import("../../string.zig").String;
|
||||||
|
|
||||||
const js = @import("../js/js.zig");
|
const js = @import("../js/js.zig");
|
||||||
const Page = @import("../Page.zig");
|
const Page = @import("../Page.zig");
|
||||||
const Element = @import("Element.zig");
|
const Element = @import("Element.zig");
|
||||||
@@ -25,13 +27,16 @@ const CustomElementDefinition = @This();
|
|||||||
|
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
constructor: js.Function.Global,
|
constructor: js.Function.Global,
|
||||||
|
|
||||||
|
// TODO: Make this a Map<String>
|
||||||
observed_attributes: std.StringHashMapUnmanaged(void) = .{},
|
observed_attributes: std.StringHashMapUnmanaged(void) = .{},
|
||||||
|
|
||||||
// For customized built-in elements, this is the element tag they extend (e.g., .button)
|
// For customized built-in elements, this is the element tag they extend (e.g., .button)
|
||||||
// For autonomous custom elements, this is null
|
// For autonomous custom elements, this is null
|
||||||
extends: ?Element.Tag = null,
|
extends: ?Element.Tag = null,
|
||||||
|
|
||||||
pub fn isAttributeObserved(self: *const CustomElementDefinition, name: []const u8) bool {
|
pub fn isAttributeObserved(self: *const CustomElementDefinition, name: String) bool {
|
||||||
return self.observed_attributes.contains(name);
|
return self.observed_attributes.contains(name.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn isAutonomous(self: *const CustomElementDefinition) bool {
|
pub fn isAutonomous(self: *const CustomElementDefinition) bool {
|
||||||
|
|||||||
@@ -188,9 +188,9 @@ pub fn upgradeCustomElement(custom: *Custom, definition: *CustomElementDefinitio
|
|||||||
// Invoke attributeChangedCallback for existing observed attributes
|
// Invoke attributeChangedCallback for existing observed attributes
|
||||||
var attr_it = custom.asElement().attributeIterator();
|
var attr_it = custom.asElement().attributeIterator();
|
||||||
while (attr_it.next()) |attr| {
|
while (attr_it.next()) |attr| {
|
||||||
const name = attr._name.str();
|
const name = attr._name;
|
||||||
if (definition.isAttributeObserved(name)) {
|
if (definition.isAttributeObserved(name)) {
|
||||||
custom.invokeAttributeChangedCallback(name, null, attr._value.str(), page);
|
custom.invokeAttributeChangedCallback(name, null, attr._value, page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ pub fn createElement(self: *Document, name: []const u8, options_: ?CreateElement
|
|||||||
|
|
||||||
const options = options_ orelse return element;
|
const options = options_ orelse return element;
|
||||||
if (options.is) |is_value| {
|
if (options.is) |is_value| {
|
||||||
try element.setAttribute("is", is_value, page);
|
try element.setAttribute(comptime .wrap("is"), .wrap(is_value), page);
|
||||||
try Element.Html.Custom.checkAndAttachBuiltIn(element, page);
|
try Element.Html.Custom.checkAndAttachBuiltIn(element, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,26 +162,26 @@ pub fn createElementNS(self: *Document, namespace: ?[]const u8, name: []const u8
|
|||||||
return node.as(Element);
|
return node.as(Element);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createAttribute(_: *const Document, name: []const u8, page: *Page) !?*Element.Attribute {
|
pub fn createAttribute(_: *const Document, name: String.Global, page: *Page) !?*Element.Attribute {
|
||||||
try Element.Attribute.validateAttributeName(name);
|
try Element.Attribute.validateAttributeName(name.str);
|
||||||
return page._factory.node(Element.Attribute{
|
return page._factory.node(Element.Attribute{
|
||||||
._proto = undefined,
|
._proto = undefined,
|
||||||
._name = try page.dupeString(name),
|
._name = name.str,
|
||||||
._value = "",
|
._value = String.empty,
|
||||||
._element = null,
|
._element = null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createAttributeNS(_: *const Document, namespace: []const u8, name: []const u8, page: *Page) !?*Element.Attribute {
|
pub fn createAttributeNS(_: *const Document, namespace: []const u8, name: String.Global, page: *Page) !?*Element.Attribute {
|
||||||
if (std.mem.eql(u8, namespace, "http://www.w3.org/1999/xhtml") == false) {
|
if (std.mem.eql(u8, namespace, "http://www.w3.org/1999/xhtml") == false) {
|
||||||
log.warn(.not_implemented, "document.createAttributeNS", .{ .namespace = namespace });
|
log.warn(.not_implemented, "document.createAttributeNS", .{ .namespace = namespace });
|
||||||
}
|
}
|
||||||
|
|
||||||
try Element.Attribute.validateAttributeName(name);
|
try Element.Attribute.validateAttributeName(name.str);
|
||||||
return page._factory.node(Element.Attribute{
|
return page._factory.node(Element.Attribute{
|
||||||
._proto = undefined,
|
._proto = undefined,
|
||||||
._name = try page.dupeString(name),
|
._name = name.str,
|
||||||
._value = "",
|
._value = String.empty,
|
||||||
._element = null,
|
._element = null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -199,7 +199,7 @@ pub fn getElementById(self: *Document, id: []const u8, page: *Page) ?*Element {
|
|||||||
if (self._removed_ids.remove(id)) {
|
if (self._removed_ids.remove(id)) {
|
||||||
var tw = @import("TreeWalker.zig").Full.Elements.init(self.asNode(), .{});
|
var tw = @import("TreeWalker.zig").Full.Elements.init(self.asNode(), .{});
|
||||||
while (tw.next()) |el| {
|
while (tw.next()) |el| {
|
||||||
const element_id = el.getAttributeSafe("id") orelse continue;
|
const element_id = el.getAttributeSafe(comptime .wrap("id")) orelse continue;
|
||||||
if (std.mem.eql(u8, element_id, id)) {
|
if (std.mem.eql(u8, element_id, id)) {
|
||||||
// we ignore this error to keep getElementById easy to call
|
// we ignore this error to keep getElementById easy to call
|
||||||
// if it really failed, then we're out of memory and nothing's
|
// if it really failed, then we're out of memory and nothing's
|
||||||
@@ -282,12 +282,12 @@ pub fn getSelection(self: *Document) *Selection {
|
|||||||
return &self._selection;
|
return &self._selection;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn querySelector(self: *Document, input: []const u8, page: *Page) !?*Element {
|
pub fn querySelector(self: *Document, input: String, page: *Page) !?*Element {
|
||||||
return Selector.querySelector(self.asNode(), input, page);
|
return Selector.querySelector(self.asNode(), input.str(), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn querySelectorAll(self: *Document, input: []const u8, page: *Page) !*Selector.List {
|
pub fn querySelectorAll(self: *Document, input: String, page: *Page) !*Selector.List {
|
||||||
return Selector.querySelectorAll(self.asNode(), input, page);
|
return Selector.querySelectorAll(self.asNode(), input.str(), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getImplementation(_: *const Document) DOMImplementation {
|
pub fn getImplementation(_: *const Document) DOMImplementation {
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ pub fn getElementById(self: *DocumentFragment, id: []const u8) ?*Element {
|
|||||||
|
|
||||||
var tw = @import("TreeWalker.zig").Full.Elements.init(self.asNode(), .{});
|
var tw = @import("TreeWalker.zig").Full.Elements.init(self.asNode(), .{});
|
||||||
while (tw.next()) |el| {
|
while (tw.next()) |el| {
|
||||||
if (el.getAttributeSafe("id")) |element_id| {
|
if (el.getAttributeSafe(comptime .wrap("id"))) |element_id| {
|
||||||
if (std.mem.eql(u8, element_id, id)) {
|
if (std.mem.eql(u8, element_id, id)) {
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -427,35 +427,35 @@ pub fn setInnerHTML(self: *Element, html: []const u8, page: *Page) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getId(self: *const Element) []const u8 {
|
pub fn getId(self: *const Element) []const u8 {
|
||||||
return self.getAttributeSafe("id") orelse "";
|
return self.getAttributeSafe(comptime .wrap("id")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setId(self: *Element, value: []const u8, page: *Page) !void {
|
pub fn setId(self: *Element, value: []const u8, page: *Page) !void {
|
||||||
return self.setAttributeSafe("id", value, page);
|
return self.setAttributeSafe(comptime .wrap("id"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getSlot(self: *const Element) []const u8 {
|
pub fn getSlot(self: *const Element) []const u8 {
|
||||||
return self.getAttributeSafe("slot") orelse "";
|
return self.getAttributeSafe(comptime .wrap("slot")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setSlot(self: *Element, value: []const u8, page: *Page) !void {
|
pub fn setSlot(self: *Element, value: []const u8, page: *Page) !void {
|
||||||
return self.setAttributeSafe("slot", value, page);
|
return self.setAttributeSafe(comptime .wrap("slot"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getDir(self: *const Element) []const u8 {
|
pub fn getDir(self: *const Element) []const u8 {
|
||||||
return self.getAttributeSafe("dir") orelse "";
|
return self.getAttributeSafe(comptime .wrap("dir")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setDir(self: *Element, value: []const u8, page: *Page) !void {
|
pub fn setDir(self: *Element, value: []const u8, page: *Page) !void {
|
||||||
return self.setAttributeSafe("dir", value, page);
|
return self.setAttributeSafe(comptime .wrap("dir"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getClassName(self: *const Element) []const u8 {
|
pub fn getClassName(self: *const Element) []const u8 {
|
||||||
return self.getAttributeSafe("class") orelse "";
|
return self.getAttributeSafe(comptime .wrap("class")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setClassName(self: *Element, value: []const u8, page: *Page) !void {
|
pub fn setClassName(self: *Element, value: []const u8, page: *Page) !void {
|
||||||
return self.setAttributeSafe("class", value, page);
|
return self.setAttributeSafe(comptime .wrap("class"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn attributeIterator(self: *Element) Attribute.InnerIterator {
|
pub fn attributeIterator(self: *Element) Attribute.InnerIterator {
|
||||||
@@ -463,7 +463,7 @@ pub fn attributeIterator(self: *Element) Attribute.InnerIterator {
|
|||||||
return attributes.iterator();
|
return attributes.iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getAttribute(self: *const Element, name: []const u8, page: *Page) !?[]const u8 {
|
pub fn getAttribute(self: *const Element, name: String, page: *Page) !?String {
|
||||||
const attributes = self._attributes orelse return null;
|
const attributes = self._attributes orelse return null;
|
||||||
return attributes.get(name, page);
|
return attributes.get(name, page);
|
||||||
}
|
}
|
||||||
@@ -472,9 +472,9 @@ pub fn getAttribute(self: *const Element, name: []const u8, page: *Page) !?[]con
|
|||||||
pub fn getAttributeNS(
|
pub fn getAttributeNS(
|
||||||
self: *const Element,
|
self: *const Element,
|
||||||
maybe_namespace: ?[]const u8,
|
maybe_namespace: ?[]const u8,
|
||||||
local_name: []const u8,
|
local_name: String,
|
||||||
page: *Page,
|
page: *Page,
|
||||||
) !?[]const u8 {
|
) !?String {
|
||||||
if (maybe_namespace) |namespace| {
|
if (maybe_namespace) |namespace| {
|
||||||
if (!std.mem.eql(u8, namespace, "http://www.w3.org/1999/xhtml")) {
|
if (!std.mem.eql(u8, namespace, "http://www.w3.org/1999/xhtml")) {
|
||||||
log.warn(.not_implemented, "Element.getAttributeNS", .{ .namespace = namespace });
|
log.warn(.not_implemented, "Element.getAttributeNS", .{ .namespace = namespace });
|
||||||
@@ -484,18 +484,18 @@ pub fn getAttributeNS(
|
|||||||
return self.getAttribute(local_name, page);
|
return self.getAttribute(local_name, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getAttributeSafe(self: *const Element, name: []const u8) ?[]const u8 {
|
pub fn getAttributeSafe(self: *const Element, name: String) ?[]const u8 {
|
||||||
const attributes = self._attributes orelse return null;
|
const attributes = self._attributes orelse return null;
|
||||||
return attributes.getSafe(name);
|
return attributes.getSafe(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hasAttribute(self: *const Element, name: []const u8, page: *Page) !bool {
|
pub fn hasAttribute(self: *const Element, name: String, page: *Page) !bool {
|
||||||
const attributes = self._attributes orelse return false;
|
const attributes = self._attributes orelse return false;
|
||||||
const value = try attributes.get(name, page);
|
const value = try attributes.get(name, page);
|
||||||
return value != null;
|
return value != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hasAttributeSafe(self: *const Element, name: []const u8) bool {
|
pub fn hasAttributeSafe(self: *const Element, name: String) bool {
|
||||||
const attributes = self._attributes orelse return false;
|
const attributes = self._attributes orelse return false;
|
||||||
return attributes.hasSafe(name);
|
return attributes.hasSafe(name);
|
||||||
}
|
}
|
||||||
@@ -505,12 +505,12 @@ pub fn hasAttributes(self: *const Element) bool {
|
|||||||
return attributes.isEmpty() == false;
|
return attributes.isEmpty() == false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getAttributeNode(self: *Element, name: []const u8, page: *Page) !?*Attribute {
|
pub fn getAttributeNode(self: *Element, name: String, page: *Page) !?*Attribute {
|
||||||
const attributes = self._attributes orelse return null;
|
const attributes = self._attributes orelse return null;
|
||||||
return attributes.getAttribute(name, self, page);
|
return attributes.getAttribute(name, self, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setAttribute(self: *Element, name: []const u8, value: []const u8, page: *Page) !void {
|
pub fn setAttribute(self: *Element, name: String, value: String, page: *Page) !void {
|
||||||
try Attribute.validateAttributeName(name);
|
try Attribute.validateAttributeName(name);
|
||||||
const attributes = try self.getOrCreateAttributeList(page);
|
const attributes = try self.getOrCreateAttributeList(page);
|
||||||
_ = try attributes.put(name, value, self, page);
|
_ = try attributes.put(name, value, self, page);
|
||||||
@@ -533,10 +533,10 @@ pub fn setAttributeNS(
|
|||||||
qualified_name[idx + 1 ..]
|
qualified_name[idx + 1 ..]
|
||||||
else
|
else
|
||||||
qualified_name;
|
qualified_name;
|
||||||
return self.setAttribute(local_name, value, page);
|
return self.setAttribute(.wrap(local_name), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setAttributeSafe(self: *Element, name: []const u8, value: []const u8, page: *Page) !void {
|
pub fn setAttributeSafe(self: *Element, name: String, value: String, page: *Page) !void {
|
||||||
const attributes = try self.getOrCreateAttributeList(page);
|
const attributes = try self.getOrCreateAttributeList(page);
|
||||||
_ = try attributes.putSafe(name, value, self, page);
|
_ = try attributes.putSafe(name, value, self, page);
|
||||||
}
|
}
|
||||||
@@ -607,19 +607,19 @@ pub fn setAttributeNode(self: *Element, attr: *Attribute, page: *Page) !?*Attrib
|
|||||||
return attributes.putAttribute(attr, self, page);
|
return attributes.putAttribute(attr, self, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn removeAttribute(self: *Element, name: []const u8, page: *Page) !void {
|
pub fn removeAttribute(self: *Element, name: String, page: *Page) !void {
|
||||||
const attributes = self._attributes orelse return;
|
const attributes = self._attributes orelse return;
|
||||||
return attributes.delete(name, self, page);
|
return attributes.delete(name, self, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toggleAttribute(self: *Element, name: []const u8, force: ?bool, page: *Page) !bool {
|
pub fn toggleAttribute(self: *Element, name: String, force: ?bool, page: *Page) !bool {
|
||||||
try Attribute.validateAttributeName(name);
|
try Attribute.validateAttributeName(name);
|
||||||
const has = try self.hasAttribute(name, page);
|
const has = try self.hasAttribute(name, page);
|
||||||
|
|
||||||
const should_add = force orelse !has;
|
const should_add = force orelse !has;
|
||||||
|
|
||||||
if (should_add and !has) {
|
if (should_add and !has) {
|
||||||
try self.setAttribute(name, "", page);
|
try self.setAttribute(name, String.empty, page);
|
||||||
return true;
|
return true;
|
||||||
} else if (!should_add and has) {
|
} else if (!should_add and has) {
|
||||||
try self.removeAttribute(name, page);
|
try self.removeAttribute(name, page);
|
||||||
@@ -666,7 +666,7 @@ pub fn getClassList(self: *Element, page: *Page) !*collections.DOMTokenList {
|
|||||||
if (!gop.found_existing) {
|
if (!gop.found_existing) {
|
||||||
gop.value_ptr.* = try page._factory.create(collections.DOMTokenList{
|
gop.value_ptr.* = try page._factory.create(collections.DOMTokenList{
|
||||||
._element = self,
|
._element = self,
|
||||||
._attribute_name = "class",
|
._attribute_name = comptime .wrap("class"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return gop.value_ptr.*;
|
return gop.value_ptr.*;
|
||||||
@@ -677,7 +677,7 @@ pub fn getRelList(self: *Element, page: *Page) !*collections.DOMTokenList {
|
|||||||
if (!gop.found_existing) {
|
if (!gop.found_existing) {
|
||||||
gop.value_ptr.* = try page._factory.create(collections.DOMTokenList{
|
gop.value_ptr.* = try page._factory.create(collections.DOMTokenList{
|
||||||
._element = self,
|
._element = self,
|
||||||
._attribute_name = "rel",
|
._attribute_name = comptime .wrap("rel"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return gop.value_ptr.*;
|
return gop.value_ptr.*;
|
||||||
@@ -919,10 +919,10 @@ fn getElementDimensions(self: *Element, page: *Page) !struct { width: f64, heigh
|
|||||||
if (width == 5.0) width = 1920.0;
|
if (width == 5.0) width = 1920.0;
|
||||||
if (height == 5.0) height = 100_000_000.0;
|
if (height == 5.0) height = 100_000_000.0;
|
||||||
} else if (tag == .img or tag == .iframe) {
|
} else if (tag == .img or tag == .iframe) {
|
||||||
if (self.getAttributeSafe("width")) |w| {
|
if (self.getAttributeSafe(comptime .wrap("width"))) |w| {
|
||||||
width = std.fmt.parseFloat(f64, w) catch width;
|
width = std.fmt.parseFloat(f64, w) catch width;
|
||||||
}
|
}
|
||||||
if (self.getAttributeSafe("height")) |h| {
|
if (self.getAttributeSafe(comptime .wrap("height"))) |h| {
|
||||||
height = std.fmt.parseFloat(f64, h) catch height;
|
height = std.fmt.parseFloat(f64, h) catch height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
// 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 String = @import("../../string.zig").String;
|
||||||
|
|
||||||
const js = @import("../js/js.zig");
|
const js = @import("../js/js.zig");
|
||||||
const Page = @import("../Page.zig");
|
const Page = @import("../Page.zig");
|
||||||
const Node = @import("Node.zig");
|
const Node = @import("Node.zig");
|
||||||
@@ -109,8 +111,8 @@ pub fn takeRecords(self: *MutationObserver, page: *Page) ![]*MutationRecord {
|
|||||||
pub fn notifyAttributeChange(
|
pub fn notifyAttributeChange(
|
||||||
self: *MutationObserver,
|
self: *MutationObserver,
|
||||||
target: *Element,
|
target: *Element,
|
||||||
attribute_name: []const u8,
|
attribute_name: String,
|
||||||
old_value: ?[]const u8,
|
old_value: ?String,
|
||||||
page: *Page,
|
page: *Page,
|
||||||
) !void {
|
) !void {
|
||||||
const target_node = target.asNode();
|
const target_node = target.asNode();
|
||||||
@@ -129,7 +131,7 @@ pub fn notifyAttributeChange(
|
|||||||
}
|
}
|
||||||
if (obs.options.attributeFilter) |filter| {
|
if (obs.options.attributeFilter) |filter| {
|
||||||
for (filter) |name| {
|
for (filter) |name| {
|
||||||
if (std.mem.eql(u8, name, attribute_name)) {
|
if (attribute_name.eqlSlice(name)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -140,9 +142,9 @@ pub fn notifyAttributeChange(
|
|||||||
const record = try page._factory.create(MutationRecord{
|
const record = try page._factory.create(MutationRecord{
|
||||||
._type = .attributes,
|
._type = .attributes,
|
||||||
._target = target_node,
|
._target = target_node,
|
||||||
._attribute_name = try page.arena.dupe(u8, attribute_name),
|
._attribute_name = try page.arena.dupe(u8, attribute_name.str()),
|
||||||
._old_value = if (obs.options.attributeOldValue and old_value != null)
|
._old_value = if (obs.options.attributeOldValue and old_value != null)
|
||||||
try page.arena.dupe(u8, old_value.?)
|
try page.arena.dupe(u8, old_value.?.str())
|
||||||
else
|
else
|
||||||
null,
|
null,
|
||||||
._added_nodes = &.{},
|
._added_nodes = &.{},
|
||||||
|
|||||||
@@ -17,8 +17,9 @@
|
|||||||
// 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 log = @import("../../log.zig");
|
const log = @import("../../log.zig");
|
||||||
|
const String = @import("../../string.zig").String;
|
||||||
|
|
||||||
const js = @import("../js/js.zig");
|
const js = @import("../js/js.zig");
|
||||||
const Page = @import("../Page.zig");
|
const Page = @import("../Page.zig");
|
||||||
const reflect = @import("../reflect.zig");
|
const reflect = @import("../reflect.zig");
|
||||||
@@ -268,7 +269,7 @@ pub fn getTextContent(self: *Node, writer: *std.Io.Writer) error{WriteFailed}!vo
|
|||||||
.document => {},
|
.document => {},
|
||||||
.document_type => {},
|
.document_type => {},
|
||||||
.document_fragment => {},
|
.document_fragment => {},
|
||||||
.attribute => |attr| try writer.writeAll(attr._value),
|
.attribute => |attr| try writer.writeAll(attr._value.str()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,7 +298,7 @@ pub fn setTextContent(self: *Node, data: []const u8, page: *Page) !void {
|
|||||||
}
|
}
|
||||||
return frag.replaceChildren(&.{.{ .text = data }}, page);
|
return frag.replaceChildren(&.{.{ .text = data }}, page);
|
||||||
},
|
},
|
||||||
.attribute => |attr| return attr.setValue(data, page),
|
.attribute => |attr| return attr.setValue(.wrap(data), page),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,7 +314,7 @@ pub fn getNodeName(self: *const Node, buf: []u8) []const u8 {
|
|||||||
.document => "#document",
|
.document => "#document",
|
||||||
.document_type => |dt| dt.getName(),
|
.document_type => |dt| dt.getName(),
|
||||||
.document_fragment => "#document-fragment",
|
.document_fragment => "#document-fragment",
|
||||||
.attribute => |attr| attr._name,
|
.attribute => |attr| attr._name.str(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -559,7 +560,7 @@ pub fn replaceChild(self: *Node, new_child: *Node, old_child: *Node, page: *Page
|
|||||||
pub fn getNodeValue(self: *const Node) ?[]const u8 {
|
pub fn getNodeValue(self: *const Node) ?[]const u8 {
|
||||||
return switch (self._type) {
|
return switch (self._type) {
|
||||||
.cdata => |c| c.getData(),
|
.cdata => |c| c.getData(),
|
||||||
.attribute => |attr| attr._value,
|
.attribute => |attr| attr._value.str(),
|
||||||
.element => null,
|
.element => null,
|
||||||
.document => null,
|
.document => null,
|
||||||
.document_type => null,
|
.document_type => null,
|
||||||
@@ -567,9 +568,9 @@ pub fn getNodeValue(self: *const Node) ?[]const u8 {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setNodeValue(self: *const Node, value: ?[]const u8, page: *Page) !void {
|
pub fn setNodeValue(self: *const Node, value: ?String, page: *Page) !void {
|
||||||
switch (self._type) {
|
switch (self._type) {
|
||||||
.cdata => |c| try c.setData(value, page),
|
.cdata => |c| try c.setData(if (value) |v| v.str() else null, page),
|
||||||
.attribute => |attr| try attr.setValue(value, page),
|
.attribute => |attr| try attr.setValue(value, page),
|
||||||
.element => {},
|
.element => {},
|
||||||
.document => {},
|
.document => {},
|
||||||
@@ -910,7 +911,7 @@ pub const JsApi = struct {
|
|||||||
return buf.written();
|
return buf.written();
|
||||||
},
|
},
|
||||||
.cdata => |cdata| return cdata.getData(),
|
.cdata => |cdata| return cdata.getData(),
|
||||||
.attribute => |attr| return attr._value,
|
.attribute => |attr| return attr._value.str(),
|
||||||
.document => return null,
|
.document => return null,
|
||||||
.document_type => return null,
|
.document_type => return null,
|
||||||
.document_fragment => return null,
|
.document_fragment => return null,
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ pub fn getElementById(self: *ShadowRoot, id: []const u8, page: *Page) ?*Element
|
|||||||
// Do a tree walk to find another element with this ID
|
// Do a tree walk to find another element with this ID
|
||||||
var tw = @import("TreeWalker.zig").Full.Elements.init(self.asNode(), .{});
|
var tw = @import("TreeWalker.zig").Full.Elements.init(self.asNode(), .{});
|
||||||
while (tw.next()) |el| {
|
while (tw.next()) |el| {
|
||||||
const element_id = el.getAttributeSafe("id") orelse continue;
|
const element_id = el.getAttributeSafe(comptime .wrap("id")) orelse continue;
|
||||||
if (std.mem.eql(u8, element_id, id)) {
|
if (std.mem.eql(u8, element_id, id)) {
|
||||||
// we ignore this error to keep getElementById easy to call
|
// we ignore this error to keep getElementById easy to call
|
||||||
// if it really failed, then we're out of memory and nothing's
|
// if it really failed, then we're out of memory and nothing's
|
||||||
|
|||||||
@@ -18,8 +18,9 @@
|
|||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const log = @import("../../../log.zig");
|
const log = @import("../../../log.zig");
|
||||||
const js = @import("../../js/js.zig");
|
const String = @import("../../../string.zig").String;
|
||||||
|
|
||||||
|
const js = @import("../../js/js.zig");
|
||||||
const Page = @import("../../Page.zig");
|
const Page = @import("../../Page.zig");
|
||||||
const Element = @import("../Element.zig");
|
const Element = @import("../Element.zig");
|
||||||
const GenericIterator = @import("iterator.zig").Entry;
|
const GenericIterator = @import("iterator.zig").Entry;
|
||||||
@@ -31,7 +32,7 @@ pub const DOMTokenList = @This();
|
|||||||
// is that lists tend to be very short (often just 1 item).
|
// is that lists tend to be very short (often just 1 item).
|
||||||
|
|
||||||
_element: *Element,
|
_element: *Element,
|
||||||
_attribute_name: []const u8,
|
_attribute_name: String,
|
||||||
|
|
||||||
pub const KeyIterator = GenericIterator(Iterator, "0");
|
pub const KeyIterator = GenericIterator(Iterator, "0");
|
||||||
pub const ValueIterator = GenericIterator(Iterator, "1");
|
pub const ValueIterator = GenericIterator(Iterator, "1");
|
||||||
@@ -159,7 +160,7 @@ pub fn getValue(self: *const DOMTokenList) []const u8 {
|
|||||||
return self._element.getAttributeSafe(self._attribute_name) orelse "";
|
return self._element.getAttributeSafe(self._attribute_name) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setValue(self: *DOMTokenList, value: []const u8, page: *Page) !void {
|
pub fn setValue(self: *DOMTokenList, value: String, page: *Page) !void {
|
||||||
try self._element.setAttribute(self._attribute_name, value, page);
|
try self._element.setAttribute(self._attribute_name, value, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +227,7 @@ fn validateToken(token: []const u8) !void {
|
|||||||
|
|
||||||
fn updateAttribute(self: *DOMTokenList, tokens: Lookup, page: *Page) !void {
|
fn updateAttribute(self: *DOMTokenList, tokens: Lookup, page: *Page) !void {
|
||||||
const joined = try std.mem.join(page.call_arena, " ", tokens.keys());
|
const joined = try std.mem.join(page.call_arena, " ", tokens.keys());
|
||||||
try self._element.setAttribute(self._attribute_name, joined, page);
|
try self._element.setAttribute(self._attribute_name, .wrap(joined), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Iterator = struct {
|
const Iterator = struct {
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ pub fn getByName(self: *HTMLAllCollection, name: []const u8, page: *Page) ?*Elem
|
|||||||
|
|
||||||
while (tw.next()) |node| {
|
while (tw.next()) |node| {
|
||||||
if (node.is(Element)) |el| {
|
if (node.is(Element)) |el| {
|
||||||
if (el.getAttributeSafe("name")) |attr_name| {
|
if (el.getAttributeSafe(comptime .wrap("name"))) |attr_name| {
|
||||||
if (std.mem.eql(u8, attr_name, name)) {
|
if (std.mem.eql(u8, attr_name, name)) {
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,12 +59,12 @@ pub fn namedItem(self: *HTMLFormControlsCollection, name: []const u8, page: *Pag
|
|||||||
var it = try self.iterator();
|
var it = try self.iterator();
|
||||||
while (it.next()) |element| {
|
while (it.next()) |element| {
|
||||||
const is_match = blk: {
|
const is_match = blk: {
|
||||||
if (element.getAttributeSafe("id")) |id| {
|
if (element.getAttributeSafe(comptime .wrap("id"))) |id| {
|
||||||
if (std.mem.eql(u8, id, name)) {
|
if (std.mem.eql(u8, id, name)) {
|
||||||
break :blk true;
|
break :blk true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (element.getAttributeSafe("name")) |elem_name| {
|
if (element.getAttributeSafe(comptime .wrap("name"))) |elem_name| {
|
||||||
if (std.mem.eql(u8, elem_name, name)) {
|
if (std.mem.eql(u8, elem_name, name)) {
|
||||||
break :blk true;
|
break :blk true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ pub fn getValue(self: *RadioNodeList) ![]const u8 {
|
|||||||
if (!input.getChecked()) {
|
if (!input.getChecked()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return element.getAttributeSafe("value") orelse "on";
|
return element.getAttributeSafe(comptime .wrap("value")) orelse "on";
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@@ -82,7 +82,7 @@ pub fn setValue(self: *RadioNodeList, value: []const u8, page: *Page) !void {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const input_value = element.getAttributeSafe("value");
|
const input_value = element.getAttributeSafe(comptime .wrap("value"));
|
||||||
const matches_value = blk: {
|
const matches_value = blk: {
|
||||||
if (std.mem.eql(u8, value, "on")) {
|
if (std.mem.eql(u8, value, "on")) {
|
||||||
break :blk input_value == null or (input_value != null and std.mem.eql(u8, input_value.?, "on"));
|
break :blk input_value == null or (input_value != null and std.mem.eql(u8, input_value.?, "on"));
|
||||||
@@ -99,12 +99,12 @@ pub fn setValue(self: *RadioNodeList, value: []const u8, page: *Page) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn matches(self: *const RadioNodeList, element: *Element) bool {
|
fn matches(self: *const RadioNodeList, element: *Element) bool {
|
||||||
if (element.getAttributeSafe("id")) |id| {
|
if (element.getAttributeSafe(comptime .wrap("id"))) |id| {
|
||||||
if (std.mem.eql(u8, id, self._name)) {
|
if (std.mem.eql(u8, id, self._name)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (element.getAttributeSafe("name")) |elem_name| {
|
if (element.getAttributeSafe(comptime .wrap("name"))) |elem_name| {
|
||||||
if (std.mem.eql(u8, elem_name, self._name)) {
|
if (std.mem.eql(u8, elem_name, self._name)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ pub fn NodeLive(comptime mode: Mode) type {
|
|||||||
// (like length or getAtIndex)
|
// (like length or getAtIndex)
|
||||||
var tw = self._tw.clone();
|
var tw = self._tw.clone();
|
||||||
while (self.nextTw(&tw)) |element| {
|
while (self.nextTw(&tw)) |element| {
|
||||||
const element_name = element.getAttributeSafe("name") orelse continue;
|
const element_name = element.getAttributeSafe(comptime .wrap("name")) orelse continue;
|
||||||
if (std.mem.eql(u8, element_name, name)) {
|
if (std.mem.eql(u8, element_name, name)) {
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
@@ -228,7 +228,7 @@ pub fn NodeLive(comptime mode: Mode) type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const el = node.is(Element) orelse return false;
|
const el = node.is(Element) orelse return false;
|
||||||
const class_attr = el.getAttributeSafe("class") orelse return false;
|
const class_attr = el.getAttributeSafe(comptime .wrap("class")) orelse return false;
|
||||||
for (self._filter) |class_name| {
|
for (self._filter) |class_name| {
|
||||||
if (!Selector.classAttributeContains(class_attr, class_name)) {
|
if (!Selector.classAttributeContains(class_attr, class_name)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -238,7 +238,7 @@ pub fn NodeLive(comptime mode: Mode) type {
|
|||||||
},
|
},
|
||||||
.name => {
|
.name => {
|
||||||
const el = node.is(Element) orelse return false;
|
const el = node.is(Element) orelse return false;
|
||||||
const name_attr = el.getAttributeSafe("name") orelse return false;
|
const name_attr = el.getAttributeSafe(comptime .wrap("name")) orelse return false;
|
||||||
return std.mem.eql(u8, name_attr, self._filter);
|
return std.mem.eql(u8, name_attr, self._filter);
|
||||||
},
|
},
|
||||||
.all_elements => return node._type == .element,
|
.all_elements => return node._type == .element,
|
||||||
@@ -258,14 +258,14 @@ pub fn NodeLive(comptime mode: Mode) type {
|
|||||||
const el = node.is(Element) orelse return false;
|
const el = node.is(Element) orelse return false;
|
||||||
const Anchor = Element.Html.Anchor;
|
const Anchor = Element.Html.Anchor;
|
||||||
if (el.is(Anchor) == null) return false;
|
if (el.is(Anchor) == null) return false;
|
||||||
return el.hasAttributeSafe("href");
|
return el.hasAttributeSafe(comptime .wrap("href"));
|
||||||
},
|
},
|
||||||
.anchors => {
|
.anchors => {
|
||||||
// Anchors are <a> elements with name attribute
|
// Anchors are <a> elements with name attribute
|
||||||
const el = node.is(Element) orelse return false;
|
const el = node.is(Element) orelse return false;
|
||||||
const Anchor = Element.Html.Anchor;
|
const Anchor = Element.Html.Anchor;
|
||||||
if (el.is(Anchor) == null) return false;
|
if (el.is(Anchor) == null) return false;
|
||||||
return el.hasAttributeSafe("name");
|
return el.hasAttributeSafe(comptime .wrap("name"));
|
||||||
},
|
},
|
||||||
.form => {
|
.form => {
|
||||||
const el = node.is(Element) orelse return false;
|
const el = node.is(Element) orelse return false;
|
||||||
@@ -273,8 +273,8 @@ pub fn NodeLive(comptime mode: Mode) type {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (el.getAttributeSafe("form")) |form_attr| {
|
if (el.getAttributeSafe(comptime .wrap("form"))) |form_attr| {
|
||||||
const form_id = self._filter.asElement().getAttributeSafe("id") orelse return false;
|
const form_id = self._filter.asElement().getAttributeSafe(comptime .wrap("id")) orelse return false;
|
||||||
return std.mem.eql(u8, form_attr, form_id);
|
return std.mem.eql(u8, form_attr, form_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,33 +39,33 @@ pub fn registerTypes() []const type {
|
|||||||
pub const Attribute = @This();
|
pub const Attribute = @This();
|
||||||
|
|
||||||
_proto: *Node,
|
_proto: *Node,
|
||||||
_name: []const u8,
|
_name: String,
|
||||||
_value: []const u8,
|
_value: String,
|
||||||
_element: ?*Element,
|
_element: ?*Element,
|
||||||
|
|
||||||
pub fn format(self: *const Attribute, writer: *std.Io.Writer) !void {
|
pub fn format(self: *const Attribute, writer: *std.Io.Writer) !void {
|
||||||
return formatAttribute(self._name, self._value, writer);
|
return formatAttribute(self._name, self._value, writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getName(self: *const Attribute) []const u8 {
|
pub fn getName(self: *const Attribute) String {
|
||||||
return self._name;
|
return self._name;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getValue(self: *const Attribute) []const u8 {
|
pub fn getValue(self: *const Attribute) String {
|
||||||
return self._value;
|
return self._value;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setValue(self: *Attribute, data_: ?[]const u8, page: *Page) !void {
|
pub fn setValue(self: *Attribute, data_: ?String, page: *Page) !void {
|
||||||
const data = data_ orelse "";
|
const data = data_ orelse String.empty;
|
||||||
const el = self._element orelse {
|
const el = self._element orelse {
|
||||||
self._value = try page.dupeString(data);
|
self._value = try data.dupe(page.arena);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
// this takes ownership of the data
|
// this takes ownership of the data
|
||||||
try el.setAttribute(self._name, data, page);
|
try el.setAttribute(self._name, data, page);
|
||||||
|
|
||||||
// not the most efficient, but we don't expect this to be called often
|
// not the most efficient, but we don't expect this to be called often
|
||||||
self._value = (try el.getAttribute(self._name, page)) orelse "";
|
self._value = (try el.getAttribute(self._name, page)) orelse String.empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getNamespaceURI(_: *const Attribute) ?[]const u8 {
|
pub fn getNamespaceURI(_: *const Attribute) ?[]const u8 {
|
||||||
@@ -77,7 +77,7 @@ pub fn getOwnerElement(self: *const Attribute) ?*Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn isEqualNode(self: *const Attribute, other: *const Attribute) bool {
|
pub fn isEqualNode(self: *const Attribute, other: *const Attribute) bool {
|
||||||
return std.mem.eql(u8, self.getName(), other.getName()) and std.mem.eql(u8, self.getValue(), other.getValue());
|
return self.getName().eql(other.getName()) and self.getValue().eql(other.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clone(self: *const Attribute, page: *Page) !*Attribute {
|
pub fn clone(self: *const Attribute, page: *Page) !*Attribute {
|
||||||
@@ -139,9 +139,9 @@ pub const List = struct {
|
|||||||
return self._list.first == null;
|
return self._list.first == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(self: *const List, name: []const u8, page: *Page) !?[]const u8 {
|
pub fn get(self: *const List, name: String, page: *Page) !?String {
|
||||||
const entry = (try self.getEntry(name, page)) orelse return null;
|
const entry = (try self.getEntry(name, page)) orelse return null;
|
||||||
return entry._value.str();
|
return entry._value;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn length(self: *const List) usize {
|
pub inline fn length(self: *const List) usize {
|
||||||
@@ -170,17 +170,17 @@ pub const List = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// meant for internal usage, where the name is known to be properly cased
|
// meant for internal usage, where the name is known to be properly cased
|
||||||
pub fn getSafe(self: *const List, name: []const u8) ?[]const u8 {
|
pub fn getSafe(self: *const List, name: String) ?[]const u8 {
|
||||||
const entry = self.getEntryWithNormalizedName(name) orelse return null;
|
const entry = self.getEntryWithNormalizedName(name) orelse return null;
|
||||||
return entry._value.str();
|
return entry._value.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
// meant for internal usage, where the name is known to be properly cased
|
// meant for internal usage, where the name is known to be properly cased
|
||||||
pub fn hasSafe(self: *const List, name: []const u8) bool {
|
pub fn hasSafe(self: *const List, name: String) bool {
|
||||||
return self.getEntryWithNormalizedName(name) != null;
|
return self.getEntryWithNormalizedName(name) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getAttribute(self: *const List, name: []const u8, element: ?*Element, page: *Page) !?*Attribute {
|
pub fn getAttribute(self: *const List, name: String, element: ?*Element, page: *Page) !?*Attribute {
|
||||||
const entry = (try self.getEntry(name, page)) orelse return null;
|
const entry = (try self.getEntry(name, page)) orelse return null;
|
||||||
const gop = try page._attribute_lookup.getOrPut(page.arena, @intFromPtr(entry));
|
const gop = try page._attribute_lookup.getOrPut(page.arena, @intFromPtr(entry));
|
||||||
if (gop.found_existing) {
|
if (gop.found_existing) {
|
||||||
@@ -191,33 +191,33 @@ pub const List = struct {
|
|||||||
return attribute;
|
return attribute;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn put(self: *List, name: []const u8, value: []const u8, element: *Element, page: *Page) !*Entry {
|
pub fn put(self: *List, name: String, value: String, element: *Element, page: *Page) !*Entry {
|
||||||
const result = try self.getEntryAndNormalizedName(name, page);
|
const result = try self.getEntryAndNormalizedName(name, page);
|
||||||
return self._put(result, value, element, page);
|
return self._put(result, value, element, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn putSafe(self: *List, name: []const u8, value: []const u8, element: *Element, page: *Page) !*Entry {
|
pub fn putSafe(self: *List, name: String, value: String, element: *Element, page: *Page) !*Entry {
|
||||||
const entry = self.getEntryWithNormalizedName(name);
|
const entry = self.getEntryWithNormalizedName(name);
|
||||||
return self._put(.{ .entry = entry, .normalized = name }, value, element, page);
|
return self._put(.{ .entry = entry, .normalized = name }, value, element, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _put(self: *List, result: NormalizeAndEntry, value: []const u8, element: *Element, page: *Page) !*Entry {
|
fn _put(self: *List, result: NormalizeAndEntry, value: String, element: *Element, page: *Page) !*Entry {
|
||||||
const is_id = shouldAddToIdMap(result.normalized, element);
|
const is_id = shouldAddToIdMap(result.normalized, element);
|
||||||
|
|
||||||
var entry: *Entry = undefined;
|
var entry: *Entry = undefined;
|
||||||
var old_value: ?[]const u8 = null;
|
var old_value: ?String = null;
|
||||||
if (result.entry) |e| {
|
if (result.entry) |e| {
|
||||||
old_value = try page.call_arena.dupe(u8, e._value.str());
|
old_value = try e._value.dupe(page.call_arena);
|
||||||
if (is_id) {
|
if (is_id) {
|
||||||
page.removeElementId(element, e._value.str());
|
page.removeElementId(element, e._value.str());
|
||||||
}
|
}
|
||||||
e._value = try String.init(page.arena, value, .{});
|
e._value = try value.dupe(page.arena);
|
||||||
entry = e;
|
entry = e;
|
||||||
} else {
|
} else {
|
||||||
entry = try page._factory.create(Entry{
|
entry = try page._factory.create(Entry{
|
||||||
._node = .{},
|
._node = .{},
|
||||||
._name = try String.init(page.arena, result.normalized, .{}),
|
._name = try result.normalized.dupe(page.arena),
|
||||||
._value = try String.init(page.arena, value, .{}),
|
._value = try value.dupe(page.arena),
|
||||||
});
|
});
|
||||||
self._list.append(&entry._node);
|
self._list.append(&entry._node);
|
||||||
self._len += 1;
|
self._len += 1;
|
||||||
@@ -230,7 +230,7 @@ pub const List = struct {
|
|||||||
try page.addElementId(parent, element, entry._value.str());
|
try page.addElementId(parent, element, entry._value.str());
|
||||||
}
|
}
|
||||||
page.domChanged();
|
page.domChanged();
|
||||||
page.attributeChange(element, result.normalized, entry._value.str(), old_value);
|
page.attributeChange(element, result.normalized, entry._value, old_value);
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,7 +266,7 @@ pub const List = struct {
|
|||||||
|
|
||||||
// called form our parser, names already lower-cased
|
// called form our parser, names already lower-cased
|
||||||
pub fn putNew(self: *List, name: []const u8, value: []const u8, page: *Page) !void {
|
pub fn putNew(self: *List, name: []const u8, value: []const u8, page: *Page) !void {
|
||||||
if (try self.getEntry(name, page) != null) {
|
if (try self.getEntry(.wrap(name), page) != null) {
|
||||||
// When parsing, if there are dupicate names, it isn't valid, and
|
// When parsing, if there are dupicate names, it isn't valid, and
|
||||||
// the first is kept
|
// the first is kept
|
||||||
return;
|
return;
|
||||||
@@ -281,12 +281,12 @@ pub const List = struct {
|
|||||||
self._len += 1;
|
self._len += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete(self: *List, name: []const u8, element: *Element, page: *Page) !void {
|
pub fn delete(self: *List, name: String, element: *Element, page: *Page) !void {
|
||||||
const result = try self.getEntryAndNormalizedName(name, page);
|
const result = try self.getEntryAndNormalizedName(name, page);
|
||||||
const entry = result.entry orelse return;
|
const entry = result.entry orelse return;
|
||||||
|
|
||||||
const is_id = shouldAddToIdMap(result.normalized, element);
|
const is_id = shouldAddToIdMap(result.normalized, element);
|
||||||
const old_value = entry._value.str();
|
const old_value = entry._value;
|
||||||
|
|
||||||
if (is_id) {
|
if (is_id) {
|
||||||
page.removeElementId(element, entry._value.str());
|
page.removeElementId(element, entry._value.str());
|
||||||
@@ -314,7 +314,7 @@ pub const List = struct {
|
|||||||
return .{ ._node = self._list.first };
|
return .{ ._node = self._list.first };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getEntry(self: *const List, name: []const u8, page: *Page) !?*Entry {
|
fn getEntry(self: *const List, name: String, page: *Page) !?*Entry {
|
||||||
const result = try self.getEntryAndNormalizedName(name, page);
|
const result = try self.getEntryAndNormalizedName(name, page);
|
||||||
return result.entry;
|
return result.entry;
|
||||||
}
|
}
|
||||||
@@ -322,10 +322,10 @@ pub const List = struct {
|
|||||||
// Dangerous, the returned normalized name is only valid until someone
|
// Dangerous, the returned normalized name is only valid until someone
|
||||||
// else uses pages.buf.
|
// else uses pages.buf.
|
||||||
const NormalizeAndEntry = struct {
|
const NormalizeAndEntry = struct {
|
||||||
normalized: []const u8,
|
|
||||||
entry: ?*Entry,
|
entry: ?*Entry,
|
||||||
|
normalized: String,
|
||||||
};
|
};
|
||||||
fn getEntryAndNormalizedName(self: *const List, name: []const u8, page: *Page) !NormalizeAndEntry {
|
fn getEntryAndNormalizedName(self: *const List, name: String, page: *Page) !NormalizeAndEntry {
|
||||||
const normalized =
|
const normalized =
|
||||||
if (self.normalize) try normalizeNameForLookup(name, page) else name;
|
if (self.normalize) try normalizeNameForLookup(name, page) else name;
|
||||||
|
|
||||||
@@ -335,11 +335,11 @@ pub const List = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getEntryWithNormalizedName(self: *const List, name: []const u8) ?*Entry {
|
fn getEntryWithNormalizedName(self: *const List, name: String) ?*Entry {
|
||||||
var node = self._list.first;
|
var node = self._list.first;
|
||||||
while (node) |n| {
|
while (node) |n| {
|
||||||
var e = Entry.fromNode(n);
|
var e = Entry.fromNode(n);
|
||||||
if (e._name.eqlSlice(name)) {
|
if (e._name.eql(name)) {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
node = n.next;
|
node = n.next;
|
||||||
@@ -363,7 +363,7 @@ pub const List = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn format(self: *const Entry, writer: *std.Io.Writer) !void {
|
pub fn format(self: *const Entry, writer: *std.Io.Writer) !void {
|
||||||
return formatAttribute(self._name.str(), self._value.str(), writer);
|
return formatAttribute(self._name, self._value, writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toAttribute(self: *const Entry, element: ?*Element, page: *Page) !*Attribute {
|
pub fn toAttribute(self: *const Entry, element: ?*Element, page: *Page) !*Attribute {
|
||||||
@@ -373,15 +373,15 @@ pub const List = struct {
|
|||||||
// Cannot directly reference self._name.str() and self._value.str()
|
// Cannot directly reference self._name.str() and self._value.str()
|
||||||
// This attribute can outlive the list entry (the node can be
|
// This attribute can outlive the list entry (the node can be
|
||||||
// removed from the element's attribute, but still exist in the DOM)
|
// removed from the element's attribute, but still exist in the DOM)
|
||||||
._name = try page.dupeString(self._name.str()),
|
._name = try self._name.dupe(page.arena),
|
||||||
._value = try page.dupeString(self._value.str()),
|
._value = try self._value.dupe(page.arena),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
fn shouldAddToIdMap(normalized_name: []const u8, element: *Element) bool {
|
fn shouldAddToIdMap(normalized_name: String, element: *Element) bool {
|
||||||
if (!std.mem.eql(u8, normalized_name, "id")) {
|
if (!normalized_name.eql(comptime .wrap("id"))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,17 +394,19 @@ fn shouldAddToIdMap(normalized_name: []const u8, element: *Element) bool {
|
|||||||
return node.isConnected();
|
return node.isConnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validateAttributeName(name: []const u8) !void {
|
pub fn validateAttributeName(name: String) !void {
|
||||||
if (name.len == 0) {
|
const name_str = name.str();
|
||||||
|
|
||||||
|
if (name_str.len == 0) {
|
||||||
return error.InvalidCharacterError;
|
return error.InvalidCharacterError;
|
||||||
}
|
}
|
||||||
|
|
||||||
const first = name[0];
|
const first = name_str[0];
|
||||||
if ((first >= '0' and first <= '9') or first == '-' or first == '.') {
|
if ((first >= '0' and first <= '9') or first == '-' or first == '.') {
|
||||||
return error.InvalidCharacterError;
|
return error.InvalidCharacterError;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name) |c| {
|
for (name_str) |c| {
|
||||||
if (c == 0 or c == '/' or c == '=' or c == '>' or std.ascii.isWhitespace(c)) {
|
if (c == 0 or c == '/' or c == '=' or c == '>' or std.ascii.isWhitespace(c)) {
|
||||||
return error.InvalidCharacterError;
|
return error.InvalidCharacterError;
|
||||||
}
|
}
|
||||||
@@ -420,14 +422,16 @@ pub fn validateAttributeName(name: []const u8) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn normalizeNameForLookup(name: []const u8, page: *Page) ![]const u8 {
|
pub fn normalizeNameForLookup(name: String, page: *Page) !String {
|
||||||
if (!needsLowerCasing(name)) {
|
if (!needsLowerCasing(name.str())) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
if (name.len < page.buf.len) {
|
const normalized = if (name.len < page.buf.len)
|
||||||
return std.ascii.lowerString(&page.buf, name);
|
std.ascii.lowerString(&page.buf, name.str())
|
||||||
}
|
else
|
||||||
return std.ascii.allocLowerString(page.call_arena, name);
|
try std.ascii.allocLowerString(page.call_arena, name.str());
|
||||||
|
|
||||||
|
return .wrap(normalized);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn needsLowerCasing(name: []const u8) bool {
|
fn needsLowerCasing(name: []const u8) bool {
|
||||||
@@ -481,7 +485,7 @@ pub const NamedNodeMap = struct {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getByName(self: *const NamedNodeMap, name: []const u8, page: *Page) !?*Attribute {
|
pub fn getByName(self: *const NamedNodeMap, name: String, page: *Page) !?*Attribute {
|
||||||
return self._list.getAttribute(name, self._element, page);
|
return self._list.getAttribute(name, self._element, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -490,7 +494,7 @@ pub const NamedNodeMap = struct {
|
|||||||
return self._list.putAttribute(attribute, self._element, page);
|
return self._list.putAttribute(attribute, self._element, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn removeByName(self: *const NamedNodeMap, name: []const u8, page: *Page) !?*Attribute {
|
pub fn removeByName(self: *const NamedNodeMap, name: String, page: *Page) !?*Attribute {
|
||||||
// this 2-step process (get then delete) isn't efficient. But we don't
|
// this 2-step process (get then delete) isn't efficient. But we don't
|
||||||
// expect this to be called often, and this lets us keep delete straightforward.
|
// expect this to be called often, and this lets us keep delete straightforward.
|
||||||
const attr = (try self.getByName(name, page)) orelse return null;
|
const attr = (try self.getByName(name, page)) orelse return null;
|
||||||
@@ -556,11 +560,13 @@ pub const InnerIterator = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fn formatAttribute(name: []const u8, value: []const u8, writer: *std.Io.Writer) !void {
|
fn formatAttribute(name: String, value_: String, writer: *std.Io.Writer) !void {
|
||||||
try writer.writeAll(name);
|
try writer.writeAll(name.str());
|
||||||
|
|
||||||
// Boolean attributes with empty values are serialized without a value
|
// Boolean attributes with empty values are serialized without a value
|
||||||
if (value.len == 0 and boolean_attributes_lookup.has(name)) {
|
|
||||||
|
const value = value_.str();
|
||||||
|
if (value.len == 0 and boolean_attributes_lookup.has(name.str())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ const js = @import("../../js/js.zig");
|
|||||||
|
|
||||||
const Element = @import("../Element.zig");
|
const Element = @import("../Element.zig");
|
||||||
const Page = @import("../../Page.zig");
|
const Page = @import("../../Page.zig");
|
||||||
|
const String = @import("../../../string.zig").String;
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
@@ -28,28 +29,60 @@ const DOMStringMap = @This();
|
|||||||
|
|
||||||
_element: *Element,
|
_element: *Element,
|
||||||
|
|
||||||
fn getProperty(self: *DOMStringMap, name: []const u8, page: *Page) !?[]const u8 {
|
fn getProperty(self: *DOMStringMap, name: String, page: *Page) !?String {
|
||||||
const attr_name = try camelToKebab(page.call_arena, name);
|
const attr_name = try camelToKebab(page.call_arena, name);
|
||||||
return try self._element.getAttribute(attr_name, page);
|
return try self._element.getAttribute(attr_name, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setProperty(self: *DOMStringMap, name: []const u8, value: []const u8, page: *Page) !void {
|
fn setProperty(self: *DOMStringMap, name: String, value: String, page: *Page) !void {
|
||||||
const attr_name = try camelToKebab(page.call_arena, name);
|
const attr_name = try camelToKebab(page.call_arena, name);
|
||||||
return self._element.setAttributeSafe(attr_name, value, page);
|
return self._element.setAttributeSafe(attr_name, value, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deleteProperty(self: *DOMStringMap, name: []const u8, page: *Page) !void {
|
fn deleteProperty(self: *DOMStringMap, name: String, page: *Page) !void {
|
||||||
const attr_name = try camelToKebab(page.call_arena, name);
|
const attr_name = try camelToKebab(page.call_arena, name);
|
||||||
try self._element.removeAttribute(attr_name, page);
|
try self._element.removeAttribute(attr_name, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
// fooBar -> foo-bar
|
// fooBar -> data-foo-bar (with SSO optimization for short strings)
|
||||||
fn camelToKebab(arena: Allocator, camel: []const u8) ![]const u8 {
|
fn camelToKebab(arena: Allocator, camel: String) !String {
|
||||||
|
const camel_str = camel.str();
|
||||||
|
|
||||||
|
// Calculate output length
|
||||||
|
var output_len: usize = 5; // "data-"
|
||||||
|
for (camel_str, 0..) |c, i| {
|
||||||
|
output_len += 1;
|
||||||
|
if (std.ascii.isUpper(c) and i > 0) output_len += 1; // extra char for '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output_len <= 12) {
|
||||||
|
// SSO path - no allocation!
|
||||||
|
var content: [12]u8 = @splat(0);
|
||||||
|
@memcpy(content[0..5], "data-");
|
||||||
|
var idx: usize = 5;
|
||||||
|
|
||||||
|
for (camel_str, 0..) |c, i| {
|
||||||
|
if (std.ascii.isUpper(c)) {
|
||||||
|
if (i > 0) {
|
||||||
|
content[idx] = '-';
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
content[idx] = std.ascii.toLower(c);
|
||||||
|
} else {
|
||||||
|
content[idx] = c;
|
||||||
|
}
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{ .len = @intCast(output_len), .payload = .{ .content = content } };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: allocate for longer strings
|
||||||
var result: std.ArrayList(u8) = .empty;
|
var result: std.ArrayList(u8) = .empty;
|
||||||
try result.ensureTotalCapacity(arena, 5 + camel.len * 2);
|
try result.ensureTotalCapacity(arena, output_len);
|
||||||
result.appendSliceAssumeCapacity("data-");
|
result.appendSliceAssumeCapacity("data-");
|
||||||
|
|
||||||
for (camel, 0..) |c, i| {
|
for (camel_str, 0..) |c, i| {
|
||||||
if (std.ascii.isUpper(c)) {
|
if (std.ascii.isUpper(c)) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
result.appendAssumeCapacity('-');
|
result.appendAssumeCapacity('-');
|
||||||
@@ -60,7 +93,7 @@ fn camelToKebab(arena: Allocator, camel: []const u8) ![]const u8 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.items;
|
return try String.init(arena, result.items, .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
// data-foo-bar -> fooBar
|
// data-foo-bar -> fooBar
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ fn _getInnerText(self: *HtmlElement, writer: *std.Io.Writer, state: *innerTextSt
|
|||||||
.document => {},
|
.document => {},
|
||||||
.document_type => {},
|
.document_type => {},
|
||||||
.document_fragment => {},
|
.document_fragment => {},
|
||||||
.attribute => |attr| try writer.writeAll(attr._value),
|
.attribute => |attr| try writer.writeAll(attr._value.str()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ pub fn asNode(self: *Anchor) *Node {
|
|||||||
|
|
||||||
pub fn getHref(self: *Anchor, page: *Page) ![]const u8 {
|
pub fn getHref(self: *Anchor, page: *Page) ![]const u8 {
|
||||||
const element = self.asElement();
|
const element = self.asElement();
|
||||||
const href = element.getAttributeSafe("href") orelse return "";
|
const href = element.getAttributeSafe(comptime .wrap("href")) orelse return "";
|
||||||
if (href.len == 0) {
|
if (href.len == 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@@ -48,15 +48,15 @@ pub fn getHref(self: *Anchor, page: *Page) ![]const u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn setHref(self: *Anchor, value: []const u8, page: *Page) !void {
|
pub fn setHref(self: *Anchor, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("href", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("href"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getTarget(self: *Anchor) []const u8 {
|
pub fn getTarget(self: *Anchor) []const u8 {
|
||||||
return self.asElement().getAttributeSafe("target") orelse "";
|
return self.asElement().getAttributeSafe(comptime .wrap("target")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setTarget(self: *Anchor, value: []const u8, page: *Page) !void {
|
pub fn setTarget(self: *Anchor, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("target", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("target"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getOrigin(self: *Anchor, page: *Page) ![]const u8 {
|
pub fn getOrigin(self: *Anchor, page: *Page) ![]const u8 {
|
||||||
@@ -167,19 +167,19 @@ pub fn setProtocol(self: *Anchor, value: []const u8, page: *Page) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getType(self: *Anchor) []const u8 {
|
pub fn getType(self: *Anchor) []const u8 {
|
||||||
return self.asElement().getAttributeSafe("type") orelse "";
|
return self.asElement().getAttributeSafe(comptime .wrap("type")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setType(self: *Anchor, value: []const u8, page: *Page) !void {
|
pub fn setType(self: *Anchor, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("type", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("type"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getName(self: *const Anchor) []const u8 {
|
pub fn getName(self: *const Anchor) []const u8 {
|
||||||
return self.asConstElement().getAttributeSafe("name") orelse "";
|
return self.asConstElement().getAttributeSafe(comptime .wrap("name")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setName(self: *Anchor, value: []const u8, page: *Page) !void {
|
pub fn setName(self: *Anchor, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("name", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("name"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getText(self: *Anchor, page: *Page) ![:0]const u8 {
|
pub fn getText(self: *Anchor, page: *Page) ![:0]const u8 {
|
||||||
@@ -191,7 +191,7 @@ pub fn setText(self: *Anchor, value: []const u8, page: *Page) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn getResolvedHref(self: *Anchor, page: *Page) !?[:0]const u8 {
|
fn getResolvedHref(self: *Anchor, page: *Page) !?[:0]const u8 {
|
||||||
const href = self.asElement().getAttributeSafe("href") orelse return null;
|
const href = self.asElement().getAttributeSafe(comptime .wrap("href")) orelse return null;
|
||||||
if (href.len == 0) {
|
if (href.len == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
// 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 String = @import("../../../../string.zig").String;
|
||||||
|
|
||||||
const js = @import("../../../js/js.zig");
|
const js = @import("../../../js/js.zig");
|
||||||
const Page = @import("../../../Page.zig");
|
const Page = @import("../../../Page.zig");
|
||||||
|
|
||||||
@@ -27,16 +29,16 @@ const Audio = @This();
|
|||||||
|
|
||||||
_proto: *Media,
|
_proto: *Media,
|
||||||
|
|
||||||
pub fn constructor(maybe_url: ?[]const u8, page: *Page) !*Media {
|
pub fn constructor(maybe_url: ?String, page: *Page) !*Media {
|
||||||
const node = try page.createElementNS(.html, "audio", null);
|
const node = try page.createElementNS(.html, "audio", null);
|
||||||
const el = node.as(Element);
|
const el = node.as(Element);
|
||||||
|
|
||||||
const list = try el.getOrCreateAttributeList(page);
|
const list = try el.getOrCreateAttributeList(page);
|
||||||
// Always set to "auto" initially.
|
// Always set to "auto" initially.
|
||||||
_ = try list.putSafe("preload", "auto", el, page);
|
_ = try list.putSafe(comptime .wrap("preload"), comptime .wrap("auto"), el, page);
|
||||||
// Set URL if provided.
|
// Set URL if provided.
|
||||||
if (maybe_url) |url| {
|
if (maybe_url) |url| {
|
||||||
_ = try list.putSafe("src", url, el, page);
|
_ = try list.putSafe(comptime .wrap("src"), url, el, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
return node.as(Media);
|
return node.as(Media);
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ pub const JsApi = struct {
|
|||||||
pub const Build = struct {
|
pub const Build = struct {
|
||||||
pub fn complete(node: *Node, page: *Page) !void {
|
pub fn complete(node: *Node, page: *Page) !void {
|
||||||
const el = node.as(Element);
|
const el = node.as(Element);
|
||||||
const on_load = el.getAttributeSafe("onload") orelse return;
|
const on_load = el.getAttributeSafe(comptime .wrap("onload")) orelse return;
|
||||||
if (page.js.stringToPersistedFunction(on_load)) |func| {
|
if (page.js.stringToPersistedFunction(on_load)) |func| {
|
||||||
page.window._on_load = func;
|
page.window._on_load = func;
|
||||||
} else |err| {
|
} else |err| {
|
||||||
|
|||||||
@@ -39,50 +39,50 @@ pub fn asNode(self: *Button) *Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getDisabled(self: *const Button) bool {
|
pub fn getDisabled(self: *const Button) bool {
|
||||||
return self.asConstElement().getAttributeSafe("disabled") != null;
|
return self.asConstElement().getAttributeSafe(comptime .wrap("disabled")) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setDisabled(self: *Button, disabled: bool, page: *Page) !void {
|
pub fn setDisabled(self: *Button, disabled: bool, page: *Page) !void {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
try self.asElement().setAttributeSafe("disabled", "", page);
|
try self.asElement().setAttributeSafe(comptime .wrap("disabled"), .wrap(""), page);
|
||||||
} else {
|
} else {
|
||||||
try self.asElement().removeAttribute("disabled", page);
|
try self.asElement().removeAttribute(comptime .wrap("disabled"), page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getName(self: *const Button) []const u8 {
|
pub fn getName(self: *const Button) []const u8 {
|
||||||
return self.asConstElement().getAttributeSafe("name") orelse "";
|
return self.asConstElement().getAttributeSafe(comptime .wrap("name")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setName(self: *Button, name: []const u8, page: *Page) !void {
|
pub fn setName(self: *Button, name: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("name", name, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("name"), .wrap(name), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getType(self: *const Button) []const u8 {
|
pub fn getType(self: *const Button) []const u8 {
|
||||||
return self.asConstElement().getAttributeSafe("type") orelse "submit";
|
return self.asConstElement().getAttributeSafe(comptime .wrap("type")) orelse "submit";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setType(self: *Button, typ: []const u8, page: *Page) !void {
|
pub fn setType(self: *Button, typ: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("type", typ, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("type"), .wrap(typ), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getValue(self: *const Button) []const u8 {
|
pub fn getValue(self: *const Button) []const u8 {
|
||||||
return self.asConstElement().getAttributeSafe("value") orelse "";
|
return self.asConstElement().getAttributeSafe(comptime .wrap("value")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setValue(self: *Button, value: []const u8, page: *Page) !void {
|
pub fn setValue(self: *Button, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("value", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("value"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getRequired(self: *const Button) bool {
|
pub fn getRequired(self: *const Button) bool {
|
||||||
return self.asConstElement().getAttributeSafe("required") != null;
|
return self.asConstElement().getAttributeSafe(comptime .wrap("required")) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setRequired(self: *Button, required: bool, page: *Page) !void {
|
pub fn setRequired(self: *Button, required: bool, page: *Page) !void {
|
||||||
if (required) {
|
if (required) {
|
||||||
try self.asElement().setAttributeSafe("required", "", page);
|
try self.asElement().setAttributeSafe(comptime .wrap("required"), .wrap(""), page);
|
||||||
} else {
|
} else {
|
||||||
try self.asElement().removeAttribute("required", page);
|
try self.asElement().removeAttribute(comptime .wrap("required"), page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ pub fn getForm(self: *Button, page: *Page) ?*Form {
|
|||||||
const element = self.asElement();
|
const element = self.asElement();
|
||||||
|
|
||||||
// If form attribute exists, ONLY use that (even if it references nothing)
|
// If form attribute exists, ONLY use that (even if it references nothing)
|
||||||
if (element.getAttributeSafe("form")) |form_id| {
|
if (element.getAttributeSafe(comptime .wrap("form"))) |form_id| {
|
||||||
if (page.document.getElementById(form_id, page)) |form_element| {
|
if (page.document.getElementById(form_id, page)) |form_element| {
|
||||||
return form_element.is(Form);
|
return form_element.is(Form);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,23 +40,23 @@ pub fn asNode(self: *Canvas) *Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getWidth(self: *const Canvas) u32 {
|
pub fn getWidth(self: *const Canvas) u32 {
|
||||||
const attr = self.asConstElement().getAttributeSafe("width") orelse return 300;
|
const attr = self.asConstElement().getAttributeSafe(comptime .wrap("width")) orelse return 300;
|
||||||
return std.fmt.parseUnsigned(u32, attr, 10) catch 300;
|
return std.fmt.parseUnsigned(u32, attr, 10) catch 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setWidth(self: *Canvas, value: u32, page: *Page) !void {
|
pub fn setWidth(self: *Canvas, value: u32, page: *Page) !void {
|
||||||
const str = try std.fmt.allocPrint(page.call_arena, "{d}", .{value});
|
const str = try std.fmt.allocPrint(page.call_arena, "{d}", .{value});
|
||||||
try self.asElement().setAttributeSafe("width", str, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("width"), .wrap(str), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getHeight(self: *const Canvas) u32 {
|
pub fn getHeight(self: *const Canvas) u32 {
|
||||||
const attr = self.asConstElement().getAttributeSafe("height") orelse return 150;
|
const attr = self.asConstElement().getAttributeSafe(comptime .wrap("height")) orelse return 150;
|
||||||
return std.fmt.parseUnsigned(u32, attr, 10) catch 150;
|
return std.fmt.parseUnsigned(u32, attr, 10) catch 150;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setHeight(self: *Canvas, value: u32, page: *Page) !void {
|
pub fn setHeight(self: *Canvas, value: u32, page: *Page) !void {
|
||||||
const str = try std.fmt.allocPrint(page.call_arena, "{d}", .{value});
|
const str = try std.fmt.allocPrint(page.call_arena, "{d}", .{value});
|
||||||
try self.asElement().setAttributeSafe("height", str, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("height"), .wrap(str), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Since there's no base class rendering contextes inherit from,
|
/// Since there's no base class rendering contextes inherit from,
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ pub fn invokeDisconnectedCallback(self: *Custom, page: *Page) void {
|
|||||||
self.invokeCallback("disconnectedCallback", .{}, page);
|
self.invokeCallback("disconnectedCallback", .{}, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn invokeAttributeChangedCallback(self: *Custom, name: []const u8, old_value: ?[]const u8, new_value: ?[]const u8, page: *Page) void {
|
pub fn invokeAttributeChangedCallback(self: *Custom, name: String, old_value: ?String, new_value: ?String, page: *Page) void {
|
||||||
const definition = self._definition orelse return;
|
const definition = self._definition orelse return;
|
||||||
if (!definition.isAttributeObserved(name)) {
|
if (!definition.isAttributeObserved(name)) {
|
||||||
return;
|
return;
|
||||||
@@ -144,7 +144,7 @@ pub fn invokeDisconnectedCallbackOnElement(element: *Element, page: *Page) void
|
|||||||
invokeCallbackOnElement(element, definition, "disconnectedCallback", .{}, page);
|
invokeCallbackOnElement(element, definition, "disconnectedCallback", .{}, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn invokeAttributeChangedCallbackOnElement(element: *Element, name: []const u8, old_value: ?[]const u8, new_value: ?[]const u8, page: *Page) void {
|
pub fn invokeAttributeChangedCallbackOnElement(element: *Element, name: String, old_value: ?String, new_value: ?String, page: *Page) void {
|
||||||
// Autonomous custom element
|
// Autonomous custom element
|
||||||
if (element.is(Custom)) |custom| {
|
if (element.is(Custom)) |custom| {
|
||||||
custom.invokeAttributeChangedCallback(name, old_value, new_value, page);
|
custom.invokeAttributeChangedCallback(name, old_value, new_value, page);
|
||||||
@@ -174,7 +174,7 @@ fn invokeCallbackOnElement(element: *Element, definition: *CustomElementDefiniti
|
|||||||
|
|
||||||
// Check if element has "is" attribute and attach customized built-in definition
|
// Check if element has "is" attribute and attach customized built-in definition
|
||||||
pub fn checkAndAttachBuiltIn(element: *Element, page: *Page) !void {
|
pub fn checkAndAttachBuiltIn(element: *Element, page: *Page) !void {
|
||||||
const is_value = element.getAttributeSafe("is") orelse return;
|
const is_value = element.getAttributeSafe(comptime .wrap("is")) orelse return;
|
||||||
|
|
||||||
const custom_elements = page.window.getCustomElements();
|
const custom_elements = page.window.getCustomElements();
|
||||||
const definition = custom_elements._definitions.get(is_value) orelse return;
|
const definition = custom_elements._definitions.get(is_value) orelse return;
|
||||||
|
|||||||
@@ -36,11 +36,11 @@ pub fn asNode(self: *Data) *Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getValue(self: *Data) []const u8 {
|
pub fn getValue(self: *Data) []const u8 {
|
||||||
return self.asElement().getAttributeSafe("value") orelse "";
|
return self.asElement().getAttributeSafe(comptime .wrap("value")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setValue(self: *Data, value: []const u8, page: *Page) !void {
|
pub fn setValue(self: *Data, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("value", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("value"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const JsApi = struct {
|
pub const JsApi = struct {
|
||||||
|
|||||||
@@ -20,23 +20,23 @@ pub fn asNode(self: *Dialog) *Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getOpen(self: *const Dialog) bool {
|
pub fn getOpen(self: *const Dialog) bool {
|
||||||
return self.asConstElement().getAttributeSafe("open") != null;
|
return self.asConstElement().getAttributeSafe(comptime .wrap("open")) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setOpen(self: *Dialog, open: bool, page: *Page) !void {
|
pub fn setOpen(self: *Dialog, open: bool, page: *Page) !void {
|
||||||
if (open) {
|
if (open) {
|
||||||
try self.asElement().setAttributeSafe("open", "", page);
|
try self.asElement().setAttributeSafe(comptime .wrap("open"), .wrap(""), page);
|
||||||
} else {
|
} else {
|
||||||
try self.asElement().removeAttribute("open", page);
|
try self.asElement().removeAttribute(comptime .wrap("open"), page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getReturnValue(self: *const Dialog) []const u8 {
|
pub fn getReturnValue(self: *const Dialog) []const u8 {
|
||||||
return self.asConstElement().getAttributeSafe("returnvalue") orelse "";
|
return self.asConstElement().getAttributeSafe(comptime .wrap("returnvalue")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setReturnValue(self: *Dialog, value: []const u8, page: *Page) !void {
|
pub fn setReturnValue(self: *Dialog, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("returnvalue", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("returnvalue"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const JsApi = struct {
|
pub const JsApi = struct {
|
||||||
|
|||||||
@@ -43,15 +43,15 @@ pub fn asNode(self: *Form) *Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getName(self: *const Form) []const u8 {
|
pub fn getName(self: *const Form) []const u8 {
|
||||||
return self.asConstElement().getAttributeSafe("name") orelse "";
|
return self.asConstElement().getAttributeSafe(comptime .wrap("name")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setName(self: *Form, name: []const u8, page: *Page) !void {
|
pub fn setName(self: *Form, name: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("name", name, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("name"), .wrap(name), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getMethod(self: *const Form) []const u8 {
|
pub fn getMethod(self: *const Form) []const u8 {
|
||||||
const method = self.asConstElement().getAttributeSafe("method") orelse return "get";
|
const method = self.asConstElement().getAttributeSafe(comptime .wrap("method")) orelse return "get";
|
||||||
|
|
||||||
if (std.ascii.eqlIgnoreCase(method, "post")) {
|
if (std.ascii.eqlIgnoreCase(method, "post")) {
|
||||||
return "post";
|
return "post";
|
||||||
@@ -64,11 +64,11 @@ pub fn getMethod(self: *const Form) []const u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn setMethod(self: *Form, method: []const u8, page: *Page) !void {
|
pub fn setMethod(self: *Form, method: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("method", method, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("method"), .wrap(method), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getElements(self: *Form, page: *Page) !*collections.HTMLFormControlsCollection {
|
pub fn getElements(self: *Form, page: *Page) !*collections.HTMLFormControlsCollection {
|
||||||
const form_id = self.asElement().getAttributeSafe("id");
|
const form_id = self.asElement().getAttributeSafe(comptime .wrap("id"));
|
||||||
const root = if (form_id != null)
|
const root = if (form_id != null)
|
||||||
self.asNode().getRootNode(null) // Has ID: walk entire document to find form=ID controls
|
self.asNode().getRootNode(null) // Has ID: walk entire document to find form=ID controls
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ pub fn constructor(w_: ?u32, h_: ?u32, page: *Page) !*Image {
|
|||||||
|
|
||||||
if (w_) |w| blk: {
|
if (w_) |w| blk: {
|
||||||
const w_string = std.fmt.bufPrint(&page.buf, "{d}", .{w}) catch break :blk;
|
const w_string = std.fmt.bufPrint(&page.buf, "{d}", .{w}) catch break :blk;
|
||||||
try el.setAttributeSafe("width", w_string, page);
|
try el.setAttributeSafe(comptime .wrap("width"), .wrap(w_string), page);
|
||||||
}
|
}
|
||||||
if (h_) |h| blk: {
|
if (h_) |h| blk: {
|
||||||
const h_string = std.fmt.bufPrint(&page.buf, "{d}", .{h}) catch break :blk;
|
const h_string = std.fmt.bufPrint(&page.buf, "{d}", .{h}) catch break :blk;
|
||||||
try el.setAttributeSafe("height", h_string, page);
|
try el.setAttributeSafe(comptime .wrap("height"), .wrap(h_string), page);
|
||||||
}
|
}
|
||||||
return el.as(Image);
|
return el.as(Image);
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,7 @@ pub fn asNode(self: *Image) *Node {
|
|||||||
|
|
||||||
pub fn getSrc(self: *const Image, page: *Page) ![]const u8 {
|
pub fn getSrc(self: *const Image, page: *Page) ![]const u8 {
|
||||||
const element = self.asConstElement();
|
const element = self.asConstElement();
|
||||||
const src = element.getAttributeSafe("src") orelse return "";
|
const src = element.getAttributeSafe(comptime .wrap("src")) orelse return "";
|
||||||
if (src.len == 0) {
|
if (src.len == 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@@ -46,54 +46,54 @@ pub fn getSrc(self: *const Image, page: *Page) ![]const u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn setSrc(self: *Image, value: []const u8, page: *Page) !void {
|
pub fn setSrc(self: *Image, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("src", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("src"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getAlt(self: *const Image) []const u8 {
|
pub fn getAlt(self: *const Image) []const u8 {
|
||||||
return self.asConstElement().getAttributeSafe("alt") orelse "";
|
return self.asConstElement().getAttributeSafe(comptime .wrap("alt")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setAlt(self: *Image, value: []const u8, page: *Page) !void {
|
pub fn setAlt(self: *Image, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("alt", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("alt"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getWidth(self: *const Image) u32 {
|
pub fn getWidth(self: *const Image) u32 {
|
||||||
const attr = self.asConstElement().getAttributeSafe("width") orelse return 0;
|
const attr = self.asConstElement().getAttributeSafe(comptime .wrap("width")) orelse return 0;
|
||||||
return std.fmt.parseUnsigned(u32, attr, 10) catch 0;
|
return std.fmt.parseUnsigned(u32, attr, 10) catch 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setWidth(self: *Image, value: u32, page: *Page) !void {
|
pub fn setWidth(self: *Image, value: u32, page: *Page) !void {
|
||||||
const str = try std.fmt.allocPrint(page.call_arena, "{d}", .{value});
|
const str = try std.fmt.allocPrint(page.call_arena, "{d}", .{value});
|
||||||
try self.asElement().setAttributeSafe("width", str, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("width"), .wrap(str), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getHeight(self: *const Image) u32 {
|
pub fn getHeight(self: *const Image) u32 {
|
||||||
const attr = self.asConstElement().getAttributeSafe("height") orelse return 0;
|
const attr = self.asConstElement().getAttributeSafe(comptime .wrap("height")) orelse return 0;
|
||||||
return std.fmt.parseUnsigned(u32, attr, 10) catch 0;
|
return std.fmt.parseUnsigned(u32, attr, 10) catch 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setHeight(self: *Image, value: u32, page: *Page) !void {
|
pub fn setHeight(self: *Image, value: u32, page: *Page) !void {
|
||||||
const str = try std.fmt.allocPrint(page.call_arena, "{d}", .{value});
|
const str = try std.fmt.allocPrint(page.call_arena, "{d}", .{value});
|
||||||
try self.asElement().setAttributeSafe("height", str, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("height"), .wrap(str), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getCrossOrigin(self: *const Image) ?[]const u8 {
|
pub fn getCrossOrigin(self: *const Image) ?[]const u8 {
|
||||||
return self.asConstElement().getAttributeSafe("crossorigin");
|
return self.asConstElement().getAttributeSafe(comptime .wrap("crossorigin"));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setCrossOrigin(self: *Image, value: ?[]const u8, page: *Page) !void {
|
pub fn setCrossOrigin(self: *Image, value: ?[]const u8, page: *Page) !void {
|
||||||
if (value) |v| {
|
if (value) |v| {
|
||||||
return self.asElement().setAttributeSafe("crossorigin", v, page);
|
return self.asElement().setAttributeSafe(comptime .wrap("crossorigin"), .wrap(v), page);
|
||||||
}
|
}
|
||||||
return self.asElement().removeAttribute("crossorigin", page);
|
return self.asElement().removeAttribute(comptime .wrap("crossorigin"), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getLoading(self: *const Image) []const u8 {
|
pub fn getLoading(self: *const Image) []const u8 {
|
||||||
return self.asConstElement().getAttributeSafe("loading") orelse "eager";
|
return self.asConstElement().getAttributeSafe(comptime .wrap("loading")) orelse "eager";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setLoading(self: *Image, value: []const u8, page: *Page) !void {
|
pub fn setLoading(self: *Image, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("loading", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("loading"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const JsApi = struct {
|
pub const JsApi = struct {
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
// 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 String = @import("../../../../string.zig").String;
|
||||||
|
|
||||||
const js = @import("../../../js/js.zig");
|
const js = @import("../../../js/js.zig");
|
||||||
const Page = @import("../../../Page.zig");
|
const Page = @import("../../../Page.zig");
|
||||||
|
|
||||||
@@ -98,7 +100,7 @@ pub fn getType(self: *const Input) []const u8 {
|
|||||||
pub fn setType(self: *Input, typ: []const u8, page: *Page) !void {
|
pub fn setType(self: *Input, typ: []const u8, page: *Page) !void {
|
||||||
// Setting the type property should update the attribute, which will trigger attributeChange
|
// Setting the type property should update the attribute, which will trigger attributeChange
|
||||||
const type_enum = Type.fromString(typ);
|
const type_enum = Type.fromString(typ);
|
||||||
try self.asElement().setAttributeSafe("type", type_enum.toString(), page);
|
try self.asElement().setAttributeSafe(comptime .wrap("type"), .wrap(type_enum.toString()), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getValue(self: *const Input) []const u8 {
|
pub fn getValue(self: *const Input) []const u8 {
|
||||||
@@ -116,7 +118,7 @@ pub fn getDefaultValue(self: *const Input) []const u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn setDefaultValue(self: *Input, value: []const u8, page: *Page) !void {
|
pub fn setDefaultValue(self: *Input, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("value", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("value"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getChecked(self: *const Input) bool {
|
pub fn getChecked(self: *const Input) bool {
|
||||||
@@ -147,52 +149,52 @@ pub fn getDefaultChecked(self: *const Input) bool {
|
|||||||
|
|
||||||
pub fn setDefaultChecked(self: *Input, checked: bool, page: *Page) !void {
|
pub fn setDefaultChecked(self: *Input, checked: bool, page: *Page) !void {
|
||||||
if (checked) {
|
if (checked) {
|
||||||
try self.asElement().setAttributeSafe("checked", "", page);
|
try self.asElement().setAttributeSafe(comptime .wrap("checked"), .wrap(""), page);
|
||||||
} else {
|
} else {
|
||||||
try self.asElement().removeAttribute("checked", page);
|
try self.asElement().removeAttribute(comptime .wrap("checked"), page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getDisabled(self: *const Input) bool {
|
pub fn getDisabled(self: *const Input) bool {
|
||||||
// TODO: Also check for disabled fieldset ancestors
|
// TODO: Also check for disabled fieldset ancestors
|
||||||
// (but not if we're inside a <legend> of that fieldset)
|
// (but not if we're inside a <legend> of that fieldset)
|
||||||
return self.asConstElement().getAttributeSafe("disabled") != null;
|
return self.asConstElement().getAttributeSafe(comptime .wrap("disabled")) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setDisabled(self: *Input, disabled: bool, page: *Page) !void {
|
pub fn setDisabled(self: *Input, disabled: bool, page: *Page) !void {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
try self.asElement().setAttributeSafe("disabled", "", page);
|
try self.asElement().setAttributeSafe(comptime .wrap("disabled"), .wrap(""), page);
|
||||||
} else {
|
} else {
|
||||||
try self.asElement().removeAttribute("disabled", page);
|
try self.asElement().removeAttribute(comptime .wrap("disabled"), page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getName(self: *const Input) []const u8 {
|
pub fn getName(self: *const Input) []const u8 {
|
||||||
return self.asConstElement().getAttributeSafe("name") orelse "";
|
return self.asConstElement().getAttributeSafe(comptime .wrap("name")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setName(self: *Input, name: []const u8, page: *Page) !void {
|
pub fn setName(self: *Input, name: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("name", name, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("name"), .wrap(name), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getAccept(self: *const Input) []const u8 {
|
pub fn getAccept(self: *const Input) []const u8 {
|
||||||
return self.asConstElement().getAttributeSafe("accept") orelse "";
|
return self.asConstElement().getAttributeSafe(comptime .wrap("accept")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setAccept(self: *Input, accept: []const u8, page: *Page) !void {
|
pub fn setAccept(self: *Input, accept: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("accept", accept, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("accept"), .wrap(accept), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getAlt(self: *const Input) []const u8 {
|
pub fn getAlt(self: *const Input) []const u8 {
|
||||||
return self.asConstElement().getAttributeSafe("alt") orelse "";
|
return self.asConstElement().getAttributeSafe(comptime .wrap("alt")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setAlt(self: *Input, alt: []const u8, page: *Page) !void {
|
pub fn setAlt(self: *Input, alt: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("alt", alt, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("alt"), .wrap(alt), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getMaxLength(self: *const Input) i32 {
|
pub fn getMaxLength(self: *const Input) i32 {
|
||||||
const attr = self.asConstElement().getAttributeSafe("maxlength") orelse return -1;
|
const attr = self.asConstElement().getAttributeSafe(comptime .wrap("maxlength")) orelse return -1;
|
||||||
return std.fmt.parseInt(i32, attr, 10) catch -1;
|
return std.fmt.parseInt(i32, attr, 10) catch -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,11 +204,11 @@ pub fn setMaxLength(self: *Input, max_length: i32, page: *Page) !void {
|
|||||||
}
|
}
|
||||||
var buf: [32]u8 = undefined;
|
var buf: [32]u8 = undefined;
|
||||||
const value = std.fmt.bufPrint(&buf, "{d}", .{max_length}) catch unreachable;
|
const value = std.fmt.bufPrint(&buf, "{d}", .{max_length}) catch unreachable;
|
||||||
try self.asElement().setAttributeSafe("maxlength", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("maxlength"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getSize(self: *const Input) i32 {
|
pub fn getSize(self: *const Input) i32 {
|
||||||
const attr = self.asConstElement().getAttributeSafe("size") orelse return 20;
|
const attr = self.asConstElement().getAttributeSafe(comptime .wrap("size")) orelse return 20;
|
||||||
const parsed = std.fmt.parseInt(i32, attr, 10) catch return 20;
|
const parsed = std.fmt.parseInt(i32, attr, 10) catch return 20;
|
||||||
return if (parsed == 0) 20 else parsed;
|
return if (parsed == 0) 20 else parsed;
|
||||||
}
|
}
|
||||||
@@ -216,46 +218,46 @@ pub fn setSize(self: *Input, size: i32, page: *Page) !void {
|
|||||||
return error.ZeroNotAllowed;
|
return error.ZeroNotAllowed;
|
||||||
}
|
}
|
||||||
if (size < 0) {
|
if (size < 0) {
|
||||||
return self.asElement().setAttributeSafe("size", "20", page);
|
return self.asElement().setAttributeSafe(comptime .wrap("size"), .wrap("20"), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
var buf: [32]u8 = undefined;
|
var buf: [32]u8 = undefined;
|
||||||
const value = std.fmt.bufPrint(&buf, "{d}", .{size}) catch unreachable;
|
const value = std.fmt.bufPrint(&buf, "{d}", .{size}) catch unreachable;
|
||||||
try self.asElement().setAttributeSafe("size", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("size"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getSrc(self: *const Input, page: *Page) ![]const u8 {
|
pub fn getSrc(self: *const Input, page: *Page) ![]const u8 {
|
||||||
const src = self.asConstElement().getAttributeSafe("src") orelse return "";
|
const src = self.asConstElement().getAttributeSafe(comptime .wrap("src")) orelse return "";
|
||||||
// If attribute is explicitly set (even if empty), resolve it against the base URL
|
// If attribute is explicitly set (even if empty), resolve it against the base URL
|
||||||
return @import("../../URL.zig").resolve(page.call_arena, page.base(), src, .{});
|
return @import("../../URL.zig").resolve(page.call_arena, page.base(), src, .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setSrc(self: *Input, src: []const u8, page: *Page) !void {
|
pub fn setSrc(self: *Input, src: []const u8, page: *Page) !void {
|
||||||
const trimmed = std.mem.trim(u8, src, &std.ascii.whitespace);
|
const trimmed = std.mem.trim(u8, src, &std.ascii.whitespace);
|
||||||
try self.asElement().setAttributeSafe("src", trimmed, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("src"), .wrap(trimmed), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getReadonly(self: *const Input) bool {
|
pub fn getReadonly(self: *const Input) bool {
|
||||||
return self.asConstElement().getAttributeSafe("readonly") != null;
|
return self.asConstElement().getAttributeSafe(comptime .wrap("readonly")) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setReadonly(self: *Input, readonly: bool, page: *Page) !void {
|
pub fn setReadonly(self: *Input, readonly: bool, page: *Page) !void {
|
||||||
if (readonly) {
|
if (readonly) {
|
||||||
try self.asElement().setAttributeSafe("readonly", "", page);
|
try self.asElement().setAttributeSafe(comptime .wrap("readonly"), .wrap(""), page);
|
||||||
} else {
|
} else {
|
||||||
try self.asElement().removeAttribute("readonly", page);
|
try self.asElement().removeAttribute(comptime .wrap("readonly"), page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getRequired(self: *const Input) bool {
|
pub fn getRequired(self: *const Input) bool {
|
||||||
return self.asConstElement().getAttributeSafe("required") != null;
|
return self.asConstElement().getAttributeSafe(comptime .wrap("required")) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setRequired(self: *Input, required: bool, page: *Page) !void {
|
pub fn setRequired(self: *Input, required: bool, page: *Page) !void {
|
||||||
if (required) {
|
if (required) {
|
||||||
try self.asElement().setAttributeSafe("required", "", page);
|
try self.asElement().setAttributeSafe(comptime .wrap("required"), .wrap(""), page);
|
||||||
} else {
|
} else {
|
||||||
try self.asElement().removeAttribute("required", page);
|
try self.asElement().removeAttribute(comptime .wrap("required"), page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,7 +381,7 @@ pub fn getForm(self: *Input, page: *Page) ?*Form {
|
|||||||
const element = self.asElement();
|
const element = self.asElement();
|
||||||
|
|
||||||
// If form attribute exists, ONLY use that (even if it references nothing)
|
// If form attribute exists, ONLY use that (even if it references nothing)
|
||||||
if (element.getAttributeSafe("form")) |form_id| {
|
if (element.getAttributeSafe(comptime .wrap("form"))) |form_id| {
|
||||||
if (page.document.getElementById(form_id, page)) |form_element| {
|
if (page.document.getElementById(form_id, page)) |form_element| {
|
||||||
return form_element.is(Form);
|
return form_element.is(Form);
|
||||||
}
|
}
|
||||||
@@ -402,7 +404,7 @@ pub fn getForm(self: *Input, page: *Page) ?*Form {
|
|||||||
fn uncheckRadioGroup(self: *Input, page: *Page) !void {
|
fn uncheckRadioGroup(self: *Input, page: *Page) !void {
|
||||||
const element = self.asElement();
|
const element = self.asElement();
|
||||||
|
|
||||||
const name = element.getAttributeSafe("name") orelse return;
|
const name = element.getAttributeSafe(comptime .wrap("name")) orelse return;
|
||||||
if (name.len == 0) {
|
if (name.len == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -420,7 +422,7 @@ fn uncheckRadioGroup(self: *Input, page: *Page) !void {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const other_name = other_element.getAttributeSafe("name") orelse continue;
|
const other_name = other_element.getAttributeSafe(comptime .wrap("name")) orelse continue;
|
||||||
if (!std.mem.eql(u8, name, other_name)) {
|
if (!std.mem.eql(u8, name, other_name)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -481,14 +483,14 @@ pub const Build = struct {
|
|||||||
const element = self.asElement();
|
const element = self.asElement();
|
||||||
|
|
||||||
// Store initial values from attributes
|
// Store initial values from attributes
|
||||||
self._default_value = element.getAttributeSafe("value");
|
self._default_value = element.getAttributeSafe(comptime .wrap("value"));
|
||||||
self._default_checked = element.getAttributeSafe("checked") != null;
|
self._default_checked = element.getAttributeSafe(comptime .wrap("checked")) != null;
|
||||||
|
|
||||||
// Current state starts equal to default
|
// Current state starts equal to default
|
||||||
self._value = self._default_value;
|
self._value = self._default_value;
|
||||||
self._checked = self._default_checked;
|
self._checked = self._default_checked;
|
||||||
|
|
||||||
self._input_type = if (element.getAttributeSafe("type")) |type_attr|
|
self._input_type = if (element.getAttributeSafe(comptime .wrap("type"))) |type_attr|
|
||||||
Type.fromString(type_attr)
|
Type.fromString(type_attr)
|
||||||
else
|
else
|
||||||
.text;
|
.text;
|
||||||
@@ -499,12 +501,12 @@ pub const Build = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn attributeChange(element: *Element, name: []const u8, value: []const u8, page: *Page) !void {
|
pub fn attributeChange(element: *Element, name: String, value: String, page: *Page) !void {
|
||||||
const attribute = std.meta.stringToEnum(enum { type, value, checked }, name) orelse return;
|
const attribute = std.meta.stringToEnum(enum { type, value, checked }, name.str()) orelse return;
|
||||||
const self = element.as(Input);
|
const self = element.as(Input);
|
||||||
switch (attribute) {
|
switch (attribute) {
|
||||||
.type => self._input_type = Type.fromString(value),
|
.type => self._input_type = Type.fromString(value.str()),
|
||||||
.value => self._default_value = value,
|
.value => self._default_value = try page.arena.dupe(u8, value.str()),
|
||||||
.checked => {
|
.checked => {
|
||||||
self._default_checked = true;
|
self._default_checked = true;
|
||||||
// Only update checked state if it hasn't been manually modified
|
// Only update checked state if it hasn't been manually modified
|
||||||
@@ -519,8 +521,8 @@ pub const Build = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn attributeRemove(element: *Element, name: []const u8, _: *Page) !void {
|
pub fn attributeRemove(element: *Element, name: String, _: *Page) !void {
|
||||||
const attribute = std.meta.stringToEnum(enum { type, value, checked }, name) orelse return;
|
const attribute = std.meta.stringToEnum(enum { type, value, checked }, name.str()) orelse return;
|
||||||
const self = element.as(Input);
|
const self = element.as(Input);
|
||||||
switch (attribute) {
|
switch (attribute) {
|
||||||
.type => self._input_type = .text,
|
.type => self._input_type = .text,
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ pub fn asNode(self: *Link) *Node {
|
|||||||
|
|
||||||
pub fn getHref(self: *Link, page: *Page) ![]const u8 {
|
pub fn getHref(self: *Link, page: *Page) ![]const u8 {
|
||||||
const element = self.asElement();
|
const element = self.asElement();
|
||||||
const href = element.getAttributeSafe("href") orelse return "";
|
const href = element.getAttributeSafe(comptime .wrap("href")) orelse return "";
|
||||||
if (href.len == 0) {
|
if (href.len == 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@@ -46,15 +46,15 @@ pub fn getHref(self: *Link, page: *Page) ![]const u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn setHref(self: *Link, value: []const u8, page: *Page) !void {
|
pub fn setHref(self: *Link, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("href", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("href"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getRel(self: *Link) []const u8 {
|
pub fn getRel(self: *Link) []const u8 {
|
||||||
return self.asElement().getAttributeSafe("rel") orelse return "";
|
return self.asElement().getAttributeSafe(comptime .wrap("rel")) orelse return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setRel(self: *Link, value: []const u8, page: *Page) !void {
|
pub fn setRel(self: *Link, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("rel", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("rel"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const JsApi = struct {
|
pub const JsApi = struct {
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ pub fn setCurrentTime(self: *Media, value: f64) void {
|
|||||||
|
|
||||||
pub fn getSrc(self: *const Media, page: *Page) ![]const u8 {
|
pub fn getSrc(self: *const Media, page: *Page) ![]const u8 {
|
||||||
const element = self.asConstElement();
|
const element = self.asConstElement();
|
||||||
const src = element.getAttributeSafe("src") orelse return "";
|
const src = element.getAttributeSafe(comptime .wrap("src")) orelse return "";
|
||||||
if (src.len == 0) {
|
if (src.len == 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@@ -228,51 +228,51 @@ pub fn getSrc(self: *const Media, page: *Page) ![]const u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn setSrc(self: *Media, value: []const u8, page: *Page) !void {
|
pub fn setSrc(self: *Media, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("src", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("src"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getAutoplay(self: *const Media) bool {
|
pub fn getAutoplay(self: *const Media) bool {
|
||||||
return self.asConstElement().getAttributeSafe("autoplay") != null;
|
return self.asConstElement().getAttributeSafe(comptime .wrap("autoplay")) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setAutoplay(self: *Media, value: bool, page: *Page) !void {
|
pub fn setAutoplay(self: *Media, value: bool, page: *Page) !void {
|
||||||
if (value) {
|
if (value) {
|
||||||
try self.asElement().setAttributeSafe("autoplay", "", page);
|
try self.asElement().setAttributeSafe(comptime .wrap("autoplay"), .wrap(""), page);
|
||||||
} else {
|
} else {
|
||||||
try self.asElement().removeAttribute("autoplay", page);
|
try self.asElement().removeAttribute(comptime .wrap("autoplay"), page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getControls(self: *const Media) bool {
|
pub fn getControls(self: *const Media) bool {
|
||||||
return self.asConstElement().getAttributeSafe("controls") != null;
|
return self.asConstElement().getAttributeSafe(comptime .wrap("controls")) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setControls(self: *Media, value: bool, page: *Page) !void {
|
pub fn setControls(self: *Media, value: bool, page: *Page) !void {
|
||||||
if (value) {
|
if (value) {
|
||||||
try self.asElement().setAttributeSafe("controls", "", page);
|
try self.asElement().setAttributeSafe(comptime .wrap("controls"), .wrap(""), page);
|
||||||
} else {
|
} else {
|
||||||
try self.asElement().removeAttribute("controls", page);
|
try self.asElement().removeAttribute(comptime .wrap("controls"), page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getLoop(self: *const Media) bool {
|
pub fn getLoop(self: *const Media) bool {
|
||||||
return self.asConstElement().getAttributeSafe("loop") != null;
|
return self.asConstElement().getAttributeSafe(comptime .wrap("loop")) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setLoop(self: *Media, value: bool, page: *Page) !void {
|
pub fn setLoop(self: *Media, value: bool, page: *Page) !void {
|
||||||
if (value) {
|
if (value) {
|
||||||
try self.asElement().setAttributeSafe("loop", "", page);
|
try self.asElement().setAttributeSafe(comptime .wrap("loop"), .wrap(""), page);
|
||||||
} else {
|
} else {
|
||||||
try self.asElement().removeAttribute("loop", page);
|
try self.asElement().removeAttribute(comptime .wrap("loop"), page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getPreload(self: *const Media) []const u8 {
|
pub fn getPreload(self: *const Media) []const u8 {
|
||||||
return self.asConstElement().getAttributeSafe("preload") orelse "auto";
|
return self.asConstElement().getAttributeSafe(comptime .wrap("preload")) orelse "auto";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setPreload(self: *Media, value: []const u8, page: *Page) !void {
|
pub fn setPreload(self: *Media, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("preload", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("preload"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const JsApi = struct {
|
pub const JsApi = struct {
|
||||||
|
|||||||
@@ -37,35 +37,35 @@ pub fn asNode(self: *Meta) *Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getName(self: *Meta) []const u8 {
|
pub fn getName(self: *Meta) []const u8 {
|
||||||
return self.asElement().getAttributeSafe("name") orelse return "";
|
return self.asElement().getAttributeSafe(comptime .wrap("name")) orelse return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setName(self: *Meta, value: []const u8, page: *Page) !void {
|
pub fn setName(self: *Meta, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("name", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("name"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getHttpEquiv(self: *Meta) []const u8 {
|
pub fn getHttpEquiv(self: *Meta) []const u8 {
|
||||||
return self.asElement().getAttributeSafe("http-equiv") orelse return "";
|
return self.asElement().getAttributeSafe(comptime .wrap("http-equiv")) orelse return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setHttpEquiv(self: *Meta, value: []const u8, page: *Page) !void {
|
pub fn setHttpEquiv(self: *Meta, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("http-equiv", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("http-equiv"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getContent(self: *Meta) []const u8 {
|
pub fn getContent(self: *Meta) []const u8 {
|
||||||
return self.asElement().getAttributeSafe("content") orelse return "";
|
return self.asElement().getAttributeSafe(comptime .wrap("content")) orelse return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setContent(self: *Meta, value: []const u8, page: *Page) !void {
|
pub fn setContent(self: *Meta, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("content", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("content"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getMedia(self: *Meta) []const u8 {
|
pub fn getMedia(self: *Meta) []const u8 {
|
||||||
return self.asElement().getAttributeSafe("media") orelse return "";
|
return self.asElement().getAttributeSafe(comptime .wrap("media")) orelse return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setMedia(self: *Meta, value: []const u8, page: *Page) !void {
|
pub fn setMedia(self: *Meta, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("media", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("media"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const JsApi = struct {
|
pub const JsApi = struct {
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
// 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 String = @import("../../../../string.zig").String;
|
||||||
|
|
||||||
const js = @import("../../../js/js.zig");
|
const js = @import("../../../js/js.zig");
|
||||||
const Page = @import("../../../Page.zig");
|
const Page = @import("../../../Page.zig");
|
||||||
|
|
||||||
@@ -55,7 +57,7 @@ pub fn getValue(self: *Option, page: *Page) []const u8 {
|
|||||||
|
|
||||||
pub fn setValue(self: *Option, value: []const u8, page: *Page) !void {
|
pub fn setValue(self: *Option, value: []const u8, page: *Page) !void {
|
||||||
const owned = try page.dupeString(value);
|
const owned = try page.dupeString(value);
|
||||||
try self.asElement().setAttributeSafe("value", owned, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("value"), .wrap(owned), page);
|
||||||
self._value = owned;
|
self._value = owned;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,18 +89,18 @@ pub fn getDisabled(self: *const Option) bool {
|
|||||||
pub fn setDisabled(self: *Option, disabled: bool, page: *Page) !void {
|
pub fn setDisabled(self: *Option, disabled: bool, page: *Page) !void {
|
||||||
self._disabled = disabled;
|
self._disabled = disabled;
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
try self.asElement().setAttributeSafe("disabled", "", page);
|
try self.asElement().setAttributeSafe(comptime .wrap("disabled"), .wrap(""), page);
|
||||||
} else {
|
} else {
|
||||||
try self.asElement().removeAttribute("disabled", page);
|
try self.asElement().removeAttribute(comptime .wrap("disabled"), page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getName(self: *const Option) []const u8 {
|
pub fn getName(self: *const Option) []const u8 {
|
||||||
return self.asConstElement().getAttributeSafe("name") orelse "";
|
return self.asConstElement().getAttributeSafe(comptime .wrap("name")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setName(self: *Option, name: []const u8, page: *Page) !void {
|
pub fn setName(self: *Option, name: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("name", name, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("name"), .wrap(name), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const JsApi = struct {
|
pub const JsApi = struct {
|
||||||
@@ -124,21 +126,21 @@ pub const Build = struct {
|
|||||||
const element = self.asElement();
|
const element = self.asElement();
|
||||||
|
|
||||||
// Check for value attribute
|
// Check for value attribute
|
||||||
self._value = element.getAttributeSafe("value");
|
self._value = element.getAttributeSafe(comptime .wrap("value"));
|
||||||
|
|
||||||
// Check for selected attribute
|
// Check for selected attribute
|
||||||
self._default_selected = element.getAttributeSafe("selected") != null;
|
self._default_selected = element.getAttributeSafe(comptime .wrap("selected")) != null;
|
||||||
self._selected = self._default_selected;
|
self._selected = self._default_selected;
|
||||||
|
|
||||||
// Check for disabled attribute
|
// Check for disabled attribute
|
||||||
self._disabled = element.getAttributeSafe("disabled") != null;
|
self._disabled = element.getAttributeSafe(comptime .wrap("disabled")) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn attributeChange(element: *Element, name: []const u8, value: []const u8, _: *Page) !void {
|
pub fn attributeChange(element: *Element, name: String, value: String, _: *Page) !void {
|
||||||
const attribute = std.meta.stringToEnum(enum { value, selected }, name) orelse return;
|
const attribute = std.meta.stringToEnum(enum { value, selected }, name.str()) orelse return;
|
||||||
const self = element.as(Option);
|
const self = element.as(Option);
|
||||||
switch (attribute) {
|
switch (attribute) {
|
||||||
.value => self._value = value,
|
.value => self._value = value.str(),
|
||||||
.selected => {
|
.selected => {
|
||||||
self._default_selected = true;
|
self._default_selected = true;
|
||||||
self._selected = true;
|
self._selected = true;
|
||||||
@@ -146,8 +148,8 @@ pub const Build = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn attributeRemove(element: *Element, name: []const u8, _: *Page) !void {
|
pub fn attributeRemove(element: *Element, name: String, _: *Page) !void {
|
||||||
const attribute = std.meta.stringToEnum(enum { value, selected }, name) orelse return;
|
const attribute = std.meta.stringToEnum(enum { value, selected }, name.str()) orelse return;
|
||||||
const self = element.as(Option);
|
const self = element.as(Option);
|
||||||
switch (attribute) {
|
switch (attribute) {
|
||||||
.value => self._value = null,
|
.value => self._value = null,
|
||||||
|
|||||||
@@ -53,27 +53,27 @@ pub fn getSrc(self: *const Script, page: *Page) ![]const u8 {
|
|||||||
|
|
||||||
pub fn setSrc(self: *Script, src: []const u8, page: *Page) !void {
|
pub fn setSrc(self: *Script, src: []const u8, page: *Page) !void {
|
||||||
const element = self.asElement();
|
const element = self.asElement();
|
||||||
try element.setAttributeSafe("src", src, page);
|
try element.setAttributeSafe(comptime .wrap("src"), .wrap(src), page);
|
||||||
self._src = element.getAttributeSafe("src") orelse unreachable;
|
self._src = element.getAttributeSafe(comptime .wrap("src")) orelse unreachable;
|
||||||
if (element.asNode().isConnected()) {
|
if (element.asNode().isConnected()) {
|
||||||
try page.scriptAddedCallback(false, self);
|
try page.scriptAddedCallback(false, self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getType(self: *const Script) []const u8 {
|
pub fn getType(self: *const Script) []const u8 {
|
||||||
return self.asConstElement().getAttributeSafe("type") orelse "";
|
return self.asConstElement().getAttributeSafe(comptime .wrap("type")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setType(self: *Script, value: []const u8, page: *Page) !void {
|
pub fn setType(self: *Script, value: []const u8, page: *Page) !void {
|
||||||
return self.asElement().setAttributeSafe("type", value, page);
|
return self.asElement().setAttributeSafe(comptime .wrap("type"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getNonce(self: *const Script) []const u8 {
|
pub fn getNonce(self: *const Script) []const u8 {
|
||||||
return self.asConstElement().getAttributeSafe("nonce") orelse "";
|
return self.asConstElement().getAttributeSafe(comptime .wrap("nonce")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setNonce(self: *Script, value: []const u8, page: *Page) !void {
|
pub fn setNonce(self: *Script, value: []const u8, page: *Page) !void {
|
||||||
return self.asElement().setAttributeSafe("nonce", value, page);
|
return self.asElement().setAttributeSafe(comptime .wrap("nonce"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getOnLoad(self: *const Script) ?js.Function.Global {
|
pub fn getOnLoad(self: *const Script) ?js.Function.Global {
|
||||||
@@ -93,7 +93,7 @@ pub fn setOnError(self: *Script, cb: ?js.Function.Global) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getNoModule(self: *const Script) bool {
|
pub fn getNoModule(self: *const Script) bool {
|
||||||
return self.asConstElement().getAttributeSafe("nomodule") != null;
|
return self.asConstElement().getAttributeSafe(comptime .wrap("nomodule")) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setInnerText(self: *Script, text: []const u8, page: *Page) !void {
|
pub fn setInnerText(self: *Script, text: []const u8, page: *Page) !void {
|
||||||
@@ -127,9 +127,9 @@ pub const Build = struct {
|
|||||||
pub fn complete(node: *Node, page: *Page) !void {
|
pub fn complete(node: *Node, page: *Page) !void {
|
||||||
const self = node.as(Script);
|
const self = node.as(Script);
|
||||||
const element = self.asElement();
|
const element = self.asElement();
|
||||||
self._src = element.getAttributeSafe("src") orelse "";
|
self._src = element.getAttributeSafe(comptime .wrap("src")) orelse "";
|
||||||
|
|
||||||
if (element.getAttributeSafe("onload")) |on_load| {
|
if (element.getAttributeSafe(comptime .wrap("onload"))) |on_load| {
|
||||||
if (page.js.stringToPersistedFunction(on_load)) |func| {
|
if (page.js.stringToPersistedFunction(on_load)) |func| {
|
||||||
self._on_load = func;
|
self._on_load = func;
|
||||||
} else |err| {
|
} else |err| {
|
||||||
@@ -137,7 +137,7 @@ pub const Build = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element.getAttributeSafe("onerror")) |on_error| {
|
if (element.getAttributeSafe(comptime .wrap("onerror"))) |on_error| {
|
||||||
if (page.js.stringToPersistedFunction(on_error)) |func| {
|
if (page.js.stringToPersistedFunction(on_error)) |func| {
|
||||||
self._on_error = func;
|
self._on_error = func;
|
||||||
} else |err| {
|
} else |err| {
|
||||||
|
|||||||
@@ -121,39 +121,39 @@ pub fn setSelectedIndex(self: *Select, index: i32) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getMultiple(self: *const Select) bool {
|
pub fn getMultiple(self: *const Select) bool {
|
||||||
return self.asConstElement().getAttributeSafe("multiple") != null;
|
return self.asConstElement().getAttributeSafe(comptime .wrap("multiple")) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setMultiple(self: *Select, multiple: bool, page: *Page) !void {
|
pub fn setMultiple(self: *Select, multiple: bool, page: *Page) !void {
|
||||||
if (multiple) {
|
if (multiple) {
|
||||||
try self.asElement().setAttributeSafe("multiple", "", page);
|
try self.asElement().setAttributeSafe(comptime .wrap("multiple"), .wrap(""), page);
|
||||||
} else {
|
} else {
|
||||||
try self.asElement().removeAttribute("multiple", page);
|
try self.asElement().removeAttribute(comptime .wrap("multiple"), page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getDisabled(self: *const Select) bool {
|
pub fn getDisabled(self: *const Select) bool {
|
||||||
return self.asConstElement().getAttributeSafe("disabled") != null;
|
return self.asConstElement().getAttributeSafe(comptime .wrap("disabled")) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setDisabled(self: *Select, disabled: bool, page: *Page) !void {
|
pub fn setDisabled(self: *Select, disabled: bool, page: *Page) !void {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
try self.asElement().setAttributeSafe("disabled", "", page);
|
try self.asElement().setAttributeSafe(comptime .wrap("disabled"), .wrap(""), page);
|
||||||
} else {
|
} else {
|
||||||
try self.asElement().removeAttribute("disabled", page);
|
try self.asElement().removeAttribute(comptime .wrap("disabled"), page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getName(self: *const Select) []const u8 {
|
pub fn getName(self: *const Select) []const u8 {
|
||||||
return self.asConstElement().getAttributeSafe("name") orelse "";
|
return self.asConstElement().getAttributeSafe(comptime .wrap("name")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setName(self: *Select, name: []const u8, page: *Page) !void {
|
pub fn setName(self: *Select, name: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("name", name, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("name"), .wrap(name), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getSize(self: *const Select) u32 {
|
pub fn getSize(self: *const Select) u32 {
|
||||||
const s = self.asConstElement().getAttributeSafe("size") orelse return 0;
|
const s = self.asConstElement().getAttributeSafe(comptime .wrap("size")) orelse return 0;
|
||||||
|
|
||||||
const trimmed = std.mem.trimLeft(u8, s, &std.ascii.whitespace);
|
const trimmed = std.mem.trimLeft(u8, s, &std.ascii.whitespace);
|
||||||
|
|
||||||
@@ -172,18 +172,18 @@ pub fn getSize(self: *const Select) u32 {
|
|||||||
|
|
||||||
pub fn setSize(self: *Select, size: u32, page: *Page) !void {
|
pub fn setSize(self: *Select, size: u32, page: *Page) !void {
|
||||||
const size_string = try std.fmt.allocPrint(page.call_arena, "{d}", .{size});
|
const size_string = try std.fmt.allocPrint(page.call_arena, "{d}", .{size});
|
||||||
try self.asElement().setAttributeSafe("size", size_string, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("size"), .wrap(size_string), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getRequired(self: *const Select) bool {
|
pub fn getRequired(self: *const Select) bool {
|
||||||
return self.asConstElement().getAttributeSafe("required") != null;
|
return self.asConstElement().getAttributeSafe(comptime .wrap("required")) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setRequired(self: *Select, required: bool, page: *Page) !void {
|
pub fn setRequired(self: *Select, required: bool, page: *Page) !void {
|
||||||
if (required) {
|
if (required) {
|
||||||
try self.asElement().setAttributeSafe("required", "", page);
|
try self.asElement().setAttributeSafe(comptime .wrap("required"), .wrap(""), page);
|
||||||
} else {
|
} else {
|
||||||
try self.asElement().removeAttribute("required", page);
|
try self.asElement().removeAttribute(comptime .wrap("required"), page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +218,7 @@ pub fn getForm(self: *Select, page: *Page) ?*Form {
|
|||||||
const element = self.asElement();
|
const element = self.asElement();
|
||||||
|
|
||||||
// If form attribute exists, ONLY use that (even if it references nothing)
|
// If form attribute exists, ONLY use that (even if it references nothing)
|
||||||
if (element.getAttributeSafe("form")) |form_id| {
|
if (element.getAttributeSafe(comptime .wrap("form"))) |form_id| {
|
||||||
if (page.document.getElementById(form_id, page)) |form_element| {
|
if (page.document.getElementById(form_id, page)) |form_element| {
|
||||||
return form_element.is(Form);
|
return form_element.is(Form);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,11 +25,11 @@ pub fn asNode(self: *Slot) *Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getName(self: *const Slot) []const u8 {
|
pub fn getName(self: *const Slot) []const u8 {
|
||||||
return self.asConstElement().getAttributeSafe("name") orelse "";
|
return self.asConstElement().getAttributeSafe(comptime .wrap("name")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setName(self: *Slot, name: []const u8, page: *Page) !void {
|
pub fn setName(self: *Slot, name: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("name", name, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("name"), .wrap(name), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
const AssignedNodesOptions = struct {
|
const AssignedNodesOptions = struct {
|
||||||
@@ -131,7 +131,7 @@ fn isAssignedToSlot(node: *Node, slot_name: []const u8) bool {
|
|||||||
// Check if a node should be assigned to a slot with the given name
|
// Check if a node should be assigned to a slot with the given name
|
||||||
if (node.is(Element)) |element| {
|
if (node.is(Element)) |element| {
|
||||||
// Get the slot attribute from the element
|
// Get the slot attribute from the element
|
||||||
const node_slot = element.getAttributeSafe("slot") orelse "";
|
const node_slot = element.getAttributeSafe(comptime .wrap("slot")) orelse "";
|
||||||
|
|
||||||
// Match if:
|
// Match if:
|
||||||
// - Both are empty (default slot)
|
// - Both are empty (default slot)
|
||||||
|
|||||||
@@ -39,38 +39,38 @@ pub fn asNode(self: *Style) *Node {
|
|||||||
// Attribute-backed properties
|
// Attribute-backed properties
|
||||||
|
|
||||||
pub fn getBlocking(self: *const Style) []const u8 {
|
pub fn getBlocking(self: *const Style) []const u8 {
|
||||||
return self.asConstElement().getAttributeSafe("blocking") orelse "";
|
return self.asConstElement().getAttributeSafe(comptime .wrap("blocking")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setBlocking(self: *Style, value: []const u8, page: *Page) !void {
|
pub fn setBlocking(self: *Style, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("blocking", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("blocking"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getMedia(self: *const Style) []const u8 {
|
pub fn getMedia(self: *const Style) []const u8 {
|
||||||
return self.asConstElement().getAttributeSafe("media") orelse "";
|
return self.asConstElement().getAttributeSafe(comptime .wrap("media")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setMedia(self: *Style, value: []const u8, page: *Page) !void {
|
pub fn setMedia(self: *Style, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("media", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("media"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getType(self: *const Style) []const u8 {
|
pub fn getType(self: *const Style) []const u8 {
|
||||||
return self.asConstElement().getAttributeSafe("type") orelse "text/css";
|
return self.asConstElement().getAttributeSafe(comptime .wrap("type")) orelse "text/css";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setType(self: *Style, value: []const u8, page: *Page) !void {
|
pub fn setType(self: *Style, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("type", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("type"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getDisabled(self: *const Style) bool {
|
pub fn getDisabled(self: *const Style) bool {
|
||||||
return self.asConstElement().getAttributeSafe("disabled") != null;
|
return self.asConstElement().getAttributeSafe(comptime .wrap("disabled")) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setDisabled(self: *Style, disabled: bool, page: *Page) !void {
|
pub fn setDisabled(self: *Style, disabled: bool, page: *Page) !void {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
try self.asElement().setAttributeSafe("disabled", "", page);
|
try self.asElement().setAttributeSafe(comptime .wrap("disabled"), .wrap(""), page);
|
||||||
} else {
|
} else {
|
||||||
try self.asElement().removeAttribute("disabled", page);
|
try self.asElement().removeAttribute(comptime .wrap("disabled"), page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,34 +84,34 @@ pub fn setDefaultValue(self: *TextArea, value: []const u8, page: *Page) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getDisabled(self: *const TextArea) bool {
|
pub fn getDisabled(self: *const TextArea) bool {
|
||||||
return self.asConstElement().getAttributeSafe("disabled") != null;
|
return self.asConstElement().getAttributeSafe(comptime .wrap("disabled")) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setDisabled(self: *TextArea, disabled: bool, page: *Page) !void {
|
pub fn setDisabled(self: *TextArea, disabled: bool, page: *Page) !void {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
try self.asElement().setAttributeSafe("disabled", "", page);
|
try self.asElement().setAttributeSafe(comptime .wrap("disabled"), .wrap(""), page);
|
||||||
} else {
|
} else {
|
||||||
try self.asElement().removeAttribute("disabled", page);
|
try self.asElement().removeAttribute(comptime .wrap("disabled"), page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getName(self: *const TextArea) []const u8 {
|
pub fn getName(self: *const TextArea) []const u8 {
|
||||||
return self.asConstElement().getAttributeSafe("name") orelse "";
|
return self.asConstElement().getAttributeSafe(comptime .wrap("name")) orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setName(self: *TextArea, name: []const u8, page: *Page) !void {
|
pub fn setName(self: *TextArea, name: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("name", name, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("name"), .wrap(name), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getRequired(self: *const TextArea) bool {
|
pub fn getRequired(self: *const TextArea) bool {
|
||||||
return self.asConstElement().getAttributeSafe("required") != null;
|
return self.asConstElement().getAttributeSafe(comptime .wrap("required")) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setRequired(self: *TextArea, required: bool, page: *Page) !void {
|
pub fn setRequired(self: *TextArea, required: bool, page: *Page) !void {
|
||||||
if (required) {
|
if (required) {
|
||||||
try self.asElement().setAttributeSafe("required", "", page);
|
try self.asElement().setAttributeSafe(comptime .wrap("required"), .wrap(""), page);
|
||||||
} else {
|
} else {
|
||||||
try self.asElement().removeAttribute("required", page);
|
try self.asElement().removeAttribute(comptime .wrap("required"), page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +221,7 @@ pub fn getForm(self: *TextArea, page: *Page) ?*Form {
|
|||||||
const element = self.asElement();
|
const element = self.asElement();
|
||||||
|
|
||||||
// If form attribute exists, ONLY use that (even if it references nothing)
|
// If form attribute exists, ONLY use that (even if it references nothing)
|
||||||
if (element.getAttributeSafe("form")) |form_id| {
|
if (element.getAttributeSafe(comptime .wrap("form"))) |form_id| {
|
||||||
if (page.document.getElementById(form_id, page)) |form_element| {
|
if (page.document.getElementById(form_id, page)) |form_element| {
|
||||||
return form_element.is(Form);
|
return form_element.is(Form);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ pub fn getVideoHeight(_: *const Video) u32 {
|
|||||||
|
|
||||||
pub fn getPoster(self: *const Video, page: *Page) ![]const u8 {
|
pub fn getPoster(self: *const Video, page: *Page) ![]const u8 {
|
||||||
const element = self.asConstElement();
|
const element = self.asConstElement();
|
||||||
const poster = element.getAttributeSafe("poster") orelse return "";
|
const poster = element.getAttributeSafe(comptime .wrap("poster")) orelse return "";
|
||||||
if (poster.len == 0) {
|
if (poster.len == 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@@ -63,7 +63,7 @@ pub fn getPoster(self: *const Video, page: *Page) ![]const u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn setPoster(self: *Video, value: []const u8, page: *Page) !void {
|
pub fn setPoster(self: *Video, value: []const u8, page: *Page) !void {
|
||||||
try self.asElement().setAttributeSafe("poster", value, page);
|
try self.asElement().setAttributeSafe(comptime .wrap("poster"), .wrap(value), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const JsApi = struct {
|
pub const JsApi = struct {
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ fn collectForm(arena: Allocator, form_: ?*Form, submitter_: ?*Element, page: *Pa
|
|||||||
var elements = try form.getElements(page);
|
var elements = try form.getElements(page);
|
||||||
var it = try elements.iterator();
|
var it = try elements.iterator();
|
||||||
while (it.next()) |element| {
|
while (it.next()) |element| {
|
||||||
if (element.getAttributeSafe("disabled") != null) {
|
if (element.getAttributeSafe(comptime .wrap("disabled")) != null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,7 +139,7 @@ fn collectForm(arena: Allocator, form_: ?*Form, submitter_: ?*Element, page: *Pa
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const name = element.getAttributeSafe("name");
|
const name = element.getAttributeSafe(comptime .wrap("name"));
|
||||||
const x_key = if (name) |n| try std.fmt.allocPrint(arena, "{s}.x", .{n}) else "x";
|
const x_key = if (name) |n| try std.fmt.allocPrint(arena, "{s}.x", .{n}) else "x";
|
||||||
const y_key = if (name) |n| try std.fmt.allocPrint(arena, "{s}.y", .{n}) else "y";
|
const y_key = if (name) |n| try std.fmt.allocPrint(arena, "{s}.y", .{n}) else "y";
|
||||||
try list.append(arena, x_key, "0");
|
try list.append(arena, x_key, "0");
|
||||||
@@ -148,7 +148,7 @@ fn collectForm(arena: Allocator, form_: ?*Form, submitter_: ?*Element, page: *Pa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const name = element.getAttributeSafe("name") orelse continue;
|
const name = element.getAttributeSafe(comptime .wrap("name")) orelse continue;
|
||||||
const value = blk: {
|
const value = blk: {
|
||||||
if (element.is(Form.Input)) |input| {
|
if (element.is(Form.Input)) |input| {
|
||||||
const input_type = input._input_type;
|
const input_type = input._input_type;
|
||||||
|
|||||||
@@ -412,11 +412,11 @@ fn matchesCompound(el: *Node.Element, compound: Selector.Compound, scope: *Node,
|
|||||||
fn matchesPart(el: *Node.Element, part: Part, scope: *Node, page: *Page) bool {
|
fn matchesPart(el: *Node.Element, part: Part, scope: *Node, page: *Page) bool {
|
||||||
switch (part) {
|
switch (part) {
|
||||||
.id => |id| {
|
.id => |id| {
|
||||||
const element_id = el.getAttributeSafe("id") orelse return false;
|
const element_id = el.getAttributeSafe(comptime .wrap("id")) orelse return false;
|
||||||
return std.mem.eql(u8, element_id, id);
|
return std.mem.eql(u8, element_id, id);
|
||||||
},
|
},
|
||||||
.class => |cls| {
|
.class => |cls| {
|
||||||
const class_attr = el.getAttributeSafe("class") orelse return false;
|
const class_attr = el.getAttributeSafe(comptime .wrap("class")) orelse return false;
|
||||||
return Selector.classAttributeContains(class_attr, cls);
|
return Selector.classAttributeContains(class_attr, cls);
|
||||||
},
|
},
|
||||||
.tag => |tag| {
|
.tag => |tag| {
|
||||||
@@ -526,10 +526,10 @@ fn matchesPseudoClass(el: *Node.Element, pseudo: Selector.PseudoClass, scope: *N
|
|||||||
return input.getChecked();
|
return input.getChecked();
|
||||||
},
|
},
|
||||||
.disabled => {
|
.disabled => {
|
||||||
return el.getAttributeSafe("disabled") != null;
|
return el.getAttributeSafe(comptime .wrap("disabled")) != null;
|
||||||
},
|
},
|
||||||
.enabled => {
|
.enabled => {
|
||||||
return el.getAttributeSafe("disabled") == null;
|
return el.getAttributeSafe(comptime .wrap("disabled")) == null;
|
||||||
},
|
},
|
||||||
.indeterminate => return false,
|
.indeterminate => return false,
|
||||||
|
|
||||||
@@ -537,19 +537,19 @@ fn matchesPseudoClass(el: *Node.Element, pseudo: Selector.PseudoClass, scope: *N
|
|||||||
.valid => return false,
|
.valid => return false,
|
||||||
.invalid => return false,
|
.invalid => return false,
|
||||||
.required => {
|
.required => {
|
||||||
return el.getAttributeSafe("required") != null;
|
return el.getAttributeSafe(comptime .wrap("required")) != null;
|
||||||
},
|
},
|
||||||
.optional => {
|
.optional => {
|
||||||
return el.getAttributeSafe("required") == null;
|
return el.getAttributeSafe(comptime .wrap("required")) == null;
|
||||||
},
|
},
|
||||||
.in_range => return false,
|
.in_range => return false,
|
||||||
.out_of_range => return false,
|
.out_of_range => return false,
|
||||||
.placeholder_shown => return false,
|
.placeholder_shown => return false,
|
||||||
.read_only => {
|
.read_only => {
|
||||||
return el.getAttributeSafe("readonly") != null;
|
return el.getAttributeSafe(comptime .wrap("readonly")) != null;
|
||||||
},
|
},
|
||||||
.read_write => {
|
.read_write => {
|
||||||
return el.getAttributeSafe("readonly") == null;
|
return el.getAttributeSafe(comptime .wrap("readonly")) == null;
|
||||||
},
|
},
|
||||||
.default => return false,
|
.default => return false,
|
||||||
|
|
||||||
@@ -571,10 +571,10 @@ fn matchesPseudoClass(el: *Node.Element, pseudo: Selector.PseudoClass, scope: *N
|
|||||||
.visited => return false,
|
.visited => return false,
|
||||||
.any_link => {
|
.any_link => {
|
||||||
if (el.getTag() != .anchor) return false;
|
if (el.getTag() != .anchor) return false;
|
||||||
return el.getAttributeSafe("href") != null;
|
return el.getAttributeSafe(comptime .wrap("href")) != null;
|
||||||
},
|
},
|
||||||
.target => {
|
.target => {
|
||||||
const element_id = el.getAttributeSafe("id") orelse return false;
|
const element_id = el.getAttributeSafe(comptime .wrap("id")) orelse return false;
|
||||||
const location = page.document._location orelse return false;
|
const location = page.document._location orelse return false;
|
||||||
const hash = location.getHash();
|
const hash = location.getHash();
|
||||||
if (hash.len <= 1) return false;
|
if (hash.len <= 1) return false;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
// 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 String = @import("../../../string.zig").String;
|
||||||
|
|
||||||
const Page = @import("../../Page.zig");
|
const Page = @import("../../Page.zig");
|
||||||
|
|
||||||
@@ -46,6 +47,7 @@ const ParseError = error{
|
|||||||
UnknownPseudoClass,
|
UnknownPseudoClass,
|
||||||
InvalidTagSelector,
|
InvalidTagSelector,
|
||||||
InvalidSelector,
|
InvalidSelector,
|
||||||
|
StringTooLarge,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parseList(arena: Allocator, input: []const u8, page: *Page) ParseError![]const Selector.Selector {
|
pub fn parseList(arena: Allocator, input: []const u8, page: *Page) ParseError![]const Selector.Selector {
|
||||||
@@ -844,9 +846,10 @@ fn attribute(self: *Parser, arena: Allocator, page: *Page) !Selector.Attribute {
|
|||||||
_ = self.skipSpaces();
|
_ = self.skipSpaces();
|
||||||
|
|
||||||
const attr_name = try self.attributeName();
|
const attr_name = try self.attributeName();
|
||||||
|
|
||||||
// Normalize the name to lowercase for fast matching (consistent with Attribute.normalizeNameForLookup)
|
// Normalize the name to lowercase for fast matching (consistent with Attribute.normalizeNameForLookup)
|
||||||
const normalized = try Attribute.normalizeNameForLookup(attr_name, page);
|
const normalized = try Attribute.normalizeNameForLookup(.wrap(attr_name), page);
|
||||||
const name = try arena.dupe(u8, normalized);
|
const name = try normalized.dupe(arena);
|
||||||
var case_insensitive = false;
|
var case_insensitive = false;
|
||||||
_ = self.skipSpaces();
|
_ = self.skipSpaces();
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
|
const String = @import("../../../string.zig").String;
|
||||||
|
|
||||||
const Parser = @import("Parser.zig");
|
const Parser = @import("Parser.zig");
|
||||||
const Node = @import("../Node.zig");
|
const Node = @import("../Node.zig");
|
||||||
const Page = @import("../../Page.zig");
|
const Page = @import("../../Page.zig");
|
||||||
@@ -117,7 +119,7 @@ pub const Part = union(enum) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const Attribute = struct {
|
pub const Attribute = struct {
|
||||||
name: []const u8,
|
name: String,
|
||||||
matcher: AttributeMatcher,
|
matcher: AttributeMatcher,
|
||||||
case_insensitive: bool,
|
case_insensitive: bool,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -289,7 +289,7 @@ pub const Writer = struct {
|
|||||||
},
|
},
|
||||||
.input => {
|
.input => {
|
||||||
const input = el.as(DOMNode.Element.Html.Input);
|
const input = el.as(DOMNode.Element.Html.Input);
|
||||||
const is_disabled = el.hasAttributeSafe("disabled");
|
const is_disabled = el.hasAttributeSafe(comptime .wrap("disabled"));
|
||||||
|
|
||||||
switch (input._input_type) {
|
switch (input._input_type) {
|
||||||
.text, .email, .tel, .url, .search, .password, .number => {
|
.text, .email, .tel, .url, .search, .password, .number => {
|
||||||
@@ -305,8 +305,8 @@ pub const Writer = struct {
|
|||||||
try self.writeAXProperty(.{ .name = .settable, .value = .{ .booleanOrUndefined = true } }, w);
|
try self.writeAXProperty(.{ .name = .settable, .value = .{ .booleanOrUndefined = true } }, w);
|
||||||
}
|
}
|
||||||
try self.writeAXProperty(.{ .name = .multiline, .value = .{ .boolean = false } }, w);
|
try self.writeAXProperty(.{ .name = .multiline, .value = .{ .boolean = false } }, w);
|
||||||
try self.writeAXProperty(.{ .name = .readonly, .value = .{ .boolean = el.hasAttributeSafe("readonly") } }, w);
|
try self.writeAXProperty(.{ .name = .readonly, .value = .{ .boolean = el.hasAttributeSafe(comptime .wrap("readonly")) } }, w);
|
||||||
try self.writeAXProperty(.{ .name = .required, .value = .{ .boolean = el.hasAttributeSafe("required") } }, w);
|
try self.writeAXProperty(.{ .name = .required, .value = .{ .boolean = el.hasAttributeSafe(comptime .wrap("required")) } }, w);
|
||||||
},
|
},
|
||||||
.button, .submit, .reset, .image => {
|
.button, .submit, .reset, .image => {
|
||||||
try self.writeAXProperty(.{ .name = .invalid, .value = .{ .token = "false" } }, w);
|
try self.writeAXProperty(.{ .name = .invalid, .value = .{ .token = "false" } }, w);
|
||||||
@@ -319,14 +319,14 @@ pub const Writer = struct {
|
|||||||
if (!is_disabled) {
|
if (!is_disabled) {
|
||||||
try self.writeAXProperty(.{ .name = .focusable, .value = .{ .booleanOrUndefined = true } }, w);
|
try self.writeAXProperty(.{ .name = .focusable, .value = .{ .booleanOrUndefined = true } }, w);
|
||||||
}
|
}
|
||||||
const is_checked = el.hasAttributeSafe("checked");
|
const is_checked = el.hasAttributeSafe(comptime .wrap("checked"));
|
||||||
try self.writeAXProperty(.{ .name = .checked, .value = .{ .token = if (is_checked) "true" else "false" } }, w);
|
try self.writeAXProperty(.{ .name = .checked, .value = .{ .token = if (is_checked) "true" else "false" } }, w);
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.textarea => {
|
.textarea => {
|
||||||
const is_disabled = el.hasAttributeSafe("disabled");
|
const is_disabled = el.hasAttributeSafe(comptime .wrap("disabled"));
|
||||||
|
|
||||||
try self.writeAXProperty(.{ .name = .invalid, .value = .{ .token = "false" } }, w);
|
try self.writeAXProperty(.{ .name = .invalid, .value = .{ .token = "false" } }, w);
|
||||||
if (!is_disabled) {
|
if (!is_disabled) {
|
||||||
@@ -337,11 +337,11 @@ pub const Writer = struct {
|
|||||||
try self.writeAXProperty(.{ .name = .settable, .value = .{ .booleanOrUndefined = true } }, w);
|
try self.writeAXProperty(.{ .name = .settable, .value = .{ .booleanOrUndefined = true } }, w);
|
||||||
}
|
}
|
||||||
try self.writeAXProperty(.{ .name = .multiline, .value = .{ .boolean = true } }, w);
|
try self.writeAXProperty(.{ .name = .multiline, .value = .{ .boolean = true } }, w);
|
||||||
try self.writeAXProperty(.{ .name = .readonly, .value = .{ .boolean = el.hasAttributeSafe("readonly") } }, w);
|
try self.writeAXProperty(.{ .name = .readonly, .value = .{ .boolean = el.hasAttributeSafe(comptime .wrap("readonly")) } }, w);
|
||||||
try self.writeAXProperty(.{ .name = .required, .value = .{ .boolean = el.hasAttributeSafe("required") } }, w);
|
try self.writeAXProperty(.{ .name = .required, .value = .{ .boolean = el.hasAttributeSafe(comptime .wrap("required")) } }, w);
|
||||||
},
|
},
|
||||||
.select => {
|
.select => {
|
||||||
const is_disabled = el.hasAttributeSafe("disabled");
|
const is_disabled = el.hasAttributeSafe(comptime .wrap("disabled"));
|
||||||
|
|
||||||
try self.writeAXProperty(.{ .name = .invalid, .value = .{ .token = "false" } }, w);
|
try self.writeAXProperty(.{ .name = .invalid, .value = .{ .token = "false" } }, w);
|
||||||
if (!is_disabled) {
|
if (!is_disabled) {
|
||||||
@@ -385,7 +385,7 @@ pub const Writer = struct {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
.button => {
|
.button => {
|
||||||
const is_disabled = el.hasAttributeSafe("disabled");
|
const is_disabled = el.hasAttributeSafe(comptime .wrap("disabled"));
|
||||||
try self.writeAXProperty(.{ .name = .invalid, .value = .{ .token = "false" } }, w);
|
try self.writeAXProperty(.{ .name = .invalid, .value = .{ .token = "false" } }, w);
|
||||||
if (!is_disabled) {
|
if (!is_disabled) {
|
||||||
try self.writeAXProperty(.{ .name = .focusable, .value = .{ .booleanOrUndefined = true } }, w);
|
try self.writeAXProperty(.{ .name = .focusable, .value = .{ .booleanOrUndefined = true } }, w);
|
||||||
@@ -629,10 +629,10 @@ pub const AXRole = enum(u8) {
|
|||||||
},
|
},
|
||||||
.textarea => .textbox,
|
.textarea => .textbox,
|
||||||
.select => {
|
.select => {
|
||||||
if (el.getAttributeSafe("multiple") != null) {
|
if (el.getAttributeSafe(comptime .wrap("multiple")) != null) {
|
||||||
return .listbox;
|
return .listbox;
|
||||||
}
|
}
|
||||||
if (el.getAttributeSafe("size")) |size| {
|
if (el.getAttributeSafe(comptime .wrap("size"))) |size| {
|
||||||
if (!std.ascii.eqlIgnoreCase(size, "1")) {
|
if (!std.ascii.eqlIgnoreCase(size, "1")) {
|
||||||
return .listbox;
|
return .listbox;
|
||||||
}
|
}
|
||||||
@@ -649,7 +649,7 @@ pub const AXRole = enum(u8) {
|
|||||||
|
|
||||||
// Interactive Elements
|
// Interactive Elements
|
||||||
.anchor, .area => {
|
.anchor, .area => {
|
||||||
if (el.getAttributeSafe("href") == null) {
|
if (el.getAttributeSafe(comptime .wrap("href")) == null) {
|
||||||
return .none;
|
return .none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -669,7 +669,7 @@ pub const AXRole = enum(u8) {
|
|||||||
.thead, .tbody, .tfoot => .rowgroup,
|
.thead, .tbody, .tfoot => .rowgroup,
|
||||||
.tr => .row,
|
.tr => .row,
|
||||||
.th => {
|
.th => {
|
||||||
if (el.getAttributeSafe("scope")) |scope| {
|
if (el.getAttributeSafe(comptime .wrap("scope"))) |scope| {
|
||||||
if (std.ascii.eqlIgnoreCase(scope, "row")) {
|
if (std.ascii.eqlIgnoreCase(scope, "row")) {
|
||||||
return .rowheader;
|
return .rowheader;
|
||||||
}
|
}
|
||||||
@@ -722,7 +722,7 @@ pub fn fromNode(dom: *DOMNode) AXNode {
|
|||||||
break :blk null;
|
break :blk null;
|
||||||
}
|
}
|
||||||
const elt = dom.as(DOMNode.Element);
|
const elt = dom.as(DOMNode.Element);
|
||||||
break :blk elt.getAttributeSafe("role");
|
break :blk elt.getAttributeSafe(comptime .wrap("role"));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -759,7 +759,7 @@ fn writeName(axnode: AXNode, w: anytype, page: *Page) !?AXSource {
|
|||||||
},
|
},
|
||||||
.element => |el| {
|
.element => |el| {
|
||||||
// Handle aria-labelledby attribute (highest priority)
|
// Handle aria-labelledby attribute (highest priority)
|
||||||
if (el.getAttributeSafe("aria-labelledby")) |labelledby| {
|
if (el.getAttributeSafe(.wrap("aria-labelledby"))) |labelledby| {
|
||||||
// Get the document to look up elements by ID
|
// Get the document to look up elements by ID
|
||||||
const doc = node.ownerDocument(page) orelse return null;
|
const doc = node.ownerDocument(page) orelse return null;
|
||||||
|
|
||||||
@@ -786,12 +786,12 @@ fn writeName(axnode: AXNode, w: anytype, page: *Page) !?AXSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (el.getAttributeSafe("aria-label")) |aria_label| {
|
if (el.getAttributeSafe(comptime .wrap("aria-label"))) |aria_label| {
|
||||||
try w.write(aria_label);
|
try w.write(aria_label);
|
||||||
return .aria_label;
|
return .aria_label;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (el.getAttributeSafe("alt")) |alt| {
|
if (el.getAttributeSafe(comptime .wrap("alt"))) |alt| {
|
||||||
try w.write(alt);
|
try w.write(alt);
|
||||||
return .alt;
|
return .alt;
|
||||||
}
|
}
|
||||||
@@ -836,12 +836,12 @@ fn writeName(axnode: AXNode, w: anytype, page: *Page) !?AXSource {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if (el.getAttributeSafe("title")) |title| {
|
if (el.getAttributeSafe(comptime .wrap("title"))) |title| {
|
||||||
try w.write(title);
|
try w.write(title);
|
||||||
return .title;
|
return .title;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (el.getAttributeSafe("placeholder")) |placeholder| {
|
if (el.getAttributeSafe(comptime .wrap("placeholder"))) |placeholder| {
|
||||||
try w.write(placeholder);
|
try w.write(placeholder);
|
||||||
return .placeholder;
|
return .placeholder;
|
||||||
}
|
}
|
||||||
@@ -857,17 +857,17 @@ fn writeName(axnode: AXNode, w: anytype, page: *Page) !?AXSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn isHidden(elt: *DOMNode.Element) bool {
|
fn isHidden(elt: *DOMNode.Element) bool {
|
||||||
if (elt.getAttributeSafe("aria-hidden")) |value| {
|
if (elt.getAttributeSafe(comptime .wrap("aria-hidden"))) |value| {
|
||||||
if (std.mem.eql(u8, value, "true")) {
|
if (std.mem.eql(u8, value, "true")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elt.hasAttributeSafe("hidden")) {
|
if (elt.hasAttributeSafe(comptime .wrap("hidden"))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elt.hasAttributeSafe("inert")) {
|
if (elt.hasAttributeSafe(comptime .wrap("inert"))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -940,7 +940,7 @@ fn isIgnore(self: AXNode, page: *Page) bool {
|
|||||||
// zig fmt: on
|
// zig fmt: on
|
||||||
.img => {
|
.img => {
|
||||||
// Check for empty decorative images
|
// Check for empty decorative images
|
||||||
const alt_ = elt.getAttributeSafe("alt");
|
const alt_ = elt.getAttributeSafe(comptime .wrap("alt"));
|
||||||
if (alt_ == null or alt_.?.len == 0) {
|
if (alt_ == null or alt_.?.len == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -967,9 +967,9 @@ fn isIgnore(self: AXNode, page: *Page) bool {
|
|||||||
|
|
||||||
// Generic containers with no semantic value
|
// Generic containers with no semantic value
|
||||||
if (tag == .div or tag == .span) {
|
if (tag == .div or tag == .span) {
|
||||||
const has_role = elt.hasAttributeSafe("role");
|
const has_role = elt.hasAttributeSafe(comptime .wrap("role"));
|
||||||
const has_aria_label = elt.hasAttributeSafe("aria-label");
|
const has_aria_label = elt.hasAttributeSafe(comptime .wrap("aria-label"));
|
||||||
const has_aria_labelledby = elt.hasAttributeSafe("aria-labelledby");
|
const has_aria_labelledby = elt.hasAttributeSafe(.wrap("aria-labelledby"));
|
||||||
|
|
||||||
if (!has_role and !has_aria_label and !has_aria_labelledby) {
|
if (!has_role and !has_aria_label and !has_aria_labelledby) {
|
||||||
// Check if it has any non-ignored children
|
// Check if it has any non-ignored children
|
||||||
|
|||||||
@@ -344,7 +344,7 @@ test "cdp Node: Registry register" {
|
|||||||
var doc = page.window._document;
|
var doc = page.window._document;
|
||||||
|
|
||||||
{
|
{
|
||||||
const dom_node = (try doc.querySelector("#a1", page)).?.asNode();
|
const dom_node = (try doc.querySelector(.wrap("#a1"), page)).?.asNode();
|
||||||
const node = try registry.register(dom_node);
|
const node = try registry.register(dom_node);
|
||||||
const n1b = registry.lookup_by_id.get(1).?;
|
const n1b = registry.lookup_by_id.get(1).?;
|
||||||
const n1c = registry.lookup_by_node.get(node.dom).?;
|
const n1c = registry.lookup_by_node.get(node.dom).?;
|
||||||
@@ -356,7 +356,7 @@ test "cdp Node: Registry register" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const dom_node = (try doc.querySelector("p", page)).?.asNode();
|
const dom_node = (try doc.querySelector(.wrap ("p"), page)).?.asNode();
|
||||||
const node = try registry.register(dom_node);
|
const node = try registry.register(dom_node);
|
||||||
const n1b = registry.lookup_by_id.get(2).?;
|
const n1b = registry.lookup_by_id.get(2).?;
|
||||||
const n1c = registry.lookup_by_node.get(node.dom).?;
|
const n1c = registry.lookup_by_node.get(node.dom).?;
|
||||||
@@ -400,18 +400,18 @@ test "cdp Node: search list" {
|
|||||||
defer page._session.removePage();
|
defer page._session.removePage();
|
||||||
var doc = page.window._document;
|
var doc = page.window._document;
|
||||||
|
|
||||||
const s1 = try search_list.create((try doc.querySelectorAll("a", page))._nodes);
|
const s1 = try search_list.create((try doc.querySelectorAll(.wrap ("a"), page))._nodes);
|
||||||
try testing.expectEqual("1", s1.name);
|
try testing.expectEqual("1", s1.name);
|
||||||
try testing.expectEqualSlices(u32, &.{ 1, 2 }, s1.node_ids);
|
try testing.expectEqualSlices(u32, &.{ 1, 2 }, s1.node_ids);
|
||||||
|
|
||||||
try testing.expectEqual(2, registry.lookup_by_id.count());
|
try testing.expectEqual(2, registry.lookup_by_id.count());
|
||||||
try testing.expectEqual(2, registry.lookup_by_node.count());
|
try testing.expectEqual(2, registry.lookup_by_node.count());
|
||||||
|
|
||||||
const s2 = try search_list.create((try doc.querySelectorAll("#a1", page))._nodes);
|
const s2 = try search_list.create((try doc.querySelectorAll(.wrap ("#a1"), page))._nodes);
|
||||||
try testing.expectEqual("2", s2.name);
|
try testing.expectEqual("2", s2.name);
|
||||||
try testing.expectEqualSlices(u32, &.{1}, s2.node_ids);
|
try testing.expectEqualSlices(u32, &.{1}, s2.node_ids);
|
||||||
|
|
||||||
const s3 = try search_list.create((try doc.querySelectorAll("#a2", page))._nodes);
|
const s3 = try search_list.create((try doc.querySelectorAll(.wrap ("#a2"), page))._nodes);
|
||||||
try testing.expectEqual("3", s3.name);
|
try testing.expectEqual("3", s3.name);
|
||||||
try testing.expectEqualSlices(u32, &.{2}, s3.node_ids);
|
try testing.expectEqualSlices(u32, &.{2}, s3.node_ids);
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ pub const expectEqual = base.expectEqual;
|
|||||||
pub const expectError = base.expectError;
|
pub const expectError = base.expectError;
|
||||||
pub const expectEqualSlices = base.expectEqualSlices;
|
pub const expectEqualSlices = base.expectEqualSlices;
|
||||||
pub const pageTest = base.pageTest;
|
pub const pageTest = base.pageTest;
|
||||||
|
pub const newString = base.newString;
|
||||||
|
|
||||||
const Client = struct {
|
const Client = struct {
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
|
|||||||
@@ -271,17 +271,21 @@ pub const Header = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const Headers = struct {
|
pub const Headers = struct {
|
||||||
headers: *c.curl_slist,
|
headers: ?*c.curl_slist,
|
||||||
cookies: ?[*c]const u8,
|
cookies: ?[*c]const u8,
|
||||||
|
|
||||||
pub fn init(user_agent: [:0]const u8) !Headers {
|
pub fn init(user_agent: [:0]const u8) !Headers {
|
||||||
const header_list = c.curl_slist_append(null, user_agent);
|
const header_list = c.curl_slist_append(null, user_agent);
|
||||||
if (header_list == null) return error.OutOfMemory;
|
if (header_list == null) {
|
||||||
|
return error.OutOfMemory;
|
||||||
|
}
|
||||||
return .{ .headers = header_list, .cookies = null };
|
return .{ .headers = header_list, .cookies = null };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *const Headers) void {
|
pub fn deinit(self: *const Headers) void {
|
||||||
c.curl_slist_free_all(self.headers);
|
if (self.headers) |hdr| {
|
||||||
|
c.curl_slist_free_all(hdr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(self: *Headers, header: [*c]const u8) !void {
|
pub fn add(self: *Headers, header: [*c]const u8) !void {
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ const std = @import("std");
|
|||||||
const js = @import("browser/js/js.zig");
|
const js = @import("browser/js/js.zig");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
const M = @This();
|
||||||
|
|
||||||
// German-string (small string optimization)
|
// German-string (small string optimization)
|
||||||
pub const String = packed struct {
|
pub const String = packed struct {
|
||||||
len: i32,
|
len: i32,
|
||||||
@@ -34,6 +36,48 @@ pub const String = packed struct {
|
|||||||
pub const empty = String{ .len = 0, .payload = .{ .content = @splat(0) } };
|
pub const empty = String{ .len = 0, .payload = .{ .content = @splat(0) } };
|
||||||
pub const deleted = String{ .len = tombstone, .payload = .{ .content = @splat(0) } };
|
pub const deleted = String{ .len = tombstone, .payload = .{ .content = @splat(0) } };
|
||||||
|
|
||||||
|
// for packages that already have String imported, then can use String.Global
|
||||||
|
pub const Global = M.Global;
|
||||||
|
|
||||||
|
// Wraps an existing string. For strings with len <= 12, this can be done at
|
||||||
|
// comptime: comptime String.wrap("id");
|
||||||
|
// For strings with len > 12, this must be done at runtime even for a string
|
||||||
|
// literal. This is because, at comptime, we do not have a ptr for data and
|
||||||
|
// thus can't store it.
|
||||||
|
pub fn wrap(input: anytype) String {
|
||||||
|
if (@inComptime()) {
|
||||||
|
const l = input.len;
|
||||||
|
if (l > 12) {
|
||||||
|
@compileError("Comptime string must be <= 12 bytes (SSO only): " ++ input);
|
||||||
|
}
|
||||||
|
|
||||||
|
var content: [12]u8 = @splat(0);
|
||||||
|
@memcpy(content[0..l], input);
|
||||||
|
return .{ .len = @intCast(l), .payload = .{ .content = content } };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runtime path - handle both String and []const u8
|
||||||
|
if (@TypeOf(input) == String) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
const l = input.len;
|
||||||
|
|
||||||
|
if (l <= 12) {
|
||||||
|
var content: [12]u8 = @splat(0);
|
||||||
|
@memcpy(content[0..l], input);
|
||||||
|
return .{ .len = @intCast(l), .payload = .{ .content = content } };
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.len = @intCast(l),
|
||||||
|
.payload = .{ .heap = .{
|
||||||
|
.prefix = input[0..4].*,
|
||||||
|
.ptr = input.ptr,
|
||||||
|
} },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub const InitOpts = struct {
|
pub const InitOpts = struct {
|
||||||
dupe: bool = true,
|
dupe: bool = true,
|
||||||
};
|
};
|
||||||
@@ -47,13 +91,11 @@ pub const String = packed struct {
|
|||||||
@memcpy(content[0..l], input);
|
@memcpy(content[0..l], input);
|
||||||
return .{ .len = @intCast(l), .payload = .{ .content = content } };
|
return .{ .len = @intCast(l), .payload = .{ .content = content } };
|
||||||
}
|
}
|
||||||
var prefix: [4]u8 = @splat(0);
|
|
||||||
@memcpy(&prefix, input[0..4]);
|
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.len = @intCast(l),
|
.len = @intCast(l),
|
||||||
.payload = .{ .heap = .{
|
.payload = .{ .heap = .{
|
||||||
.prefix = prefix,
|
.prefix = input[0..4].*,
|
||||||
.ptr = (intern(input) orelse (if (opts.dupe) (try allocator.dupe(u8, input)) else input)).ptr,
|
.ptr = (intern(input) orelse (if (opts.dupe) (try allocator.dupe(u8, input)) else input)).ptr,
|
||||||
} },
|
} },
|
||||||
};
|
};
|
||||||
@@ -66,9 +108,8 @@ pub const String = packed struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fromJS(allocator: Allocator, js_obj: js.Object) !String {
|
pub fn dupe(self: *const String, allocator: Allocator) !String {
|
||||||
const js_str = js_obj.toString();
|
return .init(allocator, self.str(), .{ .dupe = true });
|
||||||
return init(allocator, js_str, .{});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn str(self: *const String) []const u8 {
|
pub fn str(self: *const String) []const u8 {
|
||||||
@@ -96,20 +137,22 @@ pub const String = packed struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn eql(a: String, b: String) bool {
|
pub fn eql(a: String, b: String) bool {
|
||||||
if (a.len != b.len or a.len < 0 or b.len < 0) {
|
if (@as(*const u64, @ptrCast(&a)).* != @as(*const u64, @ptrCast(&b)).*) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a.len <= 12) {
|
const len = a.len;
|
||||||
|
if (len < 0 or b.len < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len <= 12) {
|
||||||
return @reduce(.And, a.payload.content == b.payload.content);
|
return @reduce(.And, a.payload.content == b.payload.content);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (@reduce(.And, a.payload.heap.prefix == b.payload.heap.prefix) == false) {
|
// a.len == b.len at this point
|
||||||
return false;
|
const al: usize = @intCast(len);
|
||||||
}
|
const bl: usize = @intCast(len);
|
||||||
|
|
||||||
const al: usize = @intCast(a.len);
|
|
||||||
const bl: usize = @intCast(a.len);
|
|
||||||
return std.mem.eql(u8, a.payload.heap.ptr[0..al], b.payload.heap.ptr[0..bl]);
|
return std.mem.eql(u8, a.payload.heap.ptr[0..al], b.payload.heap.ptr[0..bl]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,6 +231,13 @@ pub const String = packed struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Discriminatory type that signals the bridge to use arena instead of call_arena
|
||||||
|
// Use this for strings that need to persist beyond the current call
|
||||||
|
// The caller can unwrap and store just the underlying .str field
|
||||||
|
pub const Global = struct {
|
||||||
|
str: String,
|
||||||
|
};
|
||||||
|
|
||||||
fn asUint(comptime string: anytype) std.meta.Int(
|
fn asUint(comptime string: anytype) std.meta.Int(
|
||||||
.unsigned,
|
.unsigned,
|
||||||
@bitSizeOf(@TypeOf(string.*)) - 8, // (- 8) to exclude sentinel 0
|
@bitSizeOf(@TypeOf(string.*)) - 8, // (- 8) to exclude sentinel 0
|
||||||
|
|||||||
@@ -176,6 +176,11 @@ pub fn print(comptime fmt: []const u8, args: anytype) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const String = @import("string.zig").String;
|
||||||
|
pub fn newString(str: []const u8) String {
|
||||||
|
return String.init(arena_allocator, str, .{}) catch unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
pub const Random = struct {
|
pub const Random = struct {
|
||||||
var instance: ?std.Random.DefaultPrng = null;
|
var instance: ?std.Random.DefaultPrng = null;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user