diff --git a/src/browser/Frame.zig b/src/browser/Frame.zig index 7e13f3db3..abd9c6aaf 100644 --- a/src/browser/Frame.zig +++ b/src/browser/Frame.zig @@ -3404,6 +3404,31 @@ pub fn submitForm(self: *Frame, submitter_: ?*Element, form_: ?*Element.Html.For const method = Element.Html.Form.normalizeMethod(method_attr, "get"); const is_post = std.mem.eql(u8, method, "post"); + // Per the HTML form-submission algorithm, the dialog method closes the + // form's nearest ancestor dialog with the submitter's value and performs no + // navigation. Falling through here would submit the form as a GET, which + // both reloads the page and leaves the dialog open forever. + // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#form-submission-algorithm + if (std.mem.eql(u8, method, "dialog")) { + var ancestor: ?*Element = form_element; + while (ancestor) |el| : (ancestor = el.parentElement()) { + const dialog = el.is(Element.Html.Dialog) orelse continue; + // A submit button always has a value (empty when the attribute is + // absent); with no submitter at all the dialog's existing + // returnValue is left untouched. + const result: ?[]const u8 = if (submit_button) |s| + s.getAttributeSafe(comptime .wrap("value")) orelse "" + else + null; + try dialog.close(result, self); + break; + } + // Nothing is navigated, so the arena reserved for the request body goes + // unused — the errdefer above only covers the error path. + self._session.releaseArena(arena); + return; + } + // Get charset from accept-charset attribute or fall back to document charset const charset: []const u8 = blk: { if (form_element.getAttributeSafe(.wrap("accept-charset"))) |ac| { diff --git a/src/browser/tests/element/html/dialog.html b/src/browser/tests/element/html/dialog.html index e0e6fb45c..59aecd4db 100644 --- a/src/browser/tests/element/html/dialog.html +++ b/src/browser/tests/element/html/dialog.html @@ -198,3 +198,99 @@ testing.expectEqual(0, fired) } + + + + + + + + + +