(function () {
/** @namespace itm */
itm = this.itm || {};
itm.version = "0.1";
/** Class function
* Designed to create JavaScript Classes
*
* It does the inheritance, checks for arguments,
* adds the core patch to it and calls the init() method.
*
*
* To create a class do this:
*
* myClass=itm.Class(mySuperClass,myPrototype) //(mySuperClass and myPrototype are optional)
* myClass.protoype.init=function()
* {
* //call constructor of superclass
* mySuperClass.prototype.init.call(this,arg1,arg2...);
* //or this.superInit(mySuperClass,arg1,arg2...);
* //or this.superInitApply(mySuperClass,arguments);
*
* //your constructor
* }
*
*
* @memberOf itm
* @param {function} [superClass]
* @param {object} [prototype]
* @returns {function} newClass
*/
itm.Class = function (superClass, prototype) {
var _superClass = superClass;
var _prototype = prototype;
if (typeof _superClass == "object") {
_prototype = _superClass;
_superClass = null;
}
var newClass = function () {
if (this instanceof itm.Patch) {
this.init.apply(this, arguments);
}
else if (arguments.length > 0) {
itm.Class.attachListener(this);
new itm.Patch(this);
this.init.apply(this, arguments);
this.fireListeners("created");
}
};
newClass.prototype.superInit = function (_class/*,arg1,arg2,...,argN*/) {
_class.prototype.init.apply(this, [].slice.call(arguments, 1));
};
newClass.prototype.superInitApply = function (_class, args) {
this.superInit.apply(this, [_class].concat([].slice.call(args)));
};
if (_superClass) {
newClass.prototype = new _superClass();
}
newClass.prototype.constructor = newClass;
for (var i in _prototype) {
newClass.prototype[i] = _prototype[i];
}
return newClass;
};
/**
* @param {object} scope target for listeners
*/
itm.Class.attachListener = function (scope) {
var created = [function () {
created.fired = true;
}];
created.fired = false;
created._push = created.push;
created.push = function (fn) {
if (this.fired)
fn();
else
this._push(fn);
};
scope.listeners = {"created": created};
scope.createListener = function (type/*,fn1,fn2,...,fnN*/) {
var typeArr = type.split(/[ |,]+/);
for (var i = 0; i < typeArr.length; i++) {
if (this.listeners[typeArr[i]] == null)
this.listeners[typeArr[i]] = [];
}
this.addListener.apply(this, arguments);
};
scope.addListener = function (type/*,fn1,fn2,...,fnN*/) {
var typeArr = type.split(/[ |,]+/);
var rtnArr = [];
var fnArr = [].slice.call(arguments, 1);
for (var i = 0; i < typeArr.length; i++) {
if (this.listeners[typeArr[i]] != null) {
for (var f = 0; f < fnArr.length; f++)
rtnArr.push(this.listeners[typeArr[i]].push(fnArr[f]));
}
}
return rtnArr;
};
scope.removeListener = function (type/*,fn1,fn2,...,fnN*/) {
var typeArr = type.split(/[ |,]+/);
var fnArr = [].slice.call(arguments, 1);
for (var i = 0; i < typeArr.length; i++) {
if (this.listeners[typeArr[i]]) {
for (var k = 0; k < this.listeners[typeArr[i]].length; k++) {
for (var j = 0; j < fnArr.length; j++) {
if (fnArr[j] == this.listeners[typeArr[i]][k]) {
this.listeners[typeArr[i]].splice(k, 1);
k--;
j = fnArr.length;
}
}
}
}
}
};
scope.removeAllListeners = function (type) {
if (type == "ALL") {
for (var i in this.listeners) {
this.listeners[i] = [];
}
}
else {
var typeArr = type.split(/[ |,]+/);
for (var i = 0; i < typeArr.length; i++) {
if (this.listeners[typeArr[i]] != null)
this.listeners[typeArr[i]] = [];
}
}
};
scope.fireListeners = function (type/*,arg1,arg2,...,argN*/) {
var rtn = true;
for (var i = 0; this.listeners[type] && i < this.listeners[type].length && rtn; i++) {
rtn = this.listeners[type][i].apply(this, arguments) !== false;
}
return rtn;
};
};
itm.Patch = itm.Class(
/** @lends itm.Patch# */
{
/** Patch
* var myPatch=itm.Class(itm.patch,
* {
* patchID:"myPatchID",
* patch:function(param,noListeners)
* {
* this.superPatch(itm.patch);//call super.patch // in case of itm.Patch its not necessary
* //your constructor after instance is created
* }
* }
*
* The "patch" function is called on the create event (when the constructor of the instance is finished)
* var myPatch=itm.Class(mySuperPatch,
* {
* patchID:"myPatchID",
* init:function(instance,param)
* {
* //call constructor of superclass
* this.superInit(mySuperPatch,instance,param);
* //or this.superInitApply(mySuperPatch,arguments);
*
* if(this.instance!=null)
* {
* //your constructor
* //post patch: this.instance.addListener("created",function(param,noListeners){})
* }
* },
* patch:function(param,noListeners)
* {
* this.superPatch(mySuperPatch,param,noListeners);
* //post constructor
* }
* }
*
* @name itm.Patch
* @class
* @constructor
* @abstract
* @param {object} instance
* @param {*} [param]
*/
init: function (instance, param) {
if (this.constructor === itm.Patch && instance) {
if (!instance.patches) {
instance.patches = {};
instance.hasPatch = function (patch) {
return this.getPatch(patch) != null;
};
instance.getPatch = function (patch) {
return this.patches[patch.patchID || patch.prototype.patchID];
};
}
}
else if (instance && !instance.hasPatch(this)) {
this.instance = instance;
instance.patches[this.patchID] = this;
if (this.instance.addListener) {
var _self = this;
this.instance.addListener("created", function () {
_self.patch(param);
});
}
else {
this.patch(param, true);
}
}
},
/**
* @abstract
* @param {*} param
* @param {boolean} noListeners
*/
patch: function (param, noListeners) {
},
/**
* @param {function} _class
* @param {...*} [args]
*/
superPatch: function (_class/*,arg1,arg2,...,argN*/) {
_class.prototype.patch.apply(this, [].slice.call(arguments, 1));
},
/**
*
* @param {function} _class
* @param {Array} args
*/
superPatchApply: function (_class, args) {
this.superPatch.apply(this, [_class].concat([].slice.call(args)));
}
});
/**
* checks if instance is already patched
* @static
* @memberOf itm.Patch
* @param {object} instance
* @param {function|itm.Patch} patch
* @returns {boolean}
*/
itm.Patch.hasPatch = function (instance, patch) {
return itm.Patch.getPatch(instance, patch) != null;
};
/**
* @static
* @memberOf itm.Patch
* @param {object} instance
* @param {function|itm.Patch} patch
* @returns {null|itm.Patch}
*/
itm.Patch.getPatch = function (instance, patch) {
return instance.getPatch && instance.getPatch(patch) || null;
};
/**
* patches an instance and returns it