2150 |
mathias |
1 |
if(!dojo._hasResource["dojo._base.declare"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
2 |
dojo._hasResource["dojo._base.declare"] = true;
|
|
|
3 |
dojo.provide("dojo._base.declare");
|
|
|
4 |
dojo.require("dojo._base.lang");
|
|
|
5 |
|
|
|
6 |
// this file courtesy of the TurboAjax group, licensed under a Dojo CLA
|
|
|
7 |
|
|
|
8 |
dojo.declare = function(/*String*/ className, /*Function|Function[]*/ superclass, /*Object*/ props){
|
|
|
9 |
// summary:
|
|
|
10 |
// Create a feature-rich constructor from compact notation
|
|
|
11 |
// className:
|
|
|
12 |
// The name of the constructor (loosely, a "class")
|
|
|
13 |
// stored in the "declaredClass" property in the created prototype
|
|
|
14 |
// superclass:
|
|
|
15 |
// May be null, a Function, or an Array of Functions. If an array,
|
|
|
16 |
// the first element is used as the prototypical ancestor and
|
|
|
17 |
// any following Functions become mixin ancestors.
|
|
|
18 |
// props:
|
|
|
19 |
// An object whose properties are copied to the
|
|
|
20 |
// created prototype.
|
|
|
21 |
// Add an instance-initialization function by making it a property
|
|
|
22 |
// named "constructor".
|
|
|
23 |
// description:
|
|
|
24 |
// Create a constructor using a compact notation for inheritance and
|
|
|
25 |
// prototype extension.
|
|
|
26 |
//
|
|
|
27 |
// All superclasses (including mixins) must be Functions (not simple Objects).
|
|
|
28 |
//
|
|
|
29 |
// Mixin ancestors provide a type of multiple inheritance. Prototypes of mixin
|
|
|
30 |
// ancestors are copied to the new class: changes to mixin prototypes will
|
|
|
31 |
// not affect classes to which they have been mixed in.
|
|
|
32 |
//
|
|
|
33 |
// "className" is cached in "declaredClass" property of the new class.
|
|
|
34 |
//
|
|
|
35 |
// example:
|
|
|
36 |
// | dojo.declare("my.classes.bar", my.classes.foo, {
|
|
|
37 |
// | // properties to be added to the class prototype
|
|
|
38 |
// | someValue: 2,
|
|
|
39 |
// | // initialization function
|
|
|
40 |
// | constructor: function(){
|
|
|
41 |
// | this.myComplicatedObject = new ReallyComplicatedObject();
|
|
|
42 |
// | },
|
|
|
43 |
// | // other functions
|
|
|
44 |
// | someMethod: function(){
|
|
|
45 |
// | doStuff();
|
|
|
46 |
// | }
|
|
|
47 |
// | );
|
|
|
48 |
|
|
|
49 |
// argument juggling (deprecated)
|
|
|
50 |
if(dojo.isFunction(props)||(arguments.length>3)){
|
|
|
51 |
dojo.deprecated("dojo.declare: for class '" + className + "' pass initializer function as 'constructor' property instead of as a separate argument.", "", "1.0");
|
|
|
52 |
var c = props;
|
|
|
53 |
props = arguments[3] || {};
|
|
|
54 |
props.constructor = c;
|
|
|
55 |
}
|
|
|
56 |
// process superclass argument
|
|
|
57 |
// var dd=dojo.declare, mixins=null;
|
|
|
58 |
var dd=arguments.callee, mixins=null;
|
|
|
59 |
if(dojo.isArray(superclass)){
|
|
|
60 |
mixins = superclass;
|
|
|
61 |
superclass = mixins.shift();
|
|
|
62 |
}
|
|
|
63 |
// construct intermediate classes for mixins
|
|
|
64 |
if(mixins){
|
|
|
65 |
for(var i=0, m; i<mixins.length; i++){
|
|
|
66 |
m = mixins[i];
|
|
|
67 |
if(!m){throw("Mixin #" + i + " to declaration of " + className + " is null. It's likely a required module is not loaded.")};
|
|
|
68 |
superclass = dd._delegate(superclass, m);
|
|
|
69 |
}
|
|
|
70 |
}
|
|
|
71 |
// prepare values
|
|
|
72 |
var init=(props||0).constructor, ctor=dd._delegate(superclass), fn;
|
|
|
73 |
// name methods (experimental)
|
|
|
74 |
for(var i in props){if(dojo.isFunction(fn=props[i])&&(!0[i])){fn.nom=i;}}
|
|
|
75 |
// decorate prototype
|
|
|
76 |
dojo.extend(ctor, {declaredClass: className, _constructor: init, preamble: null}, props||0);
|
|
|
77 |
// special help for IE
|
|
|
78 |
ctor.prototype.constructor = ctor;
|
|
|
79 |
// create named reference
|
|
|
80 |
return dojo.setObject(className, ctor); // Function
|
|
|
81 |
}
|
|
|
82 |
|
|
|
83 |
dojo.mixin(dojo.declare, {
|
|
|
84 |
_delegate: function(base, mixin){
|
|
|
85 |
var bp = (base||0).prototype, mp = (mixin||0).prototype;
|
|
|
86 |
// fresh constructor, fresh prototype
|
|
|
87 |
var ctor = dojo.declare._makeCtor();
|
|
|
88 |
// cache ancestry
|
|
|
89 |
dojo.mixin(ctor, {superclass: bp, mixin: mp, extend: dojo.declare._extend});
|
|
|
90 |
// chain prototypes
|
|
|
91 |
if(base){ctor.prototype = dojo._delegate(bp);}
|
|
|
92 |
// add mixin and core
|
|
|
93 |
dojo.extend(ctor, dojo.declare._core, mp||0, {_constructor: null, preamble: null});
|
|
|
94 |
// special help for IE
|
|
|
95 |
ctor.prototype.constructor = ctor;
|
|
|
96 |
// name this class for debugging
|
|
|
97 |
ctor.prototype.declaredClass = (bp||0).declaredClass + '_' + (mp||0).declaredClass;
|
|
|
98 |
return ctor;
|
|
|
99 |
},
|
|
|
100 |
_extend: function(props){
|
|
|
101 |
for(var i in props){if(dojo.isFunction(fn=props[i])&&(!0[i])){fn.nom=i;}}
|
|
|
102 |
dojo.extend(this, props);
|
|
|
103 |
},
|
|
|
104 |
_makeCtor: function(){
|
|
|
105 |
// we have to make a function, but don't want to close over anything
|
|
|
106 |
return function(){ this._construct(arguments); }
|
|
|
107 |
},
|
|
|
108 |
_core: {
|
|
|
109 |
_construct: function(args){
|
|
|
110 |
var c=args.callee, s=c.superclass, ct=s&&s.constructor, m=c.mixin, mct=m&&m.constructor, a=args, ii, fn;
|
|
|
111 |
// side-effect of = used on purpose here, lint may complain, don't try this at home
|
|
|
112 |
if(a[0]){
|
|
|
113 |
// FIXME: preambles for each mixin should be allowed
|
|
|
114 |
// FIXME:
|
|
|
115 |
// should we allow the preamble here NOT to modify the
|
|
|
116 |
// default args, but instead to act on each mixin
|
|
|
117 |
// independently of the class instance being constructed
|
|
|
118 |
// (for impdedence matching)?
|
|
|
119 |
|
|
|
120 |
// allow any first argument w/ a "preamble" property to act as a
|
|
|
121 |
// class preamble (not exclusive of the prototype preamble)
|
|
|
122 |
if(/*dojo.isFunction*/(fn = a[0]["preamble"])){
|
|
|
123 |
a = fn.apply(this, a) || a;
|
|
|
124 |
}
|
|
|
125 |
}
|
|
|
126 |
// prototype preamble
|
|
|
127 |
if(fn=c.prototype.preamble){a = fn.apply(this, a) || a;}
|
|
|
128 |
// FIXME:
|
|
|
129 |
// need to provide an optional prototype-settable
|
|
|
130 |
// "_explicitSuper" property which disables this
|
|
|
131 |
// initialize superclass
|
|
|
132 |
if(ct&&ct.apply){ct.apply(this, a);}
|
|
|
133 |
// initialize mixin
|
|
|
134 |
if(mct&&mct.apply){mct.apply(this, a);}
|
|
|
135 |
// initialize self
|
|
|
136 |
if(ii=c.prototype._constructor){ii.apply(this, args);}
|
|
|
137 |
// post construction
|
|
|
138 |
if(this.constructor.prototype==c.prototype && (ct=this.postscript)){ct.apply(this, args)};
|
|
|
139 |
},
|
|
|
140 |
_findMixin: function(mixin){
|
|
|
141 |
var c = this.constructor, p, m;
|
|
|
142 |
while(c){
|
|
|
143 |
p = c.superclass;
|
|
|
144 |
m = c.mixin;
|
|
|
145 |
if(m==mixin || (m instanceof mixin.constructor)){return p;}
|
|
|
146 |
if(m && (m=m._findMixin(mixin))){return m;}
|
|
|
147 |
c = p && p.constructor;
|
|
|
148 |
}
|
|
|
149 |
},
|
|
|
150 |
_findMethod: function(name, method, ptype, has){
|
|
|
151 |
// consciously trading readability for bytes and speed in this low-level method
|
|
|
152 |
var p=ptype, c, m, f;
|
|
|
153 |
do{
|
|
|
154 |
c = p.constructor;
|
|
|
155 |
m = c.mixin;
|
|
|
156 |
// find method by name in our mixin ancestor
|
|
|
157 |
if(m && (m=this._findMethod(name, method, m, has))){return m};
|
|
|
158 |
// if we found a named method that either exactly-is or exactly-is-not 'method'
|
|
|
159 |
if((f=p[name])&&(has==(f==method))){return p};
|
|
|
160 |
// ascend chain
|
|
|
161 |
p = c.superclass;
|
|
|
162 |
}while(p);
|
|
|
163 |
// if we couldn't find an ancestor in our primary chain, try a mixin chain
|
|
|
164 |
return !has && (p=this._findMixin(ptype)) && this._findMethod(name, method, p, has);
|
|
|
165 |
},
|
|
|
166 |
inherited: function(name, args, newArgs){
|
|
|
167 |
// optionalize name argument (experimental)
|
|
|
168 |
var a = arguments;
|
|
|
169 |
if(!dojo.isString(a[0])){newArgs=args; args=name; name=args.callee.nom;}
|
|
|
170 |
var c=args.callee, p=this.constructor.prototype, a=newArgs||args, fn, mp;
|
|
|
171 |
// if not an instance override
|
|
|
172 |
if(this[name]!=c || p[name]==c){
|
|
|
173 |
mp = this._findMethod(name, c, p, true);
|
|
|
174 |
if(!mp){throw(this.declaredClass + ': name argument ("' + name + '") to inherited must match callee (declare.js)');}
|
|
|
175 |
p = this._findMethod(name, c, mp, false);
|
|
|
176 |
}
|
|
|
177 |
fn = p && p[name];
|
|
|
178 |
// FIXME: perhaps we should throw here?
|
|
|
179 |
if(!fn){console.debug(mp.declaredClass + ': no inherited "' + name + '" was found (declare.js)'); return;}
|
|
|
180 |
// if the function exists, invoke it in our scope
|
|
|
181 |
return fn.apply(this, a);
|
|
|
182 |
}
|
|
|
183 |
}
|
|
|
184 |
});
|
|
|
185 |
|
|
|
186 |
}
|