diff --git a/Tests/LibWeb/Text/expected/input-selection-start-selection-end.txt b/Tests/LibWeb/Text/expected/input-selection-start-selection-end.txt
new file mode 100644
index 00000000000..f9fa806ddf6
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/input-selection-start-selection-end.txt
@@ -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
diff --git a/Tests/LibWeb/Text/input/input-selection-start-selection-end.html b/Tests/LibWeb/Text/input/input-selection-start-selection-end.html
new file mode 100644
index 00000000000..6d01fafaaa9
--- /dev/null
+++ b/Tests/LibWeb/Text/input/input-selection-start-selection-end.html
@@ -0,0 +1,24 @@
+
+
+
+
diff --git a/Userland/Libraries/LibWeb/HTML/FormAssociatedElement.cpp b/Userland/Libraries/LibWeb/HTML/FormAssociatedElement.cpp
index cd9888c046a..d90b520803b 100644
--- a/Userland/Libraries/LibWeb/HTML/FormAssociatedElement.cpp
+++ b/Userland/Libraries/LibWeb/HTML/FormAssociatedElement.cpp
@@ -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 FormAssociatedElement::set_selection_start(WebIDL::UnsignedLong)
+WebIDL::ExceptionOr FormAssociatedElement::set_selection_start(Optional 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 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 FormAssociatedElement::set_selection_end(WebIDL::UnsignedLong)
+WebIDL::ExceptionOr FormAssociatedElement::set_selection_end(Optional 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.
diff --git a/Userland/Libraries/LibWeb/HTML/FormAssociatedElement.h b/Userland/Libraries/LibWeb/HTML/FormAssociatedElement.h
index 08579b4ed4d..8a480473234 100644
--- a/Userland/Libraries/LibWeb/HTML/FormAssociatedElement.h
+++ b/Userland/Libraries/LibWeb/HTML/FormAssociatedElement.h
@@ -90,10 +90,10 @@ public:
virtual void reset_algorithm() {};
WebIDL::UnsignedLong selection_start() const;
- WebIDL::ExceptionOr set_selection_start(WebIDL::UnsignedLong);
+ WebIDL::ExceptionOr set_selection_start(Optional const&);
WebIDL::UnsignedLong selection_end() const;
- WebIDL::ExceptionOr set_selection_end(WebIDL::UnsignedLong);
+ WebIDL::ExceptionOr set_selection_end(Optional const&);
protected:
FormAssociatedElement() = default;
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp
index c8348e756f1..e0a0c04e0dc 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp
+++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp
@@ -2,7 +2,7 @@
* Copyright (c) 2018-2023, Andreas Kling
* Copyright (c) 2022, Adam Hodgen
* Copyright (c) 2022, Andrew Kaster
- * Copyright (c) 2023, Shannon Booth
+ * Copyright (c) 2023-2024, Shannon Booth
* Copyright (c) 2023, Bastiaan van der Plaat
*
* SPDX-License-Identifier: BSD-2-Clause
@@ -2070,6 +2070,52 @@ WebIDL::ExceptionOr 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 HTMLInputElement::set_selection_start_for_bindings(Optional 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 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 HTMLInputElement::set_selection_end_for_bindings(Optional 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 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 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
{
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h
index f0289685d2f..f56cfafed48 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h
+++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h
@@ -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 set_selection_start_for_bindings(Optional const&);
+ Optional selection_start_for_bindings() const;
+
+ WebIDL::ExceptionOr set_selection_end_for_bindings(Optional const&);
+ Optional selection_end_for_bindings() const;
private:
HTMLInputElement(DOM::Document&, DOM::QualifiedName);
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.idl b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.idl
index f50216a72f7..9ff4c9e5660 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.idl
+++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.idl
@@ -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");