From f7e1f4a15b1c3e1b5086812855672ac3b3f4d49d Mon Sep 17 00:00:00 2001 From: Jelle Raaijmakers Date: Mon, 26 Aug 2024 14:08:40 +0200 Subject: [PATCH] LibWeb: Propagate input/textarea selection update to document selection Calling `.setSelectionRange()` or `.select()` now updates the document selection as well, visualizing the text selection. --- .../LibWeb/HTML/FormAssociatedElement.cpp | 21 ++++++++++++------- .../LibWeb/HTML/FormAssociatedElement.h | 2 ++ .../LibWeb/HTML/HTMLInputElement.cpp | 10 +++++++++ .../Libraries/LibWeb/HTML/HTMLInputElement.h | 3 +++ .../LibWeb/HTML/HTMLTextAreaElement.cpp | 10 +++++++++ .../LibWeb/HTML/HTMLTextAreaElement.h | 3 +++ 6 files changed, 42 insertions(+), 7 deletions(-) diff --git a/Userland/Libraries/LibWeb/HTML/FormAssociatedElement.cpp b/Userland/Libraries/LibWeb/HTML/FormAssociatedElement.cpp index 66ba41d91bc74..8e78a8a6dfb0e 100644 --- a/Userland/Libraries/LibWeb/HTML/FormAssociatedElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/FormAssociatedElement.cpp @@ -411,14 +411,21 @@ void FormAssociatedElement::set_the_selection_range(Optional(&html_element)->dispatch_event(select_event); - }); + + // AD-HOC: If there is no selection, we do not fire the event. This seems to correspond to how + // other browsers behave. + if (m_selection_start != m_selection_end) { + html_element.queue_an_element_task(Task::Source::UserInteraction, [&html_element] { + auto select_event = DOM::Event::create(html_element.realm(), EventNames::select, { .bubbles = true }); + static_cast(&html_element)->dispatch_event(select_event); + }); + } + + // AD-HOC: Notify the element that the selection was changed, so it can perform + // element-specific updates. + selection_was_changed(); } } diff --git a/Userland/Libraries/LibWeb/HTML/FormAssociatedElement.h b/Userland/Libraries/LibWeb/HTML/FormAssociatedElement.h index eea5b700ffdbb..30747c6d92889 100644 --- a/Userland/Libraries/LibWeb/HTML/FormAssociatedElement.h +++ b/Userland/Libraries/LibWeb/HTML/FormAssociatedElement.h @@ -137,6 +137,8 @@ class FormAssociatedElement { // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-textarea/input-relevant-value void relevant_value_was_changed(JS::GCPtr); + virtual void selection_was_changed() { } + private: void reset_form_owner(); diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp index ada592c5e1dae..59759bcc1ca6d 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -2353,4 +2354,13 @@ HTMLInputElement::ValueAttributeMode HTMLInputElement::value_attribute_mode() co VERIFY_NOT_REACHED(); } +void HTMLInputElement::selection_was_changed() +{ + auto selection = document().get_selection(); + if (!selection || selection->range_count() == 0) + return; + + MUST(selection->set_base_and_extent(*m_text_node, selection_start().value(), *m_text_node, selection_end().value())); +} + } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h index 5740e18332c36..9c75cb65c89b2 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h @@ -199,6 +199,9 @@ class HTMLInputElement final bool select_applies() const; bool selection_or_range_applies() const; +protected: + void selection_was_changed() override; + private: HTMLInputElement(DOM::Document&, DOM::QualifiedName); diff --git a/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp index 22c6284beab04..5d3c84248087b 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp @@ -22,6 +22,7 @@ #include #include #include +#include namespace Web::HTML { @@ -452,4 +453,13 @@ void HTMLTextAreaElement::queue_firing_input_event() }); } +void HTMLTextAreaElement::selection_was_changed() +{ + auto selection = document().get_selection(); + if (!selection || selection->range_count() == 0) + return; + + MUST(selection->set_base_and_extent(*m_text_node, selection_start().value(), *m_text_node, selection_end().value())); +} + } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.h b/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.h index e69fe45abea13..be0d7683e2a09 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.h @@ -114,6 +114,9 @@ class HTMLTextAreaElement final String selection_direction_binding() const; void set_selection_direction_binding(String direction); +protected: + void selection_was_changed() override; + private: HTMLTextAreaElement(DOM::Document&, DOM::QualifiedName);