mirror of
https://github.com/servo/servo.git
synced 2025-08-05 05:30:08 +01:00
auto merge of #4736 : mattnenterprise/servo/dispatch_input_event, r=jdm
This commit is contained in:
commit
65d4b12bf2
3 changed files with 64 additions and 10 deletions
|
@ -629,7 +629,7 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> {
|
||||||
ctrl, alt, shift, meta,
|
ctrl, alt, shift, meta,
|
||||||
None, props.key_code).root();
|
None, props.key_code).root();
|
||||||
let event = EventCast::from_ref(keyevent.r());
|
let event = EventCast::from_ref(keyevent.r());
|
||||||
let _ = target.DispatchEvent(event);
|
event.fire(target);
|
||||||
let mut prevented = event.DefaultPrevented();
|
let mut prevented = event.DefaultPrevented();
|
||||||
|
|
||||||
// https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#keys-cancelable-keys
|
// 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,
|
ctrl, alt, shift, meta,
|
||||||
props.char_code, 0).root();
|
props.char_code, 0).root();
|
||||||
let ev = EventCast::from_ref(event.r());
|
let ev = EventCast::from_ref(event.r());
|
||||||
let _ = target.DispatchEvent(ev);
|
ev.fire(target);
|
||||||
prevented = ev.DefaultPrevented();
|
prevented = ev.DefaultPrevented();
|
||||||
// TODO: if keypress event is canceled, prevent firing input events
|
// TODO: if keypress event is canceled, prevent firing input events
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,22 +9,25 @@ use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
|
||||||
use dom::bindings::codegen::Bindings::HTMLTextAreaElementBinding;
|
use dom::bindings::codegen::Bindings::HTMLTextAreaElementBinding;
|
||||||
use dom::bindings::codegen::Bindings::HTMLTextAreaElementBinding::HTMLTextAreaElementMethods;
|
use dom::bindings::codegen::Bindings::HTMLTextAreaElementBinding::HTMLTextAreaElementMethods;
|
||||||
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
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::{HTMLTextAreaElementDerived, HTMLFieldSetElementDerived};
|
||||||
use dom::bindings::codegen::InheritTypes::{KeyboardEventCast, TextDerived};
|
use dom::bindings::codegen::InheritTypes::{KeyboardEventCast, TextDerived};
|
||||||
|
use dom::bindings::global::GlobalRef;
|
||||||
use dom::bindings::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::document::{Document, DocumentHelpers};
|
||||||
use dom::element::{Element, AttributeHandlers};
|
use dom::element::{Element, AttributeHandlers};
|
||||||
use dom::event::Event;
|
use dom::event::{Event, EventBubbles, EventCancelable};
|
||||||
use dom::eventtarget::{EventTarget, EventTargetTypeId};
|
use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId};
|
||||||
use dom::element::ElementTypeId;
|
use dom::element::ElementTypeId;
|
||||||
use dom::htmlelement::{HTMLElement, HTMLElementTypeId};
|
use dom::htmlelement::{HTMLElement, HTMLElementTypeId};
|
||||||
use dom::htmlformelement::FormControl;
|
use dom::htmlformelement::FormControl;
|
||||||
use dom::keyboardevent::KeyboardEvent;
|
use dom::keyboardevent::KeyboardEvent;
|
||||||
use dom::node::{DisabledStateHelpers, Node, NodeHelpers, NodeDamage, NodeTypeId};
|
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 textinput::{TextInput, Lines, KeyReaction};
|
||||||
use dom::virtualmethods::VirtualMethods;
|
use dom::virtualmethods::VirtualMethods;
|
||||||
|
use script_task::{ScriptMsg, Runnable};
|
||||||
|
|
||||||
use util::str::DOMString;
|
use util::str::DOMString;
|
||||||
use string_cache::Atom;
|
use string_cache::Atom;
|
||||||
|
@ -38,7 +41,6 @@ pub struct HTMLTextAreaElement {
|
||||||
textinput: DOMRefCell<TextInput>,
|
textinput: DOMRefCell<TextInput>,
|
||||||
cols: Cell<u32>,
|
cols: Cell<u32>,
|
||||||
rows: Cell<u32>,
|
rows: Cell<u32>,
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/forms.html#concept-textarea-dirty
|
// https://html.spec.whatwg.org/multipage/forms.html#concept-textarea-dirty
|
||||||
value_changed: Cell<bool>,
|
value_changed: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
@ -183,6 +185,7 @@ impl<'a> HTMLTextAreaElementMethods for JSRef<'a, HTMLTextAreaElement> {
|
||||||
// TODO move the cursor to the end of the field
|
// TODO move the cursor to the end of the field
|
||||||
self.textinput.borrow_mut().set_content(value);
|
self.textinput.borrow_mut().set_content(value);
|
||||||
self.value_changed.set(true);
|
self.value_changed.set(true);
|
||||||
|
|
||||||
self.force_relayout();
|
self.force_relayout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -207,6 +210,7 @@ impl<'a> HTMLTextAreaElementHelpers for JSRef<'a, HTMLTextAreaElement> {
|
||||||
|
|
||||||
trait PrivateHTMLTextAreaElementHelpers {
|
trait PrivateHTMLTextAreaElementHelpers {
|
||||||
fn force_relayout(self);
|
fn force_relayout(self);
|
||||||
|
fn dispatch_change_event(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PrivateHTMLTextAreaElementHelpers for JSRef<'a, HTMLTextAreaElement> {
|
impl<'a> PrivateHTMLTextAreaElementHelpers for JSRef<'a, HTMLTextAreaElement> {
|
||||||
|
@ -215,6 +219,18 @@ impl<'a> PrivateHTMLTextAreaElementHelpers for JSRef<'a, HTMLTextAreaElement> {
|
||||||
let node: JSRef<Node> = NodeCast::from_ref(self);
|
let node: JSRef<Node> = NodeCast::from_ref(self);
|
||||||
doc.r().content_changed(node, NodeDamage::OtherNodeDamage)
|
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<EventTarget> = EventTargetCast::from_ref(self);
|
||||||
|
target.dispatch_event(event.r());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> VirtualMethods for JSRef<'a, HTMLTextAreaElement> {
|
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));
|
doc.r().request_focus(ElementCast::from_ref(*self));
|
||||||
} else if "keydown" == event.Type().as_slice() && !event.DefaultPrevented() {
|
} else if "keydown" == event.Type().as_slice() && !event.DefaultPrevented() {
|
||||||
let keyevent: Option<JSRef<KeyboardEvent>> = KeyboardEventCast::to_ref(event);
|
let keyevent: Option<JSRef<KeyboardEvent>> = KeyboardEventCast::to_ref(event);
|
||||||
keyevent.map(|event| {
|
keyevent.map(|kevent| {
|
||||||
match self.textinput.borrow_mut().handle_keydown(event) {
|
match self.textinput.borrow_mut().handle_keydown(kevent) {
|
||||||
KeyReaction::TriggerDefaultAction => (),
|
KeyReaction::TriggerDefaultAction => (),
|
||||||
KeyReaction::DispatchInput => {
|
KeyReaction::DispatchInput => {
|
||||||
self.force_relayout();
|
|
||||||
self.value_changed.set(true);
|
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 => (),
|
KeyReaction::Nothing => (),
|
||||||
}
|
}
|
||||||
|
@ -344,3 +372,14 @@ impl<'a> FormControl<'a> for JSRef<'a, HTMLTextAreaElement> {
|
||||||
ElementCast::from_ref(self)
|
ElementCast::from_ref(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct ChangeEventRunnable {
|
||||||
|
element: Trusted<HTMLTextAreaElement>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Runnable for ChangeEventRunnable {
|
||||||
|
fn handler(self: Box<ChangeEventRunnable>) {
|
||||||
|
let target = self.element.to_temporary().root();
|
||||||
|
target.r().dispatch_change_event();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
15
tests/html/test_textarea_input.html
Normal file
15
tests/html/test_textarea_input.html
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<textarea id="textarea">
|
||||||
|
</textarea>
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
var area = document.getElementById('textarea');
|
||||||
|
area.addEventListener('input', function() {
|
||||||
|
alert('input detected');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</html>
|
Loading…
Add table
Add a link
Reference in a new issue