From 747a8ad09c41c501cfb8855eb07a4250f69251df Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Mon, 2 Jun 2025 11:27:44 +0800 Subject: [PATCH] Submit input and button submits can now submit forms --- src/browser/html/form.zig | 4 ---- src/browser/page.zig | 43 +++++++++++++++++++++++++++++++++++ src/browser/xhr/form_data.zig | 14 ++++++++++++ 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/browser/html/form.zig b/src/browser/html/form.zig index cd90589c..13443667 100644 --- a/src/browser/html/form.zig +++ b/src/browser/html/form.zig @@ -32,10 +32,6 @@ pub const HTMLFormElement = struct { return page.submitForm(self, null); } - pub fn _requestSubmit(self: *parser.Form) !void { - try parser.formElementSubmit(self); - } - pub fn _reset(self: *parser.Form) !void { try parser.formElementReset(self); } diff --git a/src/browser/page.zig b/src/browser/page.zig index e8f29110..ae313eaa 100644 --- a/src/browser/page.zig +++ b/src/browser/page.zig @@ -553,6 +553,25 @@ pub const Page = struct { const href = (try parser.elementGetAttribute(element, "href")) orelse return; try self.navigateFromWebAPI(href, .{}); }, + .input => { + const element: *parser.Element = @ptrCast(node); + const input_type = (try parser.elementGetAttribute(element, "type")) orelse return; + if (std.ascii.eqlIgnoreCase(input_type, "submit")) { + return self.elementSubmitForm(element); + } + }, + .button => { + const element: *parser.Element = @ptrCast(node); + const button_type = (try parser.elementGetAttribute(element, "type")) orelse return; + if (std.ascii.eqlIgnoreCase(button_type, "submit")) { + return self.elementSubmitForm(element); + } + if (std.ascii.eqlIgnoreCase(button_type, "reset")) { + if (try self.formForElement(element)) |form| { + return parser.formElementReset(form); + } + } + }, else => {}, } } @@ -616,6 +635,30 @@ pub const Page = struct { try self.navigateFromWebAPI(action, opts); } + + fn elementSubmitForm(self: *Page, element: *parser.Element) !void { + const form = (try self.formForElement(element)) orelse return; + return self.submitForm(@ptrCast(form), @ptrCast(element)); + } + + fn formForElement(self: *Page, element: *parser.Element) !?*parser.Form { + if (try parser.elementGetAttribute(element, "disabled") != null) { + return null; + } + + if (try parser.elementGetAttribute(element, "form")) |form_id| { + const document = parser.documentHTMLToDocument(self.window.document); + const form_element = try parser.documentGetElementById(document, form_id) orelse return null; + if (try parser.elementHTMLGetTagType(@ptrCast(form_element)) == .form) { + return @ptrCast(form_element); + } + return null; + } + + const Element = @import("dom/element.zig").Element; + const form = (try Element._closest(element, "form", self)) orelse return null; + return @ptrCast(form); + } }; const DelayedNavigation = struct { diff --git a/src/browser/xhr/form_data.zig b/src/browser/xhr/form_data.zig index 32d56bc9..ed9e1ebe 100644 --- a/src/browser/xhr/form_data.zig +++ b/src/browser/xhr/form_data.zig @@ -268,6 +268,7 @@ fn collectForm(form: *parser.Form, submitter_: ?*parser.ElementHTML, page: *Page var entries: Entry.List = .empty; try entries.ensureTotalCapacity(arena, len); + var submitter_included = false; const submitter_name_ = try getSubmitterName(submitter_); for (0..len) |i| { @@ -295,6 +296,8 @@ fn collectForm(form: *parser.Form, submitter_: ?*parser.ElementHTML, page: *Page .key = try std.fmt.allocPrint(arena, "{s}.y", .{name}), .value = "0", }); + + submitter_included = true; } } continue; @@ -309,6 +312,7 @@ fn collectForm(form: *parser.Form, submitter_: ?*parser.ElementHTML, page: *Page if (submitter_name_ == null or !std.mem.eql(u8, submitter_name_.?, name)) { continue; } + submitter_included = true; } const value = (try parser.elementGetAttribute(element, "value")) orelse ""; try entries.append(arena, .{ .key = name, .value = value }); @@ -326,6 +330,7 @@ fn collectForm(form: *parser.Form, submitter_: ?*parser.ElementHTML, page: *Page if (std.mem.eql(u8, submitter_name, name)) { const value = (try parser.elementGetAttribute(element, "value")) orelse ""; try entries.append(arena, .{ .key = name, .value = value }); + submitter_included = true; } }, else => { @@ -335,6 +340,15 @@ fn collectForm(form: *parser.Form, submitter_: ?*parser.ElementHTML, page: *Page } } + if (submitter_included == false) { + if (submitter_) |submitter| { + // this can happen if the submitter is outside the form, but associated + // with the form via a form=ID attribute + const value = (try parser.elementGetAttribute(@ptrCast(submitter), "value")) orelse ""; + try entries.append(arena, .{ .key = submitter_name_.?, .value = value }); + } + } + return entries; }