Skip to content

Commit

Permalink
LibWeb: Update input/textarea selection on document selection change
Browse files Browse the repository at this point in the history
This causes UI interactions with the document selection to also update
the input and textarea DOM selection state.
  • Loading branch information
gmta committed Aug 26, 2024
1 parent 91379dd commit eaa7842
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 0 deletions.
56 changes: 56 additions & 0 deletions Userland/Libraries/LibWeb/Page/EventHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
#include <LibWeb/HTML/BrowsingContext.h>
#include <LibWeb/HTML/CloseWatcherManager.h>
#include <LibWeb/HTML/Focus.h>
#include <LibWeb/HTML/FormAssociatedElement.h>
#include <LibWeb/HTML/HTMLAnchorElement.h>
#include <LibWeb/HTML/HTMLFormElement.h>
#include <LibWeb/HTML/HTMLIFrameElement.h>
#include <LibWeb/HTML/HTMLImageElement.h>
#include <LibWeb/HTML/HTMLInputElement.h>
#include <LibWeb/HTML/HTMLMediaElement.h>
#include <LibWeb/HTML/HTMLTextAreaElement.h>
#include <LibWeb/HTML/HTMLVideoElement.h>
#include <LibWeb/Layout/Viewport.h>
#include <LibWeb/Page/DragAndDropEventHandler.h>
Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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();
}
}
Expand Down Expand Up @@ -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();
}
}

Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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<HTML::FormAssociatedElement&> target {};
if (is<HTML::HTMLInputElement>(shadow_host))
target = static_cast<HTML::HTMLInputElement&>(shadow_host);
else if (is<HTML::HTMLTextAreaElement>(shadow_host))
target = static_cast<HTML::HTMLTextAreaElement&>(shadow_host);

if (target.has_value())
target.value().set_the_selection_range(selection_start, selection_end, direction);
}

}
1 change: 1 addition & 0 deletions Userland/Libraries/LibWeb/Page/EventHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTML::Navigable> m_navigable;

Expand Down

0 comments on commit eaa7842

Please sign in to comment.