mirror of
https://github.com/servo/servo.git
synced 2025-06-08 08:33:26 +00:00
Hook up synthetic click activation to script_task and <>.click()
This commit is contained in:
parent
e68119f82f
commit
c89ec3910f
4 changed files with 63 additions and 5 deletions
|
@ -7,14 +7,15 @@ use dom::attr::AttrHelpers;
|
||||||
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
|
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
|
||||||
use dom::bindings::codegen::Bindings::HTMLElementBinding;
|
use dom::bindings::codegen::Bindings::HTMLElementBinding;
|
||||||
use dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
|
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::Bindings::WindowBinding::WindowMethods;
|
||||||
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLFrameSetElementDerived};
|
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::codegen::InheritTypes::{HTMLElementDerived, HTMLBodyElementDerived};
|
||||||
use dom::bindings::js::{JSRef, Temporary};
|
use dom::bindings::js::{JSRef, Temporary};
|
||||||
use dom::bindings::utils::{Reflectable, Reflector};
|
use dom::bindings::utils::{Reflectable, Reflector};
|
||||||
use dom::document::Document;
|
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::eventtarget::{EventTarget, EventTargetHelpers, NodeTargetTypeId};
|
||||||
use dom::node::{Node, ElementNodeTypeId, window_from_node};
|
use dom::node::{Node, ElementNodeTypeId, window_from_node};
|
||||||
use dom::virtualmethods::VirtualMethods;
|
use dom::virtualmethods::VirtualMethods;
|
||||||
|
@ -91,6 +92,17 @@ impl<'a> HTMLElementMethods for JSRef<'a, HTMLElement> {
|
||||||
win.SetOnload(listener)
|
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> {
|
impl<'a> VirtualMethods for JSRef<'a, HTMLElement> {
|
||||||
|
|
|
@ -23,7 +23,7 @@ interface HTMLElement : Element {
|
||||||
|
|
||||||
// user interaction
|
// user interaction
|
||||||
attribute boolean hidden;
|
attribute boolean hidden;
|
||||||
//void click();
|
void click();
|
||||||
// attribute long tabIndex;
|
// attribute long tabIndex;
|
||||||
//void focus();
|
//void focus();
|
||||||
//void blur();
|
//void blur();
|
||||||
|
|
|
@ -893,9 +893,9 @@ impl ScriptTask {
|
||||||
None, props.key_code).root();
|
None, props.key_code).root();
|
||||||
let event = EventCast::from_ref(*keyevent);
|
let event = EventCast::from_ref(*keyevent);
|
||||||
let _ = target.DispatchEvent(event);
|
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
|
// 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
|
// 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),
|
let event = KeyboardEvent::new(*window, "keypress".to_string(), true, true, Some(*window),
|
||||||
0, props.key.to_string(), props.code.to_string(),
|
0, props.key.to_string(), props.code.to_string(),
|
||||||
|
@ -904,9 +904,24 @@ impl ScriptTask {
|
||||||
props.char_code, 0).root();
|
props.char_code, 0).root();
|
||||||
let _ = target.DispatchEvent(EventCast::from_ref(*event));
|
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
|
// 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();
|
window.flush_layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
31
tests/html/test-synthetic-click-activation.html
Normal file
31
tests/html/test-synthetic-click-activation.html
Normal file
|
@ -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>
|
Loading…
Add table
Add a link
Reference in a new issue