Events (library & classes)
Overview
Summary
An object-oriented event system allowing the AS3 developer a more familiar way to use events in JSFL.Contents
Concept
Flash's standard event mechanism is a simple callback-based event model, which allows the developer to add events via string, and have a callback (event handler) called when the event fires:
var eventId = fl.addEventListener("documentClosed", onDocumentClosed);
However, there are a few problems with the standard Flash event handler implementation:
- It's impossible to keep track of (and therefore remove) listener ids between external script executions (i.e. in development)
- No information about the event is passed to the event handler function
- There's no overall management of registered event handlers
xJSFL's Event library and classes attempt to answer these shortcomings with a standard Event model and Event classes similar to AS3's, as well as the ability to add, remove and get events by event and type - and all between external calls.
Usage
Adding an event handler to fire on an event
The main difference with registering an event handle function between JSFL and xJSFL is that with xJSFL you supply the eventId you want to keep track of:
function onDocumentChanged(event) { trace(event.document.name); } xjsfl.events.add(DocumentEvent.CHANGED, onDocumentChanged, 'onDocumentChanged');
Note that the function name and the eventId name are not related, nor do they have to be the same. It is the string name that is used to add and remove the callback - the callback itself is merely stored as a reference.
What to do within the event handler
Once the handler is added, and when an appropriate event is fired within Flash, the handler is called and from within you have access to the properties at the time of the event, via the event object.
Bear in mind though that due to some inherent limitations of the Flash event model, these cannot always be relied on to return a true state of the Flash environment at the time of the event.
Updating and removing the event handler
When it comes to updating the event handler you can simply add it again with the same name, or if at any point you want to remove the event handler, you simply call the remove() method with the type and name of the previously-added handler:
xjsfl.events.remove(DocumentEvent.CHANGED, 'onDocumentChanged');
Event types
Rather than simply calling an event handler function with no information about the event that took place, the xJSFL Event model defines specific Event classes, instances of which are passed to event handler functions in a manner already familiar to AS3 developer.
Event | Type | Description | CS Version | Event Constant |
---|---|---|---|---|
Document | publish | A document is about to be published | 5.5 | DocumentEvent.PUBLISH |
Document | published | A document was published | 5.5 | DocumentEvent.PUBLISHED |
Document | saved | A document was saved | 5.5 | DocumentEvent.SAVED |
Document | new | A new document was created | 4 | DocumentEvent.NEW |
Document | opened | A document was opened | 4 | DocumentEvent.OPENED |
Document | closed | A document was closed | 4 | DocumentEvent.CLOSED |
Document | changed | A new document was opened or tabbed to | 4 | DocumentEvent.CHANGED |
Layer | changed | A new layer selection was made | 4 | LayerEvent.CHANGED |
Frame | changed | A new frame selection was made | 4 | FrameEvent.CHANGED |
Mouse | move | The mouse was moved | 4 | MouseEvent.MOVE |
These event instances have both a specific type, as well as a common name property that maps directly to the standard eventType strings as accepted by the standard fl.addEventlistener() function. Note however that the xJSFL Event constant names are slightly differently to the Flash event strings.
Additional properties are specific to each event class.
Native JSFL event model limitations
The JSAPI appears to fire a frameChanged event before it has updated the document / timeline properties, which results in frame Events reporting the previous document and timeline.
At the moment, I don't know how to solve this. I've experimented with lastParam properties, comparing the Date of the callback, firing events in order with pre and post handlers, attempting to force a document update by calling flash or document methods first, but so far every route has been a dead end. It may just be that it's not possible.
Other limitations include:
- Although "frameChanged" fires when you edit a new symbol, the document properties do not update in time, so again, you end up with the wrong document/timeline data fed into the Event.
- timeline.getSelectedframes() often returns nothing from within an event handler, so is effectively useless for interactive tools relying on the current frame selection.
- Multiple events can be fired for what seem like single events to the user - for example, selecting the same layer fires a layer event once, but selecting a new layer fires a layer event twice, with timeline.currentLayer reporting the same layer for both events.
If you can live with these fairly annoying limitations, you may be able to get some mileage out of at least the Document, Layer & Mouse events.
Event API
The event API is the central place to add and remove event handler functions.
add(type, callback, name, scope)
Add an event handler function for a particular event type
The following example traces the name of the current document when the user creates or changes the document in the Flash IDE, and also overwrites any current DocumentEvent.CHANGED handlers:
function onDocumentChanged(event) { trace(event.document.name); } xjsfl.events.add(DocumentEvent.CHANGED, onDocumentChanged, 'onDocumentChanged');
// On changing the current document Untitled-2
If you need to register a method on an object that needs to self-reference, be user to pass in the scope:
xjsfl.events.add(DocumentEvent.CHANGED, handlers.onDocumentChanged, 'onDocumentChanged', handlers);
Note that as event handler names could be overwritten by any running JSFL code, you should take the trouble to namespace them if making tools for collaborative environments.
The following example sets a namespaced event handler name from within a module (and necessarily sets the scope as well):
xjsfl.events.add(DocumentEvent.CHANGED, this.onDocumentChanged, 'myModule.onDocumentChanged', this);
remove(type, name)
Remove an event handler function for a single or all event types
The following example removes an existing named handler:
xjsfl.events.remove(DocumentEvent.CHANGED, 'onDocumentChanged');
You can also remove handlers of the same name from multiple event types by passing the name of a single event handler.
The following example removes handlers registered using the name documentHandler from all event types:
xjsfl.events.remove('documentHandler');
removeAll(type)
Remove all event handler functions for a single, or all event types
The following example removes all existing DocumentEvent.CHANGED handlers:
xjsfl.events.removeAll(DocumentEvent.CHANGED);
The following example removes all existing handlers, for all event types:
xjsfl.events.removeAll();
Note that you should never remove event handlers by type in final production code as other modules may be reliant on handlers they previously added.
get(type, name)
Get a reference to an event handler function for an event type
The following example retrieves the function assigned as 'onMouseMove' for the MouseEvent.MOVE event:
var callback = xjsfl.events.get(MouseEvent.MOVE, 'onMouseMove'); trace(callback);
function onMouseMove(event) { trace(event); }
Event classes
This section describes the Event classes that will be dispatched from the main xjsfl.event library.
DocumentEvent(type)
An object representing a the JSFL Event that fires when a user interacts with a document
The following example traces the name of a new document, when created:
function onDocumentNew(event) { trace(event.document.name); } xjsfl.events.add(DocumentEvent.NEW, onDocumentNew);
// On creating a new document Untitled-1
LayerEvent()
An object representing a the JSFL Event that fires when a user changes a layer
The following example adds an event handler to be called every time a different layer is selected (this includes changing documents and timelines), or a new layer is created:
function onLayerChanged(event) { trace(event); } xjsfl.events.add(LayerEvent.CHANGED, onLayerChanged);
// On changing layer, or creating a new layer [object LayerEvent timeline="Scene 1" layer="Layer 2"]
FrameEvent()
An object representing a the JSFL Event that fires when a user changes a frame
The following example adds an event handler to be called every time a different frame is selected (this includes changing documents, timelines and layers), or a new frame is created:
function onFrameChanged(event) { trace(event); } xjsfl.events.add(FrameEvent.CHANGED, onFrameChanged);
// On changing frame, or creating a new frame [object FrameEvent timeline="Scene 1" layer="Layer 2" frame="11"]
MouseEvent()
An object representing a the JSFL Event that fires when a user move the mouse
The following example adds an event handler to be called every time the mouse is moved:
function onMouseMove(event) { trace(event); } xjsfl.events.add(MouseEvent.MOVE, onMouseMove);
// On moving the mouse [object MouseEvent x="424.95" y="7" shift="false" ctrl="false" alt="false"]
Comments are closed.