aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2014-11-24 20:12:17 +0530
committerManish Goregaokar <manishsmail@gmail.com>2014-12-05 18:33:03 -0800
commitc89ec3910f15f3a71be66d60da5cfd9aed1b30f1 (patch)
tree97546eded2fd8a314969e67721d689a39d52900a
parente68119f82f4b0684918a76299d115b86285be97b (diff)
downloadservo-c89ec3910f15f3a71be66d60da5cfd9aed1b30f1.tar.gz
servo-c89ec3910f15f3a71be66d60da5cfd9aed1b30f1.zip
Hook up synthetic click activation to script_task and <>.click()
-rw-r--r--components/script/dom/htmlelement.rs16
-rw-r--r--components/script/dom/webidls/HTMLElement.webidl2
-rw-r--r--components/script/script_task.rs19
-rw-r--r--tests/html/test-synthetic-click-activation.html31
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>