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;
})();
@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