/*
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));
};
}
};