declare.js 30 KB

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