1
0
mirror of https://github.com/SerenityOS/serenity synced 2024-07-01 11:19:21 +00:00

LibWeb: Add HTMLSelectElement showPicker()

Adds the showPicker() function for select elements.
This doesn't do the check for "being rendered" which is in the spec.

(cherry picked from commit 5098ed6b1f881659dbdab10c74a0e17b362ce7a8)
This commit is contained in:
Luke Warlow 2024-06-13 18:11:45 +02:00 committed by Nico Weber
parent 33c315bad0
commit 1df32b7e1a
3 changed files with 72 additions and 1 deletions

View File

@ -20,6 +20,7 @@
#include <LibWeb/HTML/HTMLOptionElement.h>
#include <LibWeb/HTML/HTMLSelectElement.h>
#include <LibWeb/HTML/Numbers.h>
#include <LibWeb/HTML/Window.h>
#include <LibWeb/Infra/Strings.h>
#include <LibWeb/Layout/Node.h>
#include <LibWeb/Namespace.h>
@ -336,8 +337,37 @@ static String strip_newlines(Optional<String> string)
return MUST(Infra::strip_and_collapse_whitespace(MUST(builder.to_string())));
}
void HTMLSelectElement::activation_behavior(DOM::Event const&)
// https://html.spec.whatwg.org/multipage/input.html#show-the-picker,-if-applicable
void HTMLSelectElement::show_the_picker_if_applicable()
{
// FIXME: Deduplicate with HTMLInputElement
// To show the picker, if applicable for a select element:
// 1. If element's relevant global object does not have transient activation, then return.
auto& global_object = relevant_global_object(*this);
if (!is<HTML::Window>(global_object))
return;
auto& relevant_global_object = static_cast<HTML::Window&>(global_object);
if (!relevant_global_object.has_transient_activation())
return;
// 2. If element is not mutable, then return.
if (!enabled())
return;
// 3. Consume user activation given element's relevant global object.
relevant_global_object.consume_user_activation();
// 4. If element's type attribute is in the File Upload state, then run these steps in parallel:
// Not Applicable to select elements
// 5. Otherwise, the user agent should show any relevant user interface for selecting a value for element,
// in the way it normally would when the user interacts with the control. (If no such UI applies to element, then this step does nothing.)
// If such a user interface is shown, it must respect the requirements stated in the relevant parts of the specification for how element
// behaves given its type attribute state. (For example, various sections describe restrictions on the resulting value string.)
// This step can have side effects, such as closing other pickers that were previously shown by this algorithm.
// (If this closes a file selection picker, then per the above that will lead to firing either input and change events, or a cancel event.)
// Populate select items
m_select_items.clear();
u32 id_counter = 1;
@ -371,6 +401,41 @@ void HTMLSelectElement::activation_behavior(DOM::Event const&)
set_is_open(true);
}
// https://html.spec.whatwg.org/multipage/input.html#dom-select-showpicker
WebIDL::ExceptionOr<void> HTMLSelectElement::show_picker()
{
// FIXME: Deduplicate with HTMLInputElement
// The showPicker() method steps are:
// 1. If this is not mutable, then throw an "InvalidStateError" DOMException.
if (!enabled())
return WebIDL::InvalidStateError::create(realm(), "Element is not mutable"_fly_string);
// 2. If this's relevant settings object's origin is not same origin with this's relevant settings object's top-level origin,
// and this is a select element, then throw a "SecurityError" DOMException.
if (!relevant_settings_object(*this).origin().is_same_origin(relevant_settings_object(*this).top_level_origin)) {
return WebIDL::SecurityError::create(realm(), "Cross origin pickers are not allowed"_fly_string);
}
// 3. If this's relevant global object does not have transient activation, then throw a "NotAllowedError" DOMException.
// FIXME: The global object we get here should probably not need casted to Window to check for transient activation
auto& global_object = relevant_global_object(*this);
if (!is<HTML::Window>(global_object) || !static_cast<HTML::Window&>(global_object).has_transient_activation()) {
return WebIDL::NotAllowedError::create(realm(), "Too long since user activation to show picker"_fly_string);
}
// FIXME: 4. If this is a select element, and this is not being rendered, then throw a "NotSupportedError" DOMException.
// 5. Show the picker, if applicable, for this.
show_the_picker_if_applicable();
return {};
}
void HTMLSelectElement::activation_behavior(DOM::Event const&)
{
show_the_picker_if_applicable();
}
void HTMLSelectElement::did_select_item(Optional<u32> const& id)
{
set_is_open(false);

View File

@ -53,6 +53,8 @@ public:
bool is_open() const { return m_is_open; }
void set_is_open(bool);
WebIDL::ExceptionOr<void> show_picker();
Vector<JS::Handle<HTMLOptionElement>> list_of_options() const;
// ^EventTarget
@ -101,6 +103,8 @@ private:
virtual void computed_css_values_changed() override;
void show_the_picker_if_applicable();
void create_shadow_tree_if_needed();
void update_inner_text_element();
void queue_input_and_change_events();

View File

@ -37,5 +37,7 @@ interface HTMLSelectElement : HTMLElement {
[FIXME] boolean reportValidity();
[FIXME] undefined setCustomValidity(DOMString error);
undefined showPicker();
readonly attribute NodeList labels;
};