javascript/base.js
/*
** base.js -- base class for better OO inheritance in JavaScript
** Copyright (c) 2006 Dean Edwards <http://dean.edwards.name/>
** Copyright (c) 2007 Ralf S. Engelschall <rse@engelschall.com>
** Licensed under LGPL <http://www.gnu.org/licenses/lgpl.txt>
**
** This is derived from Dean Edwards' "Base" implementation, version
** 1.0.2 as available on http://dean.edwards.name/base/Base.js.
** It was cleaned up, modified and extended with the feedback
** under http://dean.edwards.name/weblog/2006/03/base/ by Ralf S.
** Engelschall.
**
** $LastChangedDate: $
** $LastChangedRevision: $
*/
/* class constructor */
var Base = function() {
if (arguments.length) {
if (this == window) {
// cast an object to this class
Base.prototype.extend.call(arguments[0], arguments.callee.prototype);
} else {
this.extend(arguments[0]);
}
}
};
/* class version */
Base.version = "1.0.2+FIXES+RSE";
/* class method for extending */
Base.extend = function(_instance, _static) {
var extend = Base.prototype.extend;
if (!_instance)
_instance = {};
/* build the prototype */
Base._prototyping = true;
var _prototype = new this;
extend.call(_prototype, _instance);
var constructor = _prototype.constructor;
_prototype.constructor = this;
delete Base._prototyping;
/* create the wrapper for the constructor function */
var klass = function() {
if (!Base._prototyping) {
if (this instanceof klass) {
constructor.apply(this, arguments);
} else {
if (arguments.length)
return extend.call(arguments[0], _prototype);
}
}
};
klass.prototype = _prototype;
/* build the class interface */
klass.extend = this.extend;
klass.implement = this.implement;
klass.toString = function() {
return String(constructor);
};
extend.call(klass, _static);
/* single instance */
var object = constructor ? klass : _prototype;
/* class initialisation */
if (object.init instanceof Function)
object.init();
return object;
};
/* class method for multipe inheritance support */
Base.implement = function() {
for (var i = 0; i < arguments.length; i++) {
_interface = arguments[i];
if (_interface instanceof Function)
_interface = _interface.prototype;
this.prototype.extend(_interface);
}
};
/* instance method for extending */
Base.prototype.extend = function(source, value) {
var extend = Base.prototype.extend;
if (arguments.length == 2) {
var ancestor = this[source];
if ( (ancestor instanceof Function)
&& (value instanceof Function)
&& ancestor.valueOf() != value.valueOf()
&& /\bbase\b/.test(value) ) {
var method = value;
value = function() {
var previous = this.base;
this.base = ancestor;
try {
var returnValue = method.apply(this, arguments);
} catch (ex) {
throw ex;
}
finally {
this.base = previous;
}
return returnValue;
};
// point to the underlying method
value.valueOf = function() {
return method;
};
value.toString = function() {
return String(method);
};
}
return this[source] = value;
} else if (source) {
var _prototype = {toSource: null};
// do the "toString" and other methods manually
var _protected = ["toString", "valueOf"];
// if we are prototyping then include the constructor
if (Base._prototyping)
_protected[2] = "constructor";
for (var i = 0; (name = _protected[i]); i++) {
if (source[name] != _prototype[name])
extend.call(this, name, source[name]);
}
// copy each of the source object's properties to this object
for (var name in source) {
if (!_prototype[name])
extend.call(this, name, source[name]);
}
}
return this;
};
/* instance method for invoking ancestor method */
Base.prototype.base = function() {
/* call this method from any other method to invoke that method's ancestor */
};