servo: Merge #10522 - Various cleanups in HTMLInputElement (from KiChjang:input-cleanup); r=frewsxcv
authorKeith Yeung <kungfukeith11@gmail.com>
Tue, 12 Apr 2016 07:27:08 +0500
changeset 338484 f9dd243afa2d1827045b562026df3c66ea680708
parent 338483 2cfac39666687859db617ca4cf9e217de322f001
child 338485 48d67a2d0e7ef082ce3c856972f607f6291b4127
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfrewsxcv
servo: Merge #10522 - Various cleanups in HTMLInputElement (from KiChjang:input-cleanup); r=frewsxcv Source-Repo: https://github.com/servo/servo Source-Revision: 934ae41fc982058048f460a77687ab026c9a909f
servo/components/layout/wrapper.rs
servo/components/script/dom/element.rs
servo/components/script/dom/htmlformelement.rs
servo/components/script/dom/htmlinputelement.rs
--- a/servo/components/layout/wrapper.rs
+++ b/servo/components/layout/wrapper.rs
@@ -1045,17 +1045,17 @@ impl<'ln> ThreadSafeLayoutNode for Servo
         let this = unsafe { self.get_jsmanaged() };
         if let Some(text) = this.downcast::<Text>() {
             let data = unsafe {
                 text.upcast().data_for_layout().to_owned()
             };
             return TextContent::Text(data);
         }
         if let Some(input) = this.downcast::<HTMLInputElement>() {
-            let data = unsafe { input.get_value_for_layout() };
+            let data = unsafe { input.value_for_layout() };
             return TextContent::Text(data);
         }
         if let Some(area) = this.downcast::<HTMLTextAreaElement>() {
             let data = unsafe { area.get_value_for_layout() };
             return TextContent::Text(data);
         }
 
         panic!("not text!")
@@ -1071,17 +1071,17 @@ impl<'ln> ThreadSafeLayoutNode for Servo
                 let text = unsafe { area.get_value_for_layout() };
                 let begin_byte = selection.begin();
                 let begin = search_index(begin_byte, text.char_indices());
                 let length = search_index(selection.length(), text[begin_byte..].char_indices());
                 return Some(Range::new(CharIndex(begin), CharIndex(length)));
             }
         }
         if let Some(input) = this.downcast::<HTMLInputElement>() {
-            if let Some(selection) = unsafe { input.get_selection_for_layout() } {
+            if let Some(selection) = unsafe { input.selection_for_layout() } {
                 return Some(Range::new(CharIndex(selection.begin()),
                                        CharIndex(selection.length())));
             }
         }
         None
     }
 
     fn image_url(&self) -> Option<Url> {
--- a/servo/components/script/dom/element.rs
+++ b/servo/components/script/dom/element.rs
@@ -372,17 +372,17 @@ impl LayoutElementHelpers for LayoutJS<E
                 Some("hidden") | Some("date") | Some("month") | Some("week") |
                 Some("time") | Some("datetime-local") | Some("number") | Some("range") |
                 Some("color") | Some("checkbox") | Some("radio") | Some("file") |
                 Some("submit") | Some("image") | Some("reset") | Some("button") => {
                     None
                 },
                 // Others
                 _ => {
-                    match this.get_size_for_layout() {
+                    match this.size_for_layout() {
                         0 => None,
                         s => Some(s as i32),
                     }
                 },
             }
         } else {
             None
         };
@@ -566,29 +566,29 @@ impl LayoutElementHelpers for LayoutJS<E
     }
 
     #[inline]
     #[allow(unsafe_code)]
     fn get_checked_state_for_layout(&self) -> bool {
         // TODO option and menuitem can also have a checked state.
         match self.downcast::<HTMLInputElement>() {
             Some(input) => unsafe {
-                input.get_checked_state_for_layout()
+                input.checked_state_for_layout()
             },
             None => false,
         }
     }
 
     #[inline]
     #[allow(unsafe_code)]
     fn get_indeterminate_state_for_layout(&self) -> bool {
         // TODO progress elements can also be matched with :indeterminate
         match self.downcast::<HTMLInputElement>() {
             Some(input) => unsafe {
-                input.get_indeterminate_state_for_layout()
+                input.indeterminate_state_for_layout()
             },
             None => false,
         }
     }
 
     #[inline]
     #[allow(unsafe_code)]
     fn get_state_for_layout(&self) -> ElementState {
--- a/servo/components/script/dom/htmlformelement.rs
+++ b/servo/components/script/dom/htmlformelement.rs
@@ -409,17 +409,17 @@ impl HTMLFormElement {
                     .any(|a| Root::downcast::<HTMLDataListElement>(a).is_some()) {
                 continue;
             }
             if let NodeTypeId::Element(ElementTypeId::HTMLElement(element)) = child.type_id() {
                 match element {
                     HTMLElementTypeId::HTMLInputElement => {
                         let input = child.downcast::<HTMLInputElement>().unwrap();
                         // Step 3.2-3.7
-                        if let Some(datum) = input.get_form_datum(submitter) {
+                        if let Some(datum) = input.form_datum(submitter) {
                             data_set.push(datum);
                         }
                     }
                     HTMLElementTypeId::HTMLButtonElement |
                     HTMLElementTypeId::HTMLObjectElement => {
                         // Unimplemented
                         ()
                     }
--- a/servo/components/script/dom/htmlinputelement.rs
+++ b/servo/components/script/dom/htmlinputelement.rs
@@ -159,17 +159,17 @@ impl HTMLInputElement {
 
     pub fn type_(&self) -> Atom {
         self.upcast::<Element>()
             .get_attribute(&ns!(), &atom!("type"))
             .map_or_else(|| atom!(""), |a| a.value().as_atom().to_owned())
     }
 
     // https://html.spec.whatwg.org/multipage/#input-type-attr-summary
-    fn get_value_mode(&self) -> ValueMode {
+    fn value_mode(&self) -> ValueMode {
         match self.input_type.get() {
             InputType::InputSubmit |
             InputType::InputReset |
             InputType::InputButton |
             InputType::InputImage => ValueMode::Default,
             InputType::InputCheckbox |
             InputType::InputRadio => ValueMode::DefaultOn,
             InputType::InputPassword |
@@ -203,35 +203,35 @@ impl HTMLInputElement {
         self.selection_direction.set(*direction);
         self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
     }
 
 }
 
 pub trait LayoutHTMLInputElementHelpers {
     #[allow(unsafe_code)]
-    unsafe fn get_value_for_layout(self) -> String;
+    unsafe fn value_for_layout(self) -> String;
     #[allow(unsafe_code)]
-    unsafe fn get_size_for_layout(self) -> u32;
+    unsafe fn size_for_layout(self) -> u32;
     #[allow(unsafe_code)]
-    unsafe fn get_selection_for_layout(self) -> Option<Range<isize>>;
+    unsafe fn selection_for_layout(self) -> Option<Range<isize>>;
     #[allow(unsafe_code)]
-    unsafe fn get_checked_state_for_layout(self) -> bool;
+    unsafe fn checked_state_for_layout(self) -> bool;
     #[allow(unsafe_code)]
-    unsafe fn get_indeterminate_state_for_layout(self) -> bool;
+    unsafe fn indeterminate_state_for_layout(self) -> bool;
 }
 
 #[allow(unsafe_code)]
 unsafe fn get_raw_textinput_value(input: LayoutJS<HTMLInputElement>) -> DOMString {
     (*input.unsafe_get()).textinput.borrow_for_layout().get_content()
 }
 
 impl LayoutHTMLInputElementHelpers for LayoutJS<HTMLInputElement> {
     #[allow(unsafe_code)]
-    unsafe fn get_value_for_layout(self) -> String {
+    unsafe fn value_for_layout(self) -> String {
         #[allow(unsafe_code)]
         unsafe fn get_raw_attr_value(input: LayoutJS<HTMLInputElement>, default: &str) -> String {
             let elem = input.upcast::<Element>();
             let value = (*elem.unsafe_get())
                 .get_attr_val_for_layout(&ns!(), &atom!("value"))
                 .unwrap_or(default);
             String::from(value)
         }
@@ -240,71 +240,71 @@ impl LayoutHTMLInputElementHelpers for L
             InputType::InputCheckbox | InputType::InputRadio => String::new(),
             InputType::InputFile | InputType::InputImage => String::new(),
             InputType::InputButton => get_raw_attr_value(self, ""),
             InputType::InputSubmit => get_raw_attr_value(self, DEFAULT_SUBMIT_VALUE),
             InputType::InputReset => get_raw_attr_value(self, DEFAULT_RESET_VALUE),
             InputType::InputPassword => {
                 let text = get_raw_textinput_value(self);
                 if !text.is_empty() {
-                    // The implementation of get_selection_for_layout expects a 1:1 mapping of chars.
+                    // The implementation of selection_for_layout expects a 1:1 mapping of chars.
                     text.chars().map(|_| '‚óŹ').collect()
                 } else {
                     String::from((*self.unsafe_get()).placeholder.borrow_for_layout().clone())
                 }
             },
             _ => {
                 let text = get_raw_textinput_value(self);
                 if !text.is_empty() {
-                    // The implementation of get_selection_for_layout expects a 1:1 mapping of chars.
+                    // The implementation of selection_for_layout expects a 1:1 mapping of chars.
                     String::from(text)
                 } else {
                     String::from((*self.unsafe_get()).placeholder.borrow_for_layout().clone())
                 }
             },
         }
     }
 
     #[allow(unrooted_must_root)]
     #[allow(unsafe_code)]
-    unsafe fn get_size_for_layout(self) -> u32 {
+    unsafe fn size_for_layout(self) -> u32 {
         (*self.unsafe_get()).size.get()
     }
 
     #[allow(unrooted_must_root)]
     #[allow(unsafe_code)]
-    unsafe fn get_selection_for_layout(self) -> Option<Range<isize>> {
+    unsafe fn selection_for_layout(self) -> Option<Range<isize>> {
         if !(*self.unsafe_get()).upcast::<Element>().focus_state() {
             return None;
         }
 
         // Use the raw textinput to get the index as long as we use a 1:1 char mapping
-        // in get_value_for_layout.
+        // in value_for_layout.
         let raw = match (*self.unsafe_get()).input_type.get() {
             InputType::InputText |
             InputType::InputPassword => get_raw_textinput_value(self),
             _ => return None
         };
         let textinput = (*self.unsafe_get()).textinput.borrow_for_layout();
         let selection = textinput.get_absolute_selection_range();
         let begin_byte = selection.begin();
         let begin = search_index(begin_byte, raw.char_indices());
         let length = search_index(selection.length(), raw[begin_byte..].char_indices());
         Some(Range::new(begin, length))
     }
 
     #[allow(unrooted_must_root)]
     #[allow(unsafe_code)]
-    unsafe fn get_checked_state_for_layout(self) -> bool {
+    unsafe fn checked_state_for_layout(self) -> bool {
         self.upcast::<Element>().get_state_for_layout().contains(IN_CHECKED_STATE)
     }
 
     #[allow(unrooted_must_root)]
     #[allow(unsafe_code)]
-    unsafe fn get_indeterminate_state_for_layout(self) -> bool {
+    unsafe fn indeterminate_state_for_layout(self) -> bool {
         self.upcast::<Element>().get_state_for_layout().contains(IN_INDETERMINATE_STATE)
     }
 }
 
 impl HTMLInputElementMethods for HTMLInputElement {
 
     // https://html.spec.whatwg.org/multipage/#attr-input-accept
     make_getter!(Accept, "accept");
@@ -375,17 +375,17 @@ impl HTMLInputElementMethods for HTMLInp
                             ("checkbox") | ("radio") | ("file") |
                             ("submit") | ("image") | ("reset") | ("button"));
 
     // https://html.spec.whatwg.org/multipage/#dom-input-type
     make_atomic_setter!(SetType, "type");
 
     // https://html.spec.whatwg.org/multipage/#dom-input-value
     fn Value(&self) -> DOMString {
-        match self.get_value_mode() {
+        match self.value_mode() {
             ValueMode::Value => self.textinput.borrow().get_content(),
             ValueMode::Default => {
                 self.upcast::<Element>()
                     .get_attribute(&ns!(), &atom!("value"))
                     .map_or(DOMString::from(""),
                             |a| DOMString::from(a.summarize().value))
             }
             ValueMode::DefaultOn => {
@@ -398,17 +398,17 @@ impl HTMLInputElementMethods for HTMLInp
                 // TODO: return C:\fakepath\<first of selected files> when a file is selected
                 DOMString::from("")
             }
         }
     }
 
     // https://html.spec.whatwg.org/multipage/#dom-input-value
     fn SetValue(&self, value: DOMString) -> ErrorResult {
-        match self.get_value_mode() {
+        match self.value_mode() {
             ValueMode::Value => {
                 self.textinput.borrow_mut().set_content(value);
                 self.value_dirty.set(true);
             }
             ValueMode::Default |
             ValueMode::DefaultOn => {
                 self.upcast::<Element>().set_string_attribute(&atom!("value"), value);
             }
@@ -637,32 +637,32 @@ fn broadcast_radio_checked(broadcaster: 
 }
 
 // https://html.spec.whatwg.org/multipage/#radio-button-group
 fn in_same_group(other: &HTMLInputElement, owner: Option<&HTMLFormElement>,
                  group: Option<&Atom>) -> bool {
     other.input_type.get() == InputType::InputRadio &&
     // TODO Both a and b are in the same home subtree.
     other.form_owner().r() == owner &&
-    match (other.get_radio_group_name(), group) {
+    match (other.radio_group_name(), group) {
         (Some(ref s1), Some(s2)) => compatibility_caseless_match_str(s1, s2) && s2 != &atom!(""),
         _ => false
     }
 }
 
 impl HTMLInputElement {
     fn radio_group_updated(&self, group: Option<&Atom>) {
         if self.Checked() {
             broadcast_radio_checked(self, group);
         }
     }
 
     /// https://html.spec.whatwg.org/multipage/#constructing-the-form-data-set
     /// Steps range from 3.1 to 3.7 which related to the HTMLInputElement
-    pub fn get_form_datum(&self, submitter: Option<FormSubmitter>) -> Option<FormDatum> {
+    pub fn form_datum(&self, submitter: Option<FormSubmitter>) -> Option<FormDatum> {
         // Step 3.2
         let ty = self.type_();
         // Step 3.4
         let name = self.Name();
         let is_submitter = match submitter {
             Some(FormSubmitter::InputElement(s)) => {
                 self == s
             },
@@ -688,45 +688,41 @@ impl HTMLInputElement {
         Some(FormDatum {
             ty: DOMString::from(&*ty), // FIXME(ajeffrey): Convert directly from Atoms to DOMStrings
             name: name,
             value: self.Value()
         })
     }
 
     // https://html.spec.whatwg.org/multipage/#radio-button-group
-    fn get_radio_group_name(&self) -> Option<Atom> {
+    fn radio_group_name(&self) -> Option<Atom> {
         //TODO: determine form owner
         self.upcast::<Element>()
             .get_attribute(&ns!(), &atom!("name"))
             .map(|name| name.value().as_atom().clone())
     }
 
     fn update_checked_state(&self, checked: bool, dirty: bool) {
         self.upcast::<Element>().set_state(IN_CHECKED_STATE, checked);
 
         if dirty {
             self.checked_changed.set(true);
         }
 
         if self.input_type.get() == InputType::InputRadio && checked {
             broadcast_radio_checked(self,
-                                    self.get_radio_group_name().as_ref());
+                                    self.radio_group_name().as_ref());
         }
 
         self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
         //TODO: dispatch change event
     }
 
-    pub fn get_indeterminate_state(&self) -> bool {
-        self.Indeterminate()
-    }
-
     // https://html.spec.whatwg.org/multipage/#concept-fe-mutable
-    fn mutable(&self) -> bool {
+    fn is_mutable(&self) -> bool {
         // https://html.spec.whatwg.org/multipage/#the-input-element:concept-fe-mutable
         // https://html.spec.whatwg.org/multipage/#the-readonly-attribute:concept-fe-mutable
         !(self.upcast::<Element>().disabled_state() || self.ReadOnly())
     }
 
     // https://html.spec.whatwg.org/multipage/#the-input-element:concept-form-reset-control
     pub fn reset(&self) {
         match self.input_type.get() {
@@ -796,19 +792,19 @@ impl VirtualMethods for HTMLInputElement
                             &atom!("file") => InputType::InputFile,
                             &atom!("radio") => InputType::InputRadio,
                             &atom!("checkbox") => InputType::InputCheckbox,
                             &atom!("password") => InputType::InputPassword,
                             _ => InputType::InputText,
                         };
 
                         // https://html.spec.whatwg.org/multipage/#input-type-change
-                        let (old_value_mode, old_idl_value) = (self.get_value_mode(), self.Value());
+                        let (old_value_mode, old_idl_value) = (self.value_mode(), self.Value());
                         self.input_type.set(new_type);
-                        let new_value_mode = self.get_value_mode();
+                        let new_value_mode = self.value_mode();
 
                         match (&old_value_mode, old_idl_value.is_empty(), new_value_mode) {
 
                             // Step 1
                             (&ValueMode::Value, false, ValueMode::Default) |
                             (&ValueMode::Value, false, ValueMode::DefaultOn) => {
                                 self.SetValue(old_idl_value)
                                     .expect("Failed to set input value on type change to a default ValueMode.");
@@ -830,26 +826,26 @@ impl VirtualMethods for HTMLInputElement
                                     .expect("Failed to set input value on type change to ValueMode::Filename.");
                             }
                             _ => {}
                         }
 
                         // Step 5
                         if new_type == InputType::InputRadio {
                             self.radio_group_updated(
-                                self.get_radio_group_name().as_ref());
+                                self.radio_group_name().as_ref());
                         }
 
                         // TODO: Step 6 - value sanitization
                     },
                     AttributeMutation::Removed => {
                         if self.input_type.get() == InputType::InputRadio {
                             broadcast_radio_checked(
                                 self,
-                                self.get_radio_group_name().as_ref());
+                                self.radio_group_name().as_ref());
                         }
                         self.input_type.set(InputType::InputText);
                     }
                 }
             },
             &atom!("value") if !self.value_changed.get() => {
                 let value = mutation.new_value(attr).map(|value| (**value).to_owned());
                 self.textinput.borrow_mut().set_content(
@@ -972,28 +968,28 @@ impl Activatable for HTMLInputElement {
 
     fn is_instance_activatable(&self) -> bool {
         match self.input_type.get() {
             // https://html.spec.whatwg.org/multipage/#submit-button-state-%28type=submit%29:activation-behaviour-2
             // https://html.spec.whatwg.org/multipage/#reset-button-state-%28type=reset%29:activation-behaviour-2
             // https://html.spec.whatwg.org/multipage/#checkbox-state-%28type=checkbox%29:activation-behaviour-2
             // https://html.spec.whatwg.org/multipage/#radio-button-state-%28type=radio%29:activation-behaviour-2
             InputType::InputSubmit | InputType::InputReset
-            | InputType::InputCheckbox | InputType::InputRadio => self.mutable(),
+            | InputType::InputCheckbox | InputType::InputRadio => self.is_mutable(),
             _ => false
         }
     }
 
     // https://html.spec.whatwg.org/multipage/#run-pre-click-activation-steps
     #[allow(unsafe_code)]
     fn pre_click_activation(&self) {
         let mut cache = self.activation_state.borrow_mut();
         let ty = self.input_type.get();
         cache.old_type = ty;
-        cache.was_mutable = self.mutable();
+        cache.was_mutable = self.is_mutable();
         if cache.was_mutable {
             match ty {
                 // https://html.spec.whatwg.org/multipage/#submit-button-state-(type=submit):activation-behavior
                 // InputType::InputSubmit => (), // No behavior defined
                 // https://html.spec.whatwg.org/multipage/#reset-button-state-(type=reset):activation-behavior
                 // InputType::InputSubmit => (), // No behavior defined
                 InputType::InputCheckbox => {
                     /*
@@ -1008,17 +1004,17 @@ impl Activatable for HTMLInputElement {
                     self.SetChecked(!cache.checked);
                 },
                 // https://html.spec.whatwg.org/multipage/#radio-button-state-(type=radio):pre-click-activation-steps
                 InputType::InputRadio => {
                     //TODO: if not in document, use root ancestor instead of document
                     let owner = self.form_owner();
                     let doc = document_from_node(self);
                     let doc_node = doc.upcast::<Node>();
-                    let group = self.get_radio_group_name();;
+                    let group = self.radio_group_name();;
 
                     // Safe since we only manipulate the DOM tree after finding an element
                     let checked_member = doc_node.query_selector_iter(DOMString::from("input[type=radio]"))
                             .unwrap()
                             .filter_map(Root::downcast::<HTMLInputElement>)
                             .find(|r| {
                                 in_same_group(r.r(), owner.r(), group.as_ref()) &&
                                 r.Checked()
@@ -1054,79 +1050,72 @@ impl Activatable for HTMLInputElement {
                     self.SetChecked(cache.checked);
                     self.checked_changed.set(cache.checked_changed);
                 }
             },
             // https://html.spec.whatwg.org/multipage/#radio-button-state-(type=radio):canceled-activation-steps
             InputType::InputRadio => {
                 // We want to restore state only if the element had been changed in the first place
                 if cache.was_mutable {
-                    let name = self.get_radio_group_name();
                     match cache.checked_radio.r() {
                         Some(o) => {
                             // Avoiding iterating through the whole tree here, instead
                             // we can check if the conditions for radio group siblings apply
-                            if name == o.get_radio_group_name() && // TODO should be compatibility caseless
-                               self.form_owner() == o.form_owner() &&
-                               // TODO Both a and b are in the same home subtree
-                               o.input_type.get() == InputType::InputRadio {
-                                    o.SetChecked(true);
+                            if in_same_group(&o, self.form_owner().r(), self.radio_group_name().as_ref()) {
+                                o.SetChecked(true);
                             } else {
                                 self.SetChecked(false);
                             }
                         },
                         None => self.SetChecked(false)
                     };
                     self.checked_changed.set(cache.checked_changed);
                 }
             }
             _ => ()
         }
     }
 
     // https://html.spec.whatwg.org/multipage/#run-post-click-activation-steps
     fn activation_behavior(&self, _event: &Event, _target: &EventTarget) {
         let ty = self.input_type.get();
-        if self.activation_state.borrow().old_type != ty {
-            // Type changed, abandon ship
+        if self.activation_state.borrow().old_type != ty || !self.is_mutable() {
+            // Type changed or input is immutable, abandon ship
             // https://www.w3.org/Bugs/Public/show_bug.cgi?id=27414
             return;
         }
         match ty {
             InputType::InputSubmit => {
                 // https://html.spec.whatwg.org/multipage/#submit-button-state-(type=submit):activation-behavior
                 // FIXME (Manishearth): support document owners (needs ability to get parent browsing context)
-                if self.mutable() /* and document owner is fully active */ {
-                    self.form_owner().map(|o| {
-                        o.submit(SubmittedFrom::NotFromFormSubmitMethod,
-                                 FormSubmitter::InputElement(self.clone()))
-                    });
-                }
+                // Check if document owner is fully active
+                self.form_owner().map(|o| {
+                    o.submit(SubmittedFrom::NotFromFormSubmitMethod,
+                             FormSubmitter::InputElement(self.clone()))
+                });
             },
             InputType::InputReset => {
                 // https://html.spec.whatwg.org/multipage/#reset-button-state-(type=reset):activation-behavior
                 // FIXME (Manishearth): support document owners (needs ability to get parent browsing context)
-                if self.mutable() /* and document owner is fully active */ {
-                    self.form_owner().map(|o| {
-                        o.reset(ResetFrom::NotFromFormResetMethod)
-                    });
-                }
+                // Check if document owner is fully active
+                self.form_owner().map(|o| {
+                    o.reset(ResetFrom::NotFromFormResetMethod)
+                });
             },
             InputType::InputCheckbox | InputType::InputRadio => {
                 // https://html.spec.whatwg.org/multipage/#checkbox-state-(type=checkbox):activation-behavior
                 // https://html.spec.whatwg.org/multipage/#radio-button-state-(type=radio):activation-behavior
-                if self.mutable() {
-                    let target = self.upcast::<EventTarget>();
-                    target.fire_event("input",
-                                      EventBubbles::Bubbles,
-                                      EventCancelable::NotCancelable);
-                    target.fire_event("change",
-                                      EventBubbles::Bubbles,
-                                      EventCancelable::NotCancelable);
-                }
+                // Check if document owner is fully active
+                let target = self.upcast::<EventTarget>();
+                target.fire_event("input",
+                                  EventBubbles::Bubbles,
+                                  EventCancelable::NotCancelable);
+                target.fire_event("change",
+                                  EventBubbles::Bubbles,
+                                  EventCancelable::NotCancelable);
             },
             _ => ()
         }
     }
 
     // https://html.spec.whatwg.org/multipage/#implicit-submission
     #[allow(unsafe_code)]
     fn implicit_submission(&self, ctrlKey: bool, shiftKey: bool, altKey: bool, metaKey: bool) {