2020-08-01 03:05:43 +01:00
/*
2021-04-28 22:46:44 +02:00
* Copyright ( c ) 2020 , the SerenityOS developers .
2022-03-20 16:13:58 +01:00
* Copyright ( c ) 2022 , Andreas Kling < kling @ serenityos . org >
2020-08-01 03:05:43 +01:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-08-01 03:05:43 +01:00
*/
2022-04-12 13:29:16 -03:00
# include <AK/StringBuilder.h>
2023-01-28 22:23:16 +00:00
# include <LibWeb/ARIA/Roles.h>
2024-04-27 12:09:58 +12:00
# include <LibWeb/Bindings/HTMLOptionElementPrototype.h>
2022-09-30 17:16:16 -06:00
# include <LibWeb/Bindings/Intrinsics.h>
2022-04-12 13:29:16 -03:00
# include <LibWeb/DOM/Node.h>
# include <LibWeb/DOM/Text.h>
2022-09-30 16:21:34 +01:00
# include <LibWeb/HTML/HTMLOptGroupElement.h>
2020-08-01 03:05:43 +01:00
# include <LibWeb/HTML/HTMLOptionElement.h>
2022-04-12 13:29:16 -03:00
# include <LibWeb/HTML/HTMLScriptElement.h>
# include <LibWeb/HTML/HTMLSelectElement.h>
2022-10-01 18:39:40 +01:00
# include <LibWeb/Infra/Strings.h>
2020-08-01 03:05:43 +01:00
namespace Web : : HTML {
2023-11-19 19:47:52 +01:00
JS_DEFINE_ALLOCATOR ( HTMLOptionElement ) ;
2022-02-18 21:00:52 +01:00
HTMLOptionElement : : HTMLOptionElement ( DOM : : Document & document , DOM : : QualifiedName qualified_name )
2021-02-07 11:20:15 +01:00
: HTMLElement ( document , move ( qualified_name ) )
2020-08-01 03:05:43 +01:00
{
}
2022-03-14 13:21:51 -06:00
HTMLOptionElement : : ~ HTMLOptionElement ( ) = default ;
2020-08-01 03:05:43 +01:00
2023-08-07 08:41:28 +02:00
void HTMLOptionElement : : initialize ( JS : : Realm & realm )
2023-01-10 06:28:20 -05:00
{
2023-08-07 08:41:28 +02:00
Base : : initialize ( realm ) ;
2024-03-16 13:13:08 +01:00
WEB_SET_PROTOTYPE_FOR_INTERFACE ( HTMLOptionElement ) ;
2023-01-10 06:28:20 -05:00
}
2024-07-09 20:18:41 +01:00
void HTMLOptionElement : : attribute_changed ( FlyString const & name , Optional < String > const & old_value , Optional < String > const & value )
2022-03-20 16:13:58 +01:00
{
2024-07-09 20:18:41 +01:00
HTMLElement : : attribute_changed ( name , old_value , value ) ;
2022-03-20 16:13:58 +01:00
if ( name = = HTML : : AttributeNames : : selected ) {
2023-10-10 15:00:58 +03:30
if ( ! value . has_value ( ) ) {
2023-07-03 17:31:17 +02:00
// Whenever an option element's selected attribute is removed, if its dirtiness is false, its selectedness must be set to false.
if ( ! m_dirty )
m_selected = false ;
} else {
// Except where otherwise specified, when the element is created, its selectedness must be set to true
// if the element has a selected attribute. Whenever an option element's selected attribute is added,
// if its dirtiness is false, its selectedness must be set to true.
if ( ! m_dirty )
m_selected = true ;
}
2022-03-20 16:13:58 +01:00
}
}
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-option-selected
void HTMLOptionElement : : set_selected ( bool selected )
{
// On setting, it must set the element's selectedness to the new value, set its dirtiness to true, and then cause the element to ask for a reset.
2024-07-25 21:13:22 +04:00
set_selected_internal ( selected ) ;
2022-03-20 16:13:58 +01:00
m_dirty = true ;
ask_for_a_reset ( ) ;
}
2024-07-25 21:13:22 +04:00
void HTMLOptionElement : : set_selected_internal ( bool selected )
{
m_selected = selected ;
}
2022-04-12 13:29:16 -03:00
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-option-value
2023-09-03 15:51:13 +12:00
String HTMLOptionElement : : value ( ) const
2022-04-12 13:29:16 -03:00
{
// The value of an option element is the value of the value content attribute, if there is one.
// ...or, if there is not, the value of the element's text IDL attribute.
2023-09-03 15:51:13 +12:00
return attribute ( HTML : : AttributeNames : : value ) . value_or ( text ( ) ) ;
2022-04-12 13:29:16 -03:00
}
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-option-value
2023-09-03 15:51:13 +12:00
WebIDL : : ExceptionOr < void > HTMLOptionElement : : set_value ( String const & value )
2022-04-12 13:29:16 -03:00
{
2023-05-25 20:37:57 +01:00
return set_attribute ( HTML : : AttributeNames : : value , value ) ;
2022-04-12 13:29:16 -03:00
}
static void concatenate_descendants_text_content ( DOM : : Node const * node , StringBuilder & builder )
{
// FIXME: SVGScriptElement should also be skipped, but it doesn't exist yet.
if ( is < HTMLScriptElement > ( node ) )
return ;
if ( is < DOM : : Text > ( node ) )
builder . append ( verify_cast < DOM : : Text > ( node ) - > data ( ) ) ;
node - > for_each_child ( [ & ] ( auto const & node ) {
concatenate_descendants_text_content ( & node , builder ) ;
2024-05-04 14:59:52 +01:00
return IterationDecision : : Continue ;
2022-04-12 13:29:16 -03:00
} ) ;
}
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-option-text
2023-09-03 15:51:13 +12:00
String HTMLOptionElement : : text ( ) const
2022-04-12 13:29:16 -03:00
{
StringBuilder builder ;
// Concatenation of data of all the Text node descendants of the option element, in tree order,
// excluding any that are descendants of descendants of the option element that are themselves
// script or SVG script elements.
for_each_child ( [ & ] ( auto const & node ) {
concatenate_descendants_text_content ( & node , builder ) ;
2024-05-04 14:59:52 +01:00
return IterationDecision : : Continue ;
2022-04-12 13:29:16 -03:00
} ) ;
// Return the result of stripping and collapsing ASCII whitespace from the above concatenation.
2023-09-03 15:51:13 +12:00
return MUST ( Infra : : strip_and_collapse_whitespace ( builder . string_view ( ) ) ) ;
2022-04-12 13:29:16 -03:00
}
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-option-text
2023-09-03 15:51:13 +12:00
void HTMLOptionElement : : set_text ( String const & text )
2022-04-12 13:29:16 -03:00
{
2023-12-03 08:24:04 +13:00
string_replace_all ( text ) ;
2022-04-12 13:29:16 -03:00
}
// https://html.spec.whatwg.org/multipage/form-elements.html#concept-option-index
int HTMLOptionElement : : index ( ) const
{
// An option element's index is the number of option elements that are in the same list of options but that come before it in tree order.
if ( auto select_element = first_ancestor_of_type < HTMLSelectElement > ( ) ) {
int index = 0 ;
for ( auto const & option_element : select_element - > list_of_options ( ) ) {
2022-08-28 13:42:07 +02:00
if ( option_element . ptr ( ) = = this )
2022-04-12 13:29:16 -03:00
return index ;
+ + index ;
}
}
// If the option element is not in a list of options, then the option element's index is zero.
return 0 ;
}
2022-03-20 16:13:58 +01:00
// https://html.spec.whatwg.org/multipage/form-elements.html#ask-for-a-reset
void HTMLOptionElement : : ask_for_a_reset ( )
{
// FIXME: Implement this operation.
}
2022-09-30 16:21:34 +01:00
// https://html.spec.whatwg.org/multipage/form-elements.html#concept-option-disabled
bool HTMLOptionElement : : disabled ( ) const
{
// An option element is disabled if its disabled attribute is present or if it is a child of an optgroup element whose disabled attribute is present.
return has_attribute ( AttributeNames : : disabled )
| | ( parent ( ) & & is < HTMLOptGroupElement > ( parent ( ) ) & & static_cast < HTMLOptGroupElement const & > ( * parent ( ) ) . has_attribute ( AttributeNames : : disabled ) ) ;
}
2024-05-15 22:54:17 +01:00
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-option-form
JS : : GCPtr < HTMLFormElement > HTMLOptionElement : : form ( ) const
{
// The form IDL attribute's behavior depends on whether the option element is in a select element or not.
// If the option has a select element as its parent, or has an optgroup element as its parent and that optgroup element has a select element as its parent,
// then the form IDL attribute must return the same value as the form IDL attribute on that select element.
// Otherwise, it must return null.
auto const * parent = parent_element ( ) ;
if ( is < HTMLOptGroupElement > ( parent ) )
parent = parent - > parent_element ( ) ;
if ( is < HTML : : HTMLSelectElement > ( parent ) ) {
auto const * select_element = verify_cast < HTMLSelectElement > ( parent ) ;
return const_cast < HTMLFormElement * > ( select_element - > form ( ) ) ;
}
return { } ;
}
2023-01-28 22:23:16 +00:00
Optional < ARIA : : Role > HTMLOptionElement : : default_role ( ) const
2022-11-28 17:58:13 -06:00
{
// https://www.w3.org/TR/html-aria/#el-option
// TODO: Only an option element that is in a list of options or that represents a suggestion in a datalist should return option
2023-01-28 22:23:16 +00:00
return ARIA : : Role : : option ;
2022-11-28 17:58:13 -06:00
}
2020-08-01 03:05:43 +01:00
}