Blame | Last modification | View Log | RSS feed
if(!dojo._hasResource["dojo._base.declare"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.declare"] = true;
dojo.provide("dojo._base.declare");
dojo.require("dojo._base.lang");
// this file courtesy of the TurboAjax group, licensed under a Dojo CLA
dojo.declare = function(/*String*/ className, /*Function|Function[]*/ superclass, /*Object*/ props){
// summary:
// Create a feature-rich constructor from compact notation
// className:
// The name of the constructor (loosely, a "class")
// stored in the "declaredClass" property in the created prototype
// superclass:
// May be null, a Function, or an Array of Functions. If an array,
// the first element is used as the prototypical ancestor and
// any following Functions become mixin ancestors.
// props:
// An object whose properties are copied to the
// created prototype.
// Add an instance-initialization function by making it a property
// named "constructor".
// description:
// Create a constructor using a compact notation for inheritance and
// prototype extension.
//
// All superclasses (including mixins) must be Functions (not simple Objects).
//
// Mixin ancestors provide a type of multiple inheritance. Prototypes of mixin
// ancestors are copied to the new class: changes to mixin prototypes will
// not affect classes to which they have been mixed in.
//
// "className" is cached in "declaredClass" property of the new class.
//
// example:
// | dojo.declare("my.classes.bar", my.classes.foo, {
// | // properties to be added to the class prototype
// | someValue: 2,
// | // initialization function
// | constructor: function(){
// | this.myComplicatedObject = new ReallyComplicatedObject();
// | },
// | // other functions
// | someMethod: function(){
// | doStuff();
// | }
// | );
// argument juggling (deprecated)
if(dojo.isFunction(props)||(arguments.length>3)){
dojo.deprecated("dojo.declare: for class '" + className + "' pass initializer function as 'constructor' property instead of as a separate argument.", "", "1.0");
var c = props;
props = arguments[3] || {};
props.constructor = c;
}
// process superclass argument
// var dd=dojo.declare, mixins=null;
var dd=arguments.callee, mixins=null;
if(dojo.isArray(superclass)){
mixins = superclass;
superclass = mixins.shift();
}
// construct intermediate classes for mixins
if(mixins){
for(var i=0, m; i<mixins.length; i++){
m = mixins[i];
if(!m){throw("Mixin #" + i + " to declaration of " + className + " is null. It's likely a required module is not loaded.")};
superclass = dd._delegate(superclass, m);
}
}
// prepare values
var init=(props||0).constructor, ctor=dd._delegate(superclass), fn;
// name methods (experimental)
for(var i in props){if(dojo.isFunction(fn=props[i])&&(!0[i])){fn.nom=i;}}
// decorate prototype
dojo.extend(ctor, {declaredClass: className, _constructor: init, preamble: null}, props||0);
// special help for IE
ctor.prototype.constructor = ctor;
// create named reference
return dojo.setObject(className, ctor); // Function
}
dojo.mixin(dojo.declare, {
_delegate: function(base, mixin){
var bp = (base||0).prototype, mp = (mixin||0).prototype;
// fresh constructor, fresh prototype
var ctor = dojo.declare._makeCtor();
// cache ancestry
dojo.mixin(ctor, {superclass: bp, mixin: mp, extend: dojo.declare._extend});
// chain prototypes
if(base){ctor.prototype = dojo._delegate(bp);}
// add mixin and core
dojo.extend(ctor, dojo.declare._core, mp||0, {_constructor: null, preamble: null});
// special help for IE
ctor.prototype.constructor = ctor;
// name this class for debugging
ctor.prototype.declaredClass = (bp||0).declaredClass + '_' + (mp||0).declaredClass;
return ctor;
},
_extend: function(props){
for(var i in props){if(dojo.isFunction(fn=props[i])&&(!0[i])){fn.nom=i;}}
dojo.extend(this, props);
},
_makeCtor: function(){
// we have to make a function, but don't want to close over anything
return function(){ this._construct(arguments); }
},
_core: {
_construct: function(args){
var c=args.callee, s=c.superclass, ct=s&&s.constructor, m=c.mixin, mct=m&&m.constructor, a=args, ii, fn;
// side-effect of = used on purpose here, lint may complain, don't try this at home
if(a[0]){
// FIXME: preambles for each mixin should be allowed
// FIXME:
// should we allow the preamble here NOT to modify the
// default args, but instead to act on each mixin
// independently of the class instance being constructed
// (for impdedence matching)?
// allow any first argument w/ a "preamble" property to act as a
// class preamble (not exclusive of the prototype preamble)
if(/*dojo.isFunction*/(fn = a[0]["preamble"])){
a = fn.apply(this, a) || a;
}
}
// prototype preamble
if(fn=c.prototype.preamble){a = fn.apply(this, a) || a;}
// FIXME:
// need to provide an optional prototype-settable
// "_explicitSuper" property which disables this
// initialize superclass
if(ct&&ct.apply){ct.apply(this, a);}
// initialize mixin
if(mct&&mct.apply){mct.apply(this, a);}
// initialize self
if(ii=c.prototype._constructor){ii.apply(this, args);}
// post construction
if(this.constructor.prototype==c.prototype && (ct=this.postscript)){ct.apply(this, args)};
},
_findMixin: function(mixin){
var c = this.constructor, p, m;
while(c){
p = c.superclass;
m = c.mixin;
if(m==mixin || (m instanceof mixin.constructor)){return p;}
if(m && (m=m._findMixin(mixin))){return m;}
c = p && p.constructor;
}
},
_findMethod: function(name, method, ptype, has){
// consciously trading readability for bytes and speed in this low-level method
var p=ptype, c, m, f;
do{
c = p.constructor;
m = c.mixin;
// find method by name in our mixin ancestor
if(m && (m=this._findMethod(name, method, m, has))){return m};
// if we found a named method that either exactly-is or exactly-is-not 'method'
if((f=p[name])&&(has==(f==method))){return p};
// ascend chain
p = c.superclass;
}while(p);
// if we couldn't find an ancestor in our primary chain, try a mixin chain
return !has && (p=this._findMixin(ptype)) && this._findMethod(name, method, p, has);
},
inherited: function(name, args, newArgs){
// optionalize name argument (experimental)
var a = arguments;
if(!dojo.isString(a[0])){newArgs=args; args=name; name=args.callee.nom;}
var c=args.callee, p=this.constructor.prototype, a=newArgs||args, fn, mp;
// if not an instance override
if(this[name]!=c || p[name]==c){
mp = this._findMethod(name, c, p, true);
if(!mp){throw(this.declaredClass + ': name argument ("' + name + '") to inherited must match callee (declare.js)');}
p = this._findMethod(name, c, mp, false);
}
fn = p && p[name];
// FIXME: perhaps we should throw here?
if(!fn){console.debug(mp.declaredClass + ': no inherited "' + name + '" was found (declare.js)'); return;}
// if the function exists, invoke it in our scope
return fn.apply(this, a);
}
}
});
}