source: Dev/trunk/src/client/dojo/_base/declare.js @ 532

Last change on this file since 532 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 31.3 KB
Line 
1define(["./kernel", "../has", "./lang"], function(dojo, has, lang){
2        // module:
3        //              dojo/_base/declare
4
5        var mix = lang.mixin, op = Object.prototype, opts = op.toString,
6                xtor = new Function, counter = 0, cname = "constructor";
7
8        function err(msg, cls){ throw new Error("declare" + (cls ? " " + cls : "") + ": " + msg); }
9
10        // C3 Method Resolution Order (see http://www.python.org/download/releases/2.3/mro/)
11        function c3mro(bases, className){
12                var result = [], roots = [{cls: 0, refs: []}], nameMap = {}, clsCount = 1,
13                        l = bases.length, i = 0, j, lin, base, top, proto, rec, name, refs;
14
15                // build a list of bases naming them if needed
16                for(; i < l; ++i){
17                        base = bases[i];
18                        if(!base){
19                                err("mixin #" + i + " is unknown. Did you use dojo.require to pull it in?", className);
20                        }else if(opts.call(base) != "[object Function]"){
21                                err("mixin #" + i + " is not a callable constructor.", className);
22                        }
23                        lin = base._meta ? base._meta.bases : [base];
24                        top = 0;
25                        // add bases to the name map
26                        for(j = lin.length - 1; j >= 0; --j){
27                                proto = lin[j].prototype;
28                                if(!proto.hasOwnProperty("declaredClass")){
29                                        proto.declaredClass = "uniqName_" + (counter++);
30                                }
31                                name = proto.declaredClass;
32                                if(!nameMap.hasOwnProperty(name)){
33                                        nameMap[name] = {count: 0, refs: [], cls: lin[j]};
34                                        ++clsCount;
35                                }
36                                rec = nameMap[name];
37                                if(top && top !== rec){
38                                        rec.refs.push(top);
39                                        ++top.count;
40                                }
41                                top = rec;
42                        }
43                        ++top.count;
44                        roots[0].refs.push(top);
45                }
46
47                // remove classes without external references recursively
48                while(roots.length){
49                        top = roots.pop();
50                        result.push(top.cls);
51                        --clsCount;
52                        // optimization: follow a single-linked chain
53                        while(refs = top.refs, refs.length == 1){
54                                top = refs[0];
55                                if(!top || --top.count){
56                                        // branch or end of chain => do not end to roots
57                                        top = 0;
58                                        break;
59                                }
60                                result.push(top.cls);
61                                --clsCount;
62                        }
63                        if(top){
64                                // branch
65                                for(i = 0, l = refs.length; i < l; ++i){
66                                        top = refs[i];
67                                        if(!--top.count){
68                                                roots.push(top);
69                                        }
70                                }
71                        }
72                }
73                if(clsCount){
74                        err("can't build consistent linearization", className);
75                }
76
77                // calculate the superclass offset
78                base = bases[0];
79                result[0] = base ?
80                        base._meta && base === result[result.length - base._meta.bases.length] ?
81                                base._meta.bases.length : 1 : 0;
82
83                return result;
84        }
85
86        function inherited(args, a, f){
87                var name, chains, bases, caller, meta, base, proto, opf, pos,
88                        cache = this._inherited = this._inherited || {};
89
90                // crack arguments
91                if(typeof args == "string"){
92                        name = args;
93                        args = a;
94                        a = f;
95                }
96                f = 0;
97
98                caller = args.callee;
99                name = name || caller.nom;
100                if(!name){
101                        err("can't deduce a name to call inherited()", this.declaredClass);
102                }
103
104                meta = this.constructor._meta;
105                bases = meta.bases;
106
107                pos = cache.p;
108                if(name != cname){
109                        // method
110                        if(cache.c !== caller){
111                                // cache bust
112                                pos = 0;
113                                base = bases[0];
114                                meta = base._meta;
115                                if(meta.hidden[name] !== caller){
116                                        // error detection
117                                        chains = meta.chains;
118                                        if(chains && typeof chains[name] == "string"){
119                                                err("calling chained method with inherited: " + name, this.declaredClass);
120                                        }
121                                        // find caller
122                                        do{
123                                                meta = base._meta;
124                                                proto = base.prototype;
125                                                if(meta && (proto[name] === caller && proto.hasOwnProperty(name) || meta.hidden[name] === caller)){
126                                                        break;
127                                                }
128                                        }while(base = bases[++pos]); // intentional assignment
129                                        pos = base ? pos : -1;
130                                }
131                        }
132                        // find next
133                        base = bases[++pos];
134                        if(base){
135                                proto = base.prototype;
136                                if(base._meta && proto.hasOwnProperty(name)){
137                                        f = proto[name];
138                                }else{
139                                        opf = op[name];
140                                        do{
141                                                proto = base.prototype;
142                                                f = proto[name];
143                                                if(f && (base._meta ? proto.hasOwnProperty(name) : f !== opf)){
144                                                        break;
145                                                }
146                                        }while(base = bases[++pos]); // intentional assignment
147                                }
148                        }
149                        f = base && f || op[name];
150                }else{
151                        // constructor
152                        if(cache.c !== caller){
153                                // cache bust
154                                pos = 0;
155                                meta = bases[0]._meta;
156                                if(meta && meta.ctor !== caller){
157                                        // error detection
158                                        chains = meta.chains;
159                                        if(!chains || chains.constructor !== "manual"){
160                                                err("calling chained constructor with inherited", this.declaredClass);
161                                        }
162                                        // find caller
163                                        while(base = bases[++pos]){ // intentional assignment
164                                                meta = base._meta;
165                                                if(meta && meta.ctor === caller){
166                                                        break;
167                                                }
168                                        }
169                                        pos = base ? pos : -1;
170                                }
171                        }
172                        // find next
173                        while(base = bases[++pos]){     // intentional assignment
174                                meta = base._meta;
175                                f = meta ? meta.ctor : base;
176                                if(f){
177                                        break;
178                                }
179                        }
180                        f = base && f;
181                }
182
183                // cache the found super method
184                cache.c = f;
185                cache.p = pos;
186
187                // now we have the result
188                if(f){
189                        return a === true ? f : f.apply(this, a || args);
190                }
191                // intentionally no return if a super method was not found
192        }
193
194        function getInherited(name, args){
195                if(typeof name == "string"){
196                        return this.__inherited(name, args, true);
197                }
198                return this.__inherited(name, true);
199        }
200
201        function inherited__debug(args, a1, a2){
202                var f = this.getInherited(args, a1);
203                if(f){ return f.apply(this, a2 || a1 || args); }
204                // intentionally no return if a super method was not found
205        }
206
207        var inheritedImpl = dojo.config.isDebug ? inherited__debug : inherited;
208
209        // emulation of "instanceof"
210        function isInstanceOf(cls){
211                var bases = this.constructor._meta.bases;
212                for(var i = 0, l = bases.length; i < l; ++i){
213                        if(bases[i] === cls){
214                                return true;
215                        }
216                }
217                return this instanceof cls;
218        }
219
220        function mixOwn(target, source){
221                // add props adding metadata for incoming functions skipping a constructor
222                for(var name in source){
223                        if(name != cname && source.hasOwnProperty(name)){
224                                target[name] = source[name];
225                        }
226                }
227                if(has("bug-for-in-skips-shadowed")){
228                        for(var extraNames= lang._extraNames, i= extraNames.length; i;){
229                                name = extraNames[--i];
230                                if(name != cname && source.hasOwnProperty(name)){
231                                          target[name] = source[name];
232                                }
233                        }
234                }
235        }
236
237        // implementation of safe mixin function
238        function safeMixin(target, source){
239                // summary:
240                //              Mix in properties skipping a constructor and decorating functions
241                //              like it is done by declare().
242                // target: Object
243                //              Target object to accept new properties.
244                // source: Object
245                //              Source object for new properties.
246                // description:
247                //              This function is used to mix in properties like lang.mixin does,
248                //              but it skips a constructor property and decorates functions like
249                //              declare() does.
250                //
251                //              It is meant to be used with classes and objects produced with
252                //              declare. Functions mixed in with dojo.safeMixin can use
253                //              this.inherited() like normal methods.
254                //
255                //              This function is used to implement extend() method of a constructor
256                //              produced with declare().
257                //
258                // example:
259                //      |       var A = declare(null, {
260                //      |               m1: function(){
261                //      |                       console.log("A.m1");
262                //      |               },
263                //      |               m2: function(){
264                //      |                       console.log("A.m2");
265                //      |               }
266                //      |       });
267                //      |       var B = declare(A, {
268                //      |               m1: function(){
269                //      |                       this.inherited(arguments);
270                //      |                       console.log("B.m1");
271                //      |               }
272                //      |       });
273                //      |       B.extend({
274                //      |               m2: function(){
275                //      |                       this.inherited(arguments);
276                //      |                       console.log("B.m2");
277                //      |               }
278                //      |       });
279                //      |       var x = new B();
280                //      |       dojo.safeMixin(x, {
281                //      |               m1: function(){
282                //      |                       this.inherited(arguments);
283                //      |                       console.log("X.m1");
284                //      |               },
285                //      |               m2: function(){
286                //      |                       this.inherited(arguments);
287                //      |                       console.log("X.m2");
288                //      |               }
289                //      |       });
290                //      |       x.m2();
291                //      |       // prints:
292                //      |       // A.m1
293                //      |       // B.m1
294                //      |       // X.m1
295
296                var name, t;
297                // add props adding metadata for incoming functions skipping a constructor
298                for(name in source){
299                        t = source[name];
300                        if((t !== op[name] || !(name in op)) && name != cname){
301                                if(opts.call(t) == "[object Function]"){
302                                        // non-trivial function method => attach its name
303                                        t.nom = name;
304                                }
305                                target[name] = t;
306                        }
307                }
308                if(has("bug-for-in-skips-shadowed")){
309                        for(var extraNames= lang._extraNames, i= extraNames.length; i;){
310                                name = extraNames[--i];
311                                t = source[name];
312                                if((t !== op[name] || !(name in op)) && name != cname){
313                                        if(opts.call(t) == "[object Function]"){
314                                                // non-trivial function method => attach its name
315                                                  t.nom = name;
316                                        }
317                                        target[name] = t;
318                                }
319                        }
320                }
321                return target;
322        }
323
324        function extend(source){
325                declare.safeMixin(this.prototype, source);
326                return this;
327        }
328
329        function createSubclass(mixins, props){
330                return declare([this].concat(mixins), props || {});
331        }
332
333        // chained constructor compatible with the legacy declare()
334        function chainedConstructor(bases, ctorSpecial){
335                return function(){
336                        var a = arguments, args = a, a0 = a[0], f, i, m,
337                                l = bases.length, preArgs;
338
339                        if(!(this instanceof a.callee)){
340                                // not called via new, so force it
341                                return applyNew(a);
342                        }
343
344                        //this._inherited = {};
345                        // perform the shaman's rituals of the original declare()
346                        // 1) call two types of the preamble
347                        if(ctorSpecial && (a0 && a0.preamble || this.preamble)){
348                                // full blown ritual
349                                preArgs = new Array(bases.length);
350                                // prepare parameters
351                                preArgs[0] = a;
352                                for(i = 0;;){
353                                        // process the preamble of the 1st argument
354                                        a0 = a[0];
355                                        if(a0){
356                                                f = a0.preamble;
357                                                if(f){
358                                                        a = f.apply(this, a) || a;
359                                                }
360                                        }
361                                        // process the preamble of this class
362                                        f = bases[i].prototype;
363                                        f = f.hasOwnProperty("preamble") && f.preamble;
364                                        if(f){
365                                                a = f.apply(this, a) || a;
366                                        }
367                                        // one peculiarity of the preamble:
368                                        // it is called if it is not needed,
369                                        // e.g., there is no constructor to call
370                                        // let's watch for the last constructor
371                                        // (see ticket #9795)
372                                        if(++i == l){
373                                                break;
374                                        }
375                                        preArgs[i] = a;
376                                }
377                        }
378                        // 2) call all non-trivial constructors using prepared arguments
379                        for(i = l - 1; i >= 0; --i){
380                                f = bases[i];
381                                m = f._meta;
382                                f = m ? m.ctor : f;
383                                if(f){
384                                        f.apply(this, preArgs ? preArgs[i] : a);
385                                }
386                        }
387                        // 3) continue the original ritual: call the postscript
388                        f = this.postscript;
389                        if(f){
390                                f.apply(this, args);
391                        }
392                };
393        }
394
395
396        // chained constructor compatible with the legacy declare()
397        function singleConstructor(ctor, ctorSpecial){
398                return function(){
399                        var a = arguments, t = a, a0 = a[0], f;
400
401                        if(!(this instanceof a.callee)){
402                                // not called via new, so force it
403                                return applyNew(a);
404                        }
405
406                        //this._inherited = {};
407                        // perform the shaman's rituals of the original declare()
408                        // 1) call two types of the preamble
409                        if(ctorSpecial){
410                                // full blown ritual
411                                if(a0){
412                                        // process the preamble of the 1st argument
413                                        f = a0.preamble;
414                                        if(f){
415                                                t = f.apply(this, t) || t;
416                                        }
417                                }
418                                f = this.preamble;
419                                if(f){
420                                        // process the preamble of this class
421                                        f.apply(this, t);
422                                        // one peculiarity of the preamble:
423                                        // it is called even if it is not needed,
424                                        // e.g., there is no constructor to call
425                                        // let's watch for the last constructor
426                                        // (see ticket #9795)
427                                }
428                        }
429                        // 2) call a constructor
430                        if(ctor){
431                                ctor.apply(this, a);
432                        }
433                        // 3) continue the original ritual: call the postscript
434                        f = this.postscript;
435                        if(f){
436                                f.apply(this, a);
437                        }
438                };
439        }
440
441        // plain vanilla constructor (can use inherited() to call its base constructor)
442        function simpleConstructor(bases){
443                return function(){
444                        var a = arguments, i = 0, f, m;
445
446                        if(!(this instanceof a.callee)){
447                                // not called via new, so force it
448                                return applyNew(a);
449                        }
450
451                        //this._inherited = {};
452                        // perform the shaman's rituals of the original declare()
453                        // 1) do not call the preamble
454                        // 2) call the top constructor (it can use this.inherited())
455                        for(; f = bases[i]; ++i){ // intentional assignment
456                                m = f._meta;
457                                f = m ? m.ctor : f;
458                                if(f){
459                                        f.apply(this, a);
460                                        break;
461                                }
462                        }
463                        // 3) call the postscript
464                        f = this.postscript;
465                        if(f){
466                                f.apply(this, a);
467                        }
468                };
469        }
470
471        function chain(name, bases, reversed){
472                return function(){
473                        var b, m, f, i = 0, step = 1;
474                        if(reversed){
475                                i = bases.length - 1;
476                                step = -1;
477                        }
478                        for(; b = bases[i]; i += step){ // intentional assignment
479                                m = b._meta;
480                                f = (m ? m.hidden : b.prototype)[name];
481                                if(f){
482                                        f.apply(this, arguments);
483                                }
484                        }
485                };
486        }
487
488        // forceNew(ctor)
489        // return a new object that inherits from ctor.prototype but
490        // without actually running ctor on the object.
491        function forceNew(ctor){
492                // create object with correct prototype using a do-nothing
493                // constructor
494                xtor.prototype = ctor.prototype;
495                var t = new xtor;
496                xtor.prototype = null;  // clean up
497                return t;
498        }
499
500        // applyNew(args)
501        // just like 'new ctor()' except that the constructor and its arguments come
502        // from args, which must be an array or an arguments object
503        function applyNew(args){
504                // create an object with ctor's prototype but without
505                // calling ctor on it.
506                var ctor = args.callee, t = forceNew(ctor);
507                // execute the real constructor on the new object
508                ctor.apply(t, args);
509                return t;
510        }
511
512        function declare(className, superclass, props){
513                // summary:
514                //              Create a feature-rich constructor from compact notation.
515                // className: String?
516                //              The optional name of the constructor (loosely, a "class")
517                //              stored in the "declaredClass" property in the created prototype.
518                //              It will be used as a global name for a created constructor.
519                // superclass: Function|Function[]
520                //              May be null, a Function, or an Array of Functions. This argument
521                //              specifies a list of bases (the left-most one is the most deepest
522                //              base).
523                // props: Object
524                //              An object whose properties are copied to the created prototype.
525                //              Add an instance-initialization function by making it a property
526                //              named "constructor".
527                // returns: dojo/_base/declare.__DeclareCreatedObject
528                //              New constructor function.
529                // description:
530                //              Create a constructor using a compact notation for inheritance and
531                //              prototype extension.
532                //
533                //              Mixin ancestors provide a type of multiple inheritance.
534                //              Prototypes of mixin ancestors are copied to the new class:
535                //              changes to mixin prototypes will not affect classes to which
536                //              they have been mixed in.
537                //
538                //              Ancestors can be compound classes created by this version of
539                //              declare(). In complex cases all base classes are going to be
540                //              linearized according to C3 MRO algorithm
541                //              (see http://www.python.org/download/releases/2.3/mro/ for more
542                //              details).
543                //
544                //              "className" is cached in "declaredClass" property of the new class,
545                //              if it was supplied. The immediate super class will be cached in
546                //              "superclass" property of the new class.
547                //
548                //              Methods in "props" will be copied and modified: "nom" property
549                //              (the declared name of the method) will be added to all copied
550                //              functions to help identify them for the internal machinery. Be
551                //              very careful, while reusing methods: if you use the same
552                //              function under different names, it can produce errors in some
553                //              cases.
554                //
555                //              It is possible to use constructors created "manually" (without
556                //              declare()) as bases. They will be called as usual during the
557                //              creation of an instance, their methods will be chained, and even
558                //              called by "this.inherited()".
559                //
560                //              Special property "-chains-" governs how to chain methods. It is
561                //              a dictionary, which uses method names as keys, and hint strings
562                //              as values. If a hint string is "after", this method will be
563                //              called after methods of its base classes. If a hint string is
564                //              "before", this method will be called before methods of its base
565                //              classes.
566                //
567                //              If "constructor" is not mentioned in "-chains-" property, it will
568                //              be chained using the legacy mode: using "after" chaining,
569                //              calling preamble() method before each constructor, if available,
570                //              and calling postscript() after all constructors were executed.
571                //              If the hint is "after", it is chained as a regular method, but
572                //              postscript() will be called after the chain of constructors.
573                //              "constructor" cannot be chained "before", but it allows
574                //              a special hint string: "manual", which means that constructors
575                //              are not going to be chained in any way, and programmer will call
576                //              them manually using this.inherited(). In the latter case
577                //              postscript() will be called after the construction.
578                //
579                //              All chaining hints are "inherited" from base classes and
580                //              potentially can be overridden. Be very careful when overriding
581                //              hints! Make sure that all chained methods can work in a proposed
582                //              manner of chaining.
583                //
584                //              Once a method was chained, it is impossible to unchain it. The
585                //              only exception is "constructor". You don't need to define a
586                //              method in order to supply a chaining hint.
587                //
588                //              If a method is chained, it cannot use this.inherited() because
589                //              all other methods in the hierarchy will be called automatically.
590                //
591                //              Usually constructors and initializers of any kind are chained
592                //              using "after" and destructors of any kind are chained as
593                //              "before". Note that chaining assumes that chained methods do not
594                //              return any value: any returned value will be discarded.
595                //
596                // example:
597                //      |       declare("my.classes.bar", my.classes.foo, {
598                //      |               // properties to be added to the class prototype
599                //      |               someValue: 2,
600                //      |               // initialization function
601                //      |               constructor: function(){
602                //      |                       this.myComplicatedObject = new ReallyComplicatedObject();
603                //      |               },
604                //      |               // other functions
605                //      |               someMethod: function(){
606                //      |                       doStuff();
607                //      |               }
608                //      |       });
609                //
610                // example:
611                //      |       var MyBase = declare(null, {
612                //      |               // constructor, properties, and methods go here
613                //      |               // ...
614                //      |       });
615                //      |       var MyClass1 = declare(MyBase, {
616                //      |               // constructor, properties, and methods go here
617                //      |               // ...
618                //      |       });
619                //      |       var MyClass2 = declare(MyBase, {
620                //      |               // constructor, properties, and methods go here
621                //      |               // ...
622                //      |       });
623                //      |       var MyDiamond = declare([MyClass1, MyClass2], {
624                //      |               // constructor, properties, and methods go here
625                //      |               // ...
626                //      |       });
627                //
628                // example:
629                //      |       var F = function(){ console.log("raw constructor"); };
630                //      |       F.prototype.method = function(){
631                //      |               console.log("raw method");
632                //      |       };
633                //      |       var A = declare(F, {
634                //      |               constructor: function(){
635                //      |                       console.log("A.constructor");
636                //      |               },
637                //      |               method: function(){
638                //      |                       console.log("before calling F.method...");
639                //      |                       this.inherited(arguments);
640                //      |                       console.log("...back in A");
641                //      |               }
642                //      |       });
643                //      |       new A().method();
644                //      |       // will print:
645                //      |       // raw constructor
646                //      |       // A.constructor
647                //      |       // before calling F.method...
648                //      |       // raw method
649                //      |       // ...back in A
650                //
651                // example:
652                //      |       var A = declare(null, {
653                //      |               "-chains-": {
654                //      |                       destroy: "before"
655                //      |               }
656                //      |       });
657                //      |       var B = declare(A, {
658                //      |               constructor: function(){
659                //      |                       console.log("B.constructor");
660                //      |               },
661                //      |               destroy: function(){
662                //      |                       console.log("B.destroy");
663                //      |               }
664                //      |       });
665                //      |       var C = declare(B, {
666                //      |               constructor: function(){
667                //      |                       console.log("C.constructor");
668                //      |               },
669                //      |               destroy: function(){
670                //      |                       console.log("C.destroy");
671                //      |               }
672                //      |       });
673                //      |       new C().destroy();
674                //      |       // prints:
675                //      |       // B.constructor
676                //      |       // C.constructor
677                //      |       // C.destroy
678                //      |       // B.destroy
679                //
680                // example:
681                //      |       var A = declare(null, {
682                //      |               "-chains-": {
683                //      |                       constructor: "manual"
684                //      |               }
685                //      |       });
686                //      |       var B = declare(A, {
687                //      |               constructor: function(){
688                //      |                       // ...
689                //      |                       // call the base constructor with new parameters
690                //      |                       this.inherited(arguments, [1, 2, 3]);
691                //      |                       // ...
692                //      |               }
693                //      |       });
694                //
695                // example:
696                //      |       var A = declare(null, {
697                //      |               "-chains-": {
698                //      |                       m1: "before"
699                //      |               },
700                //      |               m1: function(){
701                //      |                       console.log("A.m1");
702                //      |               },
703                //      |               m2: function(){
704                //      |                       console.log("A.m2");
705                //      |               }
706                //      |       });
707                //      |       var B = declare(A, {
708                //      |               "-chains-": {
709                //      |                       m2: "after"
710                //      |               },
711                //      |               m1: function(){
712                //      |                       console.log("B.m1");
713                //      |               },
714                //      |               m2: function(){
715                //      |                       console.log("B.m2");
716                //      |               }
717                //      |       });
718                //      |       var x = new B();
719                //      |       x.m1();
720                //      |       // prints:
721                //      |       // B.m1
722                //      |       // A.m1
723                //      |       x.m2();
724                //      |       // prints:
725                //      |       // A.m2
726                //      |       // B.m2
727
728                // crack parameters
729                if(typeof className != "string"){
730                        props = superclass;
731                        superclass = className;
732                        className = "";
733                }
734                props = props || {};
735
736                var proto, i, t, ctor, name, bases, chains, mixins = 1, parents = superclass;
737
738                // build a prototype
739                if(opts.call(superclass) == "[object Array]"){
740                        // C3 MRO
741                        bases = c3mro(superclass, className);
742                        t = bases[0];
743                        mixins = bases.length - t;
744                        superclass = bases[mixins];
745                }else{
746                        bases = [0];
747                        if(superclass){
748                                if(opts.call(superclass) == "[object Function]"){
749                                        t = superclass._meta;
750                                        bases = bases.concat(t ? t.bases : superclass);
751                                }else{
752                                        err("base class is not a callable constructor.", className);
753                                }
754                        }else if(superclass !== null){
755                                err("unknown base class. Did you use dojo.require to pull it in?", className);
756                        }
757                }
758                if(superclass){
759                        for(i = mixins - 1;; --i){
760                                proto = forceNew(superclass);
761                                if(!i){
762                                        // stop if nothing to add (the last base)
763                                        break;
764                                }
765                                // mix in properties
766                                t = bases[i];
767                                (t._meta ? mixOwn : mix)(proto, t.prototype);
768                                // chain in new constructor
769                                ctor = new Function;
770                                ctor.superclass = superclass;
771                                ctor.prototype = proto;
772                                superclass = proto.constructor = ctor;
773                        }
774                }else{
775                        proto = {};
776                }
777                // add all properties
778                declare.safeMixin(proto, props);
779                // add constructor
780                t = props.constructor;
781                if(t !== op.constructor){
782                        t.nom = cname;
783                        proto.constructor = t;
784                }
785
786                // collect chains and flags
787                for(i = mixins - 1; i; --i){ // intentional assignment
788                        t = bases[i]._meta;
789                        if(t && t.chains){
790                                chains = mix(chains || {}, t.chains);
791                        }
792                }
793                if(proto["-chains-"]){
794                        chains = mix(chains || {}, proto["-chains-"]);
795                }
796
797                // build ctor
798                t = !chains || !chains.hasOwnProperty(cname);
799                bases[0] = ctor = (chains && chains.constructor === "manual") ? simpleConstructor(bases) :
800                        (bases.length == 1 ? singleConstructor(props.constructor, t) : chainedConstructor(bases, t));
801
802                // add meta information to the constructor
803                ctor._meta  = {bases: bases, hidden: props, chains: chains,
804                        parents: parents, ctor: props.constructor};
805                ctor.superclass = superclass && superclass.prototype;
806                ctor.extend = extend;
807                ctor.createSubclass = createSubclass;
808                ctor.prototype = proto;
809                proto.constructor = ctor;
810
811                // add "standard" methods to the prototype
812                proto.getInherited = getInherited;
813                proto.isInstanceOf = isInstanceOf;
814                proto.inherited    = inheritedImpl;
815                proto.__inherited  = inherited;
816
817                // add name if specified
818                if(className){
819                        proto.declaredClass = className;
820                        lang.setObject(className, ctor);
821                }
822
823                // build chains and add them to the prototype
824                if(chains){
825                        for(name in chains){
826                                if(proto[name] && typeof chains[name] == "string" && name != cname){
827                                        t = proto[name] = chain(name, bases, chains[name] === "after");
828                                        t.nom = name;
829                                }
830                        }
831                }
832                // chained methods do not return values
833                // no need to chain "invisible" functions
834
835                return ctor;    // Function
836        }
837
838        /*=====
839        declare.__DeclareCreatedObject = {
840                // summary:
841                //              dojo/_base/declare() returns a constructor `C`.   `new C()` returns an Object with the following
842                //              methods, in addition to the methods and properties specified via the arguments passed to declare().
843
844                inherited: function(name, args, newArgs){
845                        // summary:
846                        //              Calls a super method.
847                        // name: String?
848                        //              The optional method name. Should be the same as the caller's
849                        //              name. Usually "name" is specified in complex dynamic cases, when
850                        //              the calling method was dynamically added, undecorated by
851                        //              declare(), and it cannot be determined.
852                        // args: Arguments
853                        //              The caller supply this argument, which should be the original
854                        //              "arguments".
855                        // newArgs: Object?
856                        //              If "true", the found function will be returned without
857                        //              executing it.
858                        //              If Array, it will be used to call a super method. Otherwise
859                        //              "args" will be used.
860                        // returns:
861                        //              Whatever is returned by a super method, or a super method itself,
862                        //              if "true" was specified as newArgs.
863                        // description:
864                        //              This method is used inside method of classes produced with
865                        //              declare() to call a super method (next in the chain). It is
866                        //              used for manually controlled chaining. Consider using the regular
867                        //              chaining, because it is faster. Use "this.inherited()" only in
868                        //              complex cases.
869                        //
870                        //              This method cannot me called from automatically chained
871                        //              constructors including the case of a special (legacy)
872                        //              constructor chaining. It cannot be called from chained methods.
873                        //
874                        //              If "this.inherited()" cannot find the next-in-chain method, it
875                        //              does nothing and returns "undefined". The last method in chain
876                        //              can be a default method implemented in Object, which will be
877                        //              called last.
878                        //
879                        //              If "name" is specified, it is assumed that the method that
880                        //              received "args" is the parent method for this call. It is looked
881                        //              up in the chain list and if it is found the next-in-chain method
882                        //              is called. If it is not found, the first-in-chain method is
883                        //              called.
884                        //
885                        //              If "name" is not specified, it will be derived from the calling
886                        //              method (using a methoid property "nom").
887                        //
888                        // example:
889                        //      |       var B = declare(A, {
890                        //      |               method1: function(a, b, c){
891                        //      |                       this.inherited(arguments);
892                        //      |               },
893                        //      |               method2: function(a, b){
894                        //      |                       return this.inherited(arguments, [a + b]);
895                        //      |               }
896                        //      |       });
897                        //      |       // next method is not in the chain list because it is added
898                        //      |       // manually after the class was created.
899                        //      |       B.prototype.method3 = function(){
900                        //      |               console.log("This is a dynamically-added method.");
901                        //      |               this.inherited("method3", arguments);
902                        //      |       };
903                        // example:
904                        //      |       var B = declare(A, {
905                        //      |               method: function(a, b){
906                        //      |                       var super = this.inherited(arguments, true);
907                        //      |                       // ...
908                        //      |                       if(!super){
909                        //      |                               console.log("there is no super method");
910                        //      |                               return 0;
911                        //      |                       }
912                        //      |                       return super.apply(this, arguments);
913                        //      |               }
914                        //      |       });
915                        return  {};     // Object
916                },
917
918                getInherited: function(name, args){
919                        // summary:
920                        //              Returns a super method.
921                        // name: String?
922                        //              The optional method name. Should be the same as the caller's
923                        //              name. Usually "name" is specified in complex dynamic cases, when
924                        //              the calling method was dynamically added, undecorated by
925                        //              declare(), and it cannot be determined.
926                        // args: Arguments
927                        //              The caller supply this argument, which should be the original
928                        //              "arguments".
929                        // returns:
930                        //              Returns a super method (Function) or "undefined".
931                        // description:
932                        //              This method is a convenience method for "this.inherited()".
933                        //              It uses the same algorithm but instead of executing a super
934                        //              method, it returns it, or "undefined" if not found.
935                        //
936                        // example:
937                        //      |       var B = declare(A, {
938                        //      |               method: function(a, b){
939                        //      |                       var super = this.getInherited(arguments);
940                        //      |                       // ...
941                        //      |                       if(!super){
942                        //      |                               console.log("there is no super method");
943                        //      |                               return 0;
944                        //      |                       }
945                        //      |                       return super.apply(this, arguments);
946                        //      |               }
947                        //      |       });
948                        return  {};     // Object
949                },
950
951                isInstanceOf: function(cls){
952                        // summary:
953                        //              Checks the inheritance chain to see if it is inherited from this
954                        //              class.
955                        // cls: Function
956                        //              Class constructor.
957                        // returns:
958                        //              "true", if this object is inherited from this class, "false"
959                        //              otherwise.
960                        // description:
961                        //              This method is used with instances of classes produced with
962                        //              declare() to determine of they support a certain interface or
963                        //              not. It models "instanceof" operator.
964                        //
965                        // example:
966                        //      |       var A = declare(null, {
967                        //      |               // constructor, properties, and methods go here
968                        //      |               // ...
969                        //      |       });
970                        //      |       var B = declare(null, {
971                        //      |               // constructor, properties, and methods go here
972                        //      |               // ...
973                        //      |       });
974                        //      |       var C = declare([A, B], {
975                        //      |               // constructor, properties, and methods go here
976                        //      |               // ...
977                        //      |       });
978                        //      |       var D = declare(A, {
979                        //      |               // constructor, properties, and methods go here
980                        //      |               // ...
981                        //      |       });
982                        //      |
983                        //      |       var a = new A(), b = new B(), c = new C(), d = new D();
984                        //      |
985                        //      |       console.log(a.isInstanceOf(A)); // true
986                        //      |       console.log(b.isInstanceOf(A)); // false
987                        //      |       console.log(c.isInstanceOf(A)); // true
988                        //      |       console.log(d.isInstanceOf(A)); // true
989                        //      |
990                        //      |       console.log(a.isInstanceOf(B)); // false
991                        //      |       console.log(b.isInstanceOf(B)); // true
992                        //      |       console.log(c.isInstanceOf(B)); // true
993                        //      |       console.log(d.isInstanceOf(B)); // false
994                        //      |
995                        //      |       console.log(a.isInstanceOf(C)); // false
996                        //      |       console.log(b.isInstanceOf(C)); // false
997                        //      |       console.log(c.isInstanceOf(C)); // true
998                        //      |       console.log(d.isInstanceOf(C)); // false
999                        //      |
1000                        //      |       console.log(a.isInstanceOf(D)); // false
1001                        //      |       console.log(b.isInstanceOf(D)); // false
1002                        //      |       console.log(c.isInstanceOf(D)); // false
1003                        //      |       console.log(d.isInstanceOf(D)); // true
1004                        return  {};     // Object
1005                },
1006
1007                extend: function(source){
1008                        // summary:
1009                        //              Adds all properties and methods of source to constructor's
1010                        //              prototype, making them available to all instances created with
1011                        //              constructor. This method is specific to constructors created with
1012                        //              declare().
1013                        // source: Object
1014                        //              Source object which properties are going to be copied to the
1015                        //              constructor's prototype.
1016                        // description:
1017                        //              Adds source properties to the constructor's prototype. It can
1018                        //              override existing properties.
1019                        //
1020                        //              This method is similar to dojo.extend function, but it is specific
1021                        //              to constructors produced by declare(). It is implemented
1022                        //              using dojo.safeMixin, and it skips a constructor property,
1023                        //              and properly decorates copied functions.
1024                        //
1025                        // example:
1026                        //      |       var A = declare(null, {
1027                        //      |               m1: function(){},
1028                        //      |               s1: "Popokatepetl"
1029                        //      |       });
1030                        //      |       A.extend({
1031                        //      |               m1: function(){},
1032                        //      |               m2: function(){},
1033                        //      |               f1: true,
1034                        //      |               d1: 42
1035                        //      |       });
1036                },
1037               
1038                createSubclass: function(mixins, props){
1039                        // summary:
1040                        //              Create a subclass of the declared class from a list of base classes.
1041                        // mixins: Function[]
1042                        //              Specifies a list of bases (the left-most one is the most deepest
1043                        //              base).
1044                        // props: Object?
1045                        //              An optional object whose properties are copied to the created prototype.
1046                        // returns: dojo/_base/declare.__DeclareCreatedObject
1047                        //              New constructor function.
1048                        // description:
1049                        //              Create a constructor using a compact notation for inheritance and
1050                        //              prototype extension.
1051                        //
1052                        //              Mixin ancestors provide a type of multiple inheritance.
1053                        //              Prototypes of mixin ancestors are copied to the new class:
1054                        //              changes to mixin prototypes will not affect classes to which
1055                        //              they have been mixed in.
1056                        //
1057                        // example:
1058                        //      |       var A = declare(null, {
1059                        //      |               m1: function(){},
1060                        //      |               s1: "bar"
1061                        //      |       });
1062                        //      |       var B = declare(null, {
1063                        //      |               m2: function(){},
1064                        //      |               s2: "foo"
1065                        //      |       });
1066                        //      |       var C = declare(null, {
1067                        //      |       });
1068                        //      |       var D1 = A.createSubclass([B, C], {
1069                        //      |               m1: function(){},
1070                        //      |               d1: 42
1071                        //      |       });
1072                        //      |       var d1 = new D1();
1073                        //      |
1074                        //      |       // this is equivalent to:
1075                        //      |       var D2 = declare([A, B, C], {
1076                        //      |               m1: function(){},
1077                        //      |               d1: 42
1078                        //      |       });
1079                        //      |       var d2 = new D2();
1080                }
1081        };
1082        =====*/
1083
1084        // For back-compat, remove for 2.0
1085        dojo.safeMixin = declare.safeMixin = safeMixin;
1086        dojo.declare = declare;
1087
1088        return declare;
1089});
Note: See TracBrowser for help on using the repository browser.