From 7cb851dda19e3d30543c58b26ad17d82554997d8 Mon Sep 17 00:00:00 2001 From: Matt McCoy Date: Tue, 27 Jan 2015 21:16:56 -0500 Subject: [PATCH 1/5] Fixes #4508 dispatching input event at HTMLTextareaElement --- components/script/dom/htmltextareaelement.rs | 34 ++++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs index 0e7b6de2642..763d6aa9c64 100644 --- a/components/script/dom/htmltextareaelement.rs +++ b/components/script/dom/htmltextareaelement.rs @@ -12,19 +12,22 @@ use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, NodeCast}; use dom::bindings::codegen::InheritTypes::{HTMLTextAreaElementDerived, HTMLFieldSetElementDerived}; use dom::bindings::codegen::InheritTypes::{KeyboardEventCast, TextDerived}; -use dom::bindings::js::{JSRef, LayoutJS, Temporary, OptionalRootable}; +use dom::bindings::global::GlobalRef; +use dom::bindings::js::{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::event::{Event, EventBubbles, EventCancelable}; use dom::eventtarget::{EventTarget, 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; @@ -183,6 +186,13 @@ 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); + + 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()); + chan.send(ScriptMsg::RunnableMsg(box handler)); + self.force_relayout(); } } @@ -207,6 +217,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 +226,16 @@ 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(); + self.handle_event(event.r()); + } } impl<'a> VirtualMethods for JSRef<'a, HTMLTextAreaElement> { @@ -344,3 +365,10 @@ impl<'a> FormControl<'a> for JSRef<'a, HTMLTextAreaElement> { ElementCast::from_ref(self) } } + +impl Runnable for Trusted { + fn handler(self: Box>) { + let target = self.to_temporary().root(); + target.r().dispatch_change_event(); + } +} \ No newline at end of file From bfa4fe762b105a66f2d9647f5a763f28ebe8084c Mon Sep 17 00:00:00 2001 From: Matt McCoy Date: Mon, 9 Mar 2015 18:22:44 -0400 Subject: [PATCH 2/5] #4508 Fixing issues related to dispatching input event at HTMLTextareaElement --- components/script/dom/htmltextareaelement.rs | 27 ++++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs index 763d6aa9c64..a33de9da8ab 100644 --- a/components/script/dom/htmltextareaelement.rs +++ b/components/script/dom/htmltextareaelement.rs @@ -9,7 +9,7 @@ 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; @@ -18,7 +18,7 @@ use dom::bindings::refcounted::Trusted; use dom::document::{Document, DocumentHelpers}; use dom::element::{Element, AttributeHandlers}; use dom::event::{Event, EventBubbles, EventCancelable}; -use dom::eventtarget::{EventTarget, EventTargetTypeId}; +use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId}; use dom::element::ElementTypeId; use dom::htmlelement::{HTMLElement, HTMLElementTypeId}; use dom::htmlformelement::FormControl; @@ -27,7 +27,7 @@ use dom::node::{DisabledStateHelpers, Node, NodeHelpers, NodeDamage, NodeTypeId} use dom::node::{document_from_node, window_from_node}; use textinput::{TextInput, Lines, KeyReaction}; use dom::virtualmethods::VirtualMethods; -use script_task::{ScriptMsg, Runnable}; +use script_task::{Runnable}; use util::str::DOMString; use string_cache::Atom; @@ -41,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, } @@ -187,12 +186,6 @@ impl<'a> HTMLTextAreaElementMethods for JSRef<'a, HTMLTextAreaElement> { self.textinput.borrow_mut().set_content(value); self.value_changed.set(true); - 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()); - chan.send(ScriptMsg::RunnableMsg(box handler)); - self.force_relayout(); } } @@ -234,7 +227,9 @@ impl<'a> PrivateHTMLTextAreaElementHelpers for JSRef<'a, HTMLTextAreaElement> { "input".to_owned(), EventBubbles::DoesNotBubble, EventCancelable::NotCancelable).root(); - self.handle_event(event.r()); + + let target: JSRef = EventTargetCast::from_ref(self); + target.dispatch_event(event.r()); } } @@ -366,9 +361,13 @@ impl<'a> FormControl<'a> for JSRef<'a, HTMLTextAreaElement> { } } -impl Runnable for Trusted { - fn handler(self: Box>) { - let target = self.to_temporary().root(); +pub struct TrustedHTMLTextAreaElement { + element: Trusted, +} + +impl Runnable for TrustedHTMLTextAreaElement { + fn handler(self: Box) { + let target = self.element.to_temporary().root(); target.r().dispatch_change_event(); } } \ No newline at end of file From a481c8f28a8db9002190358d9c4b986c9098f101 Mon Sep 17 00:00:00 2001 From: Matt McCoy Date: Wed, 11 Mar 2015 15:56:57 -0400 Subject: [PATCH 3/5] #4508 Only dispatching input event when the textarea receives keyboard input and not for javascript --- components/script/dom/htmltextareaelement.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs index a33de9da8ab..7aad495b1bf 100644 --- a/components/script/dom/htmltextareaelement.rs +++ b/components/script/dom/htmltextareaelement.rs @@ -27,7 +27,7 @@ use dom::node::{DisabledStateHelpers, Node, NodeHelpers, NodeDamage, NodeTypeId} use dom::node::{document_from_node, window_from_node}; use textinput::{TextInput, Lines, KeyReaction}; use dom::virtualmethods::VirtualMethods; -use script_task::{Runnable}; +use script_task::{ScriptMsg, Runnable}; use util::str::DOMString; use string_cache::Atom; @@ -345,8 +345,18 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLTextAreaElement> { match self.textinput.borrow_mut().handle_keydown(event) { KeyReaction::TriggerDefaultAction => (), KeyReaction::DispatchInput => { - self.force_relayout(); self.value_changed.set(true); + + 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 = TrustedHTMLTextAreaElement { + element: handler, + }; + chan.send(ScriptMsg::RunnableMsg(box dispatcher)); + + self.force_relayout(); } KeyReaction::Nothing => (), } From 5938a4c0f54cfaca37fa4bec867c7eedc4e84975 Mon Sep 17 00:00:00 2001 From: Matt McCoy Date: Tue, 17 Mar 2015 16:01:39 -0400 Subject: [PATCH 4/5] #4508 Ranaming the runnable and making sure the event is trusted --- components/script/dom/htmltextareaelement.rs | 28 +++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs index 7aad495b1bf..41570fd1fa1 100644 --- a/components/script/dom/htmltextareaelement.rs +++ b/components/script/dom/htmltextareaelement.rs @@ -341,20 +341,22 @@ 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.value_changed.set(true); - 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 = TrustedHTMLTextAreaElement { - element: handler, - }; - chan.send(ScriptMsg::RunnableMsg(box dispatcher)); + if event.IsTrusted() == true { + 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, + }; + chan.send(ScriptMsg::RunnableMsg(box dispatcher)); + } self.force_relayout(); } @@ -371,12 +373,12 @@ impl<'a> FormControl<'a> for JSRef<'a, HTMLTextAreaElement> { } } -pub struct TrustedHTMLTextAreaElement { +pub struct ChangeEventRunnable { element: Trusted, } -impl Runnable for TrustedHTMLTextAreaElement { - fn handler(self: Box) { +impl Runnable for ChangeEventRunnable { + fn handler(self: Box) { let target = self.element.to_temporary().root(); target.r().dispatch_change_event(); } From 0bd717e4705f2a4124a6d5200395a6c1da849183 Mon Sep 17 00:00:00 2001 From: Matt McCoy Date: Tue, 17 Mar 2015 19:54:05 -0400 Subject: [PATCH 5/5] #4508 Adding simple test and actually getting the event to dispatch --- components/script/dom/document.rs | 4 ++-- components/script/dom/htmltextareaelement.rs | 8 ++++---- tests/html/test_textarea_input.html | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 tests/html/test_textarea_input.html diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 71b3a26873c..6da0dd57316 100644 --- a/components/script/dom/document.rs +++ b/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/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs index 41570fd1fa1..acacf3cb01a 100644 --- a/components/script/dom/htmltextareaelement.rs +++ b/components/script/dom/htmltextareaelement.rs @@ -13,7 +13,7 @@ use dom::bindings::codegen::InheritTypes::{ElementCast, EventTargetCast, HTMLEle use dom::bindings::codegen::InheritTypes::{HTMLTextAreaElementDerived, HTMLFieldSetElementDerived}; use dom::bindings::codegen::InheritTypes::{KeyboardEventCast, TextDerived}; use dom::bindings::global::GlobalRef; -use dom::bindings::js::{JS, JSRef, LayoutJS, Temporary, OptionalRootable}; +use dom::bindings::js::{JSRef, LayoutJS, Temporary, OptionalRootable}; use dom::bindings::refcounted::Trusted; use dom::document::{Document, DocumentHelpers}; use dom::element::{Element, AttributeHandlers}; @@ -347,7 +347,7 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLTextAreaElement> { KeyReaction::DispatchInput => { self.value_changed.set(true); - if event.IsTrusted() == true { + if event.IsTrusted() { let window = window_from_node(*self).root(); let window = window.r(); let chan = window.script_chan(); @@ -355,7 +355,7 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLTextAreaElement> { let dispatcher = ChangeEventRunnable { element: handler, }; - chan.send(ScriptMsg::RunnableMsg(box dispatcher)); + let _ = chan.send(ScriptMsg::RunnableMsg(box dispatcher)); } self.force_relayout(); @@ -382,4 +382,4 @@ impl Runnable for ChangeEventRunnable { let target = self.element.to_temporary().root(); target.r().dispatch_change_event(); } -} \ No newline at end of file +} diff --git a/tests/html/test_textarea_input.html b/tests/html/test_textarea_input.html new file mode 100644 index 00000000000..7fd3ab7cb36 --- /dev/null +++ b/tests/html/test_textarea_input.html @@ -0,0 +1,15 @@ + + + + + + + + + \ No newline at end of file