Move CSS animation values into a mutable overlay on computed properties and make base computed style data immutable after construction. Base style mutation now goes through a builder that is consumed on publish, so installed styles no longer expose mutation APIs. Build new base style data for inherited style updates instead of cloning and mutating installed computed properties. Element-specific computed style adjustments now run before publication, while animation and transition updates continue to mutate only the animated overlay.
180 lines
6.8 KiB
C++
180 lines
6.8 KiB
C++
/*
|
|
* Copyright (c) 2020, the SerenityOS developers.
|
|
* Copyright (c) 2021-2022, Andreas Kling <andreas@ladybird.org>
|
|
* Copyright (c) 2022, Luke Wilde <lukew@serenityos.org>
|
|
* Copyright (c) 2023, Bastiaan van der Plaat <bastiaan.v.d.plaat@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <LibWeb/Export.h>
|
|
#include <LibWeb/HTML/AutocompleteElement.h>
|
|
#include <LibWeb/HTML/HTMLElement.h>
|
|
#include <LibWeb/HTML/HTMLOptionsCollection.h>
|
|
#include <LibWeb/HTML/SelectItem.h>
|
|
#include <LibWeb/WebIDL/Types.h>
|
|
|
|
namespace Web::HTML {
|
|
|
|
class WEB_API HTMLSelectElement final
|
|
: public HTMLElement
|
|
, public AutocompleteElement {
|
|
WEB_PLATFORM_OBJECT(HTMLSelectElement, HTMLElement);
|
|
GC_DECLARE_ALLOCATOR(HTMLSelectElement);
|
|
AUTOCOMPLETE_ELEMENT(HTMLElement, HTMLSelectElement);
|
|
|
|
public:
|
|
virtual ~HTMLSelectElement() override;
|
|
|
|
virtual bool is_html_select_element() const final { return true; }
|
|
|
|
virtual void adjust_computed_style(CSS::ComputedProperties::Builder&) override;
|
|
|
|
WebIDL::UnsignedLong size() const;
|
|
void set_size(WebIDL::UnsignedLong);
|
|
|
|
GC::Ptr<HTMLOptionsCollection> const& options() const;
|
|
|
|
WebIDL::UnsignedLong length();
|
|
WebIDL::ExceptionOr<void> set_length(WebIDL::UnsignedLong);
|
|
HTMLOptionElement* item(WebIDL::UnsignedLong index);
|
|
virtual Optional<JS::Value> item_value(size_t index) const override;
|
|
HTMLOptionElement* named_item(FlyString const& name);
|
|
WebIDL::ExceptionOr<void> add(HTMLOptionOrOptGroupElement element, NullableHTMLElementOrElementIndex before = { Empty {} });
|
|
virtual WebIDL::ExceptionOr<void> set_value_of_indexed_property(u32, JS::Value) override;
|
|
void remove();
|
|
void remove(WebIDL::Long);
|
|
|
|
GC::Ref<DOM::HTMLCollection> selected_options();
|
|
GC::Ref<DOM::HTMLCollection> selected_options() const { return const_cast<HTMLSelectElement*>(this)->selected_options(); }
|
|
|
|
WebIDL::Long selected_index() const;
|
|
WebIDL::ExceptionOr<void> set_selected_index(WebIDL::Long);
|
|
|
|
Utf16String value() const;
|
|
virtual Utf16String form_value() const override { return value(); }
|
|
WebIDL::ExceptionOr<void> set_value(Utf16String const&);
|
|
|
|
bool is_open() const { return m_is_open; }
|
|
void set_is_open(bool);
|
|
|
|
WebIDL::ExceptionOr<void> show_picker();
|
|
|
|
Vector<GC::Root<HTMLOptionElement>> list_of_options() const;
|
|
|
|
// ^EventTarget
|
|
// https://html.spec.whatwg.org/multipage/interaction.html#the-tabindex-attribute:the-select-element
|
|
// https://html.spec.whatwg.org/multipage/interaction.html#focusable-area
|
|
// https://html.spec.whatwg.org/multipage/semantics-other.html#concept-element-disabled
|
|
virtual bool is_focusable() const override;
|
|
|
|
// ^FormAssociatedElement
|
|
virtual bool is_form_associated_element() const override { return true; }
|
|
|
|
// ^FormAssociatedElement
|
|
// https://html.spec.whatwg.org/multipage/forms.html#category-listed
|
|
virtual bool is_listed() const override { return true; }
|
|
|
|
// https://html.spec.whatwg.org/multipage/forms.html#category-submit
|
|
virtual bool is_submittable() const override { return true; }
|
|
|
|
// https://html.spec.whatwg.org/multipage/forms.html#category-reset
|
|
virtual bool is_resettable() const override { return true; }
|
|
|
|
// https://html.spec.whatwg.org/multipage/forms.html#category-autocapitalize
|
|
virtual bool is_autocapitalize_and_autocorrect_inheriting() const override { return true; }
|
|
|
|
// ^HTMLElement
|
|
// https://html.spec.whatwg.org/multipage/forms.html#category-label
|
|
virtual bool is_labelable() const override { return true; }
|
|
|
|
virtual void reset_algorithm() override;
|
|
|
|
String const& type() const;
|
|
|
|
virtual Optional<ARIA::Role> default_role() const override;
|
|
|
|
virtual bool has_activation_behavior() const override;
|
|
virtual void activation_behavior(DOM::Event const&) override;
|
|
|
|
virtual void form_associated_element_was_inserted() override;
|
|
virtual void form_associated_element_attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_) override;
|
|
|
|
void did_select_item(Optional<u32> const& id);
|
|
|
|
void update_selectedness();
|
|
|
|
void clone_selected_option_into_select_button();
|
|
|
|
bool can_skip_selectedness_update_for_inserted_option(HTMLOptionElement const&) const;
|
|
|
|
bool user_validity() const { return m_user_validity; }
|
|
void set_user_validity(bool flag) { m_user_validity = flag; }
|
|
|
|
// https://html.spec.whatwg.org/multipage/form-elements.html#placeholder-label-option
|
|
HTMLOptionElement* placeholder_label_option() const;
|
|
|
|
// https://html.spec.whatwg.org/multipage/form-elements.html#select-enabled-selectedcontent
|
|
GC::Ptr<HTMLSelectedContentElement> enabled_selectedcontent() const;
|
|
|
|
// https://html.spec.whatwg.org/multipage/form-elements.html#clear-a-select%27s-non-primary-selectedcontent-elements
|
|
void clear_non_primary_selectedcontent();
|
|
|
|
// https://html.spec.whatwg.org/multipage/form-elements.html#update-a-select%27s-selectedcontent
|
|
WebIDL::ExceptionOr<void> update_selectedcontent();
|
|
|
|
// https://html.spec.whatwg.org/multipage/form-elements.html#the-select-element%3Asuffering-from-being-missing
|
|
virtual bool suffering_from_being_missing() const override;
|
|
|
|
virtual bool is_mutable() const override;
|
|
|
|
private:
|
|
HTMLSelectElement(DOM::Document&, DOM::QualifiedName);
|
|
|
|
virtual void initialize(JS::Realm&) override;
|
|
virtual void visit_edges(Cell::Visitor&) override;
|
|
|
|
// ^DOM::Element
|
|
virtual i32 default_tab_index_value() const override;
|
|
|
|
virtual void computed_properties_changed() override;
|
|
|
|
virtual void children_changed(ChildrenChangedMetadata const&) override;
|
|
bool can_skip_children_changed_selectedness_update(ChildrenChangedMetadata const& metadata) const;
|
|
|
|
void update_cached_list_of_options() const;
|
|
void show_the_picker_if_applicable();
|
|
|
|
void create_shadow_tree_if_needed();
|
|
// https://html.spec.whatwg.org/multipage/form-elements.html#send-select-update-notifications
|
|
void send_select_update_notifications();
|
|
|
|
u32 display_size() const;
|
|
|
|
mutable Vector<GC::Ref<HTMLOptionElement>> m_cached_list_of_options;
|
|
mutable size_t m_cached_number_of_selected_options { 0 };
|
|
|
|
mutable GC::Ptr<HTMLOptionsCollection> m_options;
|
|
GC::Ptr<DOM::HTMLCollection> m_selected_options;
|
|
bool m_is_open { false };
|
|
Vector<SelectItem> m_select_items;
|
|
GC::Ptr<DOM::Element> m_inner_text_element;
|
|
GC::Ptr<DOM::Element> m_chevron_icon_element;
|
|
|
|
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#user-validity
|
|
bool m_user_validity { false };
|
|
};
|
|
|
|
GC::Ptr<HTMLSelectElement> get_nearest_ancestor_select(DOM::Element&);
|
|
GC::Ptr<HTMLSelectElement const> get_nearest_ancestor_select(DOM::Element const&);
|
|
|
|
}
|
|
|
|
namespace Web::DOM {
|
|
|
|
template<>
|
|
inline bool Node::fast_is<HTML::HTMLSelectElement>() const { return is_html_select_element(); }
|
|
|
|
}
|