declare.js 32 KB

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