/*! Jahcode v1.1.6 | jahcode.com | Copyright 2011-2014 by Florian Buecklers | MIT license */ (function(global) { var fakePrototype = Object.getPrototypeOf({ constructor : String }) == String.prototype; if (!Function.prototype.extend) { /** * Extends the target with the properties of props and return target * @param {*=} target The target to extends or thisArg, if it is not set * @param {Object} props The properties to extend * @returns {*} The extended target */ Function.prototype.extend = function(target, props) { if (!props) { props = target; target = this; } for (var name in props) { if (props.hasOwnProperty(name)) { target[name] = props[name]; } } return target; }; } Object.extend(Function.prototype, /** @lends Function.prototype */ { /** * The linearized type hierarchy of this class * @type Function[] */ linearizedTypes : [Object], /** * Inherits this constructor and extends it by additional properties and methods. Optional there can be mixined * additional Traits * @param {Trait...} traits Additional traits to mixin * @param {Object} classDescriptor The descriptor of the class properties and methods * @returns {Function} The new created child class */ inherit : function() { var objectDescriptor = arguments[arguments.length - 1]; var klass = objectDescriptor.constructor !== Object? objectDescriptor.constructor: function Class(toCast) { if (!(this instanceof klass)) { return klass.asInstance(toCast); } if (this.initialize) arguments.length ? this.initialize.apply(this, arguments) : this.initialize(); }; var proto = Object.createPrototypeChain(klass, this, Array.prototype.slice.call(arguments, 0, arguments.length - 1)); var names = Object.getOwnPropertyNames(objectDescriptor); for ( var i = 0; i < names.length; ++i) { var name = names[i]; var result = false; if (Object.properties.hasOwnProperty(name)) { result = Object.properties[name](proto, objectDescriptor, name); } if (!result) { var d = Object.getOwnPropertyDescriptor(objectDescriptor, name); if (d.value) { var val = d.value; if (val instanceof Function) { if (/this\.superCall/.test(val.toString())) { d.value = Object.createSuperCallWrapper(klass, name, val); } } else if (val && (val.hasOwnProperty('get') || val.hasOwnProperty('value'))) { d = val; } } Object.defineProperty(proto, name, d); } } if (klass.initialize) { klass.initialize(); } return klass; }, /** * Indicates if this class is a subclass of the given class or mixin the given trait. * @param {Function} cls The parent class or trait to check * @returns {boolean} true if this class is a subclass or mixin the trait */ isA: function(cls) { return this.prototype instanceof cls || this.linearizedTypes.lastIndexOf(cls) != -1; }, /** * Indicates if the object is an instance of this class * @param obj The object to check for * @returns {boolean} true if the object is defined and */ isInstance : function(obj) { if (obj === null || obj === void 0) return false; return Object(obj) instanceof this || classOf(obj).linearizedTypes.lastIndexOf(this) != -1; }, /** * Checks if the object is an instance of this class and returns the object or try to convert the * object to an instance of this class by calling {@link #conv} * @param obj The object to check * @returns {*} The typed object or null, if the object can't be typed to an instance of this class */ asInstance : function(obj) { if (this.isInstance(obj)) { return obj; } else { return this.conv(obj); } }, /** * Converts the given value to an instance of this class, or returns null, if the value can't be converted * @param {*} value The value to convert * @returns {null} The converted value or null */ conv : function() { return null; } }); Object.extend( /** @lends Object **/ { properties : {}, cloneOwnProperties : function(target, src) { var names = Object.getOwnPropertyNames(src); for ( var i = 0; i < names.length; ++i) { var name = names[i]; if (name != '__proto__') { var descr = Object.getOwnPropertyDescriptor(src, name); Object.defineProperty(target, name, descr); } } }, createPrototypeChain : function(cls, parentClass, traits) { var proto = parentClass.prototype; var linearizedTypes = parentClass.linearizedTypes.slice(); var prototypeChain = parentClass.prototypeChain ? parentClass.prototypeChain.slice() : [proto]; for ( var i = 0, trait; trait = traits[i]; ++i) { if (!(trait.prototype instanceof Trait)) { throw new TypeError("Only traits can be mixed in."); } var linearizedTraitTypes = trait.linearizedTypes; for ( var j = 0, type; type = linearizedTraitTypes[j]; ++j) { if (linearizedTypes.indexOf(type) == -1 && type != Trait) { proto = Object.create(proto); Object.cloneOwnProperties(proto, type.wrappedPrototype ? type.wrappedPrototype : type.prototype); proto.constructor = type; linearizedTypes.push(type); prototypeChain.push(proto); } } } proto = Object.create(proto); proto.constructor = cls; linearizedTypes.push(cls); prototypeChain.push(proto); if (fakePrototype) { cls.wrappedPrototype = proto; cls.prototype = Object.create(proto); } else { cls.prototype = proto; } cls.linearizedTypes = linearizedTypes; cls.prototypeChain = prototypeChain; return proto; }, createSuperCallWrapper : function(declaringClass, methodName, method) { var superCall = function() { var cls = classOf(this); var index = cls.linearizedTypes.lastIndexOf(declaringClass); if (index == -1) { throw new ReferenceError("superCall can't determine any super method"); } var proto = cls.prototypeChain[index - 1]; if (methodName != 'initialize' || proto[methodName]) return arguments.length ? proto[methodName].apply(this, arguments) : proto[methodName].call(this); }; return function() { var current = this.superCall; this.superCall = superCall; try { return arguments.length ? method.apply(this, arguments) : method.call(this); } finally { if (current) { this.superCall = current; } else { // made the property invisible again delete this.superCall; } } }; } }); Object.extend(Object.properties, { initialize : function(proto, objectDescriptor) { var init = objectDescriptor.initialize; var test = /this\.superCall/.test(init.toString()); if (proto instanceof Trait) { if (test) { throw new TypeError('Trait constructors can not call super constructors directly.'); } objectDescriptor.initialize = function() { arguments.length ? this.superCall.apply(this, arguments) : this.superCall.call(this); init.call(this); }; } else if (!test && classOf(proto) != Object) { objectDescriptor.initialize = function() { this.superCall.call(this); arguments.length ? init.apply(this, arguments) : init.call(this); }; } }, extend : function(proto, objectDescriptor) { Object.extend(proto.constructor, objectDescriptor.extend); return true; } }); /** * Returns the constructor of the given object, works for objects and primitive types * @param {*} object The constructor to return for * @returns {Function} The constructor of the object * @global */ var classOf = function(object) { if (object === null || object === void 0) return object; return Object.getPrototypeOf(Object(object)).constructor; }; /** * @mixin Trait * @global */ var Trait = Object.inherit({}); /** * @extends Trait * @mixin Bind * @global */ var Bind = Trait.inherit({ /** @lends Bind */ extend : { initialize : function() { try { Object.defineProperty(this.prototype, 'bind', { get : function() { return this.bind = Bind.create(this); }, set : function(val) { Object.defineProperty(this, 'bind', { value : val }); }, configurable : true }); this.Object = Object.inherit({ initialize : function(self) { this.self = self; } }); } catch (e) { this.Object = Object.inherit({ initialize : function(self) { this.self = self; var bind = this; Bind.each(self, function(name, method) { bind[name] = method.bind(bind.self); }); } }); } }, /** * Creates a bind proxy for the given object * Each method of the given object is reflected on the proxy and * bound to the object context * @param {*} obj The object which will be bound * @returns {Bind} The bound proxy */ create : function(obj) { if (!obj.constructor.Bind) { try { var descr = {}; Bind.each(obj, function(name, method) { descr[name] = { get : function() { return this[name] = method.bind(this.self); }, set : function(val) { Object.defineProperty(this, name, { value : val }); }, configurable : true }; }); obj.constructor.Bind = Bind.Object.inherit(descr); } catch (e) { obj.constructor.Bind = Bind.Object.inherit({}); } } return new obj.constructor.Bind(obj); }, each : function(obj, callback) { var proto = Object.getPrototypeOf(obj); for ( var name in proto) { var method = proto[name]; if (name != 'initialize' && name != 'constructor' && method instanceof Function) { callback(name, method); } } } }, initialize : function() { if (!('bind' in this)) { this.bind = Bind.create(this); } } /** * @type Bind * @name Bind.prototype.bind */ }); var nativeClasses = [Boolean, Number, String, Function, RegExp, Error]; for ( var i = 0, cls; cls = nativeClasses[i]; ++i) { cls.conv = cls; } Date.conv = function(object) { return new Date(object); }; Array.conv = function(object) { return Array.prototype.slice.call(object); }; Array.prototype.initialize = function() { for ( var i = 0; i < arguments.length; ++i) { this[i] = arguments[i]; } this.length = arguments.length; }; Error.prototype.initialize = function(message) { var stack = new Error().stack || 'Error'; stack = stack.substring(stack.indexOf('\n') + 1); this.stack = message + '\n' + stack; this.message = message; }; if (TypeError instanceof Error) { // ie8 uses error instances for subtype constructors Error.prototype.isInstance = Error.isInstance; Error.prototype.asInstance = Error.asInstance; Error.prototype.conv = Error.conv; } Object.extend(global, { classOf : classOf, Trait : Trait, Bind : Bind }); })(typeof window != 'undefined' ? window : global);