forms: extract normalizeMethod / normalizeEnctype helpers

The "limited to only known values" canonicalization (per WHATWG HTML
§2.2.2) was duplicated five times: Form.getMethod + Form.getEnctype +
{Button,Input}.{getFormMethod,getFormEnctype}. Each callsite differed
only in the missing-value default ("" for submitter overrides, "get" /
"application/x-www-form-urlencoded" for the form-side).

Extract into two pub helpers on Form.zig taking the attribute slice +
the missing-value default. The five callers collapse to one-liners.

Behavior-preserving: existing form.html / button.html / input-attrs.html
fixtures all pass unchanged; full suite 637/637 green.

Net: -36 LOC.
This commit is contained in:
Navid EMAD
2026-05-13 17:58:55 +02:00
parent 2fdc82aa05
commit cedfdba0d7
3 changed files with 30 additions and 66 deletions

View File

@@ -144,19 +144,7 @@ pub fn setFormAction(self: *Button, value: []const u8, frame: *Frame) !void {
}
pub fn getFormEnctype(self: *const Button) []const u8 {
const enctype = self.asConstElement().getAttributeSafe(comptime .wrap("formenctype")) orelse return "";
if (std.ascii.eqlIgnoreCase(enctype, "multipart/form-data")) {
return "multipart/form-data";
}
if (std.ascii.eqlIgnoreCase(enctype, "text/plain")) {
return "text/plain";
}
if (std.ascii.eqlIgnoreCase(enctype, "application/x-www-form-urlencoded")) {
return "application/x-www-form-urlencoded";
}
// invalid -> invalid-value default state (application/x-www-form-urlencoded)
return "application/x-www-form-urlencoded";
return Form.normalizeEnctype(self.asConstElement().getAttributeSafe(comptime .wrap("formenctype")), "");
}
pub fn setFormEnctype(self: *Button, value: []const u8, frame: *Frame) !void {
@@ -164,16 +152,7 @@ pub fn setFormEnctype(self: *Button, value: []const u8, frame: *Frame) !void {
}
pub fn getFormMethod(self: *const Button) []const u8 {
const method = self.asConstElement().getAttributeSafe(comptime .wrap("formmethod")) orelse return "";
if (std.ascii.eqlIgnoreCase(method, "post")) {
return "post";
}
if (std.ascii.eqlIgnoreCase(method, "dialog")) {
return "dialog";
}
// "get" or invalid -> invalid-value default state (get)
return "get";
return Form.normalizeMethod(self.asConstElement().getAttributeSafe(comptime .wrap("formmethod")), "");
}
pub fn setFormMethod(self: *Button, value: []const u8, frame: *Frame) !void {

View File

@@ -54,19 +54,34 @@ pub fn setName(self: *Form, name: []const u8, frame: *Frame) !void {
try self.asElement().setAttributeSafe(comptime .wrap("name"), .wrap(name), frame);
}
pub fn getMethod(self: *const Form) []const u8 {
const method = self.asConstElement().getAttributeSafe(comptime .wrap("method")) orelse return "get";
if (std.ascii.eqlIgnoreCase(method, "post")) {
return "post";
}
if (std.ascii.eqlIgnoreCase(method, "dialog")) {
return "dialog";
}
// invalid, or it was get all along
/// Canonicalize the `method` content attribute (or its `formmethod` submitter
/// override) per WHATWG HTML "limited to only known values":
/// - missing → returns `missing_default`
/// - "post" / "dialog" → returns the lowercased keyword
/// - empty / invalid / "get" → returns "get" (invalid-value default)
pub fn normalizeMethod(attr: ?[]const u8, missing_default: []const u8) []const u8 {
const method = attr orelse return missing_default;
if (std.ascii.eqlIgnoreCase(method, "post")) return "post";
if (std.ascii.eqlIgnoreCase(method, "dialog")) return "dialog";
return "get";
}
/// Canonicalize the `enctype` content attribute (or its `formenctype` submitter
/// override) per WHATWG HTML "limited to only known values":
/// - missing → returns `missing_default`
/// - "multipart/form-data" / "text/plain" → returns the lowercased keyword
/// - empty / invalid / urlencoded → returns "application/x-www-form-urlencoded"
pub fn normalizeEnctype(attr: ?[]const u8, missing_default: []const u8) []const u8 {
const enctype = attr orelse return missing_default;
if (std.ascii.eqlIgnoreCase(enctype, "multipart/form-data")) return "multipart/form-data";
if (std.ascii.eqlIgnoreCase(enctype, "text/plain")) return "text/plain";
return "application/x-www-form-urlencoded";
}
pub fn getMethod(self: *const Form) []const u8 {
return normalizeMethod(self.asConstElement().getAttributeSafe(comptime .wrap("method")), "get");
}
pub fn setMethod(self: *Form, method: []const u8, frame: *Frame) !void {
try self.asElement().setAttributeSafe(comptime .wrap("method"), .wrap(method), frame);
}
@@ -120,16 +135,7 @@ pub fn setAcceptCharset(self: *Form, value: []const u8, frame: *Frame) !void {
}
pub fn getEnctype(self: *const Form) []const u8 {
const enctype = self.asConstElement().getAttributeSafe(comptime .wrap("enctype")) orelse return "application/x-www-form-urlencoded";
if (std.ascii.eqlIgnoreCase(enctype, "multipart/form-data")) {
return "multipart/form-data";
}
if (std.ascii.eqlIgnoreCase(enctype, "text/plain")) {
return "text/plain";
}
// invalid, or it was application/x-www-form-urlencoded all along
return "application/x-www-form-urlencoded";
return normalizeEnctype(self.asConstElement().getAttributeSafe(comptime .wrap("enctype")), "application/x-www-form-urlencoded");
}
pub fn setEnctype(self: *Form, value: []const u8, frame: *Frame) !void {

View File

@@ -852,19 +852,7 @@ pub fn setFormAction(self: *Input, value: []const u8, frame: *Frame) !void {
}
pub fn getFormEnctype(self: *const Input) []const u8 {
const enctype = self.asConstElement().getAttributeSafe(comptime .wrap("formenctype")) orelse return "";
if (std.ascii.eqlIgnoreCase(enctype, "multipart/form-data")) {
return "multipart/form-data";
}
if (std.ascii.eqlIgnoreCase(enctype, "text/plain")) {
return "text/plain";
}
if (std.ascii.eqlIgnoreCase(enctype, "application/x-www-form-urlencoded")) {
return "application/x-www-form-urlencoded";
}
// invalid -> invalid-value default state (application/x-www-form-urlencoded)
return "application/x-www-form-urlencoded";
return Form.normalizeEnctype(self.asConstElement().getAttributeSafe(comptime .wrap("formenctype")), "");
}
pub fn setFormEnctype(self: *Input, value: []const u8, frame: *Frame) !void {
@@ -872,16 +860,7 @@ pub fn setFormEnctype(self: *Input, value: []const u8, frame: *Frame) !void {
}
pub fn getFormMethod(self: *const Input) []const u8 {
const method = self.asConstElement().getAttributeSafe(comptime .wrap("formmethod")) orelse return "";
if (std.ascii.eqlIgnoreCase(method, "post")) {
return "post";
}
if (std.ascii.eqlIgnoreCase(method, "dialog")) {
return "dialog";
}
// "get" or invalid -> invalid-value default state (get)
return "get";
return Form.normalizeMethod(self.asConstElement().getAttributeSafe(comptime .wrap("formmethod")), "");
}
pub fn setFormMethod(self: *Input, value: []const u8, frame: *Frame) !void {