|
eventable.cls
|
|
/* --------------------------------------------------------------------------------------- */
/* No freakin' copyright, no stinkin' license, no guarantees or warranties */
/* (implied, explicit or whatever). Usage is totally and completely at your own risk. */
/* Please keep this comment block as is when modifying this code. Thanks in advance, */
/* Ruurd Idenburg */
/* --------------------------------------------------------------------------------------- */
/**
The <i>eventable</i> class is a <i>mixin</i> class, that can be used in the
inheriting class to define events (by name) and trigger those events so that
other classes may act upon those events.
<p>
Events are defined as indexes in an events directory. The events directory
is created in the events instance <b><i>init</i></b> method and is therefore
available after the inheriting class instance creation has called it's super
class <b><i>init</i></b> method, so the logical thing to do is to define the
class instance events in the inheriting class <b><i>init</i></b> method for
new instances. However events can also be defined later on by the inheriting
class instance methods.
<p>
Event handlers/listeners need to define an instance method with the name of
the defined event. That method will be invoked by the triggering of the event.
The handler/listener method should return the boolean <b>.true</b> or <b>.false</b>
depending on whether possible other handlers/listeners should be given the
opportunity to act on the event. Returning <b>.false</b> will allow other
handlers/listeners to be invoked as well, returning <b>.true</b> will stop
invoking other handlers/listeners.
<p>
Handlers/Listeners are kept as members of an array that is the item in the
directory entry for the index that has the name of the event.
*/
::class eventable public mixinclass object
/**
The events attribute is a directory, whose entries can only be set privately
by the inheriting class instance methods. The directory is created in the
<b><i>init</i></b> instance method of this (the <i>events</i>) class.
*/
::attribute events get
::attribute events set private
/**
The <b><i>init</i></b> method creates the directory that will have the event
names as indexes and the array of handlers/listeners as items.
<br>
@param eventArray=(.array~new) - optional, an array of event names provided by the inheriting class
<p>
If an array with event names is provided, the entries are created in the events directory
with empty arrays as items to hold future handlers/listeners.
*/
::method init
expose events
use strict arg eventArray=(.array~new)
events = .directory~new
if eventArray~class~id==.array then do
do a over eventArray
events[a] = .array~new
end
end
/**
<b><i>addEventHander</i></b> is a synonym for <b><i>addEventListener</i></b>
<br>
@see #addEventListener
*/
::method addEventHandler
use strict arg event, handler
self~addEventListener(event, handler)
/**
Adds an object to the group of interested parties
<br>
@param event - the name of an event
@param listener - the object interested in that event
<p>
If the array of handlers/listeners does not exist yet for the event it will
be created. The handler/listener object is appended to the existing or new array
<p>
It is not verified if the event is a valid event for the object, the result for
that condition will be that the handler/listener will never be invoked.
<p>
The same handler/listener can be added multiple times, if for some reason that
would be necessary for proper functioning and provided some earlier handler/listener
did not return <b>.true</b>.
*/
::method addEventListener
expose events
--trace i
use strict arg event, listener
if events[event]==.nil then do
events[event] = .array~new
end
events[event]~append(listener)
/**
<b><i>removeEventHandler</i></b> is a synonym for <b><i>removeEventListener</i></b>
<br>
@see #removeEventListener
*/
::method removeEventHandler
use strict arg event, handler
self~removeEventListener(event, handler)
/**
Removes a party from the group interested in an event
<br>
@param event - the name of an event
@param listener - the handler/listener object to be removed
<p>
If the event is not known, the object can not be removed obviously
<br>
If the listener is not a member of the interested handlers/listeners,
nothing can be removed.
<br>
The handlers/listeners will be regenerated to prevent sparseness.
*/
::method removeEventListener
expose events
--trace i
use strict arg event, listener
if events[event]~class~id==.array then do
events[event]~removeItem(listener)
events[event] = events[event]~makeArray
end
/**
Returns the list of defined events for the object
<br>
@return anArray - an array of event names for the object
<p>
The array can be empty if no events have been defined
*/
::method eventNames
use strict arg
return self~events~makeArray
/**
<b><i>eventHandlers</i></b> is a synonym for <b><i>eventListeners</i></b>
<br>
@see #eventListeners
*/
::method eventHandlers
use strict arg event
return self~eventListeners(event)
/**
Returns an array of handlers/listeners for an event.
<br>
@param event - the name of an event
@return anArray - an array of handlers/listeners for an event
<p>
The returned array can be empty if there are no listeners for the event
or if the event is unknown.
*/
::method eventListeners
expose events
use strict arg event
if events[event]~isA(.array) then return events[event]
return .array~new
/**
Invokes the event handling method in the handlers/listeners for an
event while successive handlers/listeners return <b>.false</b>, and stops
to invoke following handlers/listeners on the first <b>.true</b> return.
<br>
@expose events - the directory of triggerable events for the class
@param event - the name of the event to be handled
@param args=(.array~new) - optional arguments for the handler method
<p>
*/
::method triggerEvent
expose events
--trace i
use strict arg event, args=(.array~new)
if events[event]==.nil then do
--.error~lineout('Event:' event 'is not defined')
return
end
if events[event]~items==0 then do
--.error~lineout('Event:' event 'does not have listeners')
return
end
result = .false
do l over events[event] while result==.false
if l~hasMethod(event) then do
msg = .message~new(l,event,'I',args~makeString('L',','))
--.traceoutput~say(msg~messageName msg~target msg~arguments~makeString('L',','))
msg~send --start
result = msg~result
end
else do
--.error~lineout('Event:' event 'is not a defined method in handler/listener:' l)
end
end
If you feel inclined to make corrections, suggestions etc.,
please mail me any.
| |
All content © Ruurd Idenburg, 2007–2023,
except where marked otherwise. All rights reserved. This page is primarily for non-commercial use only.
The Idenburg website records no personal information and sets no ‘cookies’.
This site is hosted on a VPS(Virtual Private System) rented from Transip.nl, a Dutch company, falling under Dutch (privacy) laws (I think).
This page updated on Fri, 07 May 2021 12:15:43 +0200 by Ruurd Idenburg.
|
|