From 1352315441a4a464e861364703dd9409d4f8f7dd Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Wed, 4 Feb 2026 13:45:53 +0800 Subject: [PATCH] Execute form.onsubmit when a form is being submitted --- src/browser/Page.zig | 32 +++++++++++++++++++++--- src/browser/webapi/element/html/Form.zig | 5 +++- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/browser/Page.zig b/src/browser/Page.zig index 37c87605..9f1db6f4 100644 --- a/src/browser/Page.zig +++ b/src/browser/Page.zig @@ -3264,12 +3264,12 @@ pub fn handleClick(self: *Page, target: *Node) !void { }, .anchor); }, .input => |input| switch (input._input_type) { - .submit => return self.submitForm(element, input.getForm(self)), + .submit => return self.submitForm(element, input.getForm(self), .{}), else => self.window._document._active_element = element, }, .button => |button| { if (std.mem.eql(u8, button.getType(), "submit")) { - return self.submitForm(element, button.getForm(self)); + return self.submitForm(element, button.getForm(self), .{}); } }, .select, .textarea => self.window._document._active_element = element, @@ -3299,7 +3299,7 @@ pub fn handleKeydown(self: *Page, target: *Node, event: *Event) !void { if (target.is(Element.Html.Input)) |input| { if (key == .Enter) { - return self.submitForm(input.asElement(), input.getForm(self)); + return self.submitForm(input.asElement(), input.getForm(self), .{}); } // Don't handle text input for radio/checkbox @@ -3329,7 +3329,10 @@ pub fn handleKeydown(self: *Page, target: *Node, event: *Event) !void { } } -pub fn submitForm(self: *Page, submitter_: ?*Element, form_: ?*Element.Html.Form) !void { +const SubmitFormOpts = struct { + fire_event: bool = true, +}; +pub fn submitForm(self: *Page, submitter_: ?*Element, form_: ?*Element.Html.Form, submit_opts: SubmitFormOpts) !void { const form = form_ orelse return; if (submitter_) |submitter| { @@ -3344,6 +3347,27 @@ pub fn submitForm(self: *Page, submitter_: ?*Element, form_: ?*Element.Html.Form const form_element = form.asElement(); + if (submit_opts.fire_event) { + const submit_event = try Event.initTrusted("submit", .{ .bubbles = true, .cancelable = true }, self); + const onsubmit_handler = form.asHtmlElement().getOnSubmit(self); + + var ls: JS.Local.Scope = undefined; + self.js.localScope(&ls); + defer ls.deinit(); + + try self._event_manager.dispatchWithFunction( + form_element.asEventTarget(), + submit_event, + ls.toLocal(onsubmit_handler), + .{ .context = "form submit" }, + ); + + // If the submit event was prevented, don't submit the form + if (submit_event._prevent_default) { + return; + } + } + const FormData = @import("webapi/net/FormData.zig"); // The submitter can be an input box (if enter was entered on the box) // I don't think this is technically correct, but FormData handles it ok diff --git a/src/browser/webapi/element/html/Form.zig b/src/browser/webapi/element/html/Form.zig index 8a9279ac..9c0fd2ed 100644 --- a/src/browser/webapi/element/html/Form.zig +++ b/src/browser/webapi/element/html/Form.zig @@ -32,6 +32,9 @@ pub const TextArea = @import("TextArea.zig"); const Form = @This(); _proto: *HtmlElement, +pub fn asHtmlElement(self: *Form) *HtmlElement { + return self._proto; +} fn asConstElement(self: *const Form) *const Element { return self._proto._proto; } @@ -88,7 +91,7 @@ pub fn getLength(self: *Form, page: *Page) !u32 { } pub fn submit(self: *Form, page: *Page) !void { - return page.submitForm(null, self); + return page.submitForm(null, self, .{ .fire_event = false }); } pub const JsApi = struct {