mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-02 06:09:08 +00:00
LibWeb: Implement popovertarget buttons
This commit is contained in:
parent
a1cf5271c2
commit
108f3a9aac
Notes:
github-actions[bot]
2025-01-30 22:49:42 +00:00
Author: https://github.com/Gingeh
Commit: 108f3a9aac
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3285
Reviewed-by: https://github.com/ADKaster ✅
Reviewed-by: https://github.com/AtkinsSJ
14 changed files with 188 additions and 14 deletions
|
@ -4,8 +4,12 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
#include <LibWeb/DOM/Node.h>
|
||||
#include <LibWeb/HTML/AttributeNames.h>
|
||||
#include <LibWeb/HTML/FormAssociatedElement.h>
|
||||
#include <LibWeb/HTML/HTMLElement.h>
|
||||
#include <LibWeb/HTML/PopoverInvokerElement.h>
|
||||
|
||||
namespace Web::HTML {
|
||||
|
@ -29,4 +33,92 @@ void PopoverInvokerElement::visit_edges(JS::Cell::Visitor& visitor)
|
|||
visitor.visit(m_popover_target_element);
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/popover.html#popover-target-attribute-activation-behavior
|
||||
void PopoverInvokerElement::popover_target_activation_behaviour(GC::Ref<DOM::Node> node, GC::Ref<DOM::Node> event_target)
|
||||
{
|
||||
// To run the popover target attribute activation behavior given a Node node and a Node eventTarget:
|
||||
|
||||
// 1. Let popover be node's popover target element.
|
||||
auto popover = PopoverInvokerElement::get_the_popover_target_element(node);
|
||||
|
||||
// 2. If popover is null, then return.
|
||||
if (!popover)
|
||||
return;
|
||||
|
||||
// 3. If eventTarget is a shadow-including inclusive descendant of popover and popover is a shadow-including descendant of node, then return.
|
||||
if (event_target->is_shadow_including_inclusive_descendant_of(*popover)
|
||||
&& popover->is_shadow_including_descendant_of(node))
|
||||
return;
|
||||
|
||||
// 4. If node's popovertargetaction attribute is in the show state and popover's popover visibility state is showing, then return.
|
||||
if (as<DOM::Element>(*node).get_attribute_value(HTML::AttributeNames::popovertargetaction).equals_ignoring_ascii_case("show"sv)
|
||||
&& popover->popover_visibility_state() == HTMLElement::PopoverVisibilityState::Showing)
|
||||
return;
|
||||
|
||||
// 5. If node's popovertargetaction attribute is in the hide state and popover's popover visibility state is hidden, then return.
|
||||
if (as<DOM::Element>(*node).get_attribute_value(HTML::AttributeNames::popovertargetaction).equals_ignoring_ascii_case("hide"sv)
|
||||
&& popover->popover_visibility_state() == HTMLElement::PopoverVisibilityState::Hidden)
|
||||
return;
|
||||
|
||||
// 6. If popover's popover visibility state is showing, then run the hide popover algorithm given popover, true, true, and false.
|
||||
if (popover->popover_visibility_state() == HTMLElement::PopoverVisibilityState::Showing) {
|
||||
MUST(popover->hide_popover(FocusPreviousElement::Yes, FireEvents::Yes, ThrowExceptions::No));
|
||||
}
|
||||
|
||||
// 7. Otherwise, if popover's popover visibility state is hidden and the result of running check popover validity given popover, false, false, and null is true, then run show popover given popover, false, and node.
|
||||
else if (popover->popover_visibility_state() == HTMLElement::PopoverVisibilityState::Hidden
|
||||
&& MUST(popover->check_popover_validity(ExpectedToBeShowing::No, ThrowExceptions::No, nullptr))) {
|
||||
MUST(popover->show_popover(ThrowExceptions::No, as<HTMLElement>(*node)));
|
||||
}
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/popover.html#popover-target-element
|
||||
GC::Ptr<HTMLElement> PopoverInvokerElement::get_the_popover_target_element(GC::Ref<DOM::Node> node)
|
||||
{
|
||||
// To get the popover target element given a Node node, perform the following steps. They return an HTML element or null.
|
||||
|
||||
auto const* form_associated_element = dynamic_cast<FormAssociatedElement const*>(node.ptr());
|
||||
VERIFY(form_associated_element);
|
||||
|
||||
// 1. If node is not a button, then return null.
|
||||
if (!form_associated_element->is_button())
|
||||
return {};
|
||||
|
||||
// 2. If node is disabled, then return null.
|
||||
if (!form_associated_element->enabled())
|
||||
return {};
|
||||
|
||||
// 3. If node has a form owner and node is a submit button, then return null.
|
||||
if (form_associated_element->form() != nullptr && form_associated_element->is_submit_button())
|
||||
return {};
|
||||
|
||||
// 4. Let popoverElement be the result of running node's get the popovertarget-associated element.
|
||||
auto const* popover_invoker_element = dynamic_cast<PopoverInvokerElement const*>(node.ptr());
|
||||
VERIFY(popover_invoker_element);
|
||||
GC::Ptr<HTMLElement> popover_element = as<HTMLElement>(popover_invoker_element->m_popover_target_element.ptr());
|
||||
if (!popover_element) {
|
||||
auto target_id = as<HTMLElement>(*node).attribute("popovertarget"_fly_string);
|
||||
if (target_id.has_value()) {
|
||||
node->root().for_each_in_inclusive_subtree_of_type<HTMLElement>([&](auto& candidate) {
|
||||
if (candidate.attribute(HTML::AttributeNames::id) == target_id.value()) {
|
||||
popover_element = &candidate;
|
||||
return TraversalDecision::Break;
|
||||
}
|
||||
return TraversalDecision::Continue;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 5. If popoverElement is null, then return null.
|
||||
if (!popover_element)
|
||||
return {};
|
||||
|
||||
// 6. If popoverElement's popover attribute is in the no popover state, then return null.
|
||||
if (!popover_element->popover().has_value())
|
||||
return {};
|
||||
|
||||
// 7. Return popoverElement.
|
||||
return popover_element;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue