1
0
Fork 0
mirror of https://github.com/LadybirdBrowser/ladybird.git synced 2025-06-09 09:34:57 +09:00

LibWeb: Support :open for file and color <input> elements

This commit is contained in:
Sam Atkins 2025-01-31 15:34:34 +00:00
parent 942e14c27a
commit dc58f6567f
Notes: github-actions[bot] 2025-02-10 13:58:35 +00:00
4 changed files with 48 additions and 9 deletions

View file

@ -386,20 +386,24 @@ static bool matches_read_write_pseudo_class(DOM::Element const& element)
return element.is_editable_or_editing_host();
}
// https://www.w3.org/TR/selectors-4/#open-state
// https://drafts.csswg.org/selectors-4/#open-state
static bool matches_open_state_pseudo_class(DOM::Element const& element, bool open)
{
// The :open pseudo-class represents an element that has both “open” and “closed” states,
// and which is currently in the “open” state.
// The :closed pseudo-class represents an element that has both “open” and “closed” states,
// and which is currently in the closed state.
// NOTE: Spec specifically suggests supporting <details>, <dialog>, and <select>.
// There may be others we want to treat as open or closed.
// https://html.spec.whatwg.org/multipage/semantics-other.html#selector-open
// The :open pseudo-class must match any element falling into one of the following categories:
// - details elements that have an open attribute
// - dialog elements that have an open attribute
if (is<HTML::HTMLDetailsElement>(element) || is<HTML::HTMLDialogElement>(element))
return open == element.has_attribute(HTML::AttributeNames::open);
if (is<HTML::HTMLSelectElement>(element))
return open == static_cast<HTML::HTMLSelectElement const&>(element).is_open();
// - select elements that are a drop-down box and whose drop-down boxes are open
if (auto const* select = as_if<HTML::HTMLSelectElement>(element))
return open == select->is_open();
// - input elements that support a picker and whose pickers are open
if (auto const* input = as_if<HTML::HTMLInputElement>(element))
return open == (input->supports_a_picker() && input->is_open());
return false;
}

View file

@ -78,6 +78,7 @@ enum class ShouldComputeRole {
X(HTMLHyperlinkElementHrefChange) \
X(HTMLIFrameElementGeometryChange) \
X(HTMLInputElementSetChecked) \
X(HTMLInputElementSetIsOpen) \
X(HTMLObjectElementUpdateLayoutAndChildObjects) \
X(HTMLOptionElementSelectedChange) \
X(HTMLSelectElementSetIsOpen) \

View file

@ -299,7 +299,11 @@ static void show_the_picker_if_applicable(HTMLInputElement& element)
// 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:
// 4. If element does not support a picker, then return.
if (!element.supports_a_picker())
return;
// 5. If element's type attribute is in the File Upload state, then run these steps in parallel:
if (element.type_state() == HTMLInputElement::TypeAttributeState::FileUpload) {
// NOTE: These steps cannot be fully implemented here, and must be done in the PageClient when the response comes back from the PageHost
@ -317,11 +321,12 @@ static void show_the_picker_if_applicable(HTMLInputElement& element)
auto allow_multiple_files = element.has_attribute(HTML::AttributeNames::multiple) ? AllowMultipleFiles::Yes : AllowMultipleFiles::No;
auto weak_element = element.make_weak_ptr<HTMLInputElement>();
element.set_is_open(true);
element.document().browsing_context()->top_level_browsing_context()->page().did_request_file_picker(weak_element, move(accepted_file_types), allow_multiple_files);
return;
}
// 5. Otherwise, the user agent should show any relevant user interface for selecting a value for element,
// 6. 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.)
@ -329,6 +334,7 @@ static void show_the_picker_if_applicable(HTMLInputElement& element)
// (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.)
if (element.type_state() == HTMLInputElement::TypeAttributeState::Color) {
auto weak_element = element.make_weak_ptr<HTMLInputElement>();
element.set_is_open(true);
element.document().browsing_context()->top_level_browsing_context()->page().did_request_color_picker(weak_element, Color::from_string(element.value()).value_or(Color(0, 0, 0)));
}
}
@ -469,6 +475,8 @@ void HTMLInputElement::did_edit_text_node()
void HTMLInputElement::did_pick_color(Optional<Color> picked_color, ColorPickerUpdateState state)
{
set_is_open(false);
if (type_state() == TypeAttributeState::Color && picked_color.has_value()) {
// then when the user changes the element's value
m_value = value_sanitization_algorithm(picked_color.value().to_string_without_alpha());
@ -497,6 +505,8 @@ void HTMLInputElement::did_pick_color(Optional<Color> picked_color, ColorPickerU
void HTMLInputElement::did_select_files(Span<SelectedFile> selected_files, MultipleHandling multiple_handling)
{
set_is_open(false);
// https://html.spec.whatwg.org/multipage/input.html#show-the-picker,-if-applicable
// 4. If the user dismissed the prompt without changing their selection, then queue an element task on the user
// interaction task source given element to fire an event named cancel at element, with the bubbles attribute
@ -2949,4 +2959,22 @@ bool HTMLInputElement::suffering_from_bad_input() const
return false;
}
// https://html.spec.whatwg.org/multipage/input.html#input-support-picker
bool HTMLInputElement::supports_a_picker() const
{
// The input element can support a picker. A picker is a user interface element that allows the end user to choose a value.
// Whether an input element supports a picker depends on the type attribute state and implementation-defined behavior.
// An input element must support a picker when its type attribute is in the File Upload state.
return first_is_one_of(type_state(), TypeAttributeState::FileUpload, TypeAttributeState::Color);
}
void HTMLInputElement::set_is_open(bool is_open)
{
if (is_open == m_is_open)
return;
m_is_open = is_open;
invalidate_style(DOM::StyleInvalidationReason::HTMLInputElementSetIsOpen);
}
}

View file

@ -216,6 +216,10 @@ public:
bool selection_direction_applies() const;
bool has_selectable_text() const;
bool supports_a_picker() const;
bool is_open() const { return m_is_open; }
void set_is_open(bool);
static bool selection_or_range_applies_for_type_state(TypeAttributeState);
Optional<String> selection_direction_binding() { return selection_direction(); }
@ -368,6 +372,8 @@ private:
String m_last_src_value;
bool m_has_uncommitted_changes { false };
bool m_is_open { false };
};
}