sketch
Version:
Sketch canvas drawing component
177 lines (150 loc) • 3.48 kB
JavaScript
/**
* Module dependencies.
*/
var events = require('event');
var delegate = require('delegate');
/**
* Expose `Events`.
*/
module.exports = Events;
/**
* Initialize an `Events` with the given
* `el` object which events will be bound to,
* and the `obj` which will receive method calls.
*
* @param {Object} el
* @param {Object} obj
* @api public
*/
function Events(el, obj) {
if (!(this instanceof Events)) return new Events(el, obj);
if (!el) throw new Error('element required');
if (!obj) throw new Error('object required');
this.el = el;
this.obj = obj;
this._events = {};
}
/**
* Subscription helper.
*/
Events.prototype.sub = function(event, method, cb){
this._events[event] = this._events[event] || {};
this._events[event][method] = cb;
};
/**
* Bind to `event` with optional `method` name.
* When `method` is undefined it becomes `event`
* with the "on" prefix.
*
* Examples:
*
* Direct event handling:
*
* events.bind('click') // implies "onclick"
* events.bind('click', 'remove')
* events.bind('click', 'sort', 'asc')
*
* Delegated event handling:
*
* events.bind('click li > a')
* events.bind('click li > a', 'remove')
* events.bind('click a.sort-ascending', 'sort', 'asc')
* events.bind('click a.sort-descending', 'sort', 'desc')
*
* @param {String} event
* @param {String|function} [method]
* @return {Function} callback
* @api public
*/
Events.prototype.bind = function(event, method){
var e = parse(event);
var el = this.el;
var obj = this.obj;
var name = e.name;
var method = method || 'on' + name;
var args = [].slice.call(arguments, 2);
// callback
function cb(){
var a = [].slice.call(arguments).concat(args);
obj[method].apply(obj, a);
}
// bind
if (e.selector) {
cb = delegate.bind(el, e.selector, name, cb);
} else {
events.bind(el, name, cb);
}
// subscription for unbinding
this.sub(name, method, cb);
return cb;
};
/**
* Unbind a single binding, all bindings for `event`,
* or all bindings within the manager.
*
* Examples:
*
* Unbind direct handlers:
*
* events.unbind('click', 'remove')
* events.unbind('click')
* events.unbind()
*
* Unbind delegate handlers:
*
* events.unbind('click', 'remove')
* events.unbind('click')
* events.unbind()
*
* @param {String|Function} [event]
* @param {String|Function} [method]
* @api public
*/
Events.prototype.unbind = function(event, method){
if (0 == arguments.length) return this.unbindAll();
if (1 == arguments.length) return this.unbindAllOf(event);
// no bindings for this event
var bindings = this._events[event];
if (!bindings) return;
// no bindings for this method
var cb = bindings[method];
if (!cb) return;
events.unbind(this.el, event, cb);
};
/**
* Unbind all events.
*
* @api private
*/
Events.prototype.unbindAll = function(){
for (var event in this._events) {
this.unbindAllOf(event);
}
};
/**
* Unbind all events for `event`.
*
* @param {String} event
* @api private
*/
Events.prototype.unbindAllOf = function(event){
var bindings = this._events[event];
if (!bindings) return;
for (var method in bindings) {
this.unbind(event, method);
}
};
/**
* Parse `event`.
*
* @param {String} event
* @return {Object}
* @api private
*/
function parse(event) {
var parts = event.split(/ +/);
return {
name: parts.shift(),
selector: parts.join(' ')
}
}