2020-08-01 03:07:00 +01:00
/*
2021-04-28 22:46:44 +02:00
* Copyright ( c ) 2020 , the SerenityOS developers .
2023-08-30 17:10:38 +01:00
* Copyright ( c ) 2023 , Sam Atkins < atkinssj @ serenityos . org >
2024-03-01 08:49:04 +01:00
* Copyright ( c ) 2024 , Bastiaan van der Plaat < bastiaan . v . d . plaat @ gmail . com >
2020-08-01 03:07:00 +01:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-08-01 03:07:00 +01:00
*/
2024-07-30 06:46:30 -04:00
# include <AK/Utf16View.h>
2024-04-27 12:09:58 +12:00
# include <LibWeb/Bindings/HTMLTextAreaElementPrototype.h>
2022-09-30 17:16:16 -06:00
# include <LibWeb/Bindings/Intrinsics.h>
2023-08-30 17:10:38 +01:00
# include <LibWeb/CSS/StyleProperties.h>
# include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
2024-03-07 07:58:25 +01:00
# include <LibWeb/CSS/StyleValues/LengthStyleValue.h>
2023-08-30 17:10:38 +01:00
# include <LibWeb/DOM/Document.h>
# include <LibWeb/DOM/ElementFactory.h>
# include <LibWeb/DOM/Event.h>
# include <LibWeb/DOM/ShadowRoot.h>
# include <LibWeb/DOM/Text.h>
2020-08-01 03:07:00 +01:00
# include <LibWeb/HTML/HTMLTextAreaElement.h>
2023-11-24 17:39:38 +01:00
# include <LibWeb/HTML/Numbers.h>
2024-03-14 07:26:26 -04:00
# include <LibWeb/Infra/Strings.h>
2023-08-30 17:10:38 +01:00
# include <LibWeb/Namespace.h>
2020-08-01 03:07:00 +01:00
namespace Web : : HTML {
2023-12-23 15:15:27 +01:00
JS_DEFINE_ALLOCATOR ( HTMLTextAreaElement ) ;
2022-02-18 21:00:52 +01:00
HTMLTextAreaElement : : HTMLTextAreaElement ( DOM : : Document & document , DOM : : QualifiedName qualified_name )
2022-03-23 18:55:54 -04:00
: HTMLElement ( document , move ( qualified_name ) )
2024-04-16 20:34:01 +02:00
, m_input_event_timer ( Core : : Timer : : create_single_shot ( 0 , [ weak_this = make_weak_ptr ( ) ] ( ) {
2024-03-16 11:44:18 +01:00
if ( ! weak_this )
return ;
static_cast < HTMLTextAreaElement * > ( weak_this . ptr ( ) ) - > queue_firing_input_event ( ) ;
2024-04-16 20:34:01 +02:00
} ) )
2020-08-01 03:07:00 +01:00
{
}
2022-03-14 13:21:51 -06:00
HTMLTextAreaElement : : ~ HTMLTextAreaElement ( ) = default ;
2020-08-01 03:07:00 +01:00
2024-03-07 21:27:37 +01:00
void HTMLTextAreaElement : : adjust_computed_style ( CSS : : StyleProperties & style )
2023-08-30 17:10:38 +01:00
{
// AD-HOC: We rewrite `display: inline` to `display: inline-block`.
// This is required for the internal shadow tree to work correctly in layout.
2024-03-07 21:27:37 +01:00
if ( style . display ( ) . is_inline_outside ( ) & & style . display ( ) . is_flow_inside ( ) )
style . set_property ( CSS : : PropertyID : : Display , CSS : : DisplayStyleValue : : create ( CSS : : Display : : from_short ( CSS : : Display : : Short : : InlineBlock ) ) ) ;
2023-08-30 17:10:38 +01:00
2024-03-07 21:27:37 +01:00
if ( style . property ( CSS : : PropertyID : : Width ) - > has_auto ( ) )
style . set_property ( CSS : : PropertyID : : Width , CSS : : LengthStyleValue : : create ( CSS : : Length ( cols ( ) , CSS : : Length : : Type : : Ch ) ) ) ;
if ( style . property ( CSS : : PropertyID : : Height ) - > has_auto ( ) )
style . set_property ( CSS : : PropertyID : : Height , CSS : : LengthStyleValue : : create ( CSS : : Length ( rows ( ) , CSS : : Length : : Type : : Lh ) ) ) ;
2023-08-30 17:10:38 +01:00
}
2023-08-07 08:41:28 +02:00
void HTMLTextAreaElement : : 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 ( HTMLTextAreaElement ) ;
2023-01-10 06:28:20 -05:00
}
2023-08-30 17:10:38 +01:00
void HTMLTextAreaElement : : visit_edges ( Cell : : Visitor & visitor )
{
Base : : visit_edges ( visitor ) ;
2023-12-21 18:13:16 +01:00
visitor . visit ( m_placeholder_element ) ;
visitor . visit ( m_placeholder_text_node ) ;
2023-08-30 17:10:38 +01:00
visitor . visit ( m_inner_text_element ) ;
visitor . visit ( m_text_node ) ;
}
void HTMLTextAreaElement : : did_receive_focus ( )
{
if ( ! m_text_node )
return ;
2024-07-07 00:34:08 +01:00
m_text_node - > invalidate_style ( ) ;
2024-08-02 07:31:40 -04:00
2024-08-03 14:57:00 -06:00
if ( m_placeholder_text_node )
m_placeholder_text_node - > invalidate_style ( ) ;
2024-08-02 07:31:40 -04:00
document ( ) . set_cursor_position ( DOM : : Position : : create ( realm ( ) , * m_text_node , 0 ) ) ;
2023-08-30 17:10:38 +01:00
}
void HTMLTextAreaElement : : did_lose_focus ( )
{
2024-07-07 00:34:08 +01:00
if ( m_text_node )
m_text_node - > invalidate_style ( ) ;
2024-08-03 14:57:00 -06:00
if ( m_placeholder_text_node )
m_placeholder_text_node - > invalidate_style ( ) ;
2023-08-30 17:10:38 +01:00
// The change event fires when the value is committed, if that makes sense for the control,
// or else when the control loses focus
queue_an_element_task ( HTML : : Task : : Source : : UserInteraction , [ this ] {
auto change_event = DOM : : Event : : create ( realm ( ) , HTML : : EventNames : : change ) ;
change_event - > set_bubbles ( true ) ;
dispatch_event ( change_event ) ;
} ) ;
}
2022-11-05 03:58:14 +00:00
// https://html.spec.whatwg.org/multipage/interaction.html#dom-tabindex
i32 HTMLTextAreaElement : : default_tab_index_value ( ) const
{
// See the base function for the spec comments.
return 0 ;
}
2022-12-22 19:58:21 -05:00
// https://html.spec.whatwg.org/multipage/form-elements.html#the-textarea-element:concept-form-reset-control
void HTMLTextAreaElement : : reset_algorithm ( )
{
2023-08-30 17:10:38 +01:00
// The reset algorithm for textarea elements is to set the dirty value flag back to false,
2024-02-26 19:12:32 +01:00
m_dirty_value = false ;
2023-08-30 17:10:38 +01:00
// and set the raw value of element to its child text content.
2024-03-14 07:26:26 -04:00
set_raw_value ( child_text_content ( ) ) ;
2023-12-21 18:13:16 +01:00
2024-03-14 10:33:15 -04:00
if ( m_text_node ) {
m_text_node - > set_text_content ( m_raw_value ) ;
update_placeholder_visibility ( ) ;
}
2023-08-30 17:10:38 +01:00
}
2024-08-21 12:27:30 +01:00
// https://html.spec.whatwg.org/multipage/forms.html#the-textarea-element:concept-node-clone-ext
WebIDL : : ExceptionOr < void > HTMLTextAreaElement : : cloned ( DOM : : Node & copy , bool )
{
// The cloning steps for textarea elements must propagate the raw value and dirty value flag from the node being cloned to the copy.
auto & textarea_copy = verify_cast < HTMLTextAreaElement > ( copy ) ;
textarea_copy . m_raw_value = m_raw_value ;
textarea_copy . m_dirty_value = m_dirty_value ;
return { } ;
}
2023-08-30 17:10:38 +01:00
void HTMLTextAreaElement : : form_associated_element_was_inserted ( )
{
create_shadow_tree_if_needed ( ) ;
}
2023-11-29 18:22:16 -05:00
void HTMLTextAreaElement : : form_associated_element_was_removed ( DOM : : Node * )
{
set_shadow_root ( nullptr ) ;
}
2023-12-10 17:48:42 +01:00
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-textarea-defaultvalue
String HTMLTextAreaElement : : default_value ( ) const
{
// The defaultValue attribute's getter must return the element's child text content.
return child_text_content ( ) ;
}
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-textarea-defaultvalue
void HTMLTextAreaElement : : set_default_value ( String const & default_value )
{
// The defaultValue attribute's setter must string replace all with the given value within this element.
string_replace_all ( default_value ) ;
}
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-textarea-value
String HTMLTextAreaElement : : value ( ) const
{
// The value IDL attribute must, on getting, return the element's API value.
2024-03-14 07:26:26 -04:00
return api_value ( ) ;
2023-12-10 17:48:42 +01:00
}
2024-03-14 09:11:36 -04:00
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-textarea-value
2023-12-10 17:48:42 +01:00
void HTMLTextAreaElement : : set_value ( String const & value )
{
2024-03-14 07:37:25 -04:00
auto & realm = this - > realm ( ) ;
// 1. Let oldAPIValue be this element's API value.
auto old_api_value = api_value ( ) ;
2023-12-10 17:48:42 +01:00
// 2. Set this element's raw value to the new value.
2024-03-14 07:26:26 -04:00
set_raw_value ( value ) ;
2023-12-10 17:48:42 +01:00
// 3. Set this element's dirty value flag to true.
2024-02-26 19:12:32 +01:00
m_dirty_value = true ;
2023-12-10 17:48:42 +01:00
2024-03-14 07:37:25 -04:00
// 4. If the new API value is different from oldAPIValue, then move the text entry cursor position to the end of
// the text control, unselecting any selected text and resetting the selection direction to "none".
if ( api_value ( ) ! = old_api_value ) {
if ( m_text_node ) {
m_text_node - > set_data ( m_raw_value ) ;
update_placeholder_visibility ( ) ;
2024-08-02 07:31:40 -04:00
document ( ) . set_cursor_position ( DOM : : Position : : create ( realm , * m_text_node , m_text_node - > data ( ) . bytes ( ) . size ( ) ) ) ;
2024-03-14 07:37:25 -04:00
}
}
2023-12-10 17:48:42 +01:00
}
2024-03-14 07:26:26 -04:00
void HTMLTextAreaElement : : set_raw_value ( String value )
{
m_raw_value = move ( value ) ;
m_api_value . clear ( ) ;
}
// https://html.spec.whatwg.org/multipage/form-elements.html#the-textarea-element:concept-fe-api-value-3
String HTMLTextAreaElement : : api_value ( ) const
{
// The algorithm for obtaining the element's API value is to return the element's raw value, with newlines normalized.
if ( ! m_api_value . has_value ( ) )
m_api_value = Infra : : normalize_newlines ( m_raw_value ) ;
return * m_api_value ;
}
2023-12-10 17:48:42 +01:00
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-textarea-textlength
u32 HTMLTextAreaElement : : text_length ( ) const
{
// The textLength IDL attribute must return the length of the element's API value.
2024-07-30 06:46:30 -04:00
return AK : : utf16_code_unit_length_from_utf8 ( api_value ( ) ) ;
2023-12-10 17:48:42 +01:00
}
2024-03-06 14:44:05 -05:00
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-cva-checkvalidity
bool HTMLTextAreaElement : : check_validity ( )
{
dbgln ( " (STUBBED) HTMLTextAreaElement::check_validity(). Called on: {} " , debug_description ( ) ) ;
return true ;
}
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-cva-reportvalidity
bool HTMLTextAreaElement : : report_validity ( )
{
dbgln ( " (STUBBED) HTMLTextAreaElement::report_validity(). Called on: {} " , debug_description ( ) ) ;
return true ;
}
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-cva-setcustomvalidity
void HTMLTextAreaElement : : set_custom_validity ( String const & error )
{
dbgln ( " (STUBBED) HTMLTextAreaElement::set_custom_validity( \" {} \" ). Called on: {} " , error , debug_description ( ) ) ;
}
2024-03-01 08:49:04 +01:00
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-textarea-maxlength
WebIDL : : Long HTMLTextAreaElement : : max_length ( ) const
{
// The maxLength IDL attribute must reflect the maxlength content attribute, limited to only non-negative numbers.
if ( auto maxlength_string = get_attribute ( HTML : : AttributeNames : : maxlength ) ; maxlength_string . has_value ( ) ) {
if ( auto maxlength = parse_non_negative_integer ( * maxlength_string ) ; maxlength . has_value ( ) )
return * maxlength ;
}
return - 1 ;
}
WebIDL : : ExceptionOr < void > HTMLTextAreaElement : : set_max_length ( WebIDL : : Long value )
{
// The maxLength IDL attribute must reflect the maxlength content attribute, limited to only non-negative numbers.
return set_attribute ( HTML : : AttributeNames : : maxlength , TRY ( convert_non_negative_integer_to_string ( realm ( ) , value ) ) ) ;
}
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-textarea-minlength
WebIDL : : Long HTMLTextAreaElement : : min_length ( ) const
{
// The minLength IDL attribute must reflect the minlength content attribute, limited to only non-negative numbers.
if ( auto minlength_string = get_attribute ( HTML : : AttributeNames : : minlength ) ; minlength_string . has_value ( ) ) {
if ( auto minlength = parse_non_negative_integer ( * minlength_string ) ; minlength . has_value ( ) )
return * minlength ;
}
return - 1 ;
}
WebIDL : : ExceptionOr < void > HTMLTextAreaElement : : set_min_length ( WebIDL : : Long value )
{
// The minLength IDL attribute must reflect the minlength content attribute, limited to only non-negative numbers.
return set_attribute ( HTML : : AttributeNames : : minlength , TRY ( convert_non_negative_integer_to_string ( realm ( ) , value ) ) ) ;
}
2023-11-24 17:39:38 +01:00
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-textarea-cols
unsigned HTMLTextAreaElement : : cols ( ) const
{
// The cols and rows attributes are limited to only positive numbers with fallback. The cols IDL attribute's default value is 20.
2023-12-07 18:40:54 +01:00
if ( auto cols_string = get_attribute ( HTML : : AttributeNames : : cols ) ; cols_string . has_value ( ) ) {
if ( auto cols = parse_non_negative_integer ( * cols_string ) ; cols . has_value ( ) )
return * cols ;
2023-11-24 17:39:38 +01:00
}
return 20 ;
}
2023-12-10 17:48:42 +01:00
WebIDL : : ExceptionOr < void > HTMLTextAreaElement : : set_cols ( unsigned cols )
2023-11-24 17:39:38 +01:00
{
2023-12-10 17:48:42 +01:00
return set_attribute ( HTML : : AttributeNames : : cols , MUST ( String : : number ( cols ) ) ) ;
2023-11-24 17:39:38 +01:00
}
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-textarea-rows
unsigned HTMLTextAreaElement : : rows ( ) const
{
// The cols and rows attributes are limited to only positive numbers with fallback. The rows IDL attribute's default value is 2.
2023-12-07 18:40:54 +01:00
if ( auto rows_string = get_attribute ( HTML : : AttributeNames : : rows ) ; rows_string . has_value ( ) ) {
if ( auto rows = parse_non_negative_integer ( * rows_string ) ; rows . has_value ( ) )
return * rows ;
2023-11-24 17:39:38 +01:00
}
return 2 ;
}
2023-12-10 17:48:42 +01:00
WebIDL : : ExceptionOr < void > HTMLTextAreaElement : : set_rows ( unsigned rows )
2023-11-24 17:39:38 +01:00
{
2023-12-10 17:48:42 +01:00
return set_attribute ( HTML : : AttributeNames : : rows , MUST ( String : : number ( rows ) ) ) ;
2023-11-24 17:39:38 +01:00
}
2023-08-30 17:10:38 +01:00
void HTMLTextAreaElement : : create_shadow_tree_if_needed ( )
{
2024-06-25 11:28:58 +02:00
if ( shadow_root ( ) )
2023-08-30 17:10:38 +01:00
return ;
auto shadow_root = heap ( ) . allocate < DOM : : ShadowRoot > ( realm ( ) , document ( ) , * this , Bindings : : ShadowRootMode : : Closed ) ;
2023-12-21 18:13:16 +01:00
set_shadow_root ( shadow_root ) ;
2023-11-04 18:42:04 +01:00
auto element = MUST ( DOM : : create_element ( document ( ) , HTML : : TagNames : : div , Namespace : : HTML ) ) ;
2023-12-21 18:13:16 +01:00
MUST ( shadow_root - > append_child ( element ) ) ;
m_placeholder_element = MUST ( DOM : : create_element ( document ( ) , HTML : : TagNames : : div , Namespace : : HTML ) ) ;
m_placeholder_element - > set_use_pseudo_element ( CSS : : Selector : : PseudoElement : : Type : : Placeholder ) ;
MUST ( element - > append_child ( * m_placeholder_element ) ) ;
m_placeholder_text_node = heap ( ) . allocate < DOM : : Text > ( realm ( ) , document ( ) , String { } ) ;
2024-01-16 19:04:45 +01:00
m_placeholder_text_node - > set_data ( get_attribute_value ( HTML : : AttributeNames : : placeholder ) ) ;
2023-12-21 18:13:16 +01:00
m_placeholder_text_node - > set_editable_text_node_owner ( Badge < HTMLTextAreaElement > { } , * this ) ;
MUST ( m_placeholder_element - > append_child ( * m_placeholder_text_node ) ) ;
2023-08-30 17:10:38 +01:00
2023-11-04 18:42:04 +01:00
m_inner_text_element = MUST ( DOM : : create_element ( document ( ) , HTML : : TagNames : : div , Namespace : : HTML ) ) ;
2023-12-21 18:13:16 +01:00
MUST ( element - > append_child ( * m_inner_text_element ) ) ;
2023-08-30 17:10:38 +01:00
m_text_node = heap ( ) . allocate < DOM : : Text > ( realm ( ) , document ( ) , String { } ) ;
2024-02-26 19:12:32 +01:00
handle_readonly_attribute ( attribute ( HTML : : AttributeNames : : readonly ) ) ;
2023-08-30 17:10:38 +01:00
m_text_node - > set_editable_text_node_owner ( Badge < HTMLTextAreaElement > { } , * this ) ;
2023-09-09 11:40:43 +01:00
// NOTE: If `children_changed()` was called before now, `m_raw_value` will hold the text content.
// Otherwise, it will get filled in whenever that does get called.
2023-11-26 10:59:52 +13:00
m_text_node - > set_text_content ( m_raw_value ) ;
2024-03-01 08:49:04 +01:00
handle_maxlength_attribute ( ) ;
2023-08-30 17:10:38 +01:00
MUST ( m_inner_text_element - > append_child ( * m_text_node ) ) ;
2023-12-21 18:13:16 +01:00
update_placeholder_visibility ( ) ;
}
2024-02-26 19:12:32 +01:00
// https://html.spec.whatwg.org/multipage/input.html#attr-input-readonly
void HTMLTextAreaElement : : handle_readonly_attribute ( Optional < String > const & maybe_value )
{
// The readonly attribute is a boolean attribute that controls whether or not the user can edit the form control. When specified, the element is not mutable.
m_is_mutable = ! maybe_value . has_value ( ) ;
if ( m_text_node )
m_text_node - > set_always_editable ( m_is_mutable ) ;
}
2024-03-01 08:49:04 +01:00
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-textarea-maxlength
void HTMLTextAreaElement : : handle_maxlength_attribute ( )
{
if ( m_text_node ) {
auto max_length = this - > max_length ( ) ;
if ( max_length > = 0 ) {
m_text_node - > set_max_length ( max_length ) ;
} else {
m_text_node - > set_max_length ( { } ) ;
}
}
}
2023-12-21 18:13:16 +01:00
void HTMLTextAreaElement : : update_placeholder_visibility ( )
{
if ( ! m_placeholder_element )
return ;
if ( ! m_text_node )
return ;
auto placeholder_text = get_attribute ( AttributeNames : : placeholder ) ;
if ( placeholder_text . has_value ( ) & & m_text_node - > data ( ) . is_empty ( ) ) {
MUST ( m_placeholder_element - > style_for_bindings ( ) - > set_property ( CSS : : PropertyID : : Display , " block " sv ) ) ;
2024-03-15 18:22:57 +01:00
MUST ( m_inner_text_element - > style_for_bindings ( ) - > set_property ( CSS : : PropertyID : : Display , " none " sv ) ) ;
2023-12-21 18:13:16 +01:00
} else {
MUST ( m_placeholder_element - > style_for_bindings ( ) - > set_property ( CSS : : PropertyID : : Display , " none " sv ) ) ;
2024-03-15 18:22:57 +01:00
MUST ( m_inner_text_element - > style_for_bindings ( ) - > set_property ( CSS : : PropertyID : : Display , " block " sv ) ) ;
2023-12-21 18:13:16 +01:00
}
2023-08-30 17:10:38 +01:00
}
// https://html.spec.whatwg.org/multipage/form-elements.html#the-textarea-element:children-changed-steps
void HTMLTextAreaElement : : children_changed ( )
{
// The children changed steps for textarea elements must, if the element's dirty value flag is false,
// set the element's raw value to its child text content.
2024-02-26 19:12:32 +01:00
if ( ! m_dirty_value ) {
2024-03-14 07:26:26 -04:00
set_raw_value ( child_text_content ( ) ) ;
2023-09-09 11:40:43 +01:00
if ( m_text_node )
2023-11-26 10:59:52 +13:00
m_text_node - > set_text_content ( m_raw_value ) ;
2023-12-21 18:13:16 +01:00
update_placeholder_visibility ( ) ;
}
}
2024-02-03 09:33:33 -05:00
void HTMLTextAreaElement : : form_associated_element_attribute_changed ( FlyString const & name , Optional < String > const & value )
2023-12-21 18:13:16 +01:00
{
if ( name = = HTML : : AttributeNames : : placeholder ) {
if ( m_placeholder_text_node )
m_placeholder_text_node - > set_data ( value . value_or ( String { } ) ) ;
2024-02-26 19:12:32 +01:00
} else if ( name = = HTML : : AttributeNames : : readonly ) {
handle_readonly_attribute ( value ) ;
2024-03-01 08:49:04 +01:00
} else if ( name = = HTML : : AttributeNames : : maxlength ) {
handle_maxlength_attribute ( ) ;
2023-08-30 17:10:38 +01:00
}
}
2024-08-02 07:31:40 -04:00
void HTMLTextAreaElement : : did_edit_text_node ( Badge < DOM : : Document > )
2023-08-30 17:10:38 +01:00
{
2024-03-06 15:14:20 -05:00
VERIFY ( m_text_node ) ;
2024-03-14 07:26:26 -04:00
set_raw_value ( m_text_node - > data ( ) ) ;
2024-03-06 15:14:20 -05:00
// Any time the user causes the element's raw value to change, the user agent must queue an element task on the user
// interaction task source given the textarea element to fire an event named input at the textarea element, with the
// bubbles and composed attributes initialized to true. User agents may wait for a suitable break in the user's
// interaction before queuing the task; for example, a user agent could wait for the user to have not hit a key for
// 100ms, so as to only fire the event when the user pauses, instead of continuously for each keystroke.
m_input_event_timer - > restart ( 100 ) ;
2023-08-30 17:10:38 +01:00
// A textarea element's dirty value flag must be set to true whenever the user interacts with the control in a way that changes the raw value.
2024-02-26 19:12:32 +01:00
m_dirty_value = true ;
2023-12-21 18:13:16 +01:00
update_placeholder_visibility ( ) ;
2022-12-22 19:58:21 -05:00
}
2024-03-06 15:14:20 -05:00
void HTMLTextAreaElement : : queue_firing_input_event ( )
{
queue_an_element_task ( HTML : : Task : : Source : : UserInteraction , [ this ] ( ) {
auto change_event = DOM : : Event : : create ( realm ( ) , HTML : : EventNames : : input , { . bubbles = true , . composed = true } ) ;
dispatch_event ( change_event ) ;
} ) ;
}
2020-08-01 03:07:00 +01:00
}