mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 15:13:28 +00:00
Merge pull request #738 from lightpanda-io/buttons_submit_form
Submit input and button submits can now submit forms
This commit is contained in:
@@ -32,10 +32,6 @@ pub const HTMLFormElement = struct {
|
|||||||
return page.submitForm(self, null);
|
return page.submitForm(self, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _requestSubmit(self: *parser.Form) !void {
|
|
||||||
try parser.formElementSubmit(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn _reset(self: *parser.Form) !void {
|
pub fn _reset(self: *parser.Form) !void {
|
||||||
try parser.formElementReset(self);
|
try parser.formElementReset(self);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,6 +92,9 @@ pub const Page = struct {
|
|||||||
// current_script could by fetch module to resolve module's url to fetch.
|
// current_script could by fetch module to resolve module's url to fetch.
|
||||||
current_script: ?*const Script = null,
|
current_script: ?*const Script = null,
|
||||||
|
|
||||||
|
// indicates intention to navigate to another page on the next loop execution.
|
||||||
|
delayed_navigation: bool = false,
|
||||||
|
|
||||||
pub fn init(self: *Page, arena: Allocator, session: *Session) !void {
|
pub fn init(self: *Page, arena: Allocator, session: *Session) !void {
|
||||||
const browser = session.browser;
|
const browser = session.browser;
|
||||||
self.* = .{
|
self.* = .{
|
||||||
@@ -553,6 +556,25 @@ pub const Page = struct {
|
|||||||
const href = (try parser.elementGetAttribute(element, "href")) orelse return;
|
const href = (try parser.elementGetAttribute(element, "href")) orelse return;
|
||||||
try self.navigateFromWebAPI(href, .{});
|
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 => {},
|
else => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -561,6 +583,7 @@ pub const Page = struct {
|
|||||||
// The page.arena is safe to use here, but the transfer_arena exists
|
// The page.arena is safe to use here, but the transfer_arena exists
|
||||||
// specifically for this type of lifetime.
|
// specifically for this type of lifetime.
|
||||||
pub fn navigateFromWebAPI(self: *Page, url: []const u8, opts: NavigateOpts) !void {
|
pub fn navigateFromWebAPI(self: *Page, url: []const u8, opts: NavigateOpts) !void {
|
||||||
|
self.delayed_navigation = true;
|
||||||
const arena = self.session.transfer_arena;
|
const arena = self.session.transfer_arena;
|
||||||
const navi = try arena.create(DelayedNavigation);
|
const navi = try arena.create(DelayedNavigation);
|
||||||
navi.* = .{
|
navi.* = .{
|
||||||
@@ -616,6 +639,30 @@ pub const Page = struct {
|
|||||||
|
|
||||||
try self.navigateFromWebAPI(action, opts);
|
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 {
|
const DelayedNavigation = struct {
|
||||||
|
|||||||
@@ -128,7 +128,14 @@ pub const Session = struct {
|
|||||||
// it isn't null!
|
// it isn't null!
|
||||||
std.debug.assert(self.page != null);
|
std.debug.assert(self.page != null);
|
||||||
|
|
||||||
defer _ = self.browser.transfer_arena.reset(.{ .retain_with_limit = 1 * 1024 * 1024 });
|
defer if (self.page) |*p| {
|
||||||
|
if (!p.delayed_navigation) {
|
||||||
|
// If, while loading the page, we intend to navigate to another
|
||||||
|
// page, then we need to keep the transfer_arena around, as this
|
||||||
|
// sub-navigation is probably using it.
|
||||||
|
_ = self.browser.transfer_arena.reset(.{ .retain_with_limit = 1 * 1024 * 1024 });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// it's safe to use the transfer arena here, because the page will
|
// it's safe to use the transfer arena here, because the page will
|
||||||
// eventually clone the URL using its own page_arena (after it gets
|
// eventually clone the URL using its own page_arena (after it gets
|
||||||
|
|||||||
@@ -268,6 +268,7 @@ fn collectForm(form: *parser.Form, submitter_: ?*parser.ElementHTML, page: *Page
|
|||||||
var entries: Entry.List = .empty;
|
var entries: Entry.List = .empty;
|
||||||
try entries.ensureTotalCapacity(arena, len);
|
try entries.ensureTotalCapacity(arena, len);
|
||||||
|
|
||||||
|
var submitter_included = false;
|
||||||
const submitter_name_ = try getSubmitterName(submitter_);
|
const submitter_name_ = try getSubmitterName(submitter_);
|
||||||
|
|
||||||
for (0..len) |i| {
|
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}),
|
.key = try std.fmt.allocPrint(arena, "{s}.y", .{name}),
|
||||||
.value = "0",
|
.value = "0",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
submitter_included = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
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)) {
|
if (submitter_name_ == null or !std.mem.eql(u8, submitter_name_.?, name)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
submitter_included = true;
|
||||||
}
|
}
|
||||||
const value = (try parser.elementGetAttribute(element, "value")) orelse "";
|
const value = (try parser.elementGetAttribute(element, "value")) orelse "";
|
||||||
try entries.append(arena, .{ .key = name, .value = value });
|
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)) {
|
if (std.mem.eql(u8, submitter_name, name)) {
|
||||||
const value = (try parser.elementGetAttribute(element, "value")) orelse "";
|
const value = (try parser.elementGetAttribute(element, "value")) orelse "";
|
||||||
try entries.append(arena, .{ .key = name, .value = value });
|
try entries.append(arena, .{ .key = name, .value = value });
|
||||||
|
submitter_included = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
else => {
|
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;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user