mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 11:28:12 +00:00
LibWeb: Add initial implementation of Element.blur()
This implementation includes a first cut at run the unfocusing steps from the spec, with many things left unimplemented. The viewport related spec steps in particular don't seem to map to LibWeb concepts, which makes figuring out if things are properly focused much more difficult.
This commit is contained in:
parent
f08a979b96
commit
a0d5724a58
3 changed files with 94 additions and 2 deletions
|
@ -9,12 +9,15 @@
|
|||
#include <LibJS/Parser.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/IDLEventListener.h>
|
||||
#include <LibWeb/DOM/ShadowRoot.h>
|
||||
#include <LibWeb/HTML/BrowsingContext.h>
|
||||
#include <LibWeb/HTML/BrowsingContextContainer.h>
|
||||
#include <LibWeb/HTML/EventHandler.h>
|
||||
#include <LibWeb/HTML/HTMLAnchorElement.h>
|
||||
#include <LibWeb/HTML/HTMLAreaElement.h>
|
||||
#include <LibWeb/HTML/HTMLBodyElement.h>
|
||||
#include <LibWeb/HTML/HTMLElement.h>
|
||||
#include <LibWeb/HTML/VisibilityState.h>
|
||||
#include <LibWeb/HTML/Window.h>
|
||||
#include <LibWeb/Layout/Box.h>
|
||||
#include <LibWeb/Layout/BreakNode.h>
|
||||
|
@ -225,7 +228,7 @@ void HTMLElement::parse_attribute(FlyString const& name, String const& value)
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/interaction.html#focus-update-steps
|
||||
static void run_focus_update_steps(Vector<JS::Handle<DOM::Node>> old_chain, Vector<JS::Handle<DOM::Node>> new_chain, DOM::Node& new_focus_target)
|
||||
static void run_focus_update_steps(Vector<JS::Handle<DOM::Node>> old_chain, Vector<JS::Handle<DOM::Node>> new_chain, DOM::Node* new_focus_target)
|
||||
{
|
||||
// 1. If the last entry in old chain and the last entry in new chain are the same,
|
||||
// pop the last entry from old chain and the last entry from new chain and redo this step.
|
||||
|
@ -405,7 +408,83 @@ static void run_focusing_steps(DOM::Node* new_focus_target, DOM::Node* fallback_
|
|||
auto new_chain = focus_chain(new_focus_target);
|
||||
|
||||
// 8. Run the focus update steps with old chain, new chain, and new focus target respectively.
|
||||
run_focus_update_steps(old_chain, new_chain, *new_focus_target);
|
||||
run_focus_update_steps(old_chain, new_chain, new_focus_target);
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/interaction.html#unfocusing-steps
|
||||
static void run_unfocusing_steps(DOM::Node* old_focus_target)
|
||||
{
|
||||
// NOTE: The unfocusing steps do not always result in the focus changing, even when applied to the currently focused
|
||||
// area of a top-level browsing context. For example, if the currently focused area of a top-level browsing context
|
||||
// is a viewport, then it will usually keep its focus regardless until another focusable area is explicitly focused
|
||||
// with the focusing steps.
|
||||
|
||||
auto is_shadow_host = [](DOM::Node* node) {
|
||||
return is<DOM::Element>(node) && static_cast<DOM::Element*>(node)->shadow_root() != nullptr;
|
||||
};
|
||||
|
||||
// 1. If old focus target is a shadow host whose shadow root's delegates focus is true, and old focus target's
|
||||
// shadow root is a shadow-including inclusive ancestor of the currently focused area of a top-level browsing
|
||||
// context's DOM anchor, then set old focus target to that currently focused area of a top-level browsing
|
||||
// context.
|
||||
if (is_shadow_host(old_focus_target)) {
|
||||
auto* shadow_root = static_cast<DOM::Element*>(old_focus_target)->shadow_root();
|
||||
if (shadow_root->delegates_focus()) {
|
||||
auto& top_level_browsing_context = old_focus_target->document().browsing_context()->top_level_browsing_context();
|
||||
if (auto currently_focused_area = top_level_browsing_context.currently_focused_area()) {
|
||||
if (shadow_root->is_shadow_including_ancestor_of(*currently_focused_area)) {
|
||||
old_focus_target = currently_focused_area;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: 2. If old focus target is inert, then return.
|
||||
|
||||
// FIXME: 3. If old focus target is an area element and one of its shapes is the currently focused area of a
|
||||
// top-level browsing context, or, if old focus target is an element with one or more scrollable regions, and one
|
||||
// of them is the currently focused area of a top-level browsing context, then let old focus target be that
|
||||
// currently focused area of a top-level browsing context.
|
||||
|
||||
// NOTE: HTMLAreaElement is currently missing the shapes property
|
||||
|
||||
auto& top_level_browsing_context = old_focus_target->document().browsing_context()->top_level_browsing_context();
|
||||
|
||||
// 4. Let old chain be the current focus chain of the top-level browsing context in which old focus target finds itself.
|
||||
auto old_chain = focus_chain(top_level_browsing_context.currently_focused_area());
|
||||
|
||||
// 5. If old focus target is not one of the entries in old chain, then return.
|
||||
for (auto& node : old_chain) {
|
||||
if (old_focus_target != node) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 6. If old focus target is not a focusable area, then return.
|
||||
if (!old_focus_target->is_focusable())
|
||||
return;
|
||||
|
||||
// 7. Let topDocument be old chain's last entry.
|
||||
auto* top_document = verify_cast<DOM::Document>(old_chain.last().ptr());
|
||||
|
||||
// 8. If topDocument's browsing context has system focus, then run the focusing steps for topDocument's viewport.
|
||||
if (top_document->browsing_context()->system_visibility_state() == VisibilityState::Visible) {
|
||||
// FIXME: run the focusing steps for topDocument's viewport (??)
|
||||
} else {
|
||||
// FIXME: Otherwise, apply any relevant platform-specific conventions for removing system focus from
|
||||
// topDocument's browsing context, and run the focus update steps with old chain, an empty list, and null
|
||||
// respectively.
|
||||
|
||||
// What? It already doesn't have system focus, what possible platform-specific conventions are there?
|
||||
|
||||
run_focus_update_steps(old_chain, {}, nullptr);
|
||||
}
|
||||
|
||||
// FIXME: When the currently focused area of a top-level browsing context is somehow unfocused without another
|
||||
// element being explicitly focused in its stead, the user agent must immediately run the unfocusing steps for that
|
||||
// object.
|
||||
|
||||
// What? How are we supposed to detect when something is "somehow unfocused without another element being explicitly focused"?
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/interaction.html#dom-focus
|
||||
|
@ -480,4 +559,13 @@ void HTMLElement::click()
|
|||
m_click_in_progress = false;
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/interaction.html#dom-blur
|
||||
void HTMLElement::blur()
|
||||
{
|
||||
// The blur() method, when invoked, should run the unfocusing steps for the element on which the method was called.
|
||||
run_unfocusing_steps(this);
|
||||
|
||||
// User agents may selectively or uniformly ignore calls to this method for usability reasons.
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue