LibWeb+WebContent: Rename Document::focused_element to ::focused_area

And make it a DOM::Node, not DOM::Element. This makes everything flow
much better, such as spec texts that explicitly mention "focused area"
as the fact that we don't necessarily need to traverse a tree of
elements, since a Node can be focusable as well.

Eventually this will need to be a struct with a separate "focused area"
and "DOM anchor", but this change will make it easier to achieve that.
This commit is contained in:
Jelle Raaijmakers 2025-08-21 17:09:40 +02:00 committed by Jelle Raaijmakers
commit 518c048eb4
Notes: github-actions[bot] 2025-08-26 08:27:18 +00:00
11 changed files with 92 additions and 91 deletions

View file

@ -552,8 +552,8 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla
case CSS::PseudoClass::FocusVisible: case CSS::PseudoClass::FocusVisible:
return element.is_focused() && element.should_indicate_focus(); return element.is_focused() && element.should_indicate_focus();
case CSS::PseudoClass::FocusWithin: { case CSS::PseudoClass::FocusWithin: {
auto* focused_element = element.document().focused_element(); auto focused_area = element.document().focused_area();
return focused_element && element.is_inclusive_ancestor_of(*focused_element); return focused_area && element.is_inclusive_ancestor_of(*focused_area);
} }
case CSS::PseudoClass::FirstChild: case CSS::PseudoClass::FirstChild:
if (context.collect_per_element_selector_involvement_metadata) { if (context.collect_per_element_selector_involvement_metadata) {

View file

@ -547,7 +547,7 @@ void Document::visit_edges(Cell::Visitor& visitor)
visitor.visit(m_highlighted_node); visitor.visit(m_highlighted_node);
visitor.visit(m_active_favicon); visitor.visit(m_active_favicon);
visitor.visit(m_browsing_context); visitor.visit(m_browsing_context);
visitor.visit(m_focused_element); visitor.visit(m_focused_area);
visitor.visit(m_active_element); visitor.visit(m_active_element);
visitor.visit(m_target_element); visitor.visit(m_target_element);
visitor.visit(m_implementation); visitor.visit(m_implementation);
@ -2443,7 +2443,7 @@ String const& Document::compat_mode() const
void Document::update_active_element() void Document::update_active_element()
{ {
// 1. Let candidate be this's node document's focused area's DOM anchor. // 1. Let candidate be this's node document's focused area's DOM anchor.
Node* candidate = focused_element(); Node* candidate = focused_area();
// 2. Set candidate to the result of retargeting candidate against this. // 2. Set candidate to the result of retargeting candidate against this.
candidate = as<Node>(retarget(candidate, this)); candidate = as<Node>(retarget(candidate, this));
@ -2478,56 +2478,57 @@ void Document::update_active_element()
set_active_element(nullptr); set_active_element(nullptr);
} }
void Document::set_focused_element(GC::Ptr<Element> element) void Document::set_focused_area(GC::Ptr<Node> node)
{ {
if (m_focused_element.ptr() == element) if (m_focused_area == node)
return; return;
GC::Ptr<Element> old_focused_element = move(m_focused_element); GC::Ptr old_focused_area = m_focused_area;
if (old_focused_element) if (auto* old_focused_element = as_if<Element>(old_focused_area.ptr()))
old_focused_element->did_lose_focus(); old_focused_element->did_lose_focus();
auto* common_ancestor = find_common_ancestor(old_focused_element, element); auto* common_ancestor = find_common_ancestor(old_focused_area, node);
GC::Ptr<Node> old_focused_node_root = nullptr; GC::Ptr<Node> old_focused_node_root = nullptr;
GC::Ptr<Node> new_focused_node_root = nullptr; GC::Ptr<Node> new_focused_node_root = nullptr;
if (old_focused_element) if (old_focused_area)
old_focused_node_root = old_focused_element->root(); old_focused_node_root = old_focused_area->root();
if (element) if (node)
new_focused_node_root = element->root(); new_focused_node_root = node->root();
if (old_focused_node_root != new_focused_node_root) { if (old_focused_node_root != new_focused_node_root) {
if (old_focused_node_root) { if (old_focused_node_root) {
invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::Focus, m_focused_element, *old_focused_node_root, element); invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::Focus, m_focused_area, *old_focused_node_root, node);
invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusWithin, m_focused_element, *old_focused_node_root, element); invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusWithin, m_focused_area, *old_focused_node_root, node);
invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusVisible, m_focused_element, *old_focused_node_root, element); invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusVisible, m_focused_area, *old_focused_node_root, node);
} }
if (new_focused_node_root) { if (new_focused_node_root) {
invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::Focus, m_focused_element, *new_focused_node_root, element); invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::Focus, m_focused_area, *new_focused_node_root, node);
invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusWithin, m_focused_element, *new_focused_node_root, element); invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusWithin, m_focused_area, *new_focused_node_root, node);
invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusVisible, m_focused_element, *new_focused_node_root, element); invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusVisible, m_focused_area, *new_focused_node_root, node);
} }
} else { } else {
invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::Focus, m_focused_element, *common_ancestor, element); invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::Focus, m_focused_area, *common_ancestor, node);
invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusWithin, m_focused_element, *common_ancestor, element); invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusWithin, m_focused_area, *common_ancestor, node);
invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusVisible, m_focused_element, *common_ancestor, element); invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusVisible, m_focused_area, *common_ancestor, node);
} }
m_focused_element = element; m_focused_area = node;
if (m_focused_element) auto* new_focused_element = as_if<Element>(node.ptr());
m_focused_element->did_receive_focus(); if (new_focused_element)
new_focused_element->did_receive_focus();
if (paintable()) if (paintable())
paintable()->set_needs_display(); paintable()->set_needs_display();
// Scroll the viewport if necessary to make the newly focused element visible. // Scroll the viewport if necessary to make the newly focused element visible.
if (m_focused_element) { if (new_focused_element) {
m_focused_element->queue_an_element_task(HTML::Task::Source::UserInteraction, [&]() { new_focused_element->queue_an_element_task(HTML::Task::Source::UserInteraction, [&] {
ScrollIntoViewOptions scroll_options; ScrollIntoViewOptions scroll_options;
scroll_options.block = Bindings::ScrollLogicalPosition::Nearest; scroll_options.block = Bindings::ScrollLogicalPosition::Nearest;
scroll_options.inline_ = Bindings::ScrollLogicalPosition::Nearest; scroll_options.inline_ = Bindings::ScrollLogicalPosition::Nearest;
(void)m_focused_element->scroll_into_view(scroll_options); (void)as<Element>(*m_focused_area).scroll_into_view(scroll_options);
}); });
} }
@ -6338,38 +6339,38 @@ GC::Ref<Document> Document::parse_html_unsafe(JS::VM& vm, StringView html)
InputEventsTarget* Document::active_input_events_target() InputEventsTarget* Document::active_input_events_target()
{ {
auto* focused_element = this->focused_element(); auto focused_area = this->focused_area();
if (!focused_element) if (!focused_area)
return {}; return {};
if (is<HTML::HTMLInputElement>(*focused_element)) if (auto* input_element = as_if<HTML::HTMLInputElement>(*focused_area))
return static_cast<HTML::HTMLInputElement*>(focused_element); return input_element;
if (is<HTML::HTMLTextAreaElement>(*focused_element)) if (auto* text_area_element = as_if<HTML::HTMLTextAreaElement>(*focused_area))
return static_cast<HTML::HTMLTextAreaElement*>(focused_element); return text_area_element;
if (focused_element->is_editable_or_editing_host()) if (focused_area->is_editable_or_editing_host())
return m_editing_host_manager; return m_editing_host_manager;
return nullptr; return nullptr;
} }
GC::Ptr<DOM::Position> Document::cursor_position() const GC::Ptr<DOM::Position> Document::cursor_position() const
{ {
auto const* focused_element = this->focused_element(); auto const focused_area = this->focused_area();
if (!focused_element) if (!focused_area)
return nullptr; return nullptr;
Optional<HTML::FormAssociatedTextControlElement const&> target {}; Optional<HTML::FormAssociatedTextControlElement const&> target {};
if (auto const* input_element = as_if<HTML::HTMLInputElement>(*focused_element)) { if (auto const* input_element = as_if<HTML::HTMLInputElement>(*focused_area)) {
// Some types of <input> tags shouldn't have a cursor, like buttons // Some types of <input> tags shouldn't have a cursor, like buttons
if (!input_element->can_have_text_editing_cursor()) if (!input_element->can_have_text_editing_cursor())
return nullptr; return nullptr;
target = *input_element; target = *input_element;
} else if (is<HTML::HTMLTextAreaElement>(*focused_element)) } else if (is<HTML::HTMLTextAreaElement>(*focused_area))
target = static_cast<HTML::HTMLTextAreaElement const&>(*focused_element); target = static_cast<HTML::HTMLTextAreaElement const&>(*focused_area);
if (target.has_value()) if (target.has_value())
return target->cursor_position(); return target->cursor_position();
if (focused_element->is_editable_or_editing_host()) if (focused_area->is_editable_or_editing_host())
return m_selection->cursor_position(); return m_selection->cursor_position();
return nullptr; return nullptr;

View file

@ -35,7 +35,6 @@
#include <LibWeb/HTML/Focus.h> #include <LibWeb/HTML/Focus.h>
#include <LibWeb/HTML/HTMLScriptElement.h> #include <LibWeb/HTML/HTMLScriptElement.h>
#include <LibWeb/HTML/History.h> #include <LibWeb/HTML/History.h>
#include <LibWeb/HTML/LazyLoadingElement.h>
#include <LibWeb/HTML/NavigationType.h> #include <LibWeb/HTML/NavigationType.h>
#include <LibWeb/HTML/SandboxingFlagSet.h> #include <LibWeb/HTML/SandboxingFlagSet.h>
#include <LibWeb/HTML/Scripting/Environments.h> #include <LibWeb/HTML/Scripting/Environments.h>
@ -431,10 +430,10 @@ public:
void set_editable(bool editable) { m_editable = editable; } void set_editable(bool editable) { m_editable = editable; }
Element* focused_element() { return m_focused_element.ptr(); } // // https://html.spec.whatwg.org/multipage/interaction.html#focused-area-of-the-document
Element const* focused_element() const { return m_focused_element.ptr(); } GC::Ptr<Node> focused_area() { return m_focused_area; }
GC::Ptr<Node const> focused_area() const { return m_focused_area; }
void set_focused_element(GC::Ptr<Element>); void set_focused_area(GC::Ptr<Node>);
HTML::FocusTrigger last_focus_trigger() const { return m_last_focus_trigger; } HTML::FocusTrigger last_focus_trigger() const { return m_last_focus_trigger; }
void set_last_focus_trigger(HTML::FocusTrigger trigger) { m_last_focus_trigger = trigger; } void set_last_focus_trigger(HTML::FocusTrigger trigger) { m_last_focus_trigger = trigger; }
@ -1017,7 +1016,9 @@ private:
bool m_editable { false }; bool m_editable { false };
GC::Ptr<Element> m_focused_element; // https://html.spec.whatwg.org/multipage/interaction.html#focused-area-of-the-document
GC::Ptr<Node> m_focused_area;
HTML::FocusTrigger m_last_focus_trigger { HTML::FocusTrigger::Other }; HTML::FocusTrigger m_last_focus_trigger { HTML::FocusTrigger::Other };
GC::Ptr<Element> m_active_element; GC::Ptr<Element> m_active_element;

View file

@ -1077,7 +1077,7 @@ WebIDL::ExceptionOr<String> Element::inner_html() const
bool Element::is_focused() const bool Element::is_focused() const
{ {
return document().focused_element() == this; return document().focused_area() == this;
} }
bool Element::is_active() const bool Element::is_active() const
@ -3291,8 +3291,8 @@ bool Element::is_relevant_to_the_user()
return true; return true;
// Either the element or its contents are focused, as described in the focus section of the HTML spec. // Either the element or its contents are focused, as described in the focus section of the HTML spec.
auto* focused_element = document().focused_element(); auto focused_area = document().focused_area();
if (focused_element && is_inclusive_ancestor_of(*focused_element)) if (focused_area && is_inclusive_ancestor_of(*focused_area))
return true; return true;
// Either the element or its contents are selected, where selection is described in the selection API. // Either the element or its contents are selected, where selection is described in the selection API.

View file

@ -113,9 +113,9 @@ static void run_focus_update_steps(Vector<GC::Root<DOM::Node>> old_chain, Vector
// 1. If entry is a focusable area: designate entry as the focused area of the document. // 1. If entry is a focusable area: designate entry as the focused area of the document.
// FIXME: This isn't entirely right. // FIXME: This isn't entirely right.
if (is<DOM::Element>(*entry)) if (is<DOM::Element>(*entry))
entry->document().set_focused_element(&static_cast<DOM::Element&>(*entry)); entry->document().set_focused_area(*entry);
else if (is<DOM::Document>(*entry)) else if (is<DOM::Document>(*entry))
entry->document().set_focused_element(static_cast<DOM::Document&>(*entry).document_element()); entry->document().set_focused_area(static_cast<DOM::Document&>(*entry).document_element());
GC::Ptr<DOM::EventTarget> focus_event_target; GC::Ptr<DOM::EventTarget> focus_event_target;
if (is<DOM::Element>(*entry)) { if (is<DOM::Element>(*entry)) {

View file

@ -1369,17 +1369,17 @@ GC::Ptr<DOM::Node> TraversableNavigable::currently_focused_area()
// 3. While candidate's focused area is a navigable container with a non-null content navigable: // 3. While candidate's focused area is a navigable container with a non-null content navigable:
// set candidate to the active document of that navigable container's content navigable. // set candidate to the active document of that navigable container's content navigable.
while (candidate->focused_element() while (candidate->focused_area()
&& is<HTML::NavigableContainer>(candidate->focused_element()) && is<NavigableContainer>(candidate->focused_area().ptr())
&& static_cast<HTML::NavigableContainer&>(*candidate->focused_element()).content_navigable()) { && as<NavigableContainer>(*candidate->focused_area()).content_navigable()) {
candidate = static_cast<HTML::NavigableContainer&>(*candidate->focused_element()).content_navigable()->active_document(); candidate = as<NavigableContainer>(*candidate->focused_area()).content_navigable()->active_document();
} }
// 4. If candidate's focused area is non-null, set candidate to candidate's focused area. // 4. If candidate's focused area is non-null, set candidate to candidate's focused area.
if (candidate->focused_element()) { if (candidate->focused_area()) {
// NOTE: We return right away here instead of assigning to candidate, // NOTE: We return right away here instead of assigning to candidate,
// since that would require compromising type safety. // since that would require compromising type safety.
return candidate->focused_element(); return candidate->focused_area();
} }
// 5. Return candidate. // 5. Return candidate.

View file

@ -9,9 +9,7 @@
#include <AK/Badge.h> #include <AK/Badge.h>
#include <AK/RefPtr.h> #include <AK/RefPtr.h>
#include <AK/TypeCasts.h>
#include <LibGC/Heap.h> #include <LibGC/Heap.h>
#include <LibURL/URL.h>
#include <LibWeb/Bindings/Intrinsics.h> #include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Bindings/WindowGlobalMixin.h> #include <LibWeb/Bindings/WindowGlobalMixin.h>
#include <LibWeb/DOM/EventTarget.h> #include <LibWeb/DOM/EventTarget.h>
@ -22,6 +20,7 @@
#include <LibWeb/HTML/GlobalEventHandlers.h> #include <LibWeb/HTML/GlobalEventHandlers.h>
#include <LibWeb/HTML/MimeType.h> #include <LibWeb/HTML/MimeType.h>
#include <LibWeb/HTML/Navigable.h> #include <LibWeb/HTML/Navigable.h>
#include <LibWeb/HTML/Navigation.h>
#include <LibWeb/HTML/Plugin.h> #include <LibWeb/HTML/Plugin.h>
#include <LibWeb/HTML/ScrollOptions.h> #include <LibWeb/HTML/ScrollOptions.h>
#include <LibWeb/HTML/StructuredSerializeOptions.h> #include <LibWeb/HTML/StructuredSerializeOptions.h>

View file

@ -683,8 +683,8 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP
// Spec Note: Note that focusing is not an activation behavior, i.e. calling the click() method on an element or dispatching a synthetic click event on it won't cause the element to get focused. // Spec Note: Note that focusing is not an activation behavior, i.e. calling the click() method on an element or dispatching a synthetic click event on it won't cause the element to get focused.
if (focus_candidate) if (focus_candidate)
HTML::run_focusing_steps(focus_candidate, nullptr, HTML::FocusTrigger::Click); HTML::run_focusing_steps(focus_candidate, nullptr, HTML::FocusTrigger::Click);
else if (auto* focused_element = document->focused_element()) else if (auto focused_area = document->focused_area())
HTML::run_unfocusing_steps(focused_element); HTML::run_unfocusing_steps(focused_area);
// https://drafts.csswg.org/css-ui/#valdef-user-select-none // https://drafts.csswg.org/css-ui/#valdef-user-select-none
// Attempting to start a selection in an element where user-select is none, such as by clicking in it or starting // Attempting to start a selection in an element where user-select is none, such as by clicking in it or starting
@ -1066,17 +1066,17 @@ EventResult EventHandler::focus_next_element()
return EventResult::Dropped; return EventResult::Dropped;
}; };
auto* element = m_navigable->active_document()->focused_element(); auto node = m_navigable->active_document()->focused_area();
if (!element) if (!node)
return set_focus_to_first_focusable_element(); return set_focus_to_first_focusable_element();
for (element = element->next_element_in_pre_order(); element && !element->is_focusable(); element = element->next_element_in_pre_order()) for (node = node->next_in_pre_order(); node && !node->is_focusable(); node = node->next_in_pre_order())
; ;
if (!element) if (!node)
return set_focus_to_first_focusable_element(); return set_focus_to_first_focusable_element();
HTML::run_focusing_steps(element, nullptr, HTML::FocusTrigger::Key); HTML::run_focusing_steps(node, nullptr, HTML::FocusTrigger::Key);
return EventResult::Handled; return EventResult::Handled;
} }
@ -1101,17 +1101,17 @@ EventResult EventHandler::focus_previous_element()
return EventResult::Dropped; return EventResult::Dropped;
}; };
auto* element = m_navigable->active_document()->focused_element(); auto node = m_navigable->active_document()->focused_area();
if (!element) if (!node)
return set_focus_to_last_focusable_element(); return set_focus_to_last_focusable_element();
for (element = element->previous_element_in_pre_order(); element && !element->is_focusable(); element = element->previous_element_in_pre_order()) for (node = node->previous_in_pre_order(); node && !node->is_focusable(); node = node->previous_in_pre_order())
; ;
if (!element) if (!node)
return set_focus_to_last_focusable_element(); return set_focus_to_last_focusable_element();
HTML::run_focusing_steps(element, nullptr, HTML::FocusTrigger::Key); HTML::run_focusing_steps(node, nullptr, HTML::FocusTrigger::Key);
return EventResult::Handled; return EventResult::Handled;
} }
@ -1132,15 +1132,15 @@ EventResult EventHandler::fire_keyboard_event(FlyString const& event_name, HTML:
if (!document->is_fully_active()) if (!document->is_fully_active())
return EventResult::Dropped; return EventResult::Dropped;
if (GC::Ptr<DOM::Element> focused_element = document->focused_element()) { if (GC::Ptr focused_area = document->focused_area()) {
if (is<HTML::NavigableContainer>(*focused_element)) { if (is<HTML::NavigableContainer>(*focused_area)) {
auto& navigable_container = as<HTML::NavigableContainer>(*focused_element); auto& navigable_container = as<HTML::NavigableContainer>(*focused_area);
if (navigable_container.content_navigable()) if (navigable_container.content_navigable())
return fire_keyboard_event(event_name, *navigable_container.content_navigable(), key, modifiers, code_point, repeat); return fire_keyboard_event(event_name, *navigable_container.content_navigable(), key, modifiers, code_point, repeat);
} }
auto event = UIEvents::KeyboardEvent::create_from_platform_event(document->realm(), event_name, key, modifiers, code_point, repeat); auto event = UIEvents::KeyboardEvent::create_from_platform_event(document->realm(), event_name, key, modifiers, code_point, repeat);
return focused_element->dispatch_event(event) ? EventResult::Accepted : EventResult::Cancelled; return focused_area->dispatch_event(event) ? EventResult::Accepted : EventResult::Cancelled;
} }
// FIXME: De-duplicate this. This is just to prevent wasting a KeyboardEvent allocation when recursing into an (i)frame. // FIXME: De-duplicate this. This is just to prevent wasting a KeyboardEvent allocation when recursing into an (i)frame.
@ -1207,15 +1207,15 @@ EventResult EventHandler::input_event(FlyString const& event_name, FlyString con
input_event_init.input_type = input_type; input_event_init.input_type = input_type;
if (auto* focused_element = document->focused_element()) { if (auto focused_area = document->focused_area()) {
if (is<HTML::NavigableContainer>(*focused_element)) { if (is<HTML::NavigableContainer>(*focused_area)) {
auto& navigable_container = as<HTML::NavigableContainer>(*focused_element); auto& navigable_container = as<HTML::NavigableContainer>(*focused_area);
if (navigable_container.content_navigable()) if (navigable_container.content_navigable())
return input_event(event_name, input_type, *navigable_container.content_navigable(), move(code_point_or_string)); return input_event(event_name, input_type, *navigable_container.content_navigable(), move(code_point_or_string));
} }
auto event = UIEvents::InputEvent::create_from_platform_event(document->realm(), event_name, input_event_init, target_ranges_for_input_event(*document)); auto event = UIEvents::InputEvent::create_from_platform_event(document->realm(), event_name, input_event_init, target_ranges_for_input_event(*document));
return focused_element->dispatch_event(event) ? EventResult::Accepted : EventResult::Cancelled; return focused_area->dispatch_event(event) ? EventResult::Accepted : EventResult::Cancelled;
} }
auto event = UIEvents::InputEvent::create_from_platform_event(document->realm(), event_name, input_event_init, target_ranges_for_input_event(*document)); auto event = UIEvents::InputEvent::create_from_platform_event(document->realm(), event_name, input_event_init, target_ranges_for_input_event(*document));
@ -1270,8 +1270,8 @@ EventResult EventHandler::handle_keydown(UIEvents::KeyCode key, u32 modifiers, u
// instead interpret this interaction as some other action, instead of interpreting it as a close request. // instead interpret this interaction as some other action, instead of interpreting it as a close request.
} }
auto* focused_element = m_navigable->active_document()->focused_element(); auto focused_area = m_navigable->active_document()->focused_area();
if (auto* media_element = as_if<HTML::HTMLMediaElement>(focused_element)) { if (auto* media_element = as_if<HTML::HTMLMediaElement>(focused_area.ptr())) {
if (media_element->handle_keydown({}, key, modifiers).release_value_but_fixme_should_propagate_errors()) if (media_element->handle_keydown({}, key, modifiers).release_value_but_fixme_should_propagate_errors())
return EventResult::Handled; return EventResult::Handled;
} }
@ -1347,8 +1347,8 @@ EventResult EventHandler::handle_keydown(UIEvents::KeyCode key, u32 modifiers, u
auto input_type = modifiers == UIEvents::Mod_Shift ? UIEvents::InputTypes::insertLineBreak : UIEvents::InputTypes::insertParagraph; auto input_type = modifiers == UIEvents::Mod_Shift ? UIEvents::InputTypes::insertLineBreak : UIEvents::InputTypes::insertParagraph;
// If the editing host is contenteditable="plaintext-only", we force a line break. // If the editing host is contenteditable="plaintext-only", we force a line break.
if (focused_element) { if (focused_area) {
if (auto editing_host = focused_element->editing_host(); editing_host if (auto editing_host = focused_area->editing_host(); editing_host
&& as<HTML::HTMLElement>(*editing_host).content_editable_state() == HTML::ContentEditableState::PlaintextOnly) && as<HTML::HTMLElement>(*editing_host).content_editable_state() == HTML::ContentEditableState::PlaintextOnly)
input_type = UIEvents::InputTypes::insertLineBreak; input_type = UIEvents::InputTypes::insertLineBreak;
} }

View file

@ -180,12 +180,12 @@ Gfx::Orientation PaintableFragment::orientation() const
CSSPixelRect PaintableFragment::selection_rect() const CSSPixelRect PaintableFragment::selection_rect() const
{ {
if (auto const* focused_element = paintable().document().focused_element(); focused_element && is<HTML::FormAssociatedTextControlElement>(*focused_element)) { if (auto focused_area = paintable().document().focused_area(); is<HTML::FormAssociatedTextControlElement>(focused_area.ptr())) {
HTML::FormAssociatedTextControlElement const* text_control_element = nullptr; HTML::FormAssociatedTextControlElement const* text_control_element = nullptr;
if (is<HTML::HTMLInputElement>(*focused_element)) { if (auto const* input_element = as_if<HTML::HTMLInputElement>(*focused_area)) {
text_control_element = static_cast<HTML::HTMLInputElement const*>(focused_element); text_control_element = input_element;
} else if (is<HTML::HTMLTextAreaElement>(*focused_element)) { } else if (auto const* text_area_element = as_if<HTML::HTMLTextAreaElement>(*focused_area)) {
text_control_element = static_cast<HTML::HTMLTextAreaElement const*>(focused_element); text_control_element = text_area_element;
} else { } else {
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }

View file

@ -552,7 +552,7 @@ void Selection::set_range(GC::Ptr<DOM::Range> range)
GC::Ref new_editing_host = *range->start_container()->editing_host(); GC::Ref new_editing_host = *range->start_container()->editing_host();
while (new_editing_host->parent() && new_editing_host->parent()->is_editing_host()) while (new_editing_host->parent() && new_editing_host->parent()->is_editing_host())
new_editing_host = *new_editing_host->parent(); new_editing_host = *new_editing_host->parent();
if (document()->focused_element() != new_editing_host) { if (document()->focused_area() != new_editing_host) {
// FIXME: Determine and propagate the right focus trigger. // FIXME: Determine and propagate the right focus trigger.
HTML::run_focusing_steps(new_editing_host, nullptr, HTML::FocusTrigger::Other); HTML::run_focusing_steps(new_editing_host, nullptr, HTML::FocusTrigger::Other);
} }

View file

@ -1961,7 +1961,7 @@ Web::WebDriver::Response WebDriverConnection::element_send_keys_impl(StringView
else if (is<Web::HTML::HTMLElement>(*element) && static_cast<Web::HTML::HTMLElement&>(*element).is_content_editable()) { else if (is<Web::HTML::HTMLElement>(*element) && static_cast<Web::HTML::HTMLElement&>(*element).is_content_editable()) {
// If element does not currently have focus, set the text insertion caret after any child content. // If element does not currently have focus, set the text insertion caret after any child content.
auto* document = current_browsing_context().active_document(); auto* document = current_browsing_context().active_document();
document->set_focused_element(element); document->set_focused_area(element);
} }
// -> otherwise // -> otherwise
else if (is<Web::HTML::FormAssociatedTextControlElement>(*element)) { else if (is<Web::HTML::FormAssociatedTextControlElement>(*element)) {