|
//jshint camelcase:false |
|
|
|
(function() { |
|
|
|
function noop() {} |
|
|
|
/** |
|
* Returns true if {target} is a function |
|
* |
|
* @param target The object to analyze |
|
* @returns {Boolean} true if target is a function, false otherwise |
|
*/ |
|
function isFunction(target) { |
|
return typeof target === 'function'; |
|
} |
|
|
|
/** |
|
* Returns a hashmap with a descriptor for each property on {target} |
|
* |
|
* @param target {Object} The object to analyze |
|
* @returns {Object} a hashmap with the properties descriptors |
|
*/ |
|
function getDescriptors(target) { |
|
var descriptors = {}; |
|
Object.getOwnPropertyNames(target).map(function(prop) { |
|
descriptors[prop] = Object.getOwnPropertyDescriptor(target, prop); |
|
}); |
|
return descriptors; |
|
} |
|
|
|
/** |
|
* Add every property on {props} into {target} |
|
* |
|
* @param target {Object} The object where the properties will be added to |
|
* @param props {Object} The properties than will be added to {target} |
|
* @returns {Object} The first argument |
|
* |
|
* @example |
|
* inject(MyClass.prototype, { |
|
* a: 1, |
|
* get b() { |
|
* return this.a + 1; |
|
* } |
|
* }); |
|
*/ |
|
function inject(target, props) { |
|
Object.defineProperties(target, getDescriptors(props)); |
|
return target; |
|
} |
|
|
|
/** |
|
* Prototypes {proto} and adds every property into {props} into the new object |
|
* |
|
* @param proto {Object} The object than will be used as prototype for the |
|
* new object |
|
* @param props {Object} The properties than will be added to the new object |
|
* @returns {Object} The new object with all properties added |
|
* |
|
* @example |
|
* SubClass.prototype = extend(MyClass.prototype, { |
|
* a: 1, |
|
* get b() { |
|
* return this.a + 1; |
|
* } |
|
* }); |
|
*/ |
|
function extend(proto, props) { |
|
return Object.create(proto, getDescriptors(props)); |
|
} |
|
|
|
var defaultCtor = { |
|
|
|
extend: function(config) { |
|
ctor(config, this); |
|
}, |
|
|
|
create: function() { |
|
var instance = Object.create(this.proto); |
|
instance.init.apply(instance, arguments); |
|
return instance; |
|
}, |
|
|
|
dispose: function(instance) { |
|
instance.dispose(); |
|
}, |
|
|
|
is: function(instance) { |
|
return this.proto.isPrototypeOf(instance); |
|
} |
|
}; |
|
|
|
/** |
|
* Creates a constructor object |
|
* |
|
* @param Parent {Function|Ctor} The parent constructor function or object |
|
* @param config The properties to add to the object created with this constructor |
|
* @param statics Overwrites for default constructor methods |
|
* @returns {Ctor} A object with methos to create new type of objects |
|
*/ |
|
function ctor(Parent, config, statics) { |
|
if (isFunction(Parent)) |
|
Parent = { proto: Parent.prototype }; |
|
|
|
var proto = Parent ? extend(Parent.proto, config) : config; |
|
|
|
if (!isFunction(proto.init)) |
|
proto.init = noop; |
|
if (!isFunction(proto.dispose)) |
|
proto.dispose = noop; |
|
|
|
var Ctor = proto.ctor = extend(defaultCtor, Parent || {}); |
|
|
|
if (statics) |
|
inject(Ctor, statics); |
|
|
|
Ctor.proto = proto; |
|
return Ctor; |
|
} |
|
|
|
window.ctor = ctor; |
|
|
|
})(); |