Skip to content

Instantly share code, notes, and snippets.

@dandean
Created June 8, 2010 20:50
Show Gist options
  • Select an option

  • Save dandean/430635 to your computer and use it in GitHub Desktop.

Select an option

Save dandean/430635 to your computer and use it in GitHub Desktop.
var Evented = (function() {
var id = -1;
function uid() {
id++;
return "evented" + id;
}
function getID(obj) {
if (!("__eventedID" in obj)) {
obj.__eventedID = uid();
}
return obj.__eventedID;
}
/**
* Evented#on(obj, name, handler) -> Event.Handler
* - obj(Evented): An object which has [Evented] api methods.
* - name(String): The event name to watch.
* - handler(Function): The event handler
**/
function on(obj, name, handler) {
return document.on(getID(obj) + ":" + name, handler);
}
function observe(obj, name, handler) {
document.observe(getID(obj) + ":" + name, handler);
return this;
}
function stopObserving(obj, name, handler) {
if (!obj) { throw new Error("Argument `obj` is required."); };
if (!name) { throw new Error("Argument `name` is required."); };
document.stopObserving(getID(obj) + ":" + name, handler);
return this;
}
/**
* Evented#fire(name, handler) -> Evented
* - name(String): The event name to fire.
* - memo(Object): Event data to pass to the handler. It will have a `source` property
* set to the [Evented] object which fired the event.
**/
function fire(name, memo) {
memo = memo || {};
memo.source = this;
document.fire(getID(this) + ":" + name, memo);
return this;
}
var api = {
observe: observe,
stopObserving: stopObserving,
fire: fire
};
if ("Handler" in Event) {
api.on = on;
}
return api;
})();
@jdalton
Copy link

jdalton commented Jun 8, 2010

Keep in mind that because you are piggybacking the DOM events you are piling all custom events through the dataavailable (and filterchange for IE < 9). This means if you have 50 custom events but only 2 of them are the one:uwant it will still execute all 50 responders checking each one to see if they are the one:uwant. Also because its piggybacking on DOM events you will get random execution order in IE but FIFO in other browsers.

@dandean
Copy link
Author

dandean commented Jun 8, 2010

jdalton, you are awesome.

@dandean
Copy link
Author

dandean commented Jun 8, 2010

Is there an implementation of non-dom-driven custom events out there that you like?

@jdalton
Copy link

jdalton commented Jun 8, 2010

MooTools has a really simple one I like. You can use it as a mixin.

  var Events = new Class({

    $events: {},

    addEvent: function(type, fn, internal){
        type = Events.removeOn(type);
        if (fn != $empty){
            this.$events[type] = this.$events[type] || [];
            this.$events[type].include(fn);
            if (internal) fn.internal = true;
        }
        return this;
    },

    addEvents: function(events){
        for (var type in events) this.addEvent(type, events[type]);
        return this;
    },

    fireEvent: function(type, args, delay){
        type = Events.removeOn(type);
        if (!this.$events || !this.$events[type]) return this;
        this.$events[type].each(function(fn){
            fn.create({'bind': this, 'delay': delay, 'arguments': args})();
        }, this);
        return this;
    },

    removeEvent: function(type, fn){
        type = Events.removeOn(type);
        if (!this.$events[type]) return this;
        if (!fn.internal) this.$events[type].erase(fn);
        return this;
    },

    removeEvents: function(events){
        var type;
        if ($type(events) == 'object'){
            for (type in events) this.removeEvent(type, events[type]);
            return this;
        }
        if (events) events = Events.removeOn(events);
        for (type in this.$events){
            if (events && events != type) continue;
            var fns = this.$events[type];
            for (var i = fns.length; i--; i) this.removeEvent(type, fns[i]);
        }
        return this;
    }

  });

  Events.removeOn = function(string){
    return string.replace(/^on([A-Z])/, function(full, first){
        return first.toLowerCase();
    });
  };

You can simplify it a bit more, remove some of the fluff, and Prototypify the method names, but I dig it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment