/**
* @namespace
*/
/**
* LEvent is a lightweight events library focused in low memory footprint and fast delivery.
* It works by creating a property called "__levents" inside the object that has the bindings, and storing arrays with all the bindings.
* @class LEvent
* @constructor
*/
var LEvent = global.LEvent = GL.LEvent = {
/**
* Binds an event to an instance
* @method LEvent.bind
* @param {Object} instance where to attach the event
* @param {String} event_name string defining the event name
* @param {function} callback function to call when the event is triggered
* @param {Object} target_instance [Optional] instance to call the function (use this instead of .bind method to help removing events)
**/
bind: function( instance, event_type, callback, target_instance )
{
if(!instance)
throw("cannot bind event to null");
if(!callback)
throw("cannot bind to null callback");
if(instance.constructor === String )
throw("cannot bind event to a string");
var events = instance.__levents;
if(!events)
{
Object.defineProperty( instance, "__levents", {value: {}, enumerable: false });
events = instance.__levents;
}
if( events.hasOwnProperty( event_type ) )
events[event_type].push([callback,target_instance]);
else
events[event_type] = [[callback,target_instance]];
if( instance.onLEventBinded )
instance.onLEventBinded( event_type, callback, target_instance );
},
/**
* Unbinds an event from an instance
* @method LEvent.unbind
* @param {Object} instance where the event is binded
* @param {String} event_name string defining the event name
* @param {function} callback function that was binded
* @param {Object} target_instance [Optional] target_instance that was binded
**/
unbind: function( instance, event_type, callback, target_instance )
{
if(!instance)
throw("cannot unbind event to null");
if(!callback)
throw("cannot unbind from null callback");
if(instance.constructor === String )
throw("cannot bind event to a string");
var events = instance.__levents;
if(!events)
return;
if(!events.hasOwnProperty( event_type ))
return;
for(var i = 0, l = events[event_type].length; i < l; ++i)
{
var v = events[event_type][i];
if(v[0] === callback && v[1] === target_instance)
{
events[event_type].splice( i, 1 );
break;
}
}
if (events[event_type].length == 0)
delete events[event_type];
if( instance.onLEventUnbinded )
instance.onLEventUnbinded( event_type, callback, target_instance );
},
/**
* Unbinds all events from an instance (or the ones that match certain target_instance)
* @method LEvent.unbindAll
* @param {Object} instance where the events are binded
* @param {Object} target_instance [Optional] target_instance of the events to remove
**/
unbindAll: function( instance, target_instance, callback )
{
if(!instance)
throw("cannot unbind events in null");
var events = instance.__levents;
if(!events)
return;
if( instance.onLEventUnbindAll )
instance.onLEventUnbindAll( target_instance, callback );
if(!target_instance) //remove all
{
delete instance.__levents;
return;
}
//remove only the target_instance
//for every property in the instance
for(var i in events)
{
var array = events[i];
for(var j = array.length - 1; j >= 0; --j) //iterate backwards to avoid problems after removing
{
if( array[j][1] != target_instance || (callback && callback !== array[j][0]) )
continue;
array.splice(j,1);//remove
}
}
},
/**
* Unbinds all callbacks associated to one specific event from this instance
* @method LEvent.unbindAll
* @param {Object} instance where the events are binded
* @param {String} event name of the event you want to remove all binds
**/
unbindAllEvent: function( instance, event_type )
{
if(!instance)
throw("cannot unbind events in null");
var events = instance.__levents;
if(!events)
return;
delete events[ event_type ];
if( instance.onLEventUnbindAll )
instance.onLEventUnbindAll( event_type, target_instance, callback );
return;
},
/**
* Tells if there is a binded callback that matches the criteria
* @method LEvent.isBind
* @param {Object} instance where the are the events binded
* @param {String} event_name string defining the event name
* @param {function} callback the callback
* @param {Object} target_instance [Optional] instance binded to callback
**/
isBind: function( instance, event_type, callback, target_instance )
{
if(!instance)
throw("LEvent cannot have null as instance");
var events = instance.__levents;
if( !events )
return;
if( !events.hasOwnProperty(event_type) )
return false;
for(var i = 0, l = events[event_type].length; i < l; ++i)
{
var v = events[event_type][i];
if(v[0] === callback && v[1] === target_instance)
return true;
}
return false;
},
/**
* Tells if there is any callback binded to this event
* @method LEvent.hasBind
* @param {Object} instance where the are the events binded
* @param {String} event_name string defining the event name
* @return {boolean} true is there is at least one
**/
hasBind: function( instance, event_type )
{
if(!instance)
throw("LEvent cannot have null as instance");
var events = instance.__levents;
if(!events || !events.hasOwnProperty( event_type ) || !events[event_type].length)
return false;
return true;
},
/**
* Tells if there is any callback binded to this object pointing to a method in the target object
* @method LEvent.hasBindTo
* @param {Object} instance where there are the events binded
* @param {Object} target instance to check to
* @return {boolean} true is there is at least one
**/
hasBindTo: function( instance, target )
{
if(!instance)
throw("LEvent cannot have null as instance");
var events = instance.__levents;
//no events binded
if(!events)
return false;
for(var j in events)
{
var binds = events[j];
for(var i = 0; i < binds.length; ++i)
{
if(binds[i][1] === target) //one found
return true;
}
}
return false;
},
/**
* Triggers and event in an instance
* If the callback returns true then it will stop the propagation and return true
* @method LEvent.trigger
* @param {Object} instance that triggers the event
* @param {String} event_name string defining the event name
* @param {*} parameters that will be received by the binded function
* @param {bool} reverse_order trigger in reverse order (binded last get called first)
* @param {bool} expand_parameters parameters are passed not as one single parameter, but as many
* return {bool} true if the event passed was blocked by any binded callback
**/
trigger: function( instance, event_type, params, reverse_order, expand_parameters )
{
if(!instance)
throw("cannot trigger event from null");
if(instance.constructor === String )
throw("cannot bind event to a string");
var events = instance.__levents;
if( !events || !events.hasOwnProperty(event_type) )
return false;
var inst = events[event_type];
if( reverse_order )
{
for(var i = inst.length - 1; i >= 0; --i)
{
var v = inst[i];
if(expand_parameters)
{
if( v && v[0].apply( v[1], params ) === true)// || event.stop)
return true; //stopPropagation
}
else
{
if( v && v[0].call( v[1], event_type, params) === true)// || event.stop)
return true; //stopPropagation
}
}
}
else
{
for(var i = 0, l = inst.length; i < l; ++i)
{
var v = inst[i];
if( expand_parameters )
{
if( v && v[0].apply( v[1], params ) === true)// || event.stop)
return true; //stopPropagation
}
else
{
if( v && v[0].call(v[1], event_type, params) === true)// || event.stop)
return true; //stopPropagation
}
}
}
return false;
},
/**
* Triggers and event to every element in an array.
* If the event returns true, it must be intercepted
* @method LEvent.triggerArray
* @param {Array} array contains all instances to triggers the event
* @param {String} event_name string defining the event name
* @param {*} parameters that will be received by the binded function
* @param {bool} reverse_order trigger in reverse order (binded last get called first)
* @param {bool} expand_parameters parameters are passed not as one single parameter, but as many
* return {bool} false
**/
triggerArray: function( instances, event_type, params, reverse_order, expand_parameters )
{
var blocked = false;
for(var i = 0, l = instances.length; i < l; ++i)
{
var instance = instances[i];
if(!instance)
throw("cannot trigger event from null");
if(instance.constructor === String )
throw("cannot bind event to a string");
var events = instance.__levents;
if( !events || !events.hasOwnProperty( event_type ) )
continue;
if( reverse_order )
{
for(var j = events[event_type].length - 1; j >= 0; --j)
{
var v = events[event_type][j];
if(expand_parameters)
{
if( v[0].apply(v[1], params ) === true)// || event.stop)
{
blocked = true;
break; //stopPropagation
}
}
else
{
if( v[0].call(v[1], event_type, params) === true)// || event.stop)
{
blocked = true;
break; //stopPropagation
}
}
}
}
else
{
for(var j = 0, ll = events[event_type].length; j < ll; ++j)
{
var v = events[event_type][j];
if(expand_parameters)
{
if( v[0].apply(v[1], params ) === true)// || event.stop)
{
blocked = true;
break; //stopPropagation
}
}
else
{
if( v[0].call(v[1], event_type, params) === true)// || event.stop)
{
blocked = true;
break; //stopPropagation
}
}
}
}
}
return blocked;
},
extendObject: function( object )
{
object.bind = function( event_type, callback, instance ){
return LEvent.bind( this, event_type, callback, instance );
};
object.trigger = function( event_type, params ){
return LEvent.trigger( this, event_type, params );
};
object.unbind = function( event_type, callback, target_instance )
{
return LEvent.unbind( this, event_type, callback, instance );
};
object.unbindAll = function( target_instance, callback )
{
return LEvent.unbindAll( this, target_instance, callback );
};
},
/**
* Adds the methods to bind, trigger and unbind to this class prototype
* @method LEvent.extendClass
* @param {Object} constructor
**/
extendClass: function( constructor )
{
this.extendObject( constructor.prototype );
}
};