1use std::cell::{Cell, Ref, RefCell, RefMut};
6use std::default::Default;
7
8use dom_struct::dom_struct;
9use embedder_traits::{EmbedderControlRequest, InputMethodRequest, InputMethodType};
10use fonts::{ByteIndex, TextByteRange};
11use html5ever::{LocalName, Prefix, local_name, ns};
12use js::context::JSContext;
13use js::rust::HandleObject;
14use layout_api::{ScriptSelection, SharedSelection};
15use script_bindings::cell::DomRefCell;
16use servo_base::text::Utf16CodeUnits;
17use style::attr::AttrValue;
18use stylo_dom::ElementState;
19
20use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
21use crate::dom::bindings::codegen::Bindings::HTMLFormElementBinding::SelectionMode;
22use crate::dom::bindings::codegen::Bindings::HTMLTextAreaElementBinding::HTMLTextAreaElementMethods;
23use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
24use crate::dom::bindings::error::ErrorResult;
25use crate::dom::bindings::inheritance::Castable;
26use crate::dom::bindings::refcounted::Trusted;
27use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom};
28use crate::dom::bindings::str::DOMString;
29use crate::dom::clipboardevent::{ClipboardEvent, ClipboardEventType};
30use crate::dom::compositionevent::CompositionEvent;
31use crate::dom::document::Document;
32use crate::dom::document_embedder_controls::ControlElement;
33use crate::dom::element::attributes::storage::AttrRef;
34use crate::dom::element::{AttributeMutation, Element};
35use crate::dom::event::Event;
36use crate::dom::event::event::{EventBubbles, EventCancelable, EventComposed};
37use crate::dom::eventtarget::EventTarget;
38use crate::dom::html::form_controls::htmlinputelement::HTMLInputElement;
39use crate::dom::html::form_controls::input_type::text_input_widget::TextInputWidget;
40use crate::dom::html::form_controls::text_control::{TextControlElement, TextControlSelection};
41use crate::dom::html::form_controls::text_input::{
42 ClipboardEventFlags, EmbedderClipboardProvider, IsComposing, KeyReaction, Lines, TextInput,
43};
44use crate::dom::html::htmlelement::HTMLElement;
45use crate::dom::html::htmlfieldsetelement::HTMLFieldSetElement;
46use crate::dom::html::htmlformelement::{FormControl, HTMLFormElement};
47use crate::dom::inputevent::HitTestResult;
48use crate::dom::keyboardevent::KeyboardEvent;
49use crate::dom::node::virtualmethods::VirtualMethods;
50use crate::dom::node::{
51 BindContext, ChildrenMutation, CloneChildrenFlag, Node, NodeDamage, NodeTraits, UnbindContext,
52};
53use crate::dom::nodelist::NodeList;
54use crate::dom::types::{FocusEvent, MouseEvent};
55use crate::dom::validation::{Validatable, is_barred_by_datalist_ancestor};
56use crate::dom::validitystate::{ValidationFlags, ValidityState};
57
58#[dom_struct]
59pub(crate) struct HTMLTextAreaElement {
60 htmlelement: HTMLElement,
61 #[no_trace]
62 textinput: DomRefCell<TextInput<EmbedderClipboardProvider>>,
63 placeholder: RefCell<DOMString>,
64 value_dirty: Cell<bool>,
66 form_owner: MutNullableDom<HTMLFormElement>,
67 labels_node_list: MutNullableDom<NodeList>,
68 validity_state: MutNullableDom<ValidityState>,
69 text_input_widget: DomRefCell<TextInputWidget>,
71 #[no_trace]
74 #[conditional_malloc_size_of]
75 shared_selection: SharedSelection,
76
77 has_scheduled_selectionchange_event: Cell<bool>,
79}
80
81impl LayoutDom<'_, HTMLTextAreaElement> {
82 pub(crate) fn selection_for_layout(self) -> SharedSelection {
83 self.unsafe_get().shared_selection.clone()
84 }
85
86 pub(crate) fn get_cols(self) -> u32 {
87 self.upcast::<Element>()
88 .get_attr_for_layout(&ns!(), &local_name!("cols"))
89 .map_or(DEFAULT_COLS, AttrValue::as_uint)
90 }
91
92 pub(crate) fn get_rows(self) -> u32 {
93 self.upcast::<Element>()
94 .get_attr_for_layout(&ns!(), &local_name!("rows"))
95 .map_or(DEFAULT_ROWS, AttrValue::as_uint)
96 }
97}
98
99const DEFAULT_COLS: u32 = 20;
101
102const DEFAULT_ROWS: u32 = 2;
104
105const DEFAULT_MAX_LENGTH: i32 = -1;
106const DEFAULT_MIN_LENGTH: i32 = -1;
107
108impl HTMLTextAreaElement {
109 fn new_inherited(
110 local_name: LocalName,
111 prefix: Option<Prefix>,
112 document: &Document,
113 ) -> HTMLTextAreaElement {
114 let embedder_sender = document
115 .window()
116 .as_global_scope()
117 .script_to_embedder_chan()
118 .clone();
119 HTMLTextAreaElement {
120 htmlelement: HTMLElement::new_inherited_with_state(
121 ElementState::ENABLED | ElementState::READWRITE,
122 local_name,
123 prefix,
124 document,
125 ),
126 placeholder: Default::default(),
127 textinput: DomRefCell::new(TextInput::new(
128 Lines::Multiple,
129 DOMString::new(),
130 EmbedderClipboardProvider {
131 embedder_sender,
132 webview_id: document.webview_id(),
133 },
134 )),
135 value_dirty: Cell::new(false),
136 form_owner: Default::default(),
137 labels_node_list: Default::default(),
138 validity_state: Default::default(),
139 text_input_widget: Default::default(),
140 shared_selection: Default::default(),
141 has_scheduled_selectionchange_event: Default::default(),
142 }
143 }
144
145 pub(crate) fn new(
146 cx: &mut JSContext,
147 local_name: LocalName,
148 prefix: Option<Prefix>,
149 document: &Document,
150 proto: Option<HandleObject>,
151 ) -> DomRoot<HTMLTextAreaElement> {
152 Node::reflect_node_with_proto(
153 cx,
154 Box::new(HTMLTextAreaElement::new_inherited(
155 local_name, prefix, document,
156 )),
157 document,
158 proto,
159 )
160 }
161
162 pub(crate) fn textinput_mut(&self) -> RefMut<'_, TextInput<EmbedderClipboardProvider>> {
163 self.textinput.borrow_mut()
164 }
165
166 pub(crate) fn auto_directionality(&self) -> String {
167 let value: String = String::from(self.Value());
168 HTMLInputElement::directionality_from_value(&value)
169 }
170
171 pub(crate) fn is_mutable(&self) -> bool {
173 !(self.upcast::<Element>().disabled_state() || self.ReadOnly())
176 }
177
178 fn handle_focus_event(&self, event: &FocusEvent) {
179 let event_type = event.upcast::<Event>().type_();
180 if *event_type == *"blur" {
181 self.owner_document()
182 .embedder_controls()
183 .hide_embedder_control(self.upcast());
184 } else if *event_type == *"focus" {
185 self.owner_document()
186 .embedder_controls()
187 .show_embedder_control(
188 ControlElement::Ime(Dom::from_ref(self.upcast())),
189 EmbedderControlRequest::InputMethod(InputMethodRequest {
190 input_method_type: InputMethodType::Text,
191 text: String::from(self.Value()),
192 insertion_point: self.GetSelectionEnd(),
193 multiline: false,
194 allow_virtual_keyboard: self.owner_window().has_sticky_activation(),
196 }),
197 None,
198 );
199 }
200
201 self.maybe_update_shared_selection();
203 }
204
205 fn handle_text_content_changed(&self, cx: &mut JSContext) {
206 self.validity_state(cx)
207 .perform_validation_and_update(cx, ValidationFlags::all());
208
209 let placeholder_shown =
210 self.textinput.borrow().is_empty() && !self.placeholder.borrow().is_empty();
211 self.upcast::<Element>()
212 .set_placeholder_shown_state(placeholder_shown);
213
214 self.text_input_widget.borrow().update_shadow_tree(cx, self);
215 self.text_input_widget
216 .borrow()
217 .update_placeholder_contents(cx, self);
218 self.maybe_update_shared_selection();
219 }
220
221 fn schedule_a_selection_change_event(&self) {
223 if self.has_scheduled_selectionchange_event.get() {
225 return;
226 }
227 self.has_scheduled_selectionchange_event.set(true);
229 let this = Trusted::new(self);
231 self.owner_global()
232 .task_manager()
233 .user_interaction_task_source()
234 .queue(
235 task!(selectionchange_task_steps: move |cx| {
237 let this = this.root();
238 this.has_scheduled_selectionchange_event.set(false);
240 this.upcast::<EventTarget>().fire_event_with_params(
242 cx,
243 atom!("selectionchange"),
244 EventBubbles::Bubbles,
245 EventCancelable::NotCancelable,
246 EventComposed::Composed,
247 );
248 }),
253 );
254 }
255}
256
257impl TextControlElement for HTMLTextAreaElement {
258 fn selection_api_applies(&self) -> bool {
259 true
260 }
261
262 fn has_selectable_text(&self) -> bool {
263 !self.textinput.borrow().get_content().is_empty()
264 }
265
266 fn has_uncollapsed_selection(&self) -> bool {
267 self.textinput.borrow().has_uncollapsed_selection()
268 }
269
270 fn set_dirty_value_flag(&self, value: bool) {
271 self.value_dirty.set(value)
272 }
273
274 fn select_all(&self) {
275 self.textinput.borrow_mut().select_all();
276 self.maybe_update_shared_selection();
277 }
278
279 fn maybe_update_shared_selection(&self) {
280 let offsets = self.textinput.borrow().sorted_selection_offsets_range();
281 let (start, end) = (offsets.start.0, offsets.end.0);
282 let range = TextByteRange::new(ByteIndex(start), ByteIndex(end));
283 let enabled = self.upcast::<Element>().focus_state();
284
285 let mut shared_selection = self.shared_selection.borrow_mut();
286 let range_remained_equal = range == shared_selection.range;
287 if range_remained_equal && enabled == shared_selection.enabled {
288 return;
289 }
290
291 if !range_remained_equal {
292 self.schedule_a_selection_change_event();
297 }
298
299 *shared_selection = ScriptSelection {
300 range,
301 character_range: self
302 .textinput
303 .borrow()
304 .sorted_selection_character_offsets_range(),
305 enabled,
306 };
307 self.owner_window().layout().set_needs_new_display_list();
308 }
309
310 fn placeholder_text<'a>(&'a self) -> Ref<'a, DOMString> {
311 self.placeholder.borrow()
312 }
313
314 fn value_text(&self) -> DOMString {
315 self.Value()
316 }
317}
318
319impl HTMLTextAreaElementMethods<crate::DomTypeHolder> for HTMLTextAreaElement {
320 make_uint_getter!(Cols, "cols", DEFAULT_COLS);
325
326 make_limited_uint_setter!(SetCols, "cols", DEFAULT_COLS);
328
329 make_getter!(DirName, "dirname");
331
332 make_setter!(SetDirName, "dirname");
334
335 make_bool_getter!(Disabled, "disabled");
337
338 make_bool_setter!(SetDisabled, "disabled");
340
341 fn GetForm(&self) -> Option<DomRoot<HTMLFormElement>> {
343 self.form_owner()
344 }
345
346 make_getter!(Name, "name");
348
349 make_atomic_setter!(SetName, "name");
351
352 make_getter!(Placeholder, "placeholder");
354
355 make_setter!(SetPlaceholder, "placeholder");
357
358 make_int_getter!(MaxLength, "maxlength", DEFAULT_MAX_LENGTH);
360
361 make_limited_int_setter!(SetMaxLength, "maxlength", DEFAULT_MAX_LENGTH);
363
364 make_int_getter!(MinLength, "minlength", DEFAULT_MIN_LENGTH);
366
367 make_limited_int_setter!(SetMinLength, "minlength", DEFAULT_MIN_LENGTH);
369
370 make_bool_getter!(ReadOnly, "readonly");
372
373 make_bool_setter!(SetReadOnly, "readonly");
375
376 make_bool_getter!(Required, "required");
378
379 make_bool_setter!(SetRequired, "required");
381
382 make_uint_getter!(Rows, "rows", DEFAULT_ROWS);
384
385 make_limited_uint_setter!(SetRows, "rows", DEFAULT_ROWS);
387
388 make_getter!(Wrap, "wrap");
390
391 make_setter!(SetWrap, "wrap");
393
394 fn Type(&self) -> DOMString {
396 DOMString::from_static("textarea")
397 }
398
399 fn DefaultValue(&self) -> DOMString {
401 self.upcast::<Node>().GetTextContent().unwrap()
402 }
403
404 fn SetDefaultValue(&self, cx: &mut JSContext, value: DOMString) {
406 self.upcast::<Node>()
407 .set_text_content_for_element(cx, Some(value));
408
409 if !self.value_dirty.get() {
412 self.reset(cx);
413 }
414 }
415
416 fn Value(&self) -> DOMString {
418 self.textinput.borrow().get_content()
419 }
420
421 fn SetValue(&self, cx: &mut JSContext, value: DOMString) {
423 let old_api_value = self.Value();
425
426 self.textinput.borrow_mut().set_content(value);
428
429 self.value_dirty.set(true);
431
432 if old_api_value != self.Value() {
437 self.textinput.borrow_mut().clear_selection_to_end();
438 self.handle_text_content_changed(cx);
439 }
440 }
441
442 fn TextLength(&self) -> u32 {
444 self.textinput.borrow().len_utf16().0 as u32
445 }
446
447 make_labels_getter!(Labels, labels_node_list);
449
450 fn Select(&self) {
452 self.selection().dom_select();
453 }
454
455 fn GetSelectionStart(&self) -> Option<u32> {
457 self.selection().dom_start().map(|start| start.0 as u32)
458 }
459
460 fn SetSelectionStart(&self, _cx: &mut JSContext, start: Option<u32>) -> ErrorResult {
462 self.selection()
463 .set_dom_start(start.map(Utf16CodeUnits::from))
464 }
465
466 fn GetSelectionEnd(&self) -> Option<u32> {
468 self.selection().dom_end().map(|end| end.0 as u32)
469 }
470
471 fn SetSelectionEnd(&self, _cx: &mut JSContext, end: Option<u32>) -> ErrorResult {
473 self.selection().set_dom_end(end.map(Utf16CodeUnits::from))
474 }
475
476 fn GetSelectionDirection(&self) -> Option<DOMString> {
478 self.selection().dom_direction()
479 }
480
481 fn SetSelectionDirection(
483 &self,
484 _cx: &mut JSContext,
485 direction: Option<DOMString>,
486 ) -> ErrorResult {
487 self.selection().set_dom_direction(direction)
488 }
489
490 fn SetSelectionRange(&self, start: u32, end: u32, direction: Option<DOMString>) -> ErrorResult {
492 self.selection().set_dom_range(
493 Utf16CodeUnits::from(start),
494 Utf16CodeUnits::from(end),
495 direction,
496 )
497 }
498
499 fn SetRangeText(&self, replacement: DOMString) -> ErrorResult {
501 self.selection()
502 .set_dom_range_text(replacement, None, None, Default::default())
503 }
504
505 fn SetRangeText_(
507 &self,
508 replacement: DOMString,
509 start: u32,
510 end: u32,
511 selection_mode: SelectionMode,
512 ) -> ErrorResult {
513 self.selection().set_dom_range_text(
514 replacement,
515 Some(Utf16CodeUnits::from(start)),
516 Some(Utf16CodeUnits::from(end)),
517 selection_mode,
518 )
519 }
520
521 fn WillValidate(&self) -> bool {
523 self.is_instance_validatable()
524 }
525
526 fn Validity(&self, cx: &mut JSContext) -> DomRoot<ValidityState> {
528 self.validity_state(cx)
529 }
530
531 fn CheckValidity(&self, cx: &mut JSContext) -> bool {
533 self.check_validity(cx)
534 }
535
536 fn ReportValidity(&self, cx: &mut JSContext) -> bool {
538 self.report_validity(cx)
539 }
540
541 fn ValidationMessage(&self, cx: &mut JSContext) -> DOMString {
543 self.validation_message(cx)
544 }
545
546 fn SetCustomValidity(&self, cx: &mut JSContext, error: DOMString) {
548 self.validity_state(cx).set_custom_error_message(cx, error);
549 }
550}
551
552impl HTMLTextAreaElement {
553 pub(crate) fn clear(&self) {
556 self.value_dirty.set(false);
557 self.textinput.borrow_mut().set_content(DOMString::new());
558 }
559
560 pub(crate) fn reset(&self, cx: &mut JSContext) {
561 self.value_dirty.set(false);
563 self.textinput.borrow_mut().set_content(self.DefaultValue());
564 self.handle_text_content_changed(cx);
565 }
566
567 fn selection(&self) -> TextControlSelection<'_, Self> {
568 TextControlSelection::new(self, &self.textinput)
569 }
570
571 fn handle_key_reaction(&self, cx: &mut JSContext, action: KeyReaction, event: &Event) {
572 match action {
573 KeyReaction::TriggerDefaultAction => (),
574 KeyReaction::DispatchInput(text, is_composing, input_type) => {
575 if event.IsTrusted() {
576 self.textinput.borrow().queue_input_event(
577 self.upcast(),
578 text,
579 is_composing,
580 input_type,
581 );
582 }
583 self.value_dirty.set(true);
584 self.handle_text_content_changed(cx);
585 event.mark_as_handled();
586 },
587 KeyReaction::RedrawSelection => {
588 self.maybe_update_shared_selection();
589 event.mark_as_handled();
590 },
591 KeyReaction::Nothing => (),
592 }
593 }
594}
595
596impl VirtualMethods for HTMLTextAreaElement {
597 fn super_type(&self) -> Option<&dyn VirtualMethods> {
598 Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
599 }
600
601 fn attribute_mutated(
602 &self,
603 cx: &mut JSContext,
604 attr: AttrRef<'_>,
605 mutation: AttributeMutation,
606 ) {
607 self.super_type()
608 .unwrap()
609 .attribute_mutated(cx, attr, mutation);
610 match *attr.local_name() {
611 local_name!("disabled") => {
612 let el = self.upcast::<Element>();
613 match mutation {
614 AttributeMutation::Set(..) => {
615 el.set_disabled_state(true);
616 el.set_enabled_state(false);
617
618 el.set_read_write_state(false);
619 },
620 AttributeMutation::Removed => {
621 el.set_disabled_state(false);
622 el.set_enabled_state(true);
623 el.check_ancestors_disabled_state_for_form_control();
624
625 if !el.disabled_state() && !el.read_write_state() {
626 el.set_read_write_state(true);
627 }
628 },
629 }
630 },
631 local_name!("maxlength") => match *attr.value() {
632 AttrValue::Int(_, value) => {
633 let mut textinput = self.textinput.borrow_mut();
634
635 if value < 0 {
636 textinput.set_max_length(None);
637 } else {
638 textinput.set_max_length(Some(Utf16CodeUnits(value as usize)))
639 }
640 },
641 _ => panic!("Expected an AttrValue::Int"),
642 },
643 local_name!("minlength") => match *attr.value() {
644 AttrValue::Int(_, value) => {
645 let mut textinput = self.textinput.borrow_mut();
646
647 if value < 0 {
648 textinput.set_min_length(None);
649 } else {
650 textinput.set_min_length(Some(Utf16CodeUnits(value as usize)))
651 }
652 },
653 _ => panic!("Expected an AttrValue::Int"),
654 },
655 local_name!("placeholder") => {
656 {
657 let mut placeholder = self.placeholder.borrow_mut();
658 match mutation {
659 AttributeMutation::Set(..) => {
660 let value = attr.value();
661 let value_str: &str = value.as_ref();
662 *placeholder =
663 value_str.replace("\r\n", "\n").replace('\r', "\n").into();
664 },
665 AttributeMutation::Removed => placeholder.clear(),
666 }
667 }
668 self.handle_text_content_changed(cx);
669 },
670 local_name!("readonly") => {
671 let el = self.upcast::<Element>();
672 match mutation {
673 AttributeMutation::Set(..) => {
674 el.set_read_write_state(false);
675 },
676 AttributeMutation::Removed => {
677 el.set_read_write_state(!el.disabled_state());
678 },
679 }
680 },
681 local_name!("form") => {
682 self.form_attribute_mutated(cx, mutation);
683 },
684 _ => {},
685 }
686
687 self.validity_state(cx)
688 .perform_validation_and_update(cx, ValidationFlags::all());
689 }
690
691 fn bind_to_tree(&self, cx: &mut JSContext, context: &BindContext) {
692 if let Some(s) = self.super_type() {
693 s.bind_to_tree(cx, context);
694 }
695
696 self.upcast::<Element>()
697 .check_ancestors_disabled_state_for_form_control();
698
699 self.handle_text_content_changed(cx);
700 }
701
702 fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
703 match *name {
704 local_name!("cols") => AttrValue::from_limited_u32(value.into(), DEFAULT_COLS),
705 local_name!("rows") => AttrValue::from_limited_u32(value.into(), DEFAULT_ROWS),
706 local_name!("maxlength") => {
707 AttrValue::from_limited_i32(value.into(), DEFAULT_MAX_LENGTH)
708 },
709 local_name!("minlength") => {
710 AttrValue::from_limited_i32(value.into(), DEFAULT_MIN_LENGTH)
711 },
712 _ => self
713 .super_type()
714 .unwrap()
715 .parse_plain_attribute(name, value),
716 }
717 }
718
719 fn unbind_from_tree(&self, cx: &mut JSContext, context: &UnbindContext) {
720 self.owner_document()
722 .embedder_controls()
723 .hide_embedder_control(self.upcast());
724
725 self.super_type().unwrap().unbind_from_tree(cx, context);
726
727 let node = self.upcast::<Node>();
728 let el = self.upcast::<Element>();
729 if node
730 .ancestors()
731 .any(|ancestor| ancestor.is::<HTMLFieldSetElement>())
732 {
733 el.check_ancestors_disabled_state_for_form_control();
734 } else {
735 el.check_disabled_attribute();
736 }
737
738 self.validity_state(cx)
739 .perform_validation_and_update(cx, ValidationFlags::all());
740 }
741
742 fn cloning_steps(
745 &self,
746 cx: &mut JSContext,
747 copy: &Node,
748 maybe_doc: Option<&Document>,
749 clone_children: CloneChildrenFlag,
750 ) {
751 if let Some(s) = self.super_type() {
752 s.cloning_steps(cx, copy, maybe_doc, clone_children);
753 }
754 let el = copy.downcast::<HTMLTextAreaElement>().unwrap();
755 el.value_dirty.set(self.value_dirty.get());
756 {
757 let mut textinput = el.textinput.borrow_mut();
758 textinput.set_content(self.textinput.borrow().get_content());
759 }
760 el.validity_state(cx)
761 .perform_validation_and_update(cx, ValidationFlags::all());
762 }
763
764 fn children_changed(&self, cx: &mut JSContext, mutation: &ChildrenMutation) {
765 if let Some(s) = self.super_type() {
766 s.children_changed(cx, mutation);
767 }
768 if !self.value_dirty.get() {
769 self.reset(cx);
770 }
771 }
772
773 fn handle_event(&self, cx: &mut JSContext, event: &Event) {
775 if event.type_() == atom!("keydown") && !event.DefaultPrevented() {
776 if let Some(keyboard_event) = event.downcast::<KeyboardEvent>() {
777 let action = self.textinput.borrow_mut().handle_keydown(keyboard_event);
780 self.handle_key_reaction(cx, action, event);
781 }
782 } else if event.type_() == atom!("compositionstart") ||
783 event.type_() == atom!("compositionupdate") ||
784 event.type_() == atom!("compositionend")
785 {
786 if let Some(compositionevent) = event.downcast::<CompositionEvent>() {
787 if event.type_() == atom!("compositionend") {
788 let action = self
789 .textinput
790 .borrow_mut()
791 .handle_compositionend(compositionevent);
792 self.handle_key_reaction(cx, action, event);
793 self.upcast::<Node>().dirty(cx.no_gc(), NodeDamage::Other);
794 } else if event.type_() == atom!("compositionupdate") {
795 let action = self
796 .textinput
797 .borrow_mut()
798 .handle_compositionupdate(compositionevent);
799 self.handle_key_reaction(cx, action, event);
800 self.upcast::<Node>().dirty(cx.no_gc(), NodeDamage::Other);
801 }
802 self.maybe_update_shared_selection();
803 event.mark_as_handled();
804 }
805 } else if let Some(clipboard_event) = event.downcast::<ClipboardEvent>() {
806 let reaction = self
807 .textinput
808 .borrow_mut()
809 .handle_clipboard_event(clipboard_event);
810
811 let flags = reaction.flags;
812 if flags.contains(ClipboardEventFlags::FireClipboardChangedEvent) {
813 self.owner_document().event_handler().fire_clipboard_event(
814 cx,
815 None,
816 ClipboardEventType::Change,
817 );
818 }
819 if flags.contains(ClipboardEventFlags::QueueInputEvent) {
820 self.textinput.borrow().queue_input_event(
821 self.upcast(),
822 reaction.text,
823 IsComposing::NotComposing,
824 reaction.input_type,
825 );
826 }
827 if !flags.is_empty() {
828 event.mark_as_handled();
829 self.handle_text_content_changed(cx);
830 }
831 } else if let Some(event) = event.downcast::<FocusEvent>() {
832 self.handle_focus_event(event);
833 }
834
835 self.validity_state(cx)
836 .perform_validation_and_update(cx, ValidationFlags::all());
837
838 if let Some(super_type) = self.super_type() {
839 super_type.handle_event(cx, event);
840 }
841 }
842
843 fn handle_mousedown_event(
844 &self,
845 cx: &mut JSContext,
846 mouse_event: &MouseEvent,
847 hit_test_result: &HitTestResult,
848 ) {
849 if self.textinput.borrow().is_empty() {
851 if let Some(super_type) = self.super_type() {
852 super_type.handle_mousedown_event(cx, mouse_event, hit_test_result);
853 }
854 return;
855 }
856
857 if self.textinput.borrow_mut().handle_mousedown_event(
858 self.upcast(),
859 mouse_event,
860 hit_test_result,
861 ) {
862 self.maybe_update_shared_selection();
863 mouse_event.upcast::<Event>().mark_as_handled();
864 }
865 }
866
867 fn pop(&self, cx: &mut JSContext) {
868 self.super_type().unwrap().pop(cx);
869
870 self.reset(cx);
872 }
873}
874
875impl FormControl for HTMLTextAreaElement {
876 fn form_owner(&self) -> Option<DomRoot<HTMLFormElement>> {
877 self.form_owner.get()
878 }
879
880 fn set_form_owner(&self, _cx: &mut JSContext, form: Option<&HTMLFormElement>) {
881 self.form_owner.set(form);
882 }
883
884 fn to_html_element(&self) -> &HTMLElement {
885 self.upcast::<HTMLElement>()
886 }
887}
888
889impl Validatable for HTMLTextAreaElement {
890 fn as_element(&self) -> &Element {
891 self.upcast()
892 }
893
894 fn validity_state(&self, cx: &mut JSContext) -> DomRoot<ValidityState> {
895 self.validity_state
896 .or_init(|| ValidityState::new(cx, &self.owner_window(), self.upcast()))
897 }
898
899 fn is_instance_validatable(&self) -> bool {
900 !self.upcast::<Element>().disabled_state() &&
904 !self.ReadOnly() &&
905 !is_barred_by_datalist_ancestor(self.upcast())
906 }
907
908 fn perform_validation(
909 &self,
910 _cx: &mut JSContext,
911 validate_flags: ValidationFlags,
912 ) -> ValidationFlags {
913 let mut failed_flags = ValidationFlags::empty();
914
915 let textinput = self.textinput.borrow();
916 let Utf16CodeUnits(value_len) = textinput.len_utf16();
917 let last_edit_by_user = !textinput.was_last_change_by_set_content();
918 let value_dirty = self.value_dirty.get();
919
920 if validate_flags.contains(ValidationFlags::VALUE_MISSING) &&
923 self.Required() &&
924 self.is_mutable() &&
925 value_len == 0
926 {
927 failed_flags.insert(ValidationFlags::VALUE_MISSING);
928 }
929
930 if value_dirty && last_edit_by_user && value_len > 0 {
931 if validate_flags.contains(ValidationFlags::TOO_LONG) {
934 let max_length = self.MaxLength();
935 if max_length != DEFAULT_MAX_LENGTH && value_len > (max_length as usize) {
936 failed_flags.insert(ValidationFlags::TOO_LONG);
937 }
938 }
939
940 if validate_flags.contains(ValidationFlags::TOO_SHORT) {
943 let min_length = self.MinLength();
944 if min_length != DEFAULT_MIN_LENGTH && value_len < (min_length as usize) {
945 failed_flags.insert(ValidationFlags::TOO_SHORT);
946 }
947 }
948 }
949
950 failed_flags
951 }
952}