dojo/_base/declare.js

Maintainability

52.38

Lines of code

1098

Created with Raphaël 2.1.002550751002015-1-52014-12-42014-12-3

2015-5-18
Maintainability: 52.38

Created with Raphaël 2.1.005001,0001,5002,0002015-1-52014-12-42014-12-3

2015-5-18
Lines of Code: 1,098

Difficulty

153.63

Estimated Errors

5.01

Function weight

By Complexity

Created with Raphaël 2.1.0inherited32

By SLOC

Created with Raphaël 2.1.0<anonymous>1,098
define(["./kernel", "../has", "./lang"], function(dojo, has, lang){
1
define(["./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";
Column: 28 "The Function constructor is a form of eval."
Column: 20 "Missing '()' invoking a 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
Column: 47 "Expected a conditional expression and instead saw an 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
Column: 47 "Expected a conditional expression and instead saw an 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
Column: 46 "Expected a conditional expression and instead saw an 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
Column: 38 "Expected a conditional expression and instead saw an 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") && source){
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
        // crack parameters
331
        if(!(mixins instanceof Array || typeof mixins == 'function')){
332
            props = mixins;
333
            mixins = undefined;
334
        }
335
 
336
        props = props || {};
337
        mixins = mixins || [];
338
 
339
        return declare([this].concat(mixins), props);
340
    }
341
 
342
    // chained constructor compatible with the legacy declare()
343
    function chainedConstructor(bases, ctorSpecial){
344
        return function(){
345
            var a = arguments, args = a, a0 = a[0], f, i, m,
346
                l = bases.length, preArgs;
347
 
348
            if(!(this instanceof a.callee)){
349
                // not called via new, so force it
350
                return applyNew(a);
351
            }
352
 
353
            //this._inherited = {};
354
            // perform the shaman's rituals of the original declare()
355
            // 1) call two types of the preamble
356
            if(ctorSpecial && (a0 && a0.preamble || this.preamble)){
357
                // full blown ritual
358
                preArgs = new Array(bases.length);
359
                // prepare parameters
360
                preArgs[0] = a;
361
                for(i = 0;;){
362
                    // process the preamble of the 1st argument
363
                    a0 = a[0];
364
                    if(a0){
365
                        f = a0.preamble;
366
                        if(f){
367
                            a = f.apply(this, a) || a;
368
                        }
369
                    }
370
                    // process the preamble of this class
371
                    f = bases[i].prototype;
372
                    f = f.hasOwnProperty("preamble") && f.preamble;
373
                    if(f){
374
                        a = f.apply(this, a) || a;
375
                    }
376
                    // one peculiarity of the preamble:
377
                    // it is called if it is not needed,
378
                    // e.g., there is no constructor to call
379
                    // let's watch for the last constructor
380
                    // (see ticket #9795)
381
                    if(++i == l){
382
                        break;
383
                    }
384
                    preArgs[i] = a;
385
                }
386
            }
387
            // 2) call all non-trivial constructors using prepared arguments
388
            for(i = l - 1; i >= 0; --i){
389
                f = bases[i];
390
                m = f._meta;
391
                f = m ? m.ctor : f;
392
                if(f){
393
                    f.apply(this, preArgs ? preArgs[i] : a);
394
                }
395
            }
396
            // 3) continue the original ritual: call the postscript
397
            f = this.postscript;
398
            if(f){
399
                f.apply(this, args);
400
            }
401
        };
402
    }
403
 
404
 
405
    // chained constructor compatible with the legacy declare()
406
    function singleConstructor(ctor, ctorSpecial){
407
        return function(){
408
            var a = arguments, t = a, a0 = a[0], f;
409
 
410
            if(!(this instanceof a.callee)){
411
                // not called via new, so force it
412
                return applyNew(a);
413
            }
414
 
415
            //this._inherited = {};
416
            // perform the shaman's rituals of the original declare()
417
            // 1) call two types of the preamble
418
            if(ctorSpecial){
419
                // full blown ritual
420
                if(a0){
421
                    // process the preamble of the 1st argument
422
                    f = a0.preamble;
423
                    if(f){
424
                        t = f.apply(this, t) || t;
425
                    }
426
                }
427
                f = this.preamble;
428
                if(f){
429
                    // process the preamble of this class
430
                    f.apply(this, t);
431
                    // one peculiarity of the preamble:
432
                    // it is called even if it is not needed,
433
                    // e.g., there is no constructor to call
434
                    // let's watch for the last constructor
435
                    // (see ticket #9795)
436
                }
437
            }
438
            // 2) call a constructor
439
            if(ctor){
440
                ctor.apply(this, a);
441
            }
442
            // 3) continue the original ritual: call the postscript
443
            f = this.postscript;
444
            if(f){
445
                f.apply(this, a);
446
            }
447
        };
448
    }
449
 
450
    // plain vanilla constructor (can use inherited() to call its base constructor)
451
    function simpleConstructor(bases){
452
        return function(){
453
            var a = arguments, i = 0, f, m;
454
 
455
            if(!(this instanceof a.callee)){
456
                // not called via new, so force it
457
                return applyNew(a);
458
            }
459
 
460
            //this._inherited = {};
461
            // perform the shaman's rituals of the original declare()
462
            // 1) do not call the preamble
463
            // 2) call the top constructor (it can use this.inherited())
464
            for(; f = bases[i]; ++i){ // intentional assignment
Column: 31 "Expected a conditional expression and instead saw an assignment."
465
                m = f._meta;
466
                f = m ? m.ctor : f;
467
                if(f){
468
                    f.apply(this, a);
469
                    break;
470
                }
471
            }
472
            // 3) call the postscript
473
            f = this.postscript;
474
            if(f){
475
                f.apply(this, a);
476
            }
477
        };
478
    }
479
 
480
    function chain(name, bases, reversed){
481
        return function(){
482
            var b, m, f, i = 0, step = 1;
483
            if(reversed){
484
                i = bases.length - 1;
485
                step = -1;
486
            }
487
            for(; b = bases[i]; i += step){ // intentional assignment
Column: 31 "Expected a conditional expression and instead saw an assignment."
488
                m = b._meta;
489
                f = (m ? m.hidden : b.prototype)[name];
490
                if(f){
491
                    f.apply(this, arguments);
492
                }
493
            }
494
        };
495
    }
496
 
497
    // forceNew(ctor)
498
    // return a new object that inherits from ctor.prototype but
499
    // without actually running ctor on the object.
500
    function forceNew(ctor){
501
        // create object with correct prototype using a do-nothing
502
        // constructor
503
        xtor.prototype = ctor.prototype;
504
        var t = new xtor;
Column: 21 "Missing '()' invoking a constructor."
505
        xtor.prototype = null;  // clean up
506
        return t;
507
    }
508
 
509
    // applyNew(args)
510
    // just like 'new ctor()' except that the constructor and its arguments come
511
    // from args, which must be an array or an arguments object
512
    function applyNew(args){
513
        // create an object with ctor's prototype but without
514
        // calling ctor on it.
515
        var ctor = args.callee, t = forceNew(ctor);
516
        // execute the real constructor on the new object
517
        ctor.apply(t, args);
518
        return t;
519
    }
520
 
521
    function declare(className, superclass, props){
522
        // summary:
523
        //      Create a feature-rich constructor from compact notation.
524
        // className: String?
525
        //      The optional name of the constructor (loosely, a "class")
526
        //      stored in the "declaredClass" property in the created prototype.
527
        //      It will be used as a global name for a created constructor.
528
        // superclass: Function|Function[]
529
        //      May be null, a Function, or an Array of Functions. This argument
530
        //      specifies a list of bases (the left-most one is the most deepest
531
        //      base).
532
        // props: Object
533
        //      An object whose properties are copied to the created prototype.
534
        //      Add an instance-initialization function by making it a property
535
        //      named "constructor".
536
        // returns: dojo/_base/declare.__DeclareCreatedObject
537
        //      New constructor function.
538
        // description:
539
        //      Create a constructor using a compact notation for inheritance and
540
        //      prototype extension.
541
        //
542
        //      Mixin ancestors provide a type of multiple inheritance.
543
        //      Prototypes of mixin ancestors are copied to the new class:
544
        //      changes to mixin prototypes will not affect classes to which
545
        //      they have been mixed in.
546
        //
547
        //      Ancestors can be compound classes created by this version of
548
        //      declare(). In complex cases all base classes are going to be
549
        //      linearized according to C3 MRO algorithm
550
        //      (see http://www.python.org/download/releases/2.3/mro/ for more
551
        //      details).
552
        //
553
        //      "className" is cached in "declaredClass" property of the new class,
554
        //      if it was supplied. The immediate super class will be cached in
555
        //      "superclass" property of the new class.
556
        //
557
        //      Methods in "props" will be copied and modified: "nom" property
558
        //      (the declared name of the method) will be added to all copied
559
        //      functions to help identify them for the internal machinery. Be
560
        //      very careful, while reusing methods: if you use the same
561
        //      function under different names, it can produce errors in some
562
        //      cases.
563
        //
564
        //      It is possible to use constructors created "manually" (without
565
        //      declare()) as bases. They will be called as usual during the
566
        //      creation of an instance, their methods will be chained, and even
567
        //      called by "this.inherited()".
568
        //
569
        //      Special property "-chains-" governs how to chain methods. It is
570
        //      a dictionary, which uses method names as keys, and hint strings
571
        //      as values. If a hint string is "after", this method will be
572
        //      called after methods of its base classes. If a hint string is
573
        //      "before", this method will be called before methods of its base
574
        //      classes.
575
        //
576
        //      If "constructor" is not mentioned in "-chains-" property, it will
577
        //      be chained using the legacy mode: using "after" chaining,
578
        //      calling preamble() method before each constructor, if available,
579
        //      and calling postscript() after all constructors were executed.
580
        //      If the hint is "after", it is chained as a regular method, but
581
        //      postscript() will be called after the chain of constructors.
582
        //      "constructor" cannot be chained "before", but it allows
583
        //      a special hint string: "manual", which means that constructors
584
        //      are not going to be chained in any way, and programmer will call
585
        //      them manually using this.inherited(). In the latter case
586
        //      postscript() will be called after the construction.
587
        //
588
        //      All chaining hints are "inherited" from base classes and
589
        //      potentially can be overridden. Be very careful when overriding
590
        //      hints! Make sure that all chained methods can work in a proposed
591
        //      manner of chaining.
592
        //
593
        //      Once a method was chained, it is impossible to unchain it. The
594
        //      only exception is "constructor". You don't need to define a
595
        //      method in order to supply a chaining hint.
596
        //
597
        //      If a method is chained, it cannot use this.inherited() because
598
        //      all other methods in the hierarchy will be called automatically.
599
        //
600
        //      Usually constructors and initializers of any kind are chained
601
        //      using "after" and destructors of any kind are chained as
602
        //      "before". Note that chaining assumes that chained methods do not
603
        //      return any value: any returned value will be discarded.
604
        //
605
        // example:
606
        //  |   declare("my.classes.bar", my.classes.foo, {
607
        //  |       // properties to be added to the class prototype
608
        //  |       someValue: 2,
609
        //  |       // initialization function
610
        //  |       constructor: function(){
611
        //  |           this.myComplicatedObject = new ReallyComplicatedObject();
612
        //  |       },
613
        //  |       // other functions
614
        //  |       someMethod: function(){
615
        //  |           doStuff();
616
        //  |       }
617
        //  |   });
618
        //
619
        // example:
620
        //  |   var MyBase = declare(null, {
621
        //  |       // constructor, properties, and methods go here
622
        //  |       // ...
623
        //  |   });
624
        //  |   var MyClass1 = declare(MyBase, {
625
        //  |       // constructor, properties, and methods go here
626
        //  |       // ...
627
        //  |   });
628
        //  |   var MyClass2 = declare(MyBase, {
629
        //  |       // constructor, properties, and methods go here
630
        //  |       // ...
631
        //  |   });
632
        //  |   var MyDiamond = declare([MyClass1, MyClass2], {
633
        //  |       // constructor, properties, and methods go here
634
        //  |       // ...
635
        //  |   });
636
        //
637
        // example:
638
        //  |   var F = function(){ console.log("raw constructor"); };
639
        //  |   F.prototype.method = function(){
640
        //  |       console.log("raw method");
641
        //  |   };
642
        //  |   var A = declare(F, {
643
        //  |       constructor: function(){
644
        //  |           console.log("A.constructor");
645
        //  |       },
646
        //  |       method: function(){
647
        //  |           console.log("before calling F.method...");
648
        //  |           this.inherited(arguments);
649
        //  |           console.log("...back in A");
650
        //  |       }
651
        //  |   });
652
        //  |   new A().method();
653
        //  |   // will print:
654
        //  |   // raw constructor
655
        //  |   // A.constructor
656
        //  |   // before calling F.method...
657
        //  |   // raw method
658
        //  |   // ...back in A
659
        //
660
        // example:
661
        //  |   var A = declare(null, {
662
        //  |       "-chains-": {
663
        //  |           destroy: "before"
664
        //  |       }
665
        //  |   });
666
        //  |   var B = declare(A, {
667
        //  |       constructor: function(){
668
        //  |           console.log("B.constructor");
669
        //  |       },
670
        //  |       destroy: function(){
671
        //  |           console.log("B.destroy");
672
        //  |       }
673
        //  |   });
674
        //  |   var C = declare(B, {
675
        //  |       constructor: function(){
676
        //  |           console.log("C.constructor");
677
        //  |       },
678
        //  |       destroy: function(){
679
        //  |           console.log("C.destroy");
680
        //  |       }
681
        //  |   });
682
        //  |   new C().destroy();
683
        //  |   // prints:
684
        //  |   // B.constructor
685
        //  |   // C.constructor
686
        //  |   // C.destroy
687
        //  |   // B.destroy
688
        //
689
        // example:
690
        //  |   var A = declare(null, {
691
        //  |       "-chains-": {
692
        //  |           constructor: "manual"
693
        //  |       }
694
        //  |   });
695
        //  |   var B = declare(A, {
696
        //  |       constructor: function(){
697
        //  |           // ...
698
        //  |           // call the base constructor with new parameters
699
        //  |           this.inherited(arguments, [1, 2, 3]);
700
        //  |           // ...
701
        //  |       }
702
        //  |   });
703
        //
704
        // example:
705
        //  |   var A = declare(null, {
706
        //  |       "-chains-": {
707
        //  |           m1: "before"
708
        //  |       },
709
        //  |       m1: function(){
710
        //  |           console.log("A.m1");
711
        //  |       },
712
        //  |       m2: function(){
713
        //  |           console.log("A.m2");
714
        //  |       }
715
        //  |   });
716
        //  |   var B = declare(A, {
717
        //  |       "-chains-": {
718
        //  |           m2: "after"
719
        //  |       },
720
        //  |       m1: function(){
721
        //  |           console.log("B.m1");
722
        //  |       },
723
        //  |       m2: function(){
724
        //  |           console.log("B.m2");
725
        //  |       }
726
        //  |   });
727
        //  |   var x = new B();
728
        //  |   x.m1();
729
        //  |   // prints:
730
        //  |   // B.m1
731
        //  |   // A.m1
732
        //  |   x.m2();
733
        //  |   // prints:
734
        //  |   // A.m2
735
        //  |   // B.m2
736
 
737
        // crack parameters
738
        if(typeof className != "string"){
739
            props = superclass;
740
            superclass = className;
741
            className = "";
742
        }
743
        props = props || {};
744
 
745
        var proto, i, t, ctor, name, bases, chains, mixins = 1, parents = superclass;
746
 
747
        // build a prototype
748
        if(opts.call(superclass) == "[object Array]"){
749
            // C3 MRO
750
            bases = c3mro(superclass, className);
751
            t = bases[0];
752
            mixins = bases.length - t;
753
            superclass = bases[mixins];
754
        }else{
755
            bases = [0];
756
            if(superclass){
757
                if(opts.call(superclass) == "[object Function]"){
758
                    t = superclass._meta;
759
                    bases = bases.concat(t ? t.bases : superclass);
760
                }else{
761
                    err("base class is not a callable constructor.", className);
762
                }
763
            }else if(superclass !== null){
764
                err("unknown base class. Did you use dojo.require to pull it in?", className);
765
            }
766
        }
767
        if(superclass){
768
            for(i = mixins - 1;; --i){
769
                proto = forceNew(superclass);
770
                if(!i){
771
                    // stop if nothing to add (the last base)
772
                    break;
773
                }
774
                // mix in properties
775
                t = bases[i];
776
                (t._meta ? mixOwn : mix)(proto, t.prototype);
777
                // chain in new constructor
778
                ctor = new Function;
Column: 36 "The Function constructor is a form of eval."
Column: 28 "Missing '()' invoking a constructor."
779
                ctor.superclass = superclass;
780
                ctor.prototype = proto;
781
                superclass = proto.constructor = ctor;
782
            }
783
        }else{
784
            proto = {};
785
        }
786
        // add all properties
787
        declare.safeMixin(proto, props);
788
        // add constructor
789
        t = props.constructor;
790
        if(t !== op.constructor){
791
            t.nom = cname;
792
            proto.constructor = t;
793
        }
794
 
795
        // collect chains and flags
796
        for(i = mixins - 1; i; --i){ // intentional assignment
797
            t = bases[i]._meta;
798
            if(t && t.chains){
799
                chains = mix(chains || {}, t.chains);
800
            }
801
        }
802
        if(proto["-chains-"]){
803
            chains = mix(chains || {}, proto["-chains-"]);
804
        }
805
 
806
        // build ctor
807
        t = !chains || !chains.hasOwnProperty(cname);
808
        bases[0] = ctor = (chains && chains.constructor === "manual") ? simpleConstructor(bases) :
809
            (bases.length == 1 ? singleConstructor(props.constructor, t) : chainedConstructor(bases, t));
810
 
811
        // add meta information to the constructor
812
        ctor._meta  = {bases: bases, hidden: props, chains: chains,
813
            parents: parents, ctor: props.constructor};
814
        ctor.superclass = superclass && superclass.prototype;
815
        ctor.extend = extend;
816
        ctor.createSubclass = createSubclass;
817
        ctor.prototype = proto;
818
        proto.constructor = ctor;
819
 
820
        // add "standard" methods to the prototype
821
        proto.getInherited = getInherited;
822
        proto.isInstanceOf = isInstanceOf;
823
        proto.inherited    = inheritedImpl;
824
        proto.__inherited  = inherited;
825
 
826
        // add name if specified
827
        if(className){
828
            proto.declaredClass = className;
829
            lang.setObject(className, ctor);
830
        }
831
 
832
        // build chains and add them to the prototype
833
        if(chains){
834
            for(name in chains){
835
                if(proto[name] && typeof chains[name] == "string" && name != cname){
836
                    t = proto[name] = chain(name, bases, chains[name] === "after");
837
                    t.nom = name;
838
                }
839
            }
840
        }
841
        // chained methods do not return values
842
        // no need to chain "invisible" functions
843
 
844
        return ctor;    // Function
845
    }
846
 
847
    /*=====
848
    declare.__DeclareCreatedObject = {
849
        // summary:
850
        //      dojo/_base/declare() returns a constructor `C`.   `new C()` returns an Object with the following
851
        //      methods, in addition to the methods and properties specified via the arguments passed to declare().
852
 
853
        inherited: function(name, args, newArgs){
854
            // summary:
855
            //      Calls a super method.
856
            // name: String?
857
            //      The optional method name. Should be the same as the caller's
858
            //      name. Usually "name" is specified in complex dynamic cases, when
859
            //      the calling method was dynamically added, undecorated by
860
            //      declare(), and it cannot be determined.
861
            // args: Arguments
862
            //      The caller supply this argument, which should be the original
863
            //      "arguments".
864
            // newArgs: Object?
865
            //      If "true", the found function will be returned without
866
            //      executing it.
867
            //      If Array, it will be used to call a super method. Otherwise
868
            //      "args" will be used.
869
            // returns:
870
            //      Whatever is returned by a super method, or a super method itself,
871
            //      if "true" was specified as newArgs.
872
            // description:
873
            //      This method is used inside method of classes produced with
874
            //      declare() to call a super method (next in the chain). It is
875
            //      used for manually controlled chaining. Consider using the regular
876
            //      chaining, because it is faster. Use "this.inherited()" only in
877
            //      complex cases.
878
            //
879
            //      This method cannot me called from automatically chained
880
            //      constructors including the case of a special (legacy)
881
            //      constructor chaining. It cannot be called from chained methods.
882
            //
883
            //      If "this.inherited()" cannot find the next-in-chain method, it
884
            //      does nothing and returns "undefined". The last method in chain
885
            //      can be a default method implemented in Object, which will be
886
            //      called last.
887
            //
888
            //      If "name" is specified, it is assumed that the method that
889
            //      received "args" is the parent method for this call. It is looked
890
            //      up in the chain list and if it is found the next-in-chain method
891
            //      is called. If it is not found, the first-in-chain method is
892
            //      called.
893
            //
894
            //      If "name" is not specified, it will be derived from the calling
895
            //      method (using a methoid property "nom").
896
            //
897
            // example:
898
            //  |   var B = declare(A, {
899
            //  |       method1: function(a, b, c){
900
            //  |           this.inherited(arguments);
901
            //  |       },
902
            //  |       method2: function(a, b){
903
            //  |           return this.inherited(arguments, [a + b]);
904
            //  |       }
905
            //  |   });
906
            //  |   // next method is not in the chain list because it is added
907
            //  |   // manually after the class was created.
908
            //  |   B.prototype.method3 = function(){
909
            //  |       console.log("This is a dynamically-added method.");
910
            //  |       this.inherited("method3", arguments);
911
            //  |   };
912
            // example:
913
            //  |   var B = declare(A, {
914
            //  |       method: function(a, b){
915
            //  |           var super = this.inherited(arguments, true);
916
            //  |           // ...
917
            //  |           if(!super){
918
            //  |               console.log("there is no super method");
919
            //  |               return 0;
920
            //  |           }
921
            //  |           return super.apply(this, arguments);
922
            //  |       }
923
            //  |   });
924
            return  {}; // Object
925
        },
926
 
927
        getInherited: function(name, args){
928
            // summary:
929
            //      Returns a super method.
930
            // name: String?
931
            //      The optional method name. Should be the same as the caller's
932
            //      name. Usually "name" is specified in complex dynamic cases, when
933
            //      the calling method was dynamically added, undecorated by
934
            //      declare(), and it cannot be determined.
935
            // args: Arguments
936
            //      The caller supply this argument, which should be the original
937
            //      "arguments".
938
            // returns:
939
            //      Returns a super method (Function) or "undefined".
940
            // description:
941
            //      This method is a convenience method for "this.inherited()".
942
            //      It uses the same algorithm but instead of executing a super
943
            //      method, it returns it, or "undefined" if not found.
944
            //
945
            // example:
946
            //  |   var B = declare(A, {
947
            //  |       method: function(a, b){
948
            //  |           var super = this.getInherited(arguments);
949
            //  |           // ...
950
            //  |           if(!super){
951
            //  |               console.log("there is no super method");
952
            //  |               return 0;
953
            //  |           }
954
            //  |           return super.apply(this, arguments);
955
            //  |       }
956
            //  |   });
957
            return  {}; // Object
958
        },
959
 
960
        isInstanceOf: function(cls){
961
            // summary:
962
            //      Checks the inheritance chain to see if it is inherited from this
963
            //      class.
964
            // cls: Function
965
            //      Class constructor.
966
            // returns:
967
            //      "true", if this object is inherited from this class, "false"
968
            //      otherwise.
969
            // description:
970
            //      This method is used with instances of classes produced with
971
            //      declare() to determine of they support a certain interface or
972
            //      not. It models "instanceof" operator.
973
            //
974
            // example:
975
            //  |   var A = declare(null, {
976
            //  |       // constructor, properties, and methods go here
977
            //  |       // ...
978
            //  |   });
979
            //  |   var B = declare(null, {
980
            //  |       // constructor, properties, and methods go here
981
            //  |       // ...
982
            //  |   });
983
            //  |   var C = declare([A, B], {
984
            //  |       // constructor, properties, and methods go here
985
            //  |       // ...
986
            //  |   });
987
            //  |   var D = declare(A, {
988
            //  |       // constructor, properties, and methods go here
989
            //  |       // ...
990
            //  |   });
991
            //  |
992
            //  |   var a = new A(), b = new B(), c = new C(), d = new D();
993
            //  |
994
            //  |   console.log(a.isInstanceOf(A)); // true
995
            //  |   console.log(b.isInstanceOf(A)); // false
996
            //  |   console.log(c.isInstanceOf(A)); // true
997
            //  |   console.log(d.isInstanceOf(A)); // true
998
            //  |
999
            //  |   console.log(a.isInstanceOf(B)); // false
1000
            //  |   console.log(b.isInstanceOf(B)); // true
1001
            //  |   console.log(c.isInstanceOf(B)); // true
1002
            //  |   console.log(d.isInstanceOf(B)); // false
1003
            //  |
1004
            //  |   console.log(a.isInstanceOf(C)); // false
1005
            //  |   console.log(b.isInstanceOf(C)); // false
1006
            //  |   console.log(c.isInstanceOf(C)); // true
1007
            //  |   console.log(d.isInstanceOf(C)); // false
1008
            //  |
1009
            //  |   console.log(a.isInstanceOf(D)); // false
1010
            //  |   console.log(b.isInstanceOf(D)); // false
1011
            //  |   console.log(c.isInstanceOf(D)); // false
1012
            //  |   console.log(d.isInstanceOf(D)); // true
1013
            return  {}; // Object
1014
        },
1015
 
1016
        extend: function(source){
1017
            // summary:
1018
            //      Adds all properties and methods of source to constructor's
1019
            //      prototype, making them available to all instances created with
1020
            //      constructor. This method is specific to constructors created with
1021
            //      declare().
1022
            // source: Object
1023
            //      Source object which properties are going to be copied to the
1024
            //      constructor's prototype.
1025
            // description:
1026
            //      Adds source properties to the constructor's prototype. It can
1027
            //      override existing properties.
1028
            //
1029
            //      This method is similar to dojo.extend function, but it is specific
1030
            //      to constructors produced by declare(). It is implemented
1031
            //      using dojo.safeMixin, and it skips a constructor property,
1032
            //      and properly decorates copied functions.
1033
            //
1034
            // example:
1035
            //  |   var A = declare(null, {
1036
            //  |       m1: function(){},
1037
            //  |       s1: "Popokatepetl"
1038
            //  |   });
1039
            //  |   A.extend({
1040
            //  |       m1: function(){},
1041
            //  |       m2: function(){},
1042
            //  |       f1: true,
1043
            //  |       d1: 42
1044
            //  |   });
1045
        },
1046
 
1047
        createSubclass: function(mixins, props){
1048
            // summary:
1049
            //      Create a subclass of the declared class from a list of base classes.
1050
            // mixins: Function[]
1051
            //      Specifies a list of bases (the left-most one is the most deepest
1052
            //      base).
1053
            // props: Object?
1054
            //      An optional object whose properties are copied to the created prototype.
1055
            // returns: dojo/_base/declare.__DeclareCreatedObject
1056
            //      New constructor function.
1057
            // description:
1058
            //      Create a constructor using a compact notation for inheritance and
1059
            //      prototype extension.
1060
            //
1061
            //      Mixin ancestors provide a type of multiple inheritance.
1062
            //      Prototypes of mixin ancestors are copied to the new class:
1063
            //      changes to mixin prototypes will not affect classes to which
1064
            //      they have been mixed in.
1065
            //
1066
            // example:
1067
            //  |   var A = declare(null, {
1068
            //  |       m1: function(){},
1069
            //  |       s1: "bar"
1070
            //  |   });
1071
            //  |   var B = declare(null, {
1072
            //  |       m2: function(){},
1073
            //  |       s2: "foo"
1074
            //  |   });
1075
            //  |   var C = declare(null, {
1076
            //  |   });
1077
            //  |   var D1 = A.createSubclass([B, C], {
1078
            //  |       m1: function(){},
1079
            //  |       d1: 42
1080
            //  |   });
1081
            //  |   var d1 = new D1();
1082
            //  |
1083
            //  |   // this is equivalent to:
1084
            //  |   var D2 = declare([A, B, C], {
1085
            //  |       m1: function(){},
1086
            //  |       d1: 42
1087
            //  |   });
1088
            //  |   var d2 = new D2();
1089
        }
1090
    };
1091
    =====*/
1092
 
1093
    // For back-compat, remove for 2.0
1094
    dojo.safeMixin = declare.safeMixin = safeMixin;
1095
    dojo.declare = declare;
1096
 
1097
    return declare;
1098
});