value = (value === undefined ? def : value);
meta.obj[meta.key] = value;
- this._fireMutation('set', key, old, value, meta.obj);
+ this._emitMutation('set', key, old, value, meta.obj);
}
return this;
},
if ( meta.obj ) {
delete meta.obj[meta.key];
- this._fireMutation('remove', key, old, undefined, meta.obj);
+ this._emitMutation('remove', key, old, undefined, meta.obj);
}
}
return this;
/**
* @private
*/
- _fireMutation : function _fireMutation(evt, key, oldval, newval, obj){
+ _emitMutation : function _emitMutation(evt, key, oldval, newval, obj){
if (newval !== oldval){
var data = {
'key' : key,
'obj' : obj,
'root' : this
};
- this.fire(evt+':'+key, this, data);
- this.fire(evt, this, data);
+ this.emit(evt+':'+key, this, data);
+ this.emit(evt, this, data);
}
return this;
},
key = 'set:'+key;
return key;
}, this);
- this.addEventListener(events, function(evt){
+ this.on(events, function(evt){
obj[evt.data.key.split('.').pop()] = evt.data.newval;
});
return this;
-var Y = require('Y').Y;
-Y['event'] = exports;
+var Y = require('Y').Y
+,
/**
* A simple event.
* TODO: Detect jQuery event objects.
* TODO: If DOM event, wrap with consistent API (use jQuery if present).
*/
-var Event =
+Event =
exports['Event'] =
Y.YObject.subclass('Event', {
+ _stopped : false, // whether propagation is stopped
+
+ type : 'event', // event type
+ target : null, // target of the emitter
+ trigger : null, // object which caused this event
+ data : null, // event data
+
+
+
init : function init( type, target, trigger, data ){
data = data || {};
for (var k in data) this[k] = data[k];
this.trigger = trigger || target;
},
+ /**
+ * @see http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/events.html#Events-Event-stopPropagation
+ */
+ stopPropagation : function stopPropagation(){
+ this._stopped = true;
+ return this;
+ },
+
+ /**
+ * @see http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/events.html#Events-Event-isPropagationStopped
+ */
+ isPropagationStopped : function isPropagationStopped(){
+ return this._stopped;
+ },
+
toString: function(){ return "Event("+this.type+")"; }
})
* A simple multicaster.
*/
, methods = {
- getQueue : function getQueue(evt){
- var Qs = this.queues;
- if ( !Qs[evt] )
- Qs[evt] = Y([]);
- return Qs[evt];
+
+ listeners : function listeners(evt){
+ return this.queues[evt] ? this.queues[evt].clone() : new Y.YArray();
},
- addEventListener : function addEventListener(evts, fn){
+ willTrigger : function willTrigger(evt){
+ var queue = this.queues[evt];
+ return !!( (queue && queue.length) || (this.parent && this.parent.willTrigger(evt)) );
+ },
+
+ hasListener : function hasListener(evt){
+ var queue = this.queues[evt];
+ return !!(queue && queue.length);
+ },
+
+ addListener : function addListener(evts, fn){
fn = fn.toFunction();
if ( !Y.isArray(evts) )
evts = evts.split(/\s+/);
- evts.forEach(function addEvent(evt){
- this.getQueue(evt).push(fn);
- }, this);
+
+ var queues = this.queues
+ , i=0, L=evts.length, evt=evts[i];
+ for (; i<L; evt=evts[++i])
+ (queues[evt] || (queues[evt] = new Y.YArray()))
+ .push(fn);
+
return this.target;
},
- removeEventListener : function removeEventListener(evt, fn){
- this.getQueue(evt).remove(fn.toFunction());
+ removeListener : function removeListener(evts, fn){
+ fn = fn.toFunction();
+ if ( !Y.isArray(evts) )
+ evts = evts.split(/\s+/);
+
+ var queues = this.queues
+ , i=0, L=evts.length, evt=evts[i];
+ for (; i<L; evt=evts[++i])
+ if ( queues[evt] ) queues[evt].remove(fn);
+
+ return this.target;
},
- fire : function fire(evtname, trigger, data, async){
- var evt = new Event(evtname, this.target, trigger, data);
- if (async)
- setTimeout(this.dispatchEvent.bind(this, evt), 10);
- else
- this.dispatchEvent(evt);
+ removeAllListeners : function removeAllListeners(evts){
+ if ( !Y.isArray(evts) )
+ evts = evts.split(/\s+/);
+
+ for ( var i=0, L=evts.length, evt=evts[i]; i<L; evt=evts[++i] )
+ delete this.queues[evt];
+
+ return this;
+ },
+
+ once : function once(evts, fn){
+ fn = fn.toFunction();
+ var self = this;
+ return self.addListener(evts,
+ function onceHandler(){
+ self.removeListener(evts, arguments.callee);
+ fn.apply(this, arguments);
+ });
+ },
+
+ emit : function emit(evtname, trigger, data){
+ var q = this.queues[evtname]
+ , L = q ? q.length : 0
+ ;
+ if ( !L )
+ return this;
+
+ q = q._o.slice(0);
+ var A = arguments
+ , target = this.target
+ , evt = new Event(evtname, target, trigger, data)
+ , method = (A.length > 3 ? 'apply' : 'call')
+ , args = (A.length > 3 ? [evt].concat(Y(A,3)) : evt)
+ ;
+ for (var i=0, fn=q[i]; i<L; fn=q[++i])
+ fn[method](target, args);
+
+ if (this.parent && !evt._stopped)
+ this.parent.emit.apply(this.parent, A);
+
+ return evt;
+ },
+
+ emitAsync : function emitAsync(evtname, trigger, data){
+ setTimeout(this.emit.bind.apply(this.emit, [this].concat(Y(arguments))), 10);
return evt;
},
* XXX: does not handle degenerate or recursive event dispatch
*/
dispatchEvent : function dispatchEvent(evt){
- this.getQueue(evt.type).invoke('call', evt.target, evt);
- if (this.parent) this.parent.fire(evt.type, evt.trigger, evt.data);
+ var queue = this.queues[evt.type];
+ if (queue && queue.length)
+ queue.invoke('call', evt.target, evt);
+ if (this.parent)
+ this.parent.emit(evt.type, evt.trigger, evt.data);
return evt;
},
* Decorates object with bound methods to act as a delegate of this hub.
*/
decorate : function decorate(delegate){
- if (!delegate) return;
+ if (!delegate)
+ return delegate;
for (var k in methods)
delegate[k] = methods[k].bind(this);
return delegate;
}
-},
+}
+,
Emitter =
exports['Emitter'] =
}
}, methods) )
;
+methods.on = methods.addListener;
Emitter.methods = methods;
// Global Event Hub
Emitter.global = new Emitter()
Emitter.global.decorate(exports);
+
+Y['event'] = exports;
if (val !== this.val) {
this.old = this.val;
this.val = val;
- this.fire('change', this, {
+ this.emit('change', this, {
'key' : this.id,
'oldval' : this.old,
'newval' : this.val,
var field = new Field(chain, def, value);
fields[chain] = field;
group.append(field.el);
- config.addEventListener('set:'+chain, function onConfigSet(evt){
+ config.on('set:'+chain, function onConfigSet(evt){
// console.log('Config at '+evt.data.key+' changed!', field, evt.newval, evt);
field.update(evt.data.newval);
});
- field.addEventListener('change', function onFieldChange(evt){
+ field.on('change', function onFieldChange(evt){
// console.log('Field '+evt.data.key+' changed!', field, evt.newval, evt);
config.set(evt.data.key, evt.data.newval);
});
// Perform actions that should only happen once in Constructor
instance.__emitter__ = new Emitter(instance, cls);
- cls.fire('create', instance, {
+ cls.emit('create', instance, {
'instance' : instance,
'cls' : cls,
'args' : Y(args)
if ( isFunction(initialise) )
initialise.apply(instance, args);
- cls.fire('created', instance, {
+ cls.emit('created', instance, {
'instance' : instance,
'cls' : cls,
'args' : Y(args)
if (result) instance = result; // XXX: I think this needs to go away
}
- instance.fire('init', instance, {
+ instance.emit('init', instance, {
'instance' : instance,
'cls' : cls,
'args' : Y(arguments)
// Notify mixins to let them finish up any customization
if (mixins.length)
mixins.forEach(function(mxn){
- if ( mxn && isFunction(mxn.fire) )
- mxn.fire('mixin', NewClass, { 'mixin':mxn, 'cls':NewClass });
+ if ( mxn && isFunction(mxn.emit) )
+ mxn.emit('mixin', NewClass, { 'mixin':mxn, 'cls':NewClass });
});
// Notify parent of the subclass
- ParentEmitter.fire('subclass',
+ ParentEmitter.emit('subclass',
NewClass, {
'className' : className,
'parent' : Parent,
bases.unshift(mxn);
// Register onCreate to fire whenever a new instance is initialized
- if ( isFunction(cls.addEventListener) && hasOwn.call(mproto,'onCreate') && isFunction(onCreate) )
- cls.addEventListener('create', onCreate);
+ if ( isFunction(cls.on) && hasOwn.call(mproto,'onCreate') && isFunction(onCreate) )
+ cls.on('create', onCreate);
// Fire the mixin event on this Mixin only if we're done constructing the class
- if ( isFunction(mxn.fire) && mixin.caller !== Class )
- mxn.fire('mixin', cls, { 'mixin':mxn, 'cls':cls });
+ if ( isFunction(mxn.emit) && mixin.caller !== Class )
+ mxn.emit('mixin', cls, { 'mixin':mxn, 'cls':cls });
});
return cls;
}
-Mixin.addEventListener('subclass',
+Mixin.on('subclass',
function onMixinSubclass(evt){
var d = evt.data
, mxn = d.child
;
if ( isFunction(onMixin) )
- mxn.addEventListener('mixin', onMixin);
+ mxn.on('mixin', onMixin);
// console.log('Mixin.subclass()', mxn, '<', d.parent, 'onMixin:', onMixin);
});
this.running = true;
this.now = new Date().getTime() - (this.elapsedAtStop || this.targetTime);
- this.fire('start');
+ this.emit('start');
if (this.elapsedAtStop > 0)
this.sleepMinus(this.elapsedAtStop);
this.elapsedAtStop = Math.min(this.targetTime, new Date().getTime() - this.now);
this.timer = null;
this.running = false;
- this.fire('stop');
+ this.emit('stop');
},
sleepMinus : function sleepMinus(tFrame){
clearTimeout(this.timer);
this.timer = null;
- this.fire('tick', this, {
+ this.emit('tick', this, {
'now' : this.clock,
'elapsed' : this.perceived,
'ticks' : ++this.ticks
;
Species.__species_props__ = props;
- cls.fire('speciate', Species, { 'id':id, 'species':Species, 'cls':cls });
+ cls.emit('speciate', Species, { 'id':id, 'species':Species, 'cls':cls });
return Species;
},
},
load : function load(){
- this.fire('load');
+ this.emit('load');
jQuery.getJSON(this.path, this.process);
return this;
},
process : function process(data){
this.data = data;
- this.fire('process', data);
+ this.emit('process', data);
// console.group('DataFile: processing '+this.path);
var types = Y(data.types)
}, this);
// console.groupEnd();
- this.fire('complete');
+ this.emit('complete');
return this;
},
* @private
*/
die : function die(reason){
- this.fire('error', this, { 'reason':reason });
+ this.emit('error', this, { 'reason':reason });
throw new Error(this+' Error: '+reason);
},
start : function start(){
if (!this.running) {
this.running = true;
- this.fire('start');
+ this.emit('start');
this.nextJob();
}
return this;
*/
stop : function stop(){
if (this.running) {
- this.fire('stop');
+ this.emit('stop');
this.running = false;
}
return this;
&& self.queue.length === 0
&& self.inFlight.length === 0 ) {
self.running = false;
- self.fire('complete');
+ self.emit('complete');
return;
}
var job = self.queue.shift();
// console.log(self+'.nextJob() --> '+job);
- job.addEventListener('complete', function onJobComplete(evt){
+ job.on('complete', function onJobComplete(evt){
// console.log(self+'.onJobComplete('+job+')');
- job.removeEventListener('complete', arguments.callee);
+ job.removeListener('complete', arguments.callee);
self.inFlight.remove(job);
self.nextJob();
});
;
// Updates the midpoint square when square-size changes
-config.addEventListener('set:pathing.pathSquare', function(evt){
+config.on('set:pathing.pathSquare', function(evt){
var sq = evt.data.newval;
config.set('pathing.pathSquareMid', new Vec(sq/2, sq/2));
});
this.applyStatMods();
var data = { 'buff':this, 'unit':this.target, 'owner':this.owner };
- this.fire('buff.conjure', this.target, data);
- this.target.fire('buff.conjure', this, data);
+ this.emit('buff.conjure', this.target, data);
+ this.target.emit('buff.conjure', this, data);
},
tick : function tick(elapsed, now){
// var evt = 'buff.die.'+reason // We'll add this when we add polymorphic dispatchers
var evt = 'buff.die'
, data = { 'buff':this, 'unit':this.target, 'owner':this.owner };
- this.fire(evt, this.target, data);
- this.target.fire(evt, this, data);
+ this.emit(evt, this.target, data);
+ this.target.emit(evt, this, data);
return this;
},
});
-Buff.addEventListener('speciate',
+Buff.on('speciate',
function onSpeciate(evt){
var NewBuff = evt.data.species;
if (NewBuff.fn.timeout === -1)
this.viewport.append(this.map.ui);
// automatically keep track of units
- Thing.addEventListener('created', this.addUnit);
- Thing.addEventListener('destroy', this.killUnit);
- this.addEventListener('tick', this.tick);
+ Thing.on('created', this.addUnit);
+ Thing.on('destroy', this.killUnit);
+ this.on('tick', this.tick);
this.level.setup();
if (this.player) {
this.isReplay = true;
this.loadLog(replayFile);
} else
- this.fire('ready', this);
+ this.emit('ready', this);
},
destroy : function destroy(){
this.stop();
this.player.destroy();
- Thing.removeEventListener('created', this.addUnit);
- Thing.removeEventListener('destroy', this.killUnit);
+ Thing.removeListener('created', this.addUnit);
+ Thing.removeListener('destroy', this.killUnit);
this.root.remove();
this.resetGlobals();
},
if ( this.gameover )
setTimeout(function(){
- self.fire(self.gameover, self.player);
+ self.emit(self.gameover, self.player);
&nb