mirror of
https://github.com/servo/servo.git
synced 2025-07-25 00:00:20 +01:00
Implement document focus context and hook it up to click events.
This commit is contained in:
parent
329ba56fca
commit
84bc17e7ad
4 changed files with 57 additions and 7 deletions
|
@ -96,6 +96,10 @@ pub struct Document {
|
||||||
anchors: MutNullableJS<HTMLCollection>,
|
anchors: MutNullableJS<HTMLCollection>,
|
||||||
applets: MutNullableJS<HTMLCollection>,
|
applets: MutNullableJS<HTMLCollection>,
|
||||||
ready_state: Cell<DocumentReadyState>,
|
ready_state: Cell<DocumentReadyState>,
|
||||||
|
/// The element that has most recently requested focus for itself.
|
||||||
|
possibly_focused: MutNullableJS<Element>,
|
||||||
|
/// The element that currently has the document focus context.
|
||||||
|
focused: MutNullableJS<Element>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DocumentDerived for EventTarget {
|
impl DocumentDerived for EventTarget {
|
||||||
|
@ -178,6 +182,10 @@ pub trait DocumentHelpers<'a> {
|
||||||
fn load_anchor_href(self, href: DOMString);
|
fn load_anchor_href(self, href: DOMString);
|
||||||
fn find_fragment_node(self, fragid: DOMString) -> Option<Temporary<Element>>;
|
fn find_fragment_node(self, fragid: DOMString) -> Option<Temporary<Element>>;
|
||||||
fn set_ready_state(self, state: DocumentReadyState);
|
fn set_ready_state(self, state: DocumentReadyState);
|
||||||
|
fn get_focused_element(self) -> Option<Temporary<Element>>;
|
||||||
|
fn begin_focus_transaction(self);
|
||||||
|
fn request_focus(self, elem: JSRef<Element>);
|
||||||
|
fn commit_focus_transaction(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> {
|
impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> {
|
||||||
|
@ -327,6 +335,30 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> {
|
||||||
let target: JSRef<EventTarget> = EventTargetCast::from_ref(self);
|
let target: JSRef<EventTarget> = EventTargetCast::from_ref(self);
|
||||||
let _ = target.DispatchEvent(*event);
|
let _ = target.DispatchEvent(*event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the element that currently has focus.
|
||||||
|
// https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#events-focusevent-doc-focus
|
||||||
|
fn get_focused_element(self) -> Option<Temporary<Element>> {
|
||||||
|
self.focused.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initiate a new round of checking for elements requesting focus. The last element to call
|
||||||
|
/// `request_focus` before `commit_focus_transaction` is called will receive focus.
|
||||||
|
fn begin_focus_transaction(self) {
|
||||||
|
self.possibly_focused.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Request that the given element receive focus once the current transaction is complete.
|
||||||
|
fn request_focus(self, elem: JSRef<Element>) {
|
||||||
|
self.possibly_focused.assign(Some(elem))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reassign the focus context to the element that last requested focus during this
|
||||||
|
/// transaction, or none if no elements requested it.
|
||||||
|
fn commit_focus_transaction(self) {
|
||||||
|
//TODO: dispatch blur, focus, focusout, and focusin events
|
||||||
|
self.focused.assign(self.possibly_focused.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(PartialEq)]
|
#[deriving(PartialEq)]
|
||||||
|
@ -390,6 +422,8 @@ impl Document {
|
||||||
anchors: Default::default(),
|
anchors: Default::default(),
|
||||||
applets: Default::default(),
|
applets: Default::default(),
|
||||||
ready_state: Cell::new(ready_state),
|
ready_state: Cell::new(ready_state),
|
||||||
|
possibly_focused: Default::default(),
|
||||||
|
focused: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -415,6 +415,9 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLInputElement> {
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let doc = document_from_node(*self).root();
|
||||||
|
doc.request_focus(ElementCast::from_ref(*self));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -928,11 +928,13 @@ impl ScriptTask {
|
||||||
let frame = page.frame();
|
let frame = page.frame();
|
||||||
let window = frame.as_ref().unwrap().window.root();
|
let window = frame.as_ref().unwrap().window.root();
|
||||||
let doc = window.Document().root();
|
let doc = window.Document().root();
|
||||||
|
let focused = doc.get_focused_element().root();
|
||||||
let body = doc.GetBody().root();
|
let body = doc.GetBody().root();
|
||||||
|
|
||||||
let target: JSRef<EventTarget> = match body {
|
let target: JSRef<EventTarget> = match (&focused, &body) {
|
||||||
Some(body) => EventTargetCast::from_ref(*body),
|
(&Some(ref focused), _) => EventTargetCast::from_ref(**focused),
|
||||||
None => EventTargetCast::from_ref(*window),
|
(&None, &Some(ref body)) => EventTargetCast::from_ref(**body),
|
||||||
|
(&None, &None) => EventTargetCast::from_ref(*window),
|
||||||
};
|
};
|
||||||
|
|
||||||
let ctrl = modifiers.contains(Control);
|
let ctrl = modifiers.contains(Control);
|
||||||
|
@ -956,10 +958,10 @@ impl ScriptTask {
|
||||||
let _ = target.DispatchEvent(EventCast::from_ref(*event));
|
let _ = target.DispatchEvent(EventCast::from_ref(*event));
|
||||||
|
|
||||||
if state != Released && props.is_printable() {
|
if state != Released && props.is_printable() {
|
||||||
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.clone(), props.code.clone(), props.location,
|
0, props.key.clone(), props.code.clone(), props.location,
|
||||||
is_repeating, is_composing, ctrl, alt, shift, meta,
|
is_repeating, is_composing, ctrl, alt, shift, meta,
|
||||||
props.char_code, props.key_code).root();
|
props.char_code, props.key_code).root();
|
||||||
let _ = target.DispatchEvent(EventCast::from_ref(*event));
|
let _ = target.DispatchEvent(EventCast::from_ref(*event));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1065,6 +1067,9 @@ impl ScriptTask {
|
||||||
match *page.frame() {
|
match *page.frame() {
|
||||||
Some(ref frame) => {
|
Some(ref frame) => {
|
||||||
let window = frame.window.root();
|
let window = frame.window.root();
|
||||||
|
let doc = window.Document().root();
|
||||||
|
doc.begin_focus_transaction();
|
||||||
|
|
||||||
let event =
|
let event =
|
||||||
Event::new(&global::Window(*window),
|
Event::new(&global::Window(*window),
|
||||||
"click".to_string(),
|
"click".to_string(),
|
||||||
|
@ -1072,6 +1077,7 @@ impl ScriptTask {
|
||||||
let eventtarget: JSRef<EventTarget> = EventTargetCast::from_ref(node);
|
let eventtarget: JSRef<EventTarget> = EventTargetCast::from_ref(node);
|
||||||
let _ = eventtarget.dispatch_event_with_target(None, *event);
|
let _ = eventtarget.dispatch_event_with_target(None, *event);
|
||||||
|
|
||||||
|
doc.commit_focus_transaction();
|
||||||
window.flush_layout();
|
window.flush_layout();
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
|
|
7
tests/html/test_focus.html
Normal file
7
tests/html/test_focus.html
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<body>
|
||||||
|
<input id="focused">
|
||||||
|
<script>
|
||||||
|
document.body.addEventListener('keydown', function() { alert("body"); }, false);
|
||||||
|
document.getElementById('focused').addEventListener('keydown', function() { alert("input"); }, false);
|
||||||
|
</script>
|
||||||
|
</body>
|
Loading…
Add table
Add a link
Reference in a new issue