mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-29 20:29:18 +00:00
HTML: Partially implement HTMLInputElement's selection{Start,End}
Now that the implementation is in FormAssociatedElement, the implementation in HTMLInputElement is effectively just a passthrough, with some minor differences to handle small behavioural quirks between the two (such as the difference in nullability of types).
This commit is contained in:
parent
62bf428a7f
commit
9f24176cac
Notes:
github-actions[bot]
2024-08-01 10:17:51 +00:00
Author: https://github.com/shannonbooth
Commit: 9f24176cac
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/876
7 changed files with 114 additions and 11 deletions
|
@ -0,0 +1,7 @@
|
|||
Well hello friends text selectionStart: 0
|
||||
text selectionEnd: 0
|
||||
date selectionStart: null
|
||||
date selectionEnd: null
|
||||
text selectionStart: 18
|
||||
text selectionEnd: 18
|
||||
date input setting selectionStart error: InvalidStateError: setSelectionStart does not apply to this input type
|
|
@ -0,0 +1,24 @@
|
|||
<input type="text" id="ladybird-text-input"></input>
|
||||
<input type="date" id="ladybird-date-input"></input>
|
||||
<script src="include.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
let textInput = document.getElementById("ladybird-text-input");
|
||||
let dateInput = document.getElementById("ladybird-date-input");
|
||||
|
||||
println(`text selectionStart: ${textInput.selectionStart}`);
|
||||
println(`text selectionEnd: ${textInput.selectionEnd}`);
|
||||
println(`date selectionStart: ${dateInput.selectionStart}`);
|
||||
println(`date selectionEnd: ${dateInput.selectionEnd}`);
|
||||
|
||||
textInput.value = "Well hello friends";
|
||||
println(`text selectionStart: ${textInput.selectionStart}`);
|
||||
println(`text selectionEnd: ${textInput.selectionEnd}`);
|
||||
|
||||
try {
|
||||
dateInput.selectionStart = 0;
|
||||
} catch (e) {
|
||||
println(`date input setting selectionStart error: ${e}`);
|
||||
}
|
||||
});
|
||||
</script>
|
|
@ -155,7 +155,8 @@ void FormAssociatedElement::reset_form_owner()
|
|||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea/input-selectionstart
|
||||
WebIDL::UnsignedLong FormAssociatedElement::selection_start() const
|
||||
{
|
||||
// FIXME: 1. If this element is an input element, and selectionStart does not apply to this element, return null.
|
||||
// 1. If this element is an input element, and selectionStart does not apply to this element, return null.
|
||||
// NOTE: This is done by HTMLInputElement before calling this function
|
||||
|
||||
// 2. If there is no selection, return the code unit offset within the relevant value to the character that
|
||||
// immediately follows the text entry cursor.
|
||||
|
@ -170,10 +171,11 @@ WebIDL::UnsignedLong FormAssociatedElement::selection_start() const
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#textFieldSelection:dom-textarea/input-selectionstart-2
|
||||
WebIDL::ExceptionOr<void> FormAssociatedElement::set_selection_start(WebIDL::UnsignedLong)
|
||||
WebIDL::ExceptionOr<void> FormAssociatedElement::set_selection_start(Optional<WebIDL::UnsignedLong> const&)
|
||||
{
|
||||
// FIXME: 1. If this element is an input element, and selectionStart does not apply to this element, throw an
|
||||
// 1. If this element is an input element, and selectionStart does not apply to this element, throw an
|
||||
// "InvalidStateError" DOMException.
|
||||
// NOTE: This is done by HTMLInputElement before calling this function
|
||||
|
||||
// FIXME: 2. Let end be the value of this element's selectionEnd attribute.
|
||||
// FIXME: 3. If end is less than the given value, set end to the given value.
|
||||
|
@ -184,7 +186,8 @@ WebIDL::ExceptionOr<void> FormAssociatedElement::set_selection_start(WebIDL::Uns
|
|||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea/input-selectionend
|
||||
WebIDL::UnsignedLong FormAssociatedElement::selection_end() const
|
||||
{
|
||||
// FIXME: 1. If this element is an input element, and selectionEnd does not apply to this element, return null.
|
||||
// 1. If this element is an input element, and selectionEnd does not apply to this element, return null.
|
||||
// NOTE: This is done by HTMLInputElement before calling this function
|
||||
|
||||
// 2. If there is no selection, return the code unit offset within the relevant value to the character that
|
||||
// immediately follows the text entry cursor.
|
||||
|
@ -199,10 +202,11 @@ WebIDL::UnsignedLong FormAssociatedElement::selection_end() const
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#textFieldSelection:dom-textarea/input-selectionend-3
|
||||
WebIDL::ExceptionOr<void> FormAssociatedElement::set_selection_end(WebIDL::UnsignedLong)
|
||||
WebIDL::ExceptionOr<void> FormAssociatedElement::set_selection_end(Optional<WebIDL::UnsignedLong> const&)
|
||||
{
|
||||
// FIXME: 1. If this element is an input element, and selectionEnd does not apply to this element, throw an
|
||||
// 1. If this element is an input element, and selectionEnd does not apply to this element, throw an
|
||||
// "InvalidStateError" DOMException.
|
||||
// NOTE: This is done by HTMLInputElement before calling this function
|
||||
|
||||
// FIXME: 2. Set the selection range with the value of this element's selectionStart attribute, the given value, and the
|
||||
// value of this element's selectionDirection attribute.
|
||||
|
|
|
@ -90,10 +90,10 @@ public:
|
|||
virtual void reset_algorithm() {};
|
||||
|
||||
WebIDL::UnsignedLong selection_start() const;
|
||||
WebIDL::ExceptionOr<void> set_selection_start(WebIDL::UnsignedLong);
|
||||
WebIDL::ExceptionOr<void> set_selection_start(Optional<WebIDL::UnsignedLong> const&);
|
||||
|
||||
WebIDL::UnsignedLong selection_end() const;
|
||||
WebIDL::ExceptionOr<void> set_selection_end(WebIDL::UnsignedLong);
|
||||
WebIDL::ExceptionOr<void> set_selection_end(Optional<WebIDL::UnsignedLong> const&);
|
||||
|
||||
protected:
|
||||
FormAssociatedElement() = default;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* Copyright (c) 2018-2023, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2022, Adam Hodgen <ant1441@gmail.com>
|
||||
* Copyright (c) 2022, Andrew Kaster <akaster@serenityos.org>
|
||||
* Copyright (c) 2023, Shannon Booth <shannon@serenityos.org>
|
||||
* Copyright (c) 2023-2024, Shannon Booth <shannon@serenityos.org>
|
||||
* Copyright (c) 2023, Bastiaan van der Plaat <bastiaan.v.d.plaat@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
|
@ -2070,6 +2070,52 @@ WebIDL::ExceptionOr<void> HTMLInputElement::set_selection_range(u32 start, u32 e
|
|||
return {};
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#textFieldSelection:dom-textarea/input-selectionstart-2
|
||||
WebIDL::ExceptionOr<void> HTMLInputElement::set_selection_start_for_bindings(Optional<WebIDL::UnsignedLong> const& value)
|
||||
{
|
||||
// 1. If this element is an input element, and selectionStart does not apply to this element, throw an
|
||||
// "InvalidStateError" DOMException.
|
||||
if (!selection_or_range_applies())
|
||||
return WebIDL::InvalidStateError::create(realm(), "setSelectionStart does not apply to this input type"_fly_string);
|
||||
|
||||
// NOTE: Steps continued below:
|
||||
return set_selection_start(value);
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea/input-selectionstart
|
||||
Optional<WebIDL::UnsignedLong> HTMLInputElement::selection_start_for_bindings() const
|
||||
{
|
||||
// 1. If this element is an input element, and selectionStart does not apply to this element, return null.
|
||||
if (!selection_or_range_applies())
|
||||
return {};
|
||||
|
||||
// NOTE: Steps continued below:
|
||||
return selection_start();
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#textFieldSelection:dom-textarea/input-selectionend-3
|
||||
WebIDL::ExceptionOr<void> HTMLInputElement::set_selection_end_for_bindings(Optional<WebIDL::UnsignedLong> const& value)
|
||||
{
|
||||
// 1. If this element is an input element, and selectionEnd does not apply to this element, throw an
|
||||
// "InvalidStateError" DOMException.
|
||||
if (!selection_or_range_applies())
|
||||
return WebIDL::InvalidStateError::create(realm(), "setSelectionEnd does not apply to this input type"_fly_string);
|
||||
|
||||
// NOTE: Steps continued below:
|
||||
return set_selection_end(value);
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea/input-selectionend
|
||||
Optional<WebIDL::UnsignedLong> HTMLInputElement::selection_end_for_bindings() const
|
||||
{
|
||||
// 1. If this element is an input element, and selectionEnd does not apply to this element, return null.
|
||||
if (!selection_or_range_applies())
|
||||
return {};
|
||||
|
||||
// NOTE: Steps continued below:
|
||||
return selection_end();
|
||||
}
|
||||
|
||||
Optional<ARIA::Role> HTMLInputElement::default_role() const
|
||||
{
|
||||
// https://www.w3.org/TR/html-aria/#el-input-button
|
||||
|
@ -2198,6 +2244,21 @@ bool HTMLInputElement::has_input_activation_behavior() const
|
|||
}
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/input.html#do-not-apply
|
||||
bool HTMLInputElement::selection_or_range_applies() const
|
||||
{
|
||||
switch (type_state()) {
|
||||
case TypeAttributeState::Text:
|
||||
case TypeAttributeState::Search:
|
||||
case TypeAttributeState::Telephone:
|
||||
case TypeAttributeState::URL:
|
||||
case TypeAttributeState::Password:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/input.html#the-input-element:event-change-2
|
||||
bool HTMLInputElement::change_event_applies() const
|
||||
{
|
||||
|
|
|
@ -196,6 +196,13 @@ public:
|
|||
bool value_as_number_applies() const;
|
||||
bool step_applies() const;
|
||||
bool step_up_or_down_applies() const;
|
||||
bool selection_or_range_applies() const;
|
||||
|
||||
WebIDL::ExceptionOr<void> set_selection_start_for_bindings(Optional<WebIDL::UnsignedLong> const&);
|
||||
Optional<WebIDL::UnsignedLong> selection_start_for_bindings() const;
|
||||
|
||||
WebIDL::ExceptionOr<void> set_selection_end_for_bindings(Optional<WebIDL::UnsignedLong> const&);
|
||||
Optional<WebIDL::UnsignedLong> selection_end_for_bindings() const;
|
||||
|
||||
private:
|
||||
HTMLInputElement(DOM::Document&, DOM::QualifiedName);
|
||||
|
|
|
@ -58,8 +58,8 @@ interface HTMLInputElement : HTMLElement {
|
|||
readonly attribute NodeList? labels;
|
||||
|
||||
undefined select();
|
||||
[FIXME] attribute unsigned long? selectionStart;
|
||||
[FIXME] attribute unsigned long? selectionEnd;
|
||||
[ImplementedAs=selection_start_for_bindings] attribute unsigned long? selectionStart;
|
||||
[ImplementedAs=selection_end_for_bindings] attribute unsigned long? selectionEnd;
|
||||
[FIXME] attribute DOMString? selectionDirection;
|
||||
[FIXME] undefined setRangeText(DOMString replacement);
|
||||
[FIXME] undefined setRangeText(DOMString replacement, unsigned long start, unsigned long end, optional SelectionMode selectionMode = "preserve");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue