Events are implemented in 3 classes:
- EventType: A stateless class that manages subscribing and (optionally) generating/firing events of its kind.
- EventSource: A base class that provides convenient methods to subscribe to and fire events.
- Event: A base class from which events can derive.
As I mentioned earlier, I wanted to events to be 1st class citizens, but at a glance it would seem that EventSource is contrary to that end as it requires event-generating classes to ultimately derive from EventSource. To clear this up, lets look at the contents of EventSource:
EventSource : $class(
{
fireEvent : function (name, params)
{
return zjs.fireEvent(this, name, params);
},
on : function (name, fn, scope, opt)
{
return zjs.subscribeEvent.apply(this, arguments);
}
})
As can be seen, the real work of subscribing and firing events is handled by methods in the ZJS namespace. Thus, classes that derive from a base which does not trace back to EventSource can likewise provide these convenience methods with ease.
I have previously discussed EventType, but not in sufficient detail to see how one might implement a custom event type.
EventType : $class(
{
subscribe : function (obj, fn) // Required
{
},
// Optional (required to programmatically create and fire events):
create : function (params)
{
},
deliver : function (obj, ev)
{
}
})
The subscribe method is given the source object and the function to be called when the source object fires this type of event. Event types are assumed to know their name (e.g., "click"). The return value of the subscribe method is an object whose destroy method will unsubscribe the function.
The create and deliver methods are used to programmatically fire events. This can be done with DOM events, but is seldom an important use case. Even so, these methods can be implemented to create and fire DOM events. Outside the DOM, however, events must be created and fired in code since the browser will not know of them or when they should trigger.
As with browser-generated events, events in ZJS are objects. This is different than ExtJS where events are simply function calls that happen to have some arguments. For example, firing an event would be something like this in ExtJS:
this.fireEvent("foo", this, x, 42);
In ZJS, events are always a single object (as it is with DOM events). The reason for this (beyond simple consistency which would likely have been enough reason) is because there are behaviors for events themselves that are not related to their data members. The most important of these is the ability to control the propagation of an event. Further, by passing a single object, the event source is free to refactor and extend the data it supplies. The need for a container object with DOM events is plain because these events often have over a dozen properties!
The zjs.Event class is a basic implementation of a custom event. Obviously, a DOM event would not derive from zjs.Event, so it really serves as both an example of the interface to which events should conform as well as an implementation for the cases where it does fit. The method exposed by zjs.Event that should be supplied by all event types is consume.
In the DOM, there are two ways to effect event propagation. On the one hand, a DOM event's bubbling around for other event subscribers can be stopped. On the other, the default behavior provided by the browser for the event can be canceled (most of the time). In my experience, it is seldom that I want to cancel only one of these, so the consume method would handle both for this type of event.
Well, I think I've covered all the building blocks and concepts. Next time I'll put together an example of defining, firing and handling events.
No comments:
Post a Comment