mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-09 01:29:17 +00:00
LibWeb: Implement popover's close watcher
Auto popovers now correctly establish a close watcher when shown. This means popovers now correctly close with an escape key press. Also correctly hide open popovers when removed from the document.
This commit is contained in:
parent
09a55e56ee
commit
0a02eb639d
Notes:
github-actions[bot]
2024-12-17 03:56:49 +00:00
Author: https://github.com/lukewarlow
Commit: 0a02eb639d
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/344
2 changed files with 36 additions and 4 deletions
|
@ -5,6 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/StringBuilder.h>
|
#include <AK/StringBuilder.h>
|
||||||
|
#include <LibJS/Runtime/NativeFunction.h>
|
||||||
#include <LibWeb/ARIA/Roles.h>
|
#include <LibWeb/ARIA/Roles.h>
|
||||||
#include <LibWeb/Bindings/ExceptionOrUtils.h>
|
#include <LibWeb/Bindings/ExceptionOrUtils.h>
|
||||||
#include <LibWeb/Bindings/HTMLElementPrototype.h>
|
#include <LibWeb/Bindings/HTMLElementPrototype.h>
|
||||||
|
@ -17,6 +18,7 @@
|
||||||
#include <LibWeb/DOM/Position.h>
|
#include <LibWeb/DOM/Position.h>
|
||||||
#include <LibWeb/DOM/ShadowRoot.h>
|
#include <LibWeb/DOM/ShadowRoot.h>
|
||||||
#include <LibWeb/HTML/BrowsingContext.h>
|
#include <LibWeb/HTML/BrowsingContext.h>
|
||||||
|
#include <LibWeb/HTML/CloseWatcher.h>
|
||||||
#include <LibWeb/HTML/CustomElements/CustomElementDefinition.h>
|
#include <LibWeb/HTML/CustomElements/CustomElementDefinition.h>
|
||||||
#include <LibWeb/HTML/ElementInternals.h>
|
#include <LibWeb/HTML/ElementInternals.h>
|
||||||
#include <LibWeb/HTML/EventHandler.h>
|
#include <LibWeb/HTML/EventHandler.h>
|
||||||
|
@ -65,6 +67,7 @@ void HTMLElement::visit_edges(Cell::Visitor& visitor)
|
||||||
visitor.visit(m_labels);
|
visitor.visit(m_labels);
|
||||||
visitor.visit(m_attached_internals);
|
visitor.visit(m_attached_internals);
|
||||||
visitor.visit(m_popover_invoker);
|
visitor.visit(m_popover_invoker);
|
||||||
|
visitor.visit(m_popover_close_watcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/dom.html#dom-dir
|
// https://html.spec.whatwg.org/multipage/dom.html#dom-dir
|
||||||
|
@ -1051,9 +1054,20 @@ WebIDL::ExceptionOr<void> HTMLElement::show_popover(ThrowExceptions throw_except
|
||||||
// FIXME: 11.5. If originalType is not equal to the value of element's popover attribute, then throw a "InvalidStateError" DOMException.
|
// FIXME: 11.5. If originalType is not equal to the value of element's popover attribute, then throw a "InvalidStateError" DOMException.
|
||||||
// FIXME: 11.6. If the result of running check popover validity given element, false, throwExceptions, and document is false, then run cleanupShowingFlag and return.
|
// FIXME: 11.6. If the result of running check popover validity given element, false, throwExceptions, and document is false, then run cleanupShowingFlag and return.
|
||||||
// FIXME: 11.7. If the result of running topmost auto popover on document is null, then set shouldRestoreFocus to true.
|
// FIXME: 11.7. If the result of running topmost auto popover on document is null, then set shouldRestoreFocus to true.
|
||||||
// FIXME: 11.8. Set element's popover close watcher to the result of establishing a close watcher given element's relevant global object, with:
|
// 11.8. Set element's popover close watcher to the result of establishing a close watcher given element's relevant global object, with:
|
||||||
|
m_popover_close_watcher = CloseWatcher::establish(*document.window());
|
||||||
// - cancelAction being to return true.
|
// - cancelAction being to return true.
|
||||||
|
// We simply don't add an event listener for the cancel action.
|
||||||
// - closeAction being to hide a popover given element, true, true, and false.
|
// - closeAction being to hide a popover given element, true, true, and false.
|
||||||
|
auto close_callback_function = JS::NativeFunction::create(
|
||||||
|
realm(), [this](JS::VM&) {
|
||||||
|
MUST(hide_popover(FocusPreviousElement::Yes, FireEvents::Yes, ThrowExceptions::No));
|
||||||
|
|
||||||
|
return JS::js_undefined();
|
||||||
|
},
|
||||||
|
0, "", &realm());
|
||||||
|
auto close_callback = realm().heap().allocate<WebIDL::CallbackType>(*close_callback_function, realm());
|
||||||
|
m_popover_close_watcher->add_event_listener_without_options(HTML::EventNames::close, DOM::IDLEventListener::create(realm(), close_callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: 12. Set element's previously focused element to null.
|
// FIXME: 12. Set element's previously focused element to null.
|
||||||
|
@ -1116,9 +1130,13 @@ WebIDL::ExceptionOr<void> HTMLElement::hide_popover(FocusPreviousElement, FireEv
|
||||||
// 6.1. If nestedHide is false, then set element's popover showing or hiding to false.
|
// 6.1. If nestedHide is false, then set element's popover showing or hiding to false.
|
||||||
if (nested_hide)
|
if (nested_hide)
|
||||||
m_popover_showing_or_hiding = false;
|
m_popover_showing_or_hiding = false;
|
||||||
// FIXME: 6.2. If element's popover close watcher is not null, then:
|
// 6.2. If element's popover close watcher is not null, then:
|
||||||
// FIXME: 6.2.1. Destroy element's popover close watcher.
|
if (m_popover_close_watcher) {
|
||||||
// FIXME: 6.2.2. Set element's popover close watcher to null.
|
// 6.2.1. Destroy element's popover close watcher.
|
||||||
|
m_popover_close_watcher->destroy();
|
||||||
|
// 6.2.2. Set element's popover close watcher to null.
|
||||||
|
m_popover_close_watcher = nullptr;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 7. If element's popover attribute is in the auto state, then:
|
// 7. If element's popover attribute is in the auto state, then:
|
||||||
|
@ -1275,6 +1293,15 @@ void HTMLElement::did_lose_focus()
|
||||||
document().editing_host_manager()->set_active_contenteditable_element(nullptr);
|
document().editing_host_manager()->set_active_contenteditable_element(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HTMLElement::removed_from(Node* old_parent)
|
||||||
|
{
|
||||||
|
Element::removed_from(old_parent);
|
||||||
|
|
||||||
|
// If removedNode's popover attribute is not in the no popover state, then run the hide popover algorithm given removedNode, false, false, and false.
|
||||||
|
if (popover().has_value())
|
||||||
|
MUST(hide_popover(FocusPreviousElement::No, FireEvents::No, ThrowExceptions::No));
|
||||||
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/interaction.html#dom-accesskeylabel
|
// https://html.spec.whatwg.org/multipage/interaction.html#dom-accesskeylabel
|
||||||
String HTMLElement::access_key_label() const
|
String HTMLElement::access_key_label() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -116,6 +116,8 @@ public:
|
||||||
WebIDL::ExceptionOr<void> set_popover(Optional<String> value);
|
WebIDL::ExceptionOr<void> set_popover(Optional<String> value);
|
||||||
Optional<String> popover() const;
|
Optional<String> popover() const;
|
||||||
|
|
||||||
|
virtual void removed_from(Node*) override;
|
||||||
|
|
||||||
enum class PopoverVisibilityState {
|
enum class PopoverVisibilityState {
|
||||||
Hidden,
|
Hidden,
|
||||||
Showing,
|
Showing,
|
||||||
|
@ -181,6 +183,9 @@ private:
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/popover.html#the-popover-attribute:toggle-task-tracker
|
// https://html.spec.whatwg.org/multipage/popover.html#the-popover-attribute:toggle-task-tracker
|
||||||
Optional<ToggleTaskTracker> m_popover_toggle_task_tracker;
|
Optional<ToggleTaskTracker> m_popover_toggle_task_tracker;
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/popover.html#popover-close-watcher
|
||||||
|
GC::Ptr<CloseWatcher> m_popover_close_watcher;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue