]> git.pond.sub.org Git - eow/blob - static/dojo-release-1.1.1/dojo/_base/declare.js
add Dojo 1.1.1
[eow] / static / dojo-release-1.1.1 / dojo / _base / declare.js
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         // process superclass argument
50         // var dd=dojo.declare, mixins=null;
51         var dd = arguments.callee, mixins;
52         if(dojo.isArray(superclass)){
53                 mixins = superclass;
54                 superclass = mixins.shift();
55         }
56         // construct intermediate classes for mixins
57         if(mixins){
58                 dojo.forEach(mixins, function(m){
59                         if(!m){ throw(className + ": mixin #" + i + " is null"); } // It's likely a required module is not loaded
60                         superclass = dd._delegate(superclass, m);
61                 });
62         }
63         // prepare values
64         var init = (props||0).constructor, ctor = dd._delegate(superclass), fn;
65         // name methods (experimental)
66         for(var i in props){ if(dojo.isFunction(fn = props[i]) && !0[i]){fn.nom = i;} } // 0[i] checks Object.prototype
67         // decorate prototype
68         dojo.extend(ctor, {declaredClass: className, _constructor: init, preamble: null}, props || 0); 
69         // special help for IE
70         ctor.prototype.constructor = ctor;
71         // create named reference
72         return dojo.setObject(className, ctor); // Function
73 };
74
75 dojo.mixin(dojo.declare, {
76         _delegate: function(base, mixin){
77                 var bp = (base||0).prototype, mp = (mixin||0).prototype;
78                 // fresh constructor, fresh prototype
79                 var ctor = dojo.declare._makeCtor();
80                 // cache ancestry
81                 dojo.mixin(ctor, {superclass: bp, mixin: mp, extend: dojo.declare._extend});
82                 // chain prototypes
83                 if(base){ctor.prototype = dojo._delegate(bp);}
84                 // add mixin and core
85                 dojo.extend(ctor, dojo.declare._core, mp||0, {_constructor: null, preamble: null});
86                 // special help for IE
87                 ctor.prototype.constructor = ctor;
88                 // name this class for debugging
89                 ctor.prototype.declaredClass = (bp||0).declaredClass + '_' + (mp||0).declaredClass;
90                 return ctor;
91         },
92         _extend: function(props){
93                 for(var i in props){ if(dojo.isFunction(fn=props[i]) && !0[i]){fn.nom=i;} }
94                 dojo.extend(this, props);
95         },
96         _makeCtor: function(){
97                 // we have to make a function, but don't want to close over anything
98                 return function(){ this._construct(arguments); };
99         },
100         _core: { 
101                 _construct: function(args){
102                         var c=args.callee, s=c.superclass, ct=s&&s.constructor, m=c.mixin, mct=m&&m.constructor, a=args, ii, fn;
103                         // side-effect of = used on purpose here, lint may complain, don't try this at home
104                         if(a[0]){ 
105                                 // FIXME: preambles for each mixin should be allowed
106                                 // FIXME: 
107                                 //              should we allow the preamble here NOT to modify the
108                                 //              default args, but instead to act on each mixin
109                                 //              independently of the class instance being constructed
110                                 //              (for impedence matching)?
111
112                                 // allow any first argument w/ a "preamble" property to act as a
113                                 // class preamble (not exclusive of the prototype preamble)
114                                 if(/*dojo.isFunction*/((fn = a[0].preamble))){ 
115                                         a = fn.apply(this, a) || a; 
116                                 }
117                         } 
118                         // prototype preamble
119                         if((fn = c.prototype.preamble)){a = fn.apply(this, a) || a;}
120                         // FIXME: 
121                         //              need to provide an optional prototype-settable
122                         //              "_explicitSuper" property which disables this
123                         // initialize superclass
124                         if(ct&&ct.apply){ct.apply(this, a);}
125                         // initialize mixin
126                         if(mct&&mct.apply){mct.apply(this, a);}
127                         // initialize self
128                         if((ii=c.prototype._constructor)){ii.apply(this, args);}
129                         // post construction
130                         if(this.constructor.prototype==c.prototype && (ct=this.postscript)){ ct.apply(this, args); }
131                 },
132                 _findMixin: function(mixin){
133                         var c = this.constructor, p, m;
134                         while(c){
135                                 p = c.superclass;
136                                 m = c.mixin;
137                                 if(m==mixin || (m instanceof mixin.constructor)){return p;}
138                                 if(m && (m=m._findMixin(mixin))){return m;}
139                                 c = p && p.constructor;
140                         }
141                 },
142                 _findMethod: function(name, method, ptype, has){
143                         // consciously trading readability for bytes and speed in this low-level method
144                         var p=ptype, c, m, f;
145                         do{
146                                 c = p.constructor;
147                                 m = c.mixin;
148                                 // find method by name in our mixin ancestor
149                                 if(m && (m=this._findMethod(name, method, m, has))){return m;}
150                                 // if we found a named method that either exactly-is or exactly-is-not 'method'
151                                 if((f=p[name])&&(has==(f==method))){return p;}
152                                 // ascend chain
153                                 p = c.superclass;
154                         }while(p);
155                         // if we couldn't find an ancestor in our primary chain, try a mixin chain
156                         return !has && (p=this._findMixin(ptype)) && this._findMethod(name, method, p, has);
157                 },
158                 inherited: function(name, args, newArgs){
159                         // optionalize name argument (experimental)
160                         var a = arguments;
161                         if(!dojo.isString(a[0])){newArgs=args; args=name; name=args.callee.nom;}
162                         a = newArgs||args;
163                         var c = args.callee, p = this.constructor.prototype, fn, mp;
164                         // if not an instance override 
165                         if(this[name] != c || p[name] == c){
166                                 mp = this._findMethod(name, c, p, true);
167                                 if(!mp){throw(this.declaredClass + ': inherited method "' + name + '" mismatch');}
168                                 p = this._findMethod(name, c, mp, false);
169                         }
170                         fn = p && p[name];
171                         if(!fn){throw(mp.declaredClass + ': inherited method "' + name + '" not found');}
172                         // if the function exists, invoke it in our scope
173                         return fn.apply(this, a);
174                 }
175         }
176 });
177
178 }