Good stuff, a couple months back I posted my very lightweight EventPublisher class, along with a quick example.

http://threebit.net/mail-archive/rails-spinoffs/msg00548.html


...and here is the code...

///// 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)
                        {
                            var eventArgs = arguments[1];
                            var method = this[evtName][i].method.bind(this);
                            setTimeout(function() { method(eventArgs) }.bind(this), 10);
                        }
                        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();
                    }
                }
                catch (e) {
                    if (this.id) {
                        alert("error: error in " + this.id + ".fireevent():\n\nevent name: " + eventName + "\n\nerror message: " + e.message);
                    } else {
                        alert("error: error in [unknown object].fireevent():\n\nevent name: " + eventName + "\n\nerror message: " + e.message);
                    }
                }
            }
        }
    }
};


On 7/21/06, TJ Stankus < [EMAIL PROTECTED]> wrote:
Good stuff. I'm really looking forward to digging through this.

-TJ

On 7/21/06, Seth Dillingham <[EMAIL PROTECTED]> wrote:
> Hey all,
>
> A couple months ago I was working on a pretty complex app that uses
> Prototype.js very heavily. In the process I came up with a way to use
> Prototype to produce custom events, reliably, in _javascript_.
>
> By "custom events" I mean stuff like "message received" and "results
> available" and "progress update", not browser events like click and
> mouseover.
>
> I showed it to Sam (you know, *THE Sam*, our Sam) at RubyConf last
> month, and he got pretty excited. We skipped one of the sessions, sat
> down in the lobby, and went over the whole thing for an hour. He liked
> it. I've even received ONE WHOLE EMAIL from him on the topic, since
> then. ;-)
>
> The JS events stuff have been extracted from the project so they can
> be used by others (people or projects).
>
> ** It's all written up in a longish article (long because of the
> sample code), here:
> < http://www.truerwords.net/articles/web-tech/custom_events.html> **
>
> There are links on the page to a useless demo app, and all of the actual code.
>
> Let me warn you that there's a lot there, BUT you don't need all of it
> if you want to play with it! I included an "even tracing" module to
> help with debugging, and an optional event broker (which is explained
> in the article). The most important parts are all in one file, and are
> only about 4 kb.
>
> The basic idea is that you have event publishers and event subscribers
> (listeners). Any class or object in your app can be either or both.
> Listeners subscribe to publishers for the events they want to receive,
> publishers remain ignorant of who is listening.
>
> If you mix in an Event Broker class as well, then the listeners don't
> even need to know about the event publishers... they just tell the
> broker that they care about all events of a particular type, and
> they'll receive them regardless of which publisher produced it. (This
> is handy in cases where you have a large collection of publishers, or
> when you may not know what objects have been included on the page.)
>
> OK, this is more than long winded enough. It's all explained in the article.
>
> Seth
>
> P.S. This custom events code is a pretty thorough solution... so yes,
> I realize it's not for everyone, but I thought it might be useful for
> some people on the list. At least it's "on-topic"!
> _______________________________________________
> Rails-spinoffs mailing list
> Rails-spinoffs@lists.rubyonrails.org
> http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs
>
_______________________________________________
Rails-spinoffs mailing list
Rails-spinoffs@lists.rubyonrails.org
http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs

_______________________________________________
Rails-spinoffs mailing list
Rails-spinoffs@lists.rubyonrails.org
http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs

Reply via email to