Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Event listeners and dispatch #1065

Closed
wants to merge 3 commits into from
Closed
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Prev

Add basic event dispatch with bubbling, capturing, and propagation in…

…terruption.
  • Loading branch information
jdm committed Oct 24, 2013
commit 54bdc59736fb51867a393690d026ccc63fff27aa
@@ -772,7 +772,8 @@ pub enum Error {
NotFound,
HierarchyRequest,
InvalidCharacter,
NotSupported
NotSupported,
InvalidState
}

pub type Fallible<T> = Result<T, Error>;
@@ -31,6 +31,13 @@ pub struct AbstractEvent {
event: *mut Box<Event>
}

pub enum EventPhase {
Phase_None = 0,
Phase_Capturing,
Phase_At_Target,
Phase_Bubbling
}

impl AbstractEvent {
pub fn from_box(box: *mut Box<Event>) -> AbstractEvent {
AbstractEvent {
@@ -79,6 +86,14 @@ impl AbstractEvent {
pub fn mut_mouseevent<'a>(&'a self) -> &'a mut MouseEvent {
self.transmute_mut()
}

pub fn propagation_stopped(&self) -> bool {
self.event().stop_propagation
}

pub fn bubbles(&self) -> bool {
self.event().bubbles
}
}

impl DerivedWrapper for AbstractEvent {
@@ -121,23 +136,37 @@ pub enum EventTypeId {
pub struct Event {
type_id: EventTypeId,
reflector_: Reflector,
current_target: Option<AbstractEventTarget>,
target: Option<AbstractEventTarget>,
type_: ~str,
phase: EventPhase,
default_prevented: bool,
stop_propagation: bool,
stop_immediate: bool,
cancelable: bool,
bubbles: bool,
trusted: bool,
dispatching: bool,
initialized: bool
}

impl Event {
pub fn new_inherited(type_id: EventTypeId) -> Event {
Event {
type_id: type_id,
reflector_: Reflector::new(),
current_target: None,
target: None,
phase: Phase_None,
type_: ~"",
default_prevented: false,
cancelable: true,
bubbles: true,
trusted: false
trusted: false,
dispatching: false,
stop_propagation: false,
stop_immediate: false,
initialized: false,
}
}

@@ -156,33 +185,38 @@ impl Event {
}

pub fn EventPhase(&self) -> u16 {
0
self.phase as u16
}

pub fn Type(&self) -> DOMString {
Some(self.type_.clone())
}

pub fn GetTarget(&self) -> Option<AbstractEventTarget> {
None
self.target
}

pub fn GetCurrentTarget(&self) -> Option<AbstractEventTarget> {
None
self.current_target
}

pub fn DefaultPrevented(&self) -> bool {
self.default_prevented
}

pub fn PreventDefault(&mut self) {
self.default_prevented = true
if self.cancelable {
self.default_prevented = true
}
}

pub fn StopPropagation(&mut self) {
self.stop_propagation = true;
}

pub fn StopImmediatePropagation(&mut self) {
self.stop_immediate = true;
self.stop_propagation = true;
}

pub fn Bubbles(&self) -> bool {
@@ -204,6 +238,7 @@ impl Event {
self.type_ = null_str_as_word_null(type_);
self.cancelable = cancelable;
self.bubbles = bubbles;
self.initialized = true;
Ok(())
}

@@ -0,0 +1,114 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::callback::eReportExceptions;
use dom::eventtarget::{AbstractEventTarget, Capturing, Bubbling};
use dom::event::{AbstractEvent, Phase_At_Target, Phase_None, Phase_Bubbling, Phase_Capturing};
use dom::node::AbstractNode;
use servo_util::tree::{TreeNodeRef};

// See http://dom.spec.whatwg.org/#concept-event-dispatch for the full dispatch algorithm
pub fn dispatch_event(target: AbstractEventTarget, event: AbstractEvent) -> bool {
assert!(!event.event().dispatching);

{
let event = event.mut_event();
event.target = Some(target);
event.dispatching = true;
}

let type_ = event.event().type_.clone();
let mut chain = ~[];

//TODO: no chain if not participating in a tree
if target.is_node() {
for ancestor in AbstractNode::from_eventtarget(target).ancestors() {
chain.push(AbstractEventTarget::from_node(ancestor));
}
}

event.mut_event().phase = Phase_Capturing;

//FIXME: The "callback this value" should be currentTarget

/* capturing */
for &target in chain.rev_iter() {
//XXX bad clone
let stopped = match target.eventtarget().get_listeners_for(type_.clone(), Capturing) {
Some(listeners) => {
event.mut_event().current_target = Some(target);
for listener in listeners.iter() {
listener.HandleEvent__(event, eReportExceptions);

if event.event().stop_immediate {
break;
}
}

event.propagation_stopped()
}
None => false
};

if stopped {
break;
}
}

/* at target */
if !event.propagation_stopped() {
{
let event = event.mut_event();
event.phase = Phase_At_Target;
event.current_target = Some(target);
}

let opt_listeners = target.eventtarget().get_listeners(type_.clone());
for listeners in opt_listeners.iter() {
for listener in listeners.iter() {
listener.HandleEvent__(event, eReportExceptions);
if event.event().stop_immediate {
break;
}
}
}
}

/* bubbling */
if event.bubbles() && !event.propagation_stopped() {
event.mut_event().phase = Phase_Bubbling;

for &target in chain.iter() {
//XXX bad clone
let stopped = match target.eventtarget().get_listeners_for(type_.clone(), Bubbling) {
Some(listeners) => {
event.mut_event().current_target = Some(target);
for listener in listeners.iter() {
listener.HandleEvent__(event, eReportExceptions);

if event.event().stop_immediate {
break;
}
}

event.propagation_stopped()
}
None => false
};
if stopped {
break;
}
}
}

let prevented = {
let event = event.mut_event();

This comment has been minimized.

@Ms2ger

Ms2ger Oct 24, 2013

Contributor

Do we still need this block?

event.dispatching = false;
event.phase = Phase_None;
event.current_target = None;
event.DefaultPrevented()
};

return !prevented;
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.