From 6554a779ae4650ddbadef1ff5531f239be7b10a6 Mon Sep 17 00:00:00 2001 From: Matt McCoy Date: Tue, 17 Mar 2015 22:27:47 -0600 Subject: [PATCH] servo: Merge #4736 - Fixes #4508 dispatching input event at HTMLTextareaElement (from mattnenterprise:dispatch_input_event); r=jdm Source-Repo: https://github.com/servo/servo Source-Revision: 65d4b12bf20783ea784f1c61f4b33ec0fc975f4f --- servo/components/script/dom/document.rs | 4 +- .../script/dom/htmltextareaelement.rs | 55 ++++++++++++++++--- servo/tests/html/test_textarea_input.html | 15 +++++ 3 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 servo/tests/html/test_textarea_input.html diff --git a/servo/components/script/dom/document.rs b/servo/components/script/dom/document.rs index 71b3a26873c8..6da0dd573167 100644 --- a/servo/components/script/dom/document.rs +++ b/servo/components/script/dom/document.rs @@ -629,7 +629,7 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { ctrl, alt, shift, meta, None, props.key_code).root(); let event = EventCast::from_ref(keyevent.r()); - let _ = target.DispatchEvent(event); + event.fire(target); let mut prevented = event.DefaultPrevented(); // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#keys-cancelable-keys @@ -642,7 +642,7 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { ctrl, alt, shift, meta, props.char_code, 0).root(); let ev = EventCast::from_ref(event.r()); - let _ = target.DispatchEvent(ev); + ev.fire(target); prevented = ev.DefaultPrevented(); // TODO: if keypress event is canceled, prevent firing input events } diff --git a/servo/components/script/dom/htmltextareaelement.rs b/servo/components/script/dom/htmltextareaelement.rs index 0e7b6de2642b..acacf3cb01a7 100644 --- a/servo/components/script/dom/htmltextareaelement.rs +++ b/servo/components/script/dom/htmltextareaelement.rs @@ -9,22 +9,25 @@ use dom::bindings::codegen::Bindings::EventBinding::EventMethods; use dom::bindings::codegen::Bindings::HTMLTextAreaElementBinding; use dom::bindings::codegen::Bindings::HTMLTextAreaElementBinding::HTMLTextAreaElementMethods; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; -use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, NodeCast}; +use dom::bindings::codegen::InheritTypes::{ElementCast, EventTargetCast, HTMLElementCast, NodeCast}; use dom::bindings::codegen::InheritTypes::{HTMLTextAreaElementDerived, HTMLFieldSetElementDerived}; use dom::bindings::codegen::InheritTypes::{KeyboardEventCast, TextDerived}; +use dom::bindings::global::GlobalRef; use dom::bindings::js::{JSRef, LayoutJS, Temporary, OptionalRootable}; +use dom::bindings::refcounted::Trusted; use dom::document::{Document, DocumentHelpers}; use dom::element::{Element, AttributeHandlers}; -use dom::event::Event; -use dom::eventtarget::{EventTarget, EventTargetTypeId}; +use dom::event::{Event, EventBubbles, EventCancelable}; +use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId}; use dom::element::ElementTypeId; use dom::htmlelement::{HTMLElement, HTMLElementTypeId}; use dom::htmlformelement::FormControl; use dom::keyboardevent::KeyboardEvent; use dom::node::{DisabledStateHelpers, Node, NodeHelpers, NodeDamage, NodeTypeId}; -use dom::node::{document_from_node}; +use dom::node::{document_from_node, window_from_node}; use textinput::{TextInput, Lines, KeyReaction}; use dom::virtualmethods::VirtualMethods; +use script_task::{ScriptMsg, Runnable}; use util::str::DOMString; use string_cache::Atom; @@ -38,7 +41,6 @@ pub struct HTMLTextAreaElement { textinput: DOMRefCell, cols: Cell, rows: Cell, - // https://html.spec.whatwg.org/multipage/forms.html#concept-textarea-dirty value_changed: Cell, } @@ -183,6 +185,7 @@ impl<'a> HTMLTextAreaElementMethods for JSRef<'a, HTMLTextAreaElement> { // TODO move the cursor to the end of the field self.textinput.borrow_mut().set_content(value); self.value_changed.set(true); + self.force_relayout(); } } @@ -207,6 +210,7 @@ impl<'a> HTMLTextAreaElementHelpers for JSRef<'a, HTMLTextAreaElement> { trait PrivateHTMLTextAreaElementHelpers { fn force_relayout(self); + fn dispatch_change_event(self); } impl<'a> PrivateHTMLTextAreaElementHelpers for JSRef<'a, HTMLTextAreaElement> { @@ -215,6 +219,18 @@ impl<'a> PrivateHTMLTextAreaElementHelpers for JSRef<'a, HTMLTextAreaElement> { let node: JSRef = NodeCast::from_ref(self); doc.r().content_changed(node, NodeDamage::OtherNodeDamage) } + + fn dispatch_change_event(self) { + let window = window_from_node(self).root(); + let window = window.r(); + let event = Event::new(GlobalRef::Window(window), + "input".to_owned(), + EventBubbles::DoesNotBubble, + EventCancelable::NotCancelable).root(); + + let target: JSRef = EventTargetCast::from_ref(self); + target.dispatch_event(event.r()); + } } impl<'a> VirtualMethods for JSRef<'a, HTMLTextAreaElement> { @@ -325,12 +341,24 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLTextAreaElement> { doc.r().request_focus(ElementCast::from_ref(*self)); } else if "keydown" == event.Type().as_slice() && !event.DefaultPrevented() { let keyevent: Option> = KeyboardEventCast::to_ref(event); - keyevent.map(|event| { - match self.textinput.borrow_mut().handle_keydown(event) { + keyevent.map(|kevent| { + match self.textinput.borrow_mut().handle_keydown(kevent) { KeyReaction::TriggerDefaultAction => (), KeyReaction::DispatchInput => { - self.force_relayout(); self.value_changed.set(true); + + if event.IsTrusted() { + let window = window_from_node(*self).root(); + let window = window.r(); + let chan = window.script_chan(); + let handler = Trusted::new(window.get_cx(), *self , chan.clone()); + let dispatcher = ChangeEventRunnable { + element: handler, + }; + let _ = chan.send(ScriptMsg::RunnableMsg(box dispatcher)); + } + + self.force_relayout(); } KeyReaction::Nothing => (), } @@ -344,3 +372,14 @@ impl<'a> FormControl<'a> for JSRef<'a, HTMLTextAreaElement> { ElementCast::from_ref(self) } } + +pub struct ChangeEventRunnable { + element: Trusted, +} + +impl Runnable for ChangeEventRunnable { + fn handler(self: Box) { + let target = self.element.to_temporary().root(); + target.r().dispatch_change_event(); + } +} diff --git a/servo/tests/html/test_textarea_input.html b/servo/tests/html/test_textarea_input.html new file mode 100644 index 000000000000..7fd3ab7cb365 --- /dev/null +++ b/servo/tests/html/test_textarea_input.html @@ -0,0 +1,15 @@ + + + + + + + + + \ No newline at end of file