declare.js 30 KB

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