mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-06-11 01:25:53 -04:00
forms: extract Select.effectiveOption to centralize selectedness
Per review: collectForm walked the children once to look for a non-disabled <option>, then Select.getValue walked them again to emit the value. Extract the selectedness-candidate algorithm into Select.effectiveOption() ?*Option so both call sites share it and each runs a single iteration. - Select.getValue is now a one-liner over effectiveOption. - collectForm replaces the candidate-check + getValue pair with `select.effectiveOption() orelse continue; break :blk opt.getValue(frame);`. Behavior is unchanged; the existing form_data.html fixtures (selectWithoutOptions, selectMultipleWithoutOptions, selectAllOptionsDisabled) still pass.
This commit is contained in:
@@ -44,8 +44,13 @@ pub fn asConstNode(self: *const Select) *const Node {
|
||||
return self.asConstElement().asConstNode();
|
||||
}
|
||||
|
||||
pub fn getValue(self: *Select, frame: *Frame) []const u8 {
|
||||
// Return value of first selected option, or first option if none selected
|
||||
// Resolves the option whose selectedness contributes to the select's value
|
||||
// per HTML §form-elements§selectedness-setting-algorithm: an explicitly
|
||||
// selected non-disabled option, falling back to the first non-disabled
|
||||
// option in tree order. Returns null if there is no candidate (zero options
|
||||
// or every option disabled), in which case the select has no selectedness
|
||||
// and contributes no entry to a FormData set.
|
||||
pub fn effectiveOption(self: *Select) ?*Option {
|
||||
var first_option: ?*Option = null;
|
||||
var iter = self.asNode().childrenIterator();
|
||||
while (iter.next()) |child| {
|
||||
@@ -55,14 +60,17 @@ pub fn getValue(self: *Select, frame: *Frame) []const u8 {
|
||||
}
|
||||
|
||||
if (option.getSelected()) {
|
||||
return option.getValue(frame);
|
||||
return option;
|
||||
}
|
||||
if (first_option == null) {
|
||||
first_option = option;
|
||||
}
|
||||
}
|
||||
// No explicitly selected option, return first option's value
|
||||
if (first_option) |opt| {
|
||||
return first_option;
|
||||
}
|
||||
|
||||
pub fn getValue(self: *Select, frame: *Frame) []const u8 {
|
||||
if (self.effectiveOption()) |opt| {
|
||||
return opt.getValue(frame);
|
||||
}
|
||||
return "";
|
||||
|
||||
@@ -196,18 +196,12 @@ fn collectForm(arena: Allocator, form_: ?*Form, submitter_: ?*Element, frame: *F
|
||||
|
||||
if (element.is(Form.Select)) |select| {
|
||||
if (select.getMultiple() == false) {
|
||||
// Per the HTML spec, a single-select's selectedness comes
|
||||
// from an explicitly-selected option, falling back to the
|
||||
// first non-disabled option in tree order. With no options
|
||||
// (or only disabled ones), nothing is selected and no
|
||||
// entry is appended.
|
||||
var children = select.asNode().childrenIterator();
|
||||
const has_candidate = while (children.next()) |child| {
|
||||
const option = child.is(Form.Select.Option) orelse continue;
|
||||
if (!option.getDisabled()) break true;
|
||||
} else false;
|
||||
if (!has_candidate) continue;
|
||||
break :blk select.getValue(frame);
|
||||
// Per the HTML spec, a single-select with no selectedness
|
||||
// candidate (zero options or every option disabled)
|
||||
// contributes no entry. Otherwise emit the candidate's
|
||||
// value.
|
||||
const opt = select.effectiveOption() orelse continue;
|
||||
break :blk opt.getValue(frame);
|
||||
}
|
||||
|
||||
var options = try select.getSelectedOptions(frame);
|
||||
|
||||
Reference in New Issue
Block a user