Merge pull request #3620 from lightpanda-io/new-options

webapi: add new Option() support
This commit is contained in:
Karl Seguin authored and GitHub committed 2026-09-24 15:28:28 +08:00
commit 606089f5a8
2 files changed
+88

No files matched your search

@@ -191,3 +191,69 @@
$('#opt4').disabled = false
testing.expectEqual(false, $('#opt4').disabled)
</script>
<script id="constructor">
{
const opt = new Option()
testing.expectEqual('OPTION', opt.tagName)
testing.expectEqual(true, opt instanceof HTMLOptionElement)
testing.expectEqual(0, opt.childNodes.length)
testing.expectEqual(false, opt.hasAttribute('value'))
testing.expectEqual(false, opt.defaultSelected)
testing.expectEqual(false, opt.selected)
}
{
const opt = new Option('Label', 'v1')
testing.expectEqual('Label', opt.text)
testing.expectEqual(1, opt.childNodes.length)
testing.expectEqual('v1', opt.getAttribute('value'))
testing.expectEqual('v1', opt.value)
}
{
// An empty text appends no Text node; null is stringified.
testing.expectEqual(0, new Option('').childNodes.length)
testing.expectEqual('null', new Option(null).text)
testing.expectEqual('', new Option('x', '').value)
const undef = new Option(undefined, undefined)
testing.expectEqual(0, undef.childNodes.length)
testing.expectEqual(false, undef.hasAttribute('value'))
const falsy = new Option(false, false)
testing.expectEqual('false', falsy.text)
testing.expectEqual('false', falsy.getAttribute('value'))
}
{
// WebIDL boolean conversion
const falsy = new Option('text', 'value', 0, '')
testing.expectEqual(false, falsy.hasAttribute('selected'))
testing.expectEqual(false, falsy.selected)
const truthy = new Option('text', 'value', {}, 1)
testing.expectEqual(true, truthy.hasAttribute('selected'))
testing.expectEqual(true, truthy.selected)
}
{
// defaultSelected sets the attribute, selectedness comes from `selected` only.
const opt = new Option('a', 'b', true)
testing.expectEqual(true, opt.defaultSelected)
testing.expectEqual('', opt.getAttribute('selected'))
testing.expectEqual(false, opt.selected)
const opt2 = new Option('a', 'b', false, true)
testing.expectEqual(false, opt2.defaultSelected)
testing.expectEqual(true, opt2.selected)
}
{
const select = document.createElement('select')
select.add(new Option('One', '1'))
select.add(new Option('Two', '2', false, true))
testing.expectEqual('2', select.value)
testing.expectEqual(1, select.selectedIndex)
}
</script>
@@ -39,6 +39,26 @@ _value: ?[]const u8 = null,
_selected: bool = false,
_default_selected: bool = false,
pub fn constructor(text_: ?js.NullableString, value_: ?js.NullableString, default_selected_: ?bool, selected_: ?bool, frame: *Frame) !*Option {
const node = try Frame.node_factory.createElementNS(frame.document, .html, "option", null);
const el = node.as(Element);
const text = if (text_) |t| t.value else "";
if (text.len > 0) {
_ = try node.appendChild(try frame.document.createTextNode(text), frame);
}
if (value_) |v| {
try el.setAttributeSafe(comptime .wrap("value"), .wrap(v.value), frame);
}
if (default_selected_ orelse false) {
try el.setAttributeSafe(comptime .wrap("selected"), comptime .wrap(""), frame);
}
const self = el.as(Option);
self._selected = selected_ orelse false;
return self;
}
pub fn asElement(self: *Option) *Element {
return Factory.protoOf(self).asElement();
}
@@ -135,12 +155,14 @@ pub const JsApi = struct {
pub const Meta = struct {
pub const name = "HTMLOptionElement";
pub const constructor_alias = "Option";
pub const prototype_chain = bridge.prototypeChain();
pub var class_id: bridge.ClassId = undefined;
};
const reflect = Element.Reflect(Option);
pub const constructor = bridge.constructor(Option.constructor, .{});
pub const value = bridge.accessor(Option.getValue, Option.setValue, .{ .ce_reactions = true });
pub const text = bridge.accessor(Option.getText, Option.setText, .{ .ce_reactions = true });
pub const label = bridge.accessor(Option.getLabel, Option.setLabel, .{ .ce_reactions = true });