diff --git a/Tests/LibWeb/Text/expected/UIEvents/KeyEvent-tab.txt b/Tests/LibWeb/Text/expected/UIEvents/KeyEvent-tab.txt new file mode 100644 index 00000000000..46757bd93ec --- /dev/null +++ b/Tests/LibWeb/Text/expected/UIEvents/KeyEvent-tab.txt @@ -0,0 +1,4 @@ +input1 keydown Tab + +input2 keydown Tab + diff --git a/Tests/LibWeb/Text/input/UIEvents/KeyEvent-tab.html b/Tests/LibWeb/Text/input/UIEvents/KeyEvent-tab.html new file mode 100644 index 00000000000..ee7b0478fc7 --- /dev/null +++ b/Tests/LibWeb/Text/input/UIEvents/KeyEvent-tab.html @@ -0,0 +1,22 @@ + + + + diff --git a/Userland/Libraries/LibWeb/Page/EventHandler.cpp b/Userland/Libraries/LibWeb/Page/EventHandler.cpp index 4e3fc372822..67a7442e01a 100644 --- a/Userland/Libraries/LibWeb/Page/EventHandler.cpp +++ b/Userland/Libraries/LibWeb/Page/EventHandler.cpp @@ -763,20 +763,31 @@ bool EventHandler::focus_next_element() if (!m_navigable->active_document()->is_fully_active()) return false; - auto* element = m_navigable->active_document()->focused_element(); - if (!element) { - element = m_navigable->active_document()->first_child_of_type(); - if (element && element->is_focusable()) { - m_navigable->active_document()->set_focused_element(element); - return true; + auto set_focus_to_first_focusable_element = [&]() { + auto* element = m_navigable->active_document()->first_child_of_type(); + + for (; element; element = element->next_element_in_pre_order()) { + if (element->is_focusable()) { + m_navigable->active_document()->set_focused_element(element); + return true; + } } - } + + return false; + }; + + auto* element = m_navigable->active_document()->focused_element(); + if (!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()) ; + if (!element) + return set_focus_to_first_focusable_element(); + m_navigable->active_document()->set_focused_element(element); - return element; + return true; } bool EventHandler::focus_previous_element() @@ -786,20 +797,32 @@ bool EventHandler::focus_previous_element() if (!m_navigable->active_document()->is_fully_active()) return false; - auto* element = m_navigable->active_document()->focused_element(); - if (!element) { - element = m_navigable->active_document()->last_child_of_type(); - if (element && element->is_focusable()) { - m_navigable->active_document()->set_focused_element(element); - return true; + auto set_focus_to_last_focusable_element = [&]() { + // FIXME: This often returns the HTML element itself, which has no previous sibling. + auto* element = m_navigable->active_document()->last_child_of_type(); + + for (; element; element = element->previous_element_in_pre_order()) { + if (element->is_focusable()) { + m_navigable->active_document()->set_focused_element(element); + return true; + } } - } + + return false; + }; + + auto* element = m_navigable->active_document()->focused_element(); + if (!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()) ; + if (!element) + return set_focus_to_last_focusable_element(); + m_navigable->active_document()->set_focused_element(element); - return element; + return true; } constexpr bool should_ignore_keydown_event(u32 code_point, u32 modifiers)