/* Script: Class.js Contains the Class Function for easily creating, extending, and implementing reusable Classes. License: MIT-style license. */ var Class = new Native({ name: 'Class', initialize: function(properties){ properties = properties || {}; var klass = function(empty){ for (var key in this) this[key] = $unlink(this[key]); for (var mutator in Class.Mutators){ if (!this[mutator]) continue; Class.Mutators[mutator](this, this[mutator]); delete this[mutator]; } this.constructor = klass; if (empty === $empty) return this; var self = (this.initialize) ? this.initialize.apply(this, arguments) : this; if (this.options && this.options.initialize) this.options.initialize.call(this); return self; }; $extend(klass, this); klass.constructor = Class; klass.prototype = properties; return klass; } }); Class.implement({ implement: function(){ Class.Mutators.Implements(this.prototype, Array.slice(arguments)); return this; } }); Class.Mutators = { Implements: function(self, klasses){ $splat(klasses).each(function(klass){ $extend(self, ($type(klass) == 'class') ? new klass($empty) : klass); }); }, Extends: function(self, klass){ var instance = new klass($empty); delete instance.parent; delete instance.parentOf; for (var key in instance){ var current = self[key], previous = instance[key]; if (current == undefined){ self[key] = previous; continue; } var ctype = $type(current), ptype = $type(previous); if (ctype != ptype) continue; switch (ctype){ case 'function': // this code will be only executed if the current browser does not support function.caller (currently only opera). // we replace the function code with brute force. Not pretty, but it will only be executed if function.caller is not supported. if (!arguments.callee.caller) self[key] = eval('(' + String(current).replace(/\bthis\.parent\(\s*(\))?/g, function(full, close){ return 'arguments.callee._parent_.call(this' + (close || ', '); }) + ')'); // end "opera" code self[key]._parent_ = previous; break; case 'object': self[key] = $merge(previous, current); } } self.parent = function(){ return arguments.callee.caller._parent_.apply(this, arguments); }; self.parentOf = function(descendant){ return descendant._parent_.apply(this, Array.slice(arguments, 1)); }; } };