]>
git.wh0rd.org - tt-rss.git/blob - lib/dojo/_base/declare.js.uncompressed.js
1 define("dojo/_base/declare", ["./kernel", "../has", "./lang"], function(dojo
, has
, lang
){
5 var mix
= lang
.mixin
, op
= Object
.prototype, opts
= op
.toString
,
6 xtor
= new Function
, counter
= 0, cname
= "constructor";
8 function err(msg
, cls
){ throw new Error("declare" + (cls
? " " + cls
: "") + ": " + msg
); }
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
;
15 // build a list of bases naming them if needed
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
);
23 lin
= base
._meta
? base
._meta
.bases
: [base
];
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
++);
31 name
= proto
.declaredClass
;
32 if(!nameMap
.hasOwnProperty(name
)){
33 nameMap
[name
] = {count
: 0, refs
: [], cls
: lin
[j
]};
37 if(top
&& top
!== rec
){
44 roots
[0].refs
.push(top
);
47 // remove classes without external references recursively
52 // optimization: follow a single-linked chain
53 while(refs
= top
.refs
, refs
.length
== 1){
55 if(!top
|| --top
.count
){
56 // branch or end of chain => do not end to roots
65 for(i
= 0, l
= refs
.length
; i
< l
; ++i
){
74 err("can't build consistent linearization", className
);
77 // calculate the superclass offset
80 base
._meta
&& base
=== result
[result
.length
- base
._meta
.bases
.length
] ?
81 base
._meta
.bases
.length
: 1 : 0;
86 function inherited(args
, a
, f
){
87 var name
, chains
, bases
, caller
, meta
, base
, proto
, opf
, pos
,
88 cache
= this._inherited
= this._inherited
|| {};
91 if(typeof args
== "string"){
99 name
= name
|| caller
.nom
;
101 err("can't deduce a name to call inherited()", this.declaredClass
);
104 meta
= this.constructor._meta
;
110 if(cache
.c
!== caller
){
115 if(meta
.hidden
[name
] !== caller
){
117 chains
= meta
.chains
;
118 if(chains
&& typeof chains
[name
] == "string"){
119 err("calling chained method with inherited: " + name
, this.declaredClass
);
124 proto
= base
.prototype;
125 if(meta
&& (proto
[name
] === caller
&& proto
.hasOwnProperty(name
) || meta
.hidden
[name
] === caller
)){
128 }while(base
= bases
[++pos
]); // intentional assignment
129 pos
= base
? pos
: -1;
135 proto
= base
.prototype;
136 if(base
._meta
&& proto
.hasOwnProperty(name
)){
141 proto
= base
.prototype;
143 if(f
&& (base
._meta
? proto
.hasOwnProperty(name
) : f
!== opf
)){
146 }while(base
= bases
[++pos
]); // intentional assignment
149 f
= base
&& f
|| op
[name
];
152 if(cache
.c
!== caller
){
155 meta
= bases
[0]._meta
;
156 if(meta
&& meta
.ctor
!== caller
){
158 chains
= meta
.chains
;
159 if(!chains
|| chains
.constructor !== "manual"){
160 err("calling chained constructor with inherited", this.declaredClass
);
163 while(base
= bases
[++pos
]){ // intentional assignment
165 if(meta
&& meta
.ctor
=== caller
){
169 pos
= base
? pos
: -1;
173 while(base
= bases
[++pos
]){ // intentional assignment
175 f
= meta
? meta
.ctor
: base
;
183 // cache the found super method
187 // now we have the result
189 return a
=== true ? f
: f
.apply(this, a
|| args
);
191 // intentionally no return if a super method was not found
194 function getInherited(name
, args
){
195 if(typeof name
== "string"){
196 return this.__inherited(name
, args
, true);
198 return this.__inherited(name
, true);
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
207 var inheritedImpl
= dojo
.config
.isDebug
? inherited__debug
: inherited
;
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
){
217 return this instanceof cls
;
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
];
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
];
237 // implementation of safe mixin function
238 function safeMixin(target
, source
){
240 // Mix in properties skipping a constructor and decorating functions
241 // like it is done by declare().
243 // Target object to accept new properties.
245 // Source object for new properties.
247 // This function is used to mix in properties like lang.mixin does,
248 // but it skips a constructor property and decorates functions like
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.
255 // This function is used to implement extend() method of a constructor
256 // produced with declare().
259 // | var A = declare(null, {
261 // | console.log("A.m1");
264 // | console.log("A.m2");
267 // | var B = declare(A, {
269 // | this.inherited(arguments);
270 // | console.log("B.m1");
275 // | this.inherited(arguments);
276 // | console.log("B.m2");
279 // | var x = new B();
280 // | dojo.safeMixin(x, {
282 // | this.inherited(arguments);
283 // | console.log("X.m1");
286 // | this.inherited(arguments);
287 // | console.log("X.m2");
297 // add props adding metadata for incoming functions skipping a constructor
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
308 if(has("bug-for-in-skips-shadowed")){
309 for(var extraNames
= lang
._extraNames
, i
= extraNames
.length
; i
;){
310 name
= extraNames
[--i
];
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
324 function extend(source
){
325 declare
.safeMixin(this.prototype, source
);
329 function createSubclass(mixins
){
330 return declare([this].concat(mixins
));
333 // chained constructor compatible with the legacy declare()
334 function chainedConstructor(bases
, ctorSpecial
){
336 var a
= arguments
, args
= a
, a0
= a
[0], f
, i
, m
,
337 l
= bases
.length
, preArgs
;
339 if(!(this instanceof a
.callee
)){
340 // not called via new, so force it
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
)){
349 preArgs
= new Array(bases
.length
);
350 // prepare parameters
353 // process the preamble of the 1st argument
358 a
= f
.apply(this, a
) || a
;
361 // process the preamble of this class
362 f
= bases
[i
].prototype;
363 f
= f
.hasOwnProperty("preamble") && f
.preamble
;
365 a
= f
.apply(this, a
) || a
;
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)
378 // 2) call all non-trivial constructors using prepared arguments
379 for(i
= l
- 1; i
>= 0; --i
){
384 f
.apply(this, preArgs
? preArgs
[i
] : a
);
387 // 3) continue the original ritual: call the postscript
396 // chained constructor compatible with the legacy declare()
397 function singleConstructor(ctor
, ctorSpecial
){
399 var a
= arguments
, t
= a
, a0
= a
[0], f
;
401 if(!(this instanceof a
.callee
)){
402 // not called via new, so force it
406 //this._inherited = {};
407 // perform the shaman's rituals of the original declare()
408 // 1) call two types of the preamble
412 // process the preamble of the 1st argument
415 t
= f
.apply(this, t
) || t
;
420 // process the preamble of this class
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)
429 // 2) call a constructor
433 // 3) continue the original ritual: call the postscript
441 // plain vanilla constructor (can use inherited() to call its base constructor)
442 function simpleConstructor(bases
){
444 var a
= arguments
, i
= 0, f
, m
;
446 if(!(this instanceof a
.callee
)){
447 // not called via new, so force it
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
463 // 3) call the postscript
471 function chain(name
, bases
, reversed
){
473 var b
, m
, f
, i
= 0, step
= 1;
475 i
= bases
.length
- 1;
478 for(; b
= bases
[i
]; i
+= step
){ // intentional assignment
480 f
= (m
? m
.hidden
: b
.prototype)[name
];
482 f
.apply(this, arguments
);
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
494 xtor
.prototype = ctor
.prototype;
496 xtor
.prototype = null; // clean up
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
512 function declare(className
, superclass
, props
){
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
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.
530 // Create a constructor using a compact notation for inheritance and
531 // prototype extension.
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.
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
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.
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
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()".
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
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.
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.
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.
588 // If a method is chained, it cannot use this.inherited() because
589 // all other methods in the hierarchy will be called automatically.
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.
597 // | declare("my.classes.bar", my.classes.foo, {
598 // | // properties to be added to the class prototype
600 // | // initialization function
601 // | constructor: function(){
602 // | this.myComplicatedObject = new ReallyComplicatedObject();
604 // | // other functions
605 // | someMethod: function(){
611 // | var MyBase = declare(null, {
612 // | // constructor, properties, and methods go here
615 // | var MyClass1 = declare(MyBase, {
616 // | // constructor, properties, and methods go here
619 // | var MyClass2 = declare(MyBase, {
620 // | // constructor, properties, and methods go here
623 // | var MyDiamond = declare([MyClass1, MyClass2], {
624 // | // constructor, properties, and methods go here
629 // | var F = function(){ console.log("raw constructor"); };
630 // | F.prototype.method = function(){
631 // | console.log("raw method");
633 // | var A = declare(F, {
634 // | constructor: function(){
635 // | console.log("A.constructor");
637 // | method: function(){
638 // | console.log("before calling F.method...");
639 // | this.inherited(arguments);
640 // | console.log("...back in A");
643 // | new A().method();
645 // | // raw constructor
646 // | // A.constructor
647 // | // before calling F.method...
652 // | var A = declare(null, {
654 // | destroy: "before"
657 // | var B = declare(A, {
658 // | constructor: function(){
659 // | console.log("B.constructor");
661 // | destroy: function(){
662 // | console.log("B.destroy");
665 // | var C = declare(B, {
666 // | constructor: function(){
667 // | console.log("C.constructor");
669 // | destroy: function(){
670 // | console.log("C.destroy");
673 // | new C().destroy();
675 // | // B.constructor
676 // | // C.constructor
681 // | var A = declare(null, {
683 // | constructor: "manual"
686 // | var B = declare(A, {
687 // | constructor: function(){
689 // | // call the base constructor with new parameters
690 // | this.inherited(arguments, [1, 2, 3]);
696 // | var A = declare(null, {
701 // | console.log("A.m1");
704 // | console.log("A.m2");
707 // | var B = declare(A, {
712 // | console.log("B.m1");
715 // | console.log("B.m2");
718 // | var x = new B();
729 if(typeof className
!= "string"){
731 superclass
= className
;
736 var proto
, i
, t
, ctor
, name
, bases
, chains
, mixins
= 1, parents
= superclass
;
739 if(opts
.call(superclass
) == "[object Array]"){
741 bases
= c3mro(superclass
, className
);
743 mixins
= bases
.length
- t
;
744 superclass
= bases
[mixins
];
748 if(opts
.call(superclass
) == "[object Function]"){
749 t
= superclass
._meta
;
750 bases
= bases
.concat(t
? t
.bases
: superclass
);
752 err("base class is not a callable constructor.", className
);
754 }else if(superclass
!== null){
755 err("unknown base class. Did you use dojo.require to pull it in?", className
);
759 for(i
= mixins
- 1;; --i
){
760 proto
= forceNew(superclass
);
762 // stop if nothing to add (the last base)
767 (t
._meta
? mixOwn
: mix
)(proto
, t
.prototype);
768 // chain in new constructor
770 ctor
.superclass
= superclass
;
771 ctor
.prototype = proto
;
772 superclass
= proto
.constructor = ctor
;
777 // add all properties
778 declare
.safeMixin(proto
, props
);
780 t
= props
.constructor;
781 if(t
!== op
.constructor){
783 proto
.constructor = t
;
786 // collect chains and flags
787 for(i
= mixins
- 1; i
; --i
){ // intentional assignment
790 chains
= mix(chains
|| {}, t
.chains
);
793 if(proto
["-chains-"]){
794 chains
= mix(chains
|| {}, proto
["-chains-"]);
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
));
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
;
811 // add "standard" methods to the prototype
812 proto
.getInherited
= getInherited
;
813 proto
.isInstanceOf
= isInstanceOf
;
814 proto
.inherited
= inheritedImpl
;
815 proto
.__inherited
= inherited
;
817 // add name if specified
819 proto
.declaredClass
= className
;
820 lang
.setObject(className
, ctor
);
823 // build chains and add them to the prototype
826 if(proto
[name
] && typeof chains
[name
] == "string" && name
!= cname
){
827 t
= proto
[name
] = chain(name
, bases
, chains
[name
] === "after");
832 // chained methods do not return values
833 // no need to chain "invisible" functions
835 return ctor
; // Function
839 declare.__DeclareCreatedObject = {
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().
844 inherited: function(name, args, newArgs){
846 // Calls a super method.
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.
853 // The caller supply this argument, which should be the original
856 // If "true", the found function will be returned without
858 // If Array, it will be used to call a super method. Otherwise
859 // "args" will be used.
861 // Whatever is returned by a super method, or a super method itself,
862 // if "true" was specified as newArgs.
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
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.
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
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
885 // If "name" is not specified, it will be derived from the calling
886 // method (using a methoid property "nom").
889 // | var B = declare(A, {
890 // | method1: function(a, b, c){
891 // | this.inherited(arguments);
893 // | method2: function(a, b){
894 // | return this.inherited(arguments, [a + b]);
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);
904 // | var B = declare(A, {
905 // | method: function(a, b){
906 // | var super = this.inherited(arguments, true);
909 // | console.log("there is no super method");
912 // | return super.apply(this, arguments);
918 getInherited: function(name, args){
920 // Returns a super method.
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.
927 // The caller supply this argument, which should be the original
930 // Returns a super method (Function) or "undefined".
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.
937 // | var B = declare(A, {
938 // | method: function(a, b){
939 // | var super = this.getInherited(arguments);
942 // | console.log("there is no super method");
945 // | return super.apply(this, arguments);
951 isInstanceOf: function(cls){
953 // Checks the inheritance chain to see if it is inherited from this
956 // Class constructor.
958 // "true", if this object is inherited from this class, "false"
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.
966 // | var A = declare(null, {
967 // | // constructor, properties, and methods go here
970 // | var B = declare(null, {
971 // | // constructor, properties, and methods go here
974 // | var C = declare([A, B], {
975 // | // constructor, properties, and methods go here
978 // | var D = declare(A, {
979 // | // constructor, properties, and methods go here
983 // | var a = new A(), b = new B(), c = new C(), d = new D();
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
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
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
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
1007 extend: function(source){
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
1014 // Source object which properties are going to be copied to the
1015 // constructor's prototype.
1017 // Adds source properties to the constructor's prototype. It can
1018 // override existing properties.
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.
1026 // | var A = declare(null, {
1027 // | m1: function(){},
1028 // | s1: "Popokatepetl"
1031 // | m1: function(){},
1032 // | m2: function(){},
1040 // For back-compat, remove for 2.0
1041 dojo
.safeMixin
= declare
.safeMixin
= safeMixin
;
1042 dojo
.declare
= declare
;