I got a lot of great help yesterday on my calendar questions. Makes me want to post another contribution :-)
 
This one is called EventPublisher. This was packaged also in Marco Jaeger's recent post with his excellent Dialogs (a la Windows), but now I'll post it by itself in case someone missed it, and also give a little explanation for ya'll.
 
This class allows you to very easily fire and subscribe to events from any object. It allows you to attach event handlers both synchronously and asynchronously, attach any number of event handlers to a specific event, and pass any arguments to those handlers that you want. The file is attached (sans the ".js" extension to get past my company's firewall, just re-add that once you have the file, replacing the ".txt").
 
USAGE:
 
Let's say you have an object called BouncingBall, and you'd like to fire notification events every time the ball bounces. To enable this, just extend BouncingBall to inherit from EventPublisher, and then use the fireEvent method...
 
Object.extend(Object.extend(BouncingBall.prototype, EventPublisher.prototype),
{
    initialize: function(color)
    {
        this.color = color;
        ...other setup stuff and some code the makes the ball start bouncing...
    },
 
    _bounce: function(howHigh)
    {
        //...fire the onBounce event with no arguments...
        this.fireEvent( "onBounce" );
 
        //...or fire it with some arguments...
        this.fireEvent( "onBounce", {ball: this, howHigh: howHigh} );
 
        ...make the ball bounce here...
    }
});
 
 
Then let's say you have a class called Floor that tracks all your BouncingBalls, and needs to know when they bounce so it can push back on them (you know, for every action there is an equal and opposite reaction)...
 
Floor.prototype =
{
    initialize: function(balls)
    {
        this.balls = [];
 
        //if an initial balls collection was passed in, loop through it, adding each ball separately in order to setup the event handlers...
        if (balls)
            $A(balls).each(function(b) { this.addBall(b); }.bind(this));
    },
   
    addBall: function(ball)
    {
        this.balls.push(ball);
 
        // set up the event handler for this ball (synchronously, so no 3rd parameter)...
        ball.attachEventHandler( "onBounce", this.ballBounce.bind(this) );
 
        // ...or set it up so it executes asynchronously (pass in "true" as the 3rd parameter)
        // obviously a real floor can handle many balls bouncing at the same time, so this is probably the way to go
        ball.attachEventHandler( "onBounce", this.ballBounce.bind(this), true );
    },
 
    ballBounce: function(args)
    {
        // assuming arguments are passed (the 2nd fireEvent is used from the 1st example)...
       
        // special physics... red balls bounce twice as high :-)
        if (args.ball.color == "red")
            this.doTheBounceStuff(args.ball, args.howHigh * 2);
        else
            this.doTheBounceStuff(args.ball, args.howHigh);
    },
 
    doTheBounceStuff: function(ball, howHigh)
    {
        ...push back on the ball to make a bunch of dead physicists proud...
    }
};
 
 
Please let me know if you have any questions about this class... Most of the other methods should be pretty self-explanatory though. You should be able to drop it in and be on your way to a consistent, robust event model for all your objects :-) Enjoy!
 
 
 

Sincerely,

Ryan Gahl

Design Engineer

Camtronics Medical Systems (an Emageon Company)

[EMAIL PROTECTED]

262-369-3251

 

The information transmitted in this electronic mail is intended only for the person or entity to which it is addressed and may contain confidential, proprietary, and/or privileged material.  Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from all computers.

///// EventPublisher Class 
/////////////////////////////////////////////////////////
//
// The EventPublisher class allows objects to fire events (and other objects to
// subscribe handlers to those events). The events can be fired either 
// synchronously or asynchonously (depending on how the handlers register 
themselves),
// and may pass optional arguments to the handlers.

EventPublisher = Class.create();
EventPublisher.prototype = {
        initialize: function() {
        },
        
        // pass the asynch flag (true/false) as the 3rd argument, or omit it to 
default to false
        attachEventHandler: function(eventName, handler) {
                // using an event cache array to track all handlers for proper 
cleanup
                if (this.allEvents == null)
                        this.allEvents = new Array();
                // loop through the event cache to prevent adding duplicates
                var len = this.allEvents.length;
                var foundEvent = false;
                for (var i = 0; i < len; i++) {
                        if (this.allEvents[i] == eventName) {
                                foundEvent = true;
                                break;
                        }
                }
                if (!foundEvent)
                        this.allEvents.push(eventName);
                        
                eventName = eventName + "_evt"; // appending _evt to event name 
to avoid collisions
                if (this[eventName] == null)
                        this[eventName] = new Array();
                        
                //create a custom object containing the handler method and the 
asynch flag
                var asynchVar = arguments.length > 2 ? arguments[1] : false;
                var handlerObj = {
                        method: handler,
                        asynch: asynchVar
                };
                
                this[eventName].push(handlerObj);
        },
        
        // Removes a single handler from a specific event
        removeEventHandler: function(eventName, handler) {
                eventName = eventName + "_evt"; // appending _evt to event name 
to avoid collisions
                if (this[eventName] != null)
                        this[eventName] = this[eventName].reject(function(obj) 
{ return obj.method == handler; });
        },
        
        // Removes all handlers from a single event
        clearEventHandlers: function(eventName) {
                eventName = eventName + "_evt"; // appending _evt to event name 
to avoid collisions
                this[eventName] = null;
        },
        
        // Removes all handlers from ALL events
        clearAllEventHandlers: function() {
                if (this.allEvents) {
                        var len = this.allEvents.length;
                        for (var i = 0; i < len; i++) {
                                this.clearEventHandlers(this.allEvents[i]);
                        }
                }
        },    
        
        //to pass arguments to the handlers, include a 2nd argument (anonymous 
object that can contain whatever you want)
        fireEvent: function(eventName) {
                var evtName = eventName + "_evt"; // appending _evt to event 
name to avoid collisions
                if (this[evtName] != null) {
                        var len = this[evtName].length; //optimization
                                                        
                        for (var i = 0; i < len; i++)
                        {
                                try
                                {
                                        if (arguments.length > 1)
                                        {
                                                if (this[evtName][i].asynch)
                                                {
                                                        //using a double 
closure to maintain "this" scope and pass all arguments properly (not sure if 
this is overkill or not)
                                                        var eventArgs = 
arguments[1];
                                                        var eventHandler = 
function(evt, index, args) { this[evt][index].method(args); }.bind(this);
                                                        var eventHandlerPointer 
= function() { eventHandler(evtName, i, eventArgs); }.bind(this);
                                                        
setTimeout(eventHandlerPointer, 1);
                                                }
                                                else
                                                        
this[evtName][i].method(arguments[1]);                        
                                        } else {
                                                if (this[evtName][i].asynch)
                                                {
                                                        var eventHandler = 
this[evtName][i].method;
                                                        
setTimeout(eventHandler, 1);
                                                }
                                                else
                                                        if (this && 
this[evtName] && this[evtName][i] && this[evtName][i].method)
                                                                
this[evtName][i].method();
                                                        
//this[evtName][i].method();
                                        }
                                }
                                catch (e) {
                                        if (this.id) {
                                                alert("ERROR: error in " + 
this.id + ".fireEvent():\n\n"  + e.message);
                                        } else {
                                                alert("ERROR: error in [unknown 
object].fireEvent():\n\n" + e.message);
                                        }
                                }
                        }
                }
        }
};
_______________________________________________
Rails-spinoffs mailing list
Rails-spinoffs@lists.rubyonrails.org
http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs

Reply via email to