Ver código fonte

LibWeb: Implement EventHandler::focus_previous_element()

This implements EventHandler::focus_previous_element() so we can cycle
backwards through focusable elements on a web page with Shift+Tab.
Kenneth Myhra 3 anos atrás
pai
commit
bf7f6a9e98

+ 10 - 0
Userland/Libraries/LibWeb/DOM/NonDocumentTypeChildNode.h

@@ -24,6 +24,15 @@ public:
         return nullptr;
         return nullptr;
     }
     }
 
 
+    Element* previous_element_in_pre_order()
+    {
+        for (auto* node = static_cast<NodeType*>(this)->previous_in_pre_order(); node; node = node->previous_in_pre_order()) {
+            if (is<Element>(*node))
+                return verify_cast<Element>(node);
+        }
+        return nullptr;
+    }
+
     Element* next_element_sibling()
     Element* next_element_sibling()
     {
     {
         for (auto* sibling = static_cast<NodeType*>(this)->next_sibling(); sibling; sibling = sibling->next_sibling()) {
         for (auto* sibling = static_cast<NodeType*>(this)->next_sibling(); sibling; sibling = sibling->next_sibling()) {
@@ -43,6 +52,7 @@ public:
     }
     }
 
 
     const Element* previous_element_sibling() const { return const_cast<NonDocumentTypeChildNode*>(this)->previous_element_sibling(); }
     const Element* previous_element_sibling() const { return const_cast<NonDocumentTypeChildNode*>(this)->previous_element_sibling(); }
+    const Element* previous_element_in_pre_order() const { return const_cast<NonDocumentTypeChildNode*>(this)->previous_element_in_pre_order(); }
     const Element* next_element_sibling() const { return const_cast<NonDocumentTypeChildNode*>(this)->next_element_sibling(); }
     const Element* next_element_sibling() const { return const_cast<NonDocumentTypeChildNode*>(this)->next_element_sibling(); }
     const Element* next_element_in_pre_order() const { return const_cast<NonDocumentTypeChildNode*>(this)->next_element_in_pre_order(); }
     const Element* next_element_in_pre_order() const { return const_cast<NonDocumentTypeChildNode*>(this)->next_element_in_pre_order(); }
 
 

+ 16 - 2
Userland/Libraries/LibWeb/Page/EventHandler.cpp

@@ -413,8 +413,22 @@ bool EventHandler::focus_next_element()
 
 
 bool EventHandler::focus_previous_element()
 bool EventHandler::focus_previous_element()
 {
 {
-    // FIXME: Implement Shift-Tab cycling backwards through focusable elements!
-    return false;
+    if (!m_browsing_context.active_document())
+        return false;
+    auto* element = m_browsing_context.active_document()->focused_element();
+    if (!element) {
+        element = m_browsing_context.active_document()->last_child_of_type<DOM::Element>();
+        if (element && element->is_focusable()) {
+            m_browsing_context.active_document()->set_focused_element(element);
+            return true;
+        }
+    }
+
+    for (element = element->previous_element_in_pre_order(); element && !element->is_focusable(); element = element->previous_element_in_pre_order())
+        ;
+
+    m_browsing_context.active_document()->set_focused_element(element);
+    return element;
 }
 }
 
 
 constexpr bool should_ignore_keydown_event(u32 code_point)
 constexpr bool should_ignore_keydown_event(u32 code_point)