diff options
author | Manish Goregaokar <manishsmail@gmail.com> | 2014-11-24 20:12:17 +0530 |
---|---|---|
committer | Manish Goregaokar <manishsmail@gmail.com> | 2014-12-05 18:33:03 -0800 |
commit | c89ec3910f15f3a71be66d60da5cfd9aed1b30f1 (patch) | |
tree | 97546eded2fd8a314969e67721d689a39d52900a | |
parent | e68119f82f4b0684918a76299d115b86285be97b (diff) | |
download | servo-c89ec3910f15f3a71be66d60da5cfd9aed1b30f1.tar.gz servo-c89ec3910f15f3a71be66d60da5cfd9aed1b30f1.zip |
Hook up synthetic click activation to script_task and <>.click()
-rw-r--r-- | components/script/dom/htmlelement.rs | 16 | ||||
-rw-r--r-- | components/script/dom/webidls/HTMLElement.webidl | 2 | ||||
-rw-r--r-- | components/script/script_task.rs | 19 | ||||
-rw-r--r-- | tests/html/test-synthetic-click-activation.html | 31 |
4 files changed, 63 insertions, 5 deletions
diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index 75ad910ee2e..728f0ee573d 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -7,14 +7,15 @@ use dom::attr::AttrHelpers; use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; use dom::bindings::codegen::Bindings::HTMLElementBinding; use dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods; +use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods; use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLFrameSetElementDerived}; -use dom::bindings::codegen::InheritTypes::EventTargetCast; +use dom::bindings::codegen::InheritTypes::{EventTargetCast, HTMLInputElementCast}; use dom::bindings::codegen::InheritTypes::{HTMLElementDerived, HTMLBodyElementDerived}; use dom::bindings::js::{JSRef, Temporary}; use dom::bindings::utils::{Reflectable, Reflector}; use dom::document::Document; -use dom::element::{Element, ElementTypeId, ElementTypeId_, HTMLElementTypeId}; +use dom::element::{Element, ElementTypeId, ElementTypeId_, HTMLElementTypeId, ActivationElementHelpers}; use dom::eventtarget::{EventTarget, EventTargetHelpers, NodeTargetTypeId}; use dom::node::{Node, ElementNodeTypeId, window_from_node}; use dom::virtualmethods::VirtualMethods; @@ -91,6 +92,17 @@ impl<'a> HTMLElementMethods for JSRef<'a, HTMLElement> { win.SetOnload(listener) } } + + // https://html.spec.whatwg.org/multipage/interaction.html#dom-click + fn Click(self) { + let maybe_input = HTMLInputElementCast::to_ref(self); + match maybe_input { + Some(i) if i.Disabled() => return, + _ => () + } + let element: JSRef<Element> = ElementCast::from_ref(self); + element.as_maybe_activatable().map(|a| a.synthetic_click_activation(false, false, false, false)); + } } impl<'a> VirtualMethods for JSRef<'a, HTMLElement> { diff --git a/components/script/dom/webidls/HTMLElement.webidl b/components/script/dom/webidls/HTMLElement.webidl index 10be66c62e3..359ef11f0a7 100644 --- a/components/script/dom/webidls/HTMLElement.webidl +++ b/components/script/dom/webidls/HTMLElement.webidl @@ -23,7 +23,7 @@ interface HTMLElement : Element { // user interaction attribute boolean hidden; - //void click(); + void click(); // attribute long tabIndex; //void focus(); //void blur(); diff --git a/components/script/script_task.rs b/components/script/script_task.rs index acbd2cfbab3..9ccf7653af5 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -893,9 +893,9 @@ impl ScriptTask { None, props.key_code).root(); let event = EventCast::from_ref(*keyevent); let _ = target.DispatchEvent(event); - + let mut prevented = event.DefaultPrevented(); // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#keys-cancelable-keys - if state != Released && props.is_printable() && !event.DefaultPrevented() { + if state != Released && props.is_printable() && !prevented { // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#keypress-event-order let event = KeyboardEvent::new(*window, "keypress".to_string(), true, true, Some(*window), 0, props.key.to_string(), props.code.to_string(), @@ -904,9 +904,24 @@ impl ScriptTask { props.char_code, 0).root(); let _ = target.DispatchEvent(EventCast::from_ref(*event)); + let ev = EventCast::from_ref(*event); + prevented = ev.DefaultPrevented(); // TODO: if keypress event is canceled, prevent firing input events } + // This behavior is unspecced + // We are supposed to dispatch synthetic click activation for Space and/or Return, + // however *when* we do it is up to us + // I'm dispatching it after the key event so the script has a chance to cancel it + // https://www.w3.org/Bugs/Public/show_bug.cgi?id=27337 + match key { + Key::KeySpace | Key::KeyEnter if !prevented && state == Released => { + // TODO handle space and enter slightly differently + let maybe_elem: Option<JSRef<Element>> = ElementCast::to_ref(target); + maybe_elem.map(|el| el.as_maybe_activatable().map(|a| a.synthetic_click_activation(ctrl, alt, shift, meta))); + } + _ => () + } window.flush_layout(); } diff --git a/tests/html/test-synthetic-click-activation.html b/tests/html/test-synthetic-click-activation.html new file mode 100644 index 00000000000..011914895a7 --- /dev/null +++ b/tests/html/test-synthetic-click-activation.html @@ -0,0 +1,31 @@ +<style> +</style> +<form action="http://example.com" method="get"> +<div><input type="checkbox"></div> +<div><input type="submit"><input type="reset"></div> +<div><input type="checkbox"></div> +<div><input type="checkbox" checked></div> +<div>group 1 + <div><input type="radio"></div> + <div><input type="radio" checked></div> +</div> +<div>group 2 + <div><input type="radio" name="a" checked></div> + <div><input type="radio" name="a"></div> +</div> +</form> +<br> +Use the buttons below to shift "fake" focus and trigger click events. The first form widget is initually focused. +<br> +<button type=button id="left">Shift fake focus left</button><br> +<button type=button id="right">Shift fake focus right</button><br> +<button type=button id="click">Trigger synthetic click</button><br> + + +<script> +i = 0; +tags = document.getElementsByTagName("input"); +document.getElementById("left").onclick=function(){i--;} +document.getElementById("right").onclick=function(){i++;} +document.getElementById("click").onclick=function(){tags[i].click()} +</script> |