diff --git a/Userland/Libraries/LibWeb/Page/EventHandler.cpp b/Userland/Libraries/LibWeb/Page/EventHandler.cpp index c5746e876fa14..edb1cf9386c25 100644 --- a/Userland/Libraries/LibWeb/Page/EventHandler.cpp +++ b/Userland/Libraries/LibWeb/Page/EventHandler.cpp @@ -10,12 +10,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -472,6 +474,7 @@ bool EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSPixelPoi (void)selection->set_base_and_extent(*dom_node, result->index_in_node, *dom_node, result->index_in_node); } } + update_selection_range_for_input_or_textarea(); m_in_mouse_selection = true; } } @@ -593,6 +596,7 @@ bool EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSPixelPoi if (should_set_cursor_position) document.set_cursor_position(DOM::Position::create(realm, *hit->dom_node(), *start_index)); + update_selection_range_for_input_or_textarea(); document.set_needs_display(); } } @@ -716,6 +720,7 @@ bool EventHandler::handle_doubleclick(CSSPixelPoint viewport_position, CSSPixelP if (auto selection = node->document().get_selection()) { (void)selection->set_base_and_extent(hit_dom_node, first_word_break_before, hit_dom_node, first_word_break_after); } + update_selection_range_for_input_or_textarea(); } } @@ -988,6 +993,8 @@ bool EventHandler::handle_keydown(UIEvents::KeyCode key, u32 modifiers, u32 code } } + update_selection_range_for_input_or_textarea(); + // FIXME: Implement scroll by line and by page instead of approximating the behavior of other browsers. auto arrow_key_scroll_distance = 100; auto page_scroll_distance = document->window()->inner_height() - (document->window()->outer_height() - document->window()->inner_height()); @@ -1123,4 +1130,53 @@ void EventHandler::visit_edges(JS::Cell::Visitor& visitor) const visitor.visit(m_mouse_event_tracking_paintable); } +// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#textFieldSelection:set-the-selection-range +void EventHandler::update_selection_range_for_input_or_textarea() +{ + // Where possible, user interface features for changing the text selection in input and + // textarea elements must be implemented using the set the selection range algorithm so that, + // e.g., all the same events fire. + + // NOTE: It seems like only new selections are registered with the respective elements. I.e. + // existing selections in other elements are not cleared, so we only need to set the + // selection range for the element with the current selection. + + // Get the active selection + auto active_document = m_navigable->active_document(); + if (!active_document) + return; + auto selection = active_document->get_selection(); + if (!selection) + return; + + // Do we have a range within the same node? + auto range = selection->range(); + if (!range || range->start_container() != range->end_container()) + return; + + // We are only interested in text nodes with a shadow root + auto& node = *range->start_container(); + if (!node.is_text()) + return; + auto& root = node.root(); + if (!root.is_shadow_root()) + return; + auto& shadow_host = *root.parent_or_shadow_host(); + + // Invoke "set the selection range" on the form associated element + auto selection_start = range->start_offset(); + auto selection_end = range->end_offset(); + // FIXME: support selection directions other than ::Forward + auto direction = HTML::SelectionDirection::Forward; + + Optional target {}; + if (is(shadow_host)) + target = static_cast(shadow_host); + else if (is(shadow_host)) + target = static_cast(shadow_host); + + if (target.has_value()) + target.value().set_the_selection_range(selection_start, selection_end, direction); +} + } diff --git a/Userland/Libraries/LibWeb/Page/EventHandler.h b/Userland/Libraries/LibWeb/Page/EventHandler.h index c76e95fa1c8c1..d6c5392c18656 100644 --- a/Userland/Libraries/LibWeb/Page/EventHandler.h +++ b/Userland/Libraries/LibWeb/Page/EventHandler.h @@ -60,6 +60,7 @@ class EventHandler { Painting::PaintableBox const* paint_root() const; bool should_ignore_device_input_event() const; + void update_selection_range_for_input_or_textarea(); JS::NonnullGCPtr m_navigable;