From a089699c8915636ba4f158d77dba9b012bc93208 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Fri, 4 Mar 2011 19:02:28 +0300 Subject: build custom layer of Dojo to speed up loading of tt-rss (refs #293) --- lib/dojo/_base/declare.js | 1445 ++++++++++++++++++++++++++++++++------------- 1 file changed, 1035 insertions(+), 410 deletions(-) (limited to 'lib/dojo/_base/declare.js') diff --git a/lib/dojo/_base/declare.js b/lib/dojo/_base/declare.js index f8ce201ec..8e46b12c0 100644 --- a/lib/dojo/_base/declare.js +++ b/lib/dojo/_base/declare.js @@ -5,419 +5,1044 @@ */ -if(!dojo._hasResource["dojo._base.declare"]){ -dojo._hasResource["dojo._base.declare"]=true; +if(!dojo._hasResource["dojo._base.declare"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojo._base.declare"] = true; dojo.provide("dojo._base.declare"); + dojo.require("dojo._base.lang"); dojo.require("dojo._base.array"); + (function(){ -var d=dojo,_1=d._mixin,op=Object.prototype,_2=op.toString,_3=new Function,_4=0,_5="constructor"; -function _6(_7){ -throw new Error("declare: "+_7); -}; -function _8(_9){ -var _a=[],_b=[{cls:0,refs:[]}],_c={},_d=1,l=_9.length,i=0,j,_e,_f,top,_10,rec,_11,_12; -for(;i=0;--j){ -_10=_e[j].prototype; -if(!_10.hasOwnProperty("declaredClass")){ -_10.declaredClass="uniqName_"+(_4++); -} -_11=_10.declaredClass; -if(!_c.hasOwnProperty(_11)){ -_c[_11]={count:0,refs:[],cls:_e[j]}; -++_d; -} -rec=_c[_11]; -if(top&&top!==rec){ -rec.refs.push(top); -++top.count; -} -top=rec; -} -++top.count; -_b[0].refs.push(top); -} -while(_b.length){ -top=_b.pop(); -_a.push(top.cls); ---_d; -while(_12=top.refs,_12.length==1){ -top=_12[0]; -if(!top||--top.count){ -top=0; -break; -} -_a.push(top.cls); ---_d; -} -if(top){ -for(i=0,l=_12.length;i=0;--i){ -f=_2d[i]; -m=f._meta; -f=m?m.ctor:f; -if(f){ -f.apply(this,_30?_30[i]:a); -} -} -f=this.postscript; -if(f){ -f.apply(this,_2f); -} -}; -}; -function _32(_33,_34){ -return function(){ -var a=arguments,t=a,a0=a[0],f; -if(!(this instanceof a.callee)){ -return _31(a); -} -if(_34){ -if(a0){ -f=a0.preamble; -if(f){ -t=f.apply(this,t)||t; -} -} -f=this.preamble; -if(f){ -f.apply(this,t); -} -} -if(_33){ -_33.apply(this,a); -} -f=this.postscript; -if(f){ -f.apply(this,a); -} -}; -}; -function _35(_36){ -return function(){ -var a=arguments,i=0,f,m; -if(!(this instanceof a.callee)){ -return _31(a); -} -for(;f=_36[i];++i){ -m=f._meta; -f=m?m.ctor:f; -if(f){ -f.apply(this,a); -break; -} -} -f=this.postscript; -if(f){ -f.apply(this,a); -} -}; -}; -function _37(_38,_39,_3a){ -return function(){ -var b,m,f,i=0,_3b=1; -if(_3a){ -i=_39.length-1; -_3b=-1; -} -for(;b=_39[i];i+=_3b){ -m=b._meta; -f=(m?m.hidden:b.prototype)[_38]; -if(f){ -f.apply(this,arguments); -} -} -}; -}; -function _3c(_3d){ -_3.prototype=_3d.prototype; -var t=new _3; -_3.prototype=null; -return t; -}; -function _31(_3e){ -var _3f=_3e.callee,t=_3c(_3f); -_3f.apply(t,_3e); -return t; -}; -d.declare=function(_40,_41,_42){ -if(typeof _40!="string"){ -_42=_41; -_41=_40; -_40=""; -} -_42=_42||{}; -var _43,i,t,_44,_45,_46,_47,_48=1,_49=_41; -if(_2.call(_41)=="[object Array]"){ -_46=_8(_41); -t=_46[0]; -_48=_46.length-t; -_41=_46[_48]; -}else{ -_46=[0]; -if(_41){ -if(_2.call(_41)=="[object Function]"){ -t=_41._meta; -_46=_46.concat(t?t.bases:_41); -}else{ -_6("base class is not a callable constructor."); -} -}else{ -if(_41!==null){ -_6("unknown base class. Did you use dojo.require to pull it in?"); -} -} -} -if(_41){ -for(i=_48-1;;--i){ -_43=_3c(_41); -if(!i){ -break; -} -t=_46[i]; -(t._meta?_22:_1)(_43,t.prototype); -_44=new Function; -_44.superclass=_41; -_44.prototype=_43; -_41=_43.constructor=_44; -} -}else{ -_43={}; -} -_26(_43,_42); -t=_42.constructor; -if(t!==op.constructor){ -t.nom=_5; -_43.constructor=t; -} -for(i=_48-1;i;--i){ -t=_46[i]._meta; -if(t&&t.chains){ -_47=_1(_47||{},t.chains); -} -} -if(_43["-chains-"]){ -_47=_1(_47||{},_43["-chains-"]); -} -t=!_47||!_47.hasOwnProperty(_5); -_46[0]=_44=(_47&&_47.constructor==="manual")?_35(_46):(_46.length==1?_32(_42.constructor,t):_2c(_46,t)); -_44._meta={bases:_46,hidden:_42,chains:_47,parents:_49,ctor:_42.constructor}; -_44.superclass=_41&&_41.prototype; -_44.extend=_2a; -_44.prototype=_43; -_43.constructor=_44; -_43.getInherited=_1d; -_43.inherited=_13; -_43.isInstanceOf=_20; -if(_40){ -_43.declaredClass=_40; -d.setObject(_40,_44); -} -if(_47){ -for(_45 in _47){ -if(_43[_45]&&typeof _47[_45]=="string"&&_45!=_5){ -t=_43[_45]=_37(_45,_46,_47[_45]==="after"); -t.nom=_45; -} -} -} -return _44; -}; -d.safeMixin=_26; + var d = dojo, mix = d._mixin, op = Object.prototype, opts = op.toString, + xtor = new Function, counter = 0, cname = "constructor"; + + function err(msg){ throw new Error("declare: " + msg); } + + // C3 Method Resolution Order (see http://www.python.org/download/releases/2.3/mro/) + function c3mro(bases){ + var result = [], roots = [{cls: 0, refs: []}], nameMap = {}, clsCount = 1, + l = bases.length, i = 0, j, lin, base, top, proto, rec, name, refs; + + // build a list of bases naming them if needed + for(; i < l; ++i){ + base = bases[i]; + if(!base){ + err("mixin #" + i + " is unknown. Did you use dojo.require to pull it in?"); + }else if(opts.call(base) != "[object Function]"){ + err("mixin #" + i + " is not a callable constructor."); + } + lin = base._meta ? base._meta.bases : [base]; + top = 0; + // add bases to the name map + for(j = lin.length - 1; j >= 0; --j){ + proto = lin[j].prototype; + if(!proto.hasOwnProperty("declaredClass")){ + proto.declaredClass = "uniqName_" + (counter++); + } + name = proto.declaredClass; + if(!nameMap.hasOwnProperty(name)){ + nameMap[name] = {count: 0, refs: [], cls: lin[j]}; + ++clsCount; + } + rec = nameMap[name]; + if(top && top !== rec){ + rec.refs.push(top); + ++top.count; + } + top = rec; + } + ++top.count; + roots[0].refs.push(top); + } + + // remove classes without external references recursively + while(roots.length){ + top = roots.pop(); + result.push(top.cls); + --clsCount; + // optimization: follow a single-linked chain + while(refs = top.refs, refs.length == 1){ + top = refs[0]; + if(!top || --top.count){ + // branch or end of chain => do not end to roots + top = 0; + break; + } + result.push(top.cls); + --clsCount; + } + if(top){ + // branch + for(i = 0, l = refs.length; i < l; ++i){ + top = refs[i]; + if(!--top.count){ + roots.push(top); + } + } + } + } + if(clsCount){ + err("can't build consistent linearization"); + } + + // calculate the superclass offset + base = bases[0]; + result[0] = base ? + base._meta && base === result[result.length - base._meta.bases.length] ? + base._meta.bases.length : 1 : 0; + + return result; + } + + function inherited(args, a, f){ + var name, chains, bases, caller, meta, base, proto, opf, pos, + cache = this._inherited = this._inherited || {}; + + // crack arguments + if(typeof args == "string"){ + name = args; + args = a; + a = f; + } + f = 0; + + caller = args.callee; + name = name || caller.nom; + if(!name){ + err("can't deduce a name to call inherited()"); + } + + meta = this.constructor._meta; + bases = meta.bases; + + pos = cache.p; + if(name != cname){ + // method + if(cache.c !== caller){ + // cache bust + pos = 0; + base = bases[0]; + meta = base._meta; + if(meta.hidden[name] !== caller){ + // error detection + chains = meta.chains; + if(chains && typeof chains[name] == "string"){ + err("calling chained method with inherited: " + name); + } + // find caller + do{ + meta = base._meta; + proto = base.prototype; + if(meta && (proto[name] === caller && proto.hasOwnProperty(name) || meta.hidden[name] === caller)){ + break; + } + }while(base = bases[++pos]); // intentional assignment + pos = base ? pos : -1; + } + } + // find next + base = bases[++pos]; + if(base){ + proto = base.prototype; + if(base._meta && proto.hasOwnProperty(name)){ + f = proto[name]; + }else{ + opf = op[name]; + do{ + proto = base.prototype; + f = proto[name]; + if(f && (base._meta ? proto.hasOwnProperty(name) : f !== opf)){ + break; + } + }while(base = bases[++pos]); // intentional assignment + } + } + f = base && f || op[name]; + }else{ + // constructor + if(cache.c !== caller){ + // cache bust + pos = 0; + meta = bases[0]._meta; + if(meta && meta.ctor !== caller){ + // error detection + chains = meta.chains; + if(!chains || chains.constructor !== "manual"){ + err("calling chained constructor with inherited"); + } + // find caller + while(base = bases[++pos]){ // intentional assignment + meta = base._meta; + if(meta && meta.ctor === caller){ + break; + } + } + pos = base ? pos : -1; + } + } + // find next + while(base = bases[++pos]){ // intentional assignment + meta = base._meta; + f = meta ? meta.ctor : base; + if(f){ + break; + } + } + f = base && f; + } + + // cache the found super method + cache.c = f; + cache.p = pos; + + // now we have the result + if(f){ + return a === true ? f : f.apply(this, a || args); + } + // intentionally if a super method was not found + } + + function getInherited(name, args){ + if(typeof name == "string"){ + return this.inherited(name, args, true); + } + return this.inherited(name, true); + } + + // emulation of "instanceof" + function isInstanceOf(cls){ + var bases = this.constructor._meta.bases; + for(var i = 0, l = bases.length; i < l; ++i){ + if(bases[i] === cls){ + return true; + } + } + return this instanceof cls; + } + + function mixOwn(target, source){ + var name, i = 0, l = d._extraNames.length; + // add props adding metadata for incoming functions skipping a constructor + for(name in source){ + if(name != cname && source.hasOwnProperty(name)){ + target[name] = source[name]; + } + } + // process unenumerable methods on IE + for(; i < l; ++i){ + name = d._extraNames[i]; + if(name != cname && source.hasOwnProperty(name)){ + target[name] = source[name]; + } + } + } + + // implementation of safe mixin function + function safeMixin(target, source){ + var name, t, i = 0, l = d._extraNames.length; + // add props adding metadata for incoming functions skipping a constructor + for(name in source){ + t = source[name]; + if((t !== op[name] || !(name in op)) && name != cname){ + if(opts.call(t) == "[object Function]"){ + // non-trivial function method => attach its name + t.nom = name; + } + target[name] = t; + } + } + // process unenumerable methods on IE + for(; i < l; ++i){ + name = d._extraNames[i]; + t = source[name]; + if((t !== op[name] || !(name in op)) && name != cname){ + if(opts.call(t) == "[object Function]"){ + // non-trivial function method => attach its name + t.nom = name; + } + target[name] = t; + } + } + return target; + } + + function extend(source){ + safeMixin(this.prototype, source); + return this; + } + + // chained constructor compatible with the legacy dojo.declare() + function chainedConstructor(bases, ctorSpecial){ + return function(){ + var a = arguments, args = a, a0 = a[0], f, i, m, + l = bases.length, preArgs; + + if(!(this instanceof a.callee)){ + // not called via new, so force it + return applyNew(a); + } + + //this._inherited = {}; + // perform the shaman's rituals of the original dojo.declare() + // 1) call two types of the preamble + if(ctorSpecial && (a0 && a0.preamble || this.preamble)){ + // full blown ritual + preArgs = new Array(bases.length); + // prepare parameters + preArgs[0] = a; + for(i = 0;;){ + // process the preamble of the 1st argument + a0 = a[0]; + if(a0){ + f = a0.preamble; + if(f){ + a = f.apply(this, a) || a; + } + } + // process the preamble of this class + f = bases[i].prototype; + f = f.hasOwnProperty("preamble") && f.preamble; + if(f){ + a = f.apply(this, a) || a; + } + // one peculiarity of the preamble: + // it is called if it is not needed, + // e.g., there is no constructor to call + // let's watch for the last constructor + // (see ticket #9795) + if(++i == l){ + break; + } + preArgs[i] = a; + } + } + // 2) call all non-trivial constructors using prepared arguments + for(i = l - 1; i >= 0; --i){ + f = bases[i]; + m = f._meta; + f = m ? m.ctor : f; + if(f){ + f.apply(this, preArgs ? preArgs[i] : a); + } + } + // 3) continue the original ritual: call the postscript + f = this.postscript; + if(f){ + f.apply(this, args); + } + }; + } + + + // chained constructor compatible with the legacy dojo.declare() + function singleConstructor(ctor, ctorSpecial){ + return function(){ + var a = arguments, t = a, a0 = a[0], f; + + if(!(this instanceof a.callee)){ + // not called via new, so force it + return applyNew(a); + } + + //this._inherited = {}; + // perform the shaman's rituals of the original dojo.declare() + // 1) call two types of the preamble + if(ctorSpecial){ + // full blown ritual + if(a0){ + // process the preamble of the 1st argument + f = a0.preamble; + if(f){ + t = f.apply(this, t) || t; + } + } + f = this.preamble; + if(f){ + // process the preamble of this class + f.apply(this, t); + // one peculiarity of the preamble: + // it is called even if it is not needed, + // e.g., there is no constructor to call + // let's watch for the last constructor + // (see ticket #9795) + } + } + // 2) call a constructor + if(ctor){ + ctor.apply(this, a); + } + // 3) continue the original ritual: call the postscript + f = this.postscript; + if(f){ + f.apply(this, a); + } + }; + } + + // plain vanilla constructor (can use inherited() to call its base constructor) + function simpleConstructor(bases){ + return function(){ + var a = arguments, i = 0, f, m; + + if(!(this instanceof a.callee)){ + // not called via new, so force it + return applyNew(a); + } + + //this._inherited = {}; + // perform the shaman's rituals of the original dojo.declare() + // 1) do not call the preamble + // 2) call the top constructor (it can use this.inherited()) + for(; f = bases[i]; ++i){ // intentional assignment + m = f._meta; + f = m ? m.ctor : f; + if(f){ + f.apply(this, a); + break; + } + } + // 3) call the postscript + f = this.postscript; + if(f){ + f.apply(this, a); + } + }; + } + + function chain(name, bases, reversed){ + return function(){ + var b, m, f, i = 0, step = 1; + if(reversed){ + i = bases.length - 1; + step = -1; + } + for(; b = bases[i]; i += step){ // intentional assignment + m = b._meta; + f = (m ? m.hidden : b.prototype)[name]; + if(f){ + f.apply(this, arguments); + } + } + }; + } + + // forceNew(ctor) + // return a new object that inherits from ctor.prototype but + // without actually running ctor on the object. + function forceNew(ctor){ + // create object with correct prototype using a do-nothing + // constructor + xtor.prototype = ctor.prototype; + var t = new xtor; + xtor.prototype = null; // clean up + return t; + } + + // applyNew(args) + // just like 'new ctor()' except that the constructor and its arguments come + // from args, which must be an array or an arguments object + function applyNew(args){ + // create an object with ctor's prototype but without + // calling ctor on it. + var ctor = args.callee, t = forceNew(ctor); + // execute the real constructor on the new object + ctor.apply(t, args); + return t; + } + + d.declare = function(className, superclass, props){ + // crack parameters + if(typeof className != "string"){ + props = superclass; + superclass = className; + className = ""; + } + props = props || {}; + + var proto, i, t, ctor, name, bases, chains, mixins = 1, parents = superclass; + + // build a prototype + if(opts.call(superclass) == "[object Array]"){ + // C3 MRO + bases = c3mro(superclass); + t = bases[0]; + mixins = bases.length - t; + superclass = bases[mixins]; + }else{ + bases = [0]; + if(superclass){ + if(opts.call(superclass) == "[object Function]"){ + t = superclass._meta; + bases = bases.concat(t ? t.bases : superclass); + }else{ + err("base class is not a callable constructor."); + } + }else if(superclass !== null){ + err("unknown base class. Did you use dojo.require to pull it in?") + } + } + if(superclass){ + for(i = mixins - 1;; --i){ + proto = forceNew(superclass); + if(!i){ + // stop if nothing to add (the last base) + break; + } + // mix in properties + t = bases[i]; + (t._meta ? mixOwn : mix)(proto, t.prototype); + // chain in new constructor + ctor = new Function; + ctor.superclass = superclass; + ctor.prototype = proto; + superclass = proto.constructor = ctor; + } + }else{ + proto = {}; + } + // add all properties + safeMixin(proto, props); + // add constructor + t = props.constructor; + if(t !== op.constructor){ + t.nom = cname; + proto.constructor = t; + } + + // collect chains and flags + for(i = mixins - 1; i; --i){ // intentional assignment + t = bases[i]._meta; + if(t && t.chains){ + chains = mix(chains || {}, t.chains); + } + } + if(proto["-chains-"]){ + chains = mix(chains || {}, proto["-chains-"]); + } + + // build ctor + t = !chains || !chains.hasOwnProperty(cname); + bases[0] = ctor = (chains && chains.constructor === "manual") ? simpleConstructor(bases) : + (bases.length == 1 ? singleConstructor(props.constructor, t) : chainedConstructor(bases, t)); + + // add meta information to the constructor + ctor._meta = {bases: bases, hidden: props, chains: chains, + parents: parents, ctor: props.constructor}; + ctor.superclass = superclass && superclass.prototype; + ctor.extend = extend; + ctor.prototype = proto; + proto.constructor = ctor; + + // add "standard" methods to the prototype + proto.getInherited = getInherited; + proto.inherited = inherited; + proto.isInstanceOf = isInstanceOf; + + // add name if specified + if(className){ + proto.declaredClass = className; + d.setObject(className, ctor); + } + + // build chains and add them to the prototype + if(chains){ + for(name in chains){ + if(proto[name] && typeof chains[name] == "string" && name != cname){ + t = proto[name] = chain(name, bases, chains[name] === "after"); + t.nom = name; + } + } + } + // chained methods do not return values + // no need to chain "invisible" functions + + return ctor; // Function + }; + + d.safeMixin = safeMixin; + + /*===== + dojo.declare = function(className, superclass, props){ + // summary: + // Create a feature-rich constructor from compact notation. + // className: String?: + // The optional name of the constructor (loosely, a "class") + // stored in the "declaredClass" property in the created prototype. + // It will be used as a global name for a created constructor. + // superclass: Function|Function[]: + // May be null, a Function, or an Array of Functions. This argument + // specifies a list of bases (the left-most one is the most deepest + // base). + // props: Object: + // An object whose properties are copied to the created prototype. + // Add an instance-initialization function by making it a property + // named "constructor". + // returns: + // New constructor function. + // description: + // Create a constructor using a compact notation for inheritance and + // prototype extension. + // + // Mixin ancestors provide a type of multiple inheritance. + // Prototypes of mixin ancestors are copied to the new class: + // changes to mixin prototypes will not affect classes to which + // they have been mixed in. + // + // Ancestors can be compound classes created by this version of + // dojo.declare. In complex cases all base classes are going to be + // linearized according to C3 MRO algorithm + // (see http://www.python.org/download/releases/2.3/mro/ for more + // details). + // + // "className" is cached in "declaredClass" property of the new class, + // if it was supplied. The immediate super class will be cached in + // "superclass" property of the new class. + // + // Methods in "props" will be copied and modified: "nom" property + // (the declared name of the method) will be added to all copied + // functions to help identify them for the internal machinery. Be + // very careful, while reusing methods: if you use the same + // function under different names, it can produce errors in some + // cases. + // + // It is possible to use constructors created "manually" (without + // dojo.declare) as bases. They will be called as usual during the + // creation of an instance, their methods will be chained, and even + // called by "this.inherited()". + // + // Special property "-chains-" governs how to chain methods. It is + // a dictionary, which uses method names as keys, and hint strings + // as values. If a hint string is "after", this method will be + // called after methods of its base classes. If a hint string is + // "before", this method will be called before methods of its base + // classes. + // + // If "constructor" is not mentioned in "-chains-" property, it will + // be chained using the legacy mode: using "after" chaining, + // calling preamble() method before each constructor, if available, + // and calling postscript() after all constructors were executed. + // If the hint is "after", it is chained as a regular method, but + // postscript() will be called after the chain of constructors. + // "constructor" cannot be chained "before", but it allows + // a special hint string: "manual", which means that constructors + // are not going to be chained in any way, and programmer will call + // them manually using this.inherited(). In the latter case + // postscript() will be called after the construction. + // + // All chaining hints are "inherited" from base classes and + // potentially can be overridden. Be very careful when overriding + // hints! Make sure that all chained methods can work in a proposed + // manner of chaining. + // + // Once a method was chained, it is impossible to unchain it. The + // only exception is "constructor". You don't need to define a + // method in order to supply a chaining hint. + // + // If a method is chained, it cannot use this.inherited() because + // all other methods in the hierarchy will be called automatically. + // + // Usually constructors and initializers of any kind are chained + // using "after" and destructors of any kind are chained as + // "before". Note that chaining assumes that chained methods do not + // return any value: any returned value will be discarded. + // + // example: + // | dojo.declare("my.classes.bar", my.classes.foo, { + // | // properties to be added to the class prototype + // | someValue: 2, + // | // initialization function + // | constructor: function(){ + // | this.myComplicatedObject = new ReallyComplicatedObject(); + // | }, + // | // other functions + // | someMethod: function(){ + // | doStuff(); + // | } + // | }); + // + // example: + // | var MyBase = dojo.declare(null, { + // | // constructor, properties, and methods go here + // | // ... + // | }); + // | var MyClass1 = dojo.declare(MyBase, { + // | // constructor, properties, and methods go here + // | // ... + // | }); + // | var MyClass2 = dojo.declare(MyBase, { + // | // constructor, properties, and methods go here + // | // ... + // | }); + // | var MyDiamond = dojo.declare([MyClass1, MyClass2], { + // | // constructor, properties, and methods go here + // | // ... + // | }); + // + // example: + // | var F = function(){ console.log("raw constructor"); }; + // | F.prototype.method = function(){ + // | console.log("raw method"); + // | }; + // | var A = dojo.declare(F, { + // | constructor: function(){ + // | console.log("A.constructor"); + // | }, + // | method: function(){ + // | console.log("before calling F.method..."); + // | this.inherited(arguments); + // | console.log("...back in A"); + // | } + // | }); + // | new A().method(); + // | // will print: + // | // raw constructor + // | // A.constructor + // | // before calling F.method... + // | // raw method + // | // ...back in A + // + // example: + // | var A = dojo.declare(null, { + // | "-chains-": { + // | destroy: "before" + // | } + // | }); + // | var B = dojo.declare(A, { + // | constructor: function(){ + // | console.log("B.constructor"); + // | }, + // | destroy: function(){ + // | console.log("B.destroy"); + // | } + // | }); + // | var C = dojo.declare(B, { + // | constructor: function(){ + // | console.log("C.constructor"); + // | }, + // | destroy: function(){ + // | console.log("C.destroy"); + // | } + // | }); + // | new C().destroy(); + // | // prints: + // | // B.constructor + // | // C.constructor + // | // C.destroy + // | // B.destroy + // + // example: + // | var A = dojo.declare(null, { + // | "-chains-": { + // | constructor: "manual" + // | } + // | }); + // | var B = dojo.declare(A, { + // | constructor: function(){ + // | // ... + // | // call the base constructor with new parameters + // | this.inherited(arguments, [1, 2, 3]); + // | // ... + // | } + // | }); + // + // example: + // | var A = dojo.declare(null, { + // | "-chains-": { + // | m1: "before" + // | }, + // | m1: function(){ + // | console.log("A.m1"); + // | }, + // | m2: function(){ + // | console.log("A.m2"); + // | } + // | }); + // | var B = dojo.declare(A, { + // | "-chains-": { + // | m2: "after" + // | }, + // | m1: function(){ + // | console.log("B.m1"); + // | }, + // | m2: function(){ + // | console.log("B.m2"); + // | } + // | }); + // | var x = new B(); + // | x.m1(); + // | // prints: + // | // B.m1 + // | // A.m1 + // | x.m2(); + // | // prints: + // | // A.m2 + // | // B.m2 + return new Function(); // Function + }; + =====*/ + + /*===== + dojo.safeMixin = function(target, source){ + // summary: + // Mix in properties skipping a constructor and decorating functions + // like it is done by dojo.declare. + // target: Object + // Target object to accept new properties. + // source: Object + // Source object for new properties. + // description: + // This function is used to mix in properties like dojo._mixin does, + // but it skips a constructor property and decorates functions like + // dojo.declare does. + // + // It is meant to be used with classes and objects produced with + // dojo.declare. Functions mixed in with dojo.safeMixin can use + // this.inherited() like normal methods. + // + // This function is used to implement extend() method of a constructor + // produced with dojo.declare(). + // + // example: + // | var A = dojo.declare(null, { + // | m1: function(){ + // | console.log("A.m1"); + // | }, + // | m2: function(){ + // | console.log("A.m2"); + // | } + // | }); + // | var B = dojo.declare(A, { + // | m1: function(){ + // | this.inherited(arguments); + // | console.log("B.m1"); + // | } + // | }); + // | B.extend({ + // | m2: function(){ + // | this.inherited(arguments); + // | console.log("B.m2"); + // | } + // | }); + // | var x = new B(); + // | dojo.safeMixin(x, { + // | m1: function(){ + // | this.inherited(arguments); + // | console.log("X.m1"); + // | }, + // | m2: function(){ + // | this.inherited(arguments); + // | console.log("X.m2"); + // | } + // | }); + // | x.m2(); + // | // prints: + // | // A.m1 + // | // B.m1 + // | // X.m1 + }; + =====*/ + + /*===== + Object.inherited = function(name, args, newArgs){ + // summary: + // Calls a super method. + // name: String? + // The optional method name. Should be the same as the caller's + // name. Usually "name" is specified in complex dynamic cases, when + // the calling method was dynamically added, undecorated by + // dojo.declare, and it cannot be determined. + // args: Arguments + // The caller supply this argument, which should be the original + // "arguments". + // newArgs: Object? + // If "true", the found function will be returned without + // executing it. + // If Array, it will be used to call a super method. Otherwise + // "args" will be used. + // returns: + // Whatever is returned by a super method, or a super method itself, + // if "true" was specified as newArgs. + // description: + // This method is used inside method of classes produced with + // dojo.declare to call a super method (next in the chain). It is + // used for manually controlled chaining. Consider using the regular + // chaining, because it is faster. Use "this.inherited()" only in + // complex cases. + // + // This method cannot me called from automatically chained + // constructors including the case of a special (legacy) + // constructor chaining. It cannot be called from chained methods. + // + // If "this.inherited()" cannot find the next-in-chain method, it + // does nothing and returns "undefined". The last method in chain + // can be a default method implemented in Object, which will be + // called last. + // + // If "name" is specified, it is assumed that the method that + // received "args" is the parent method for this call. It is looked + // up in the chain list and if it is found the next-in-chain method + // is called. If it is not found, the first-in-chain method is + // called. + // + // If "name" is not specified, it will be derived from the calling + // method (using a methoid property "nom"). + // + // example: + // | var B = dojo.declare(A, { + // | method1: function(a, b, c){ + // | this.inherited(arguments); + // | }, + // | method2: function(a, b){ + // | return this.inherited(arguments, [a + b]); + // | } + // | }); + // | // next method is not in the chain list because it is added + // | // manually after the class was created. + // | B.prototype.method3 = function(){ + // | console.log("This is a dynamically-added method."); + // | this.inherited("method3", arguments); + // | }; + // example: + // | var B = dojo.declare(A, { + // | method: function(a, b){ + // | var super = this.inherited(arguments, true); + // | // ... + // | if(!super){ + // | console.log("there is no super method"); + // | return 0; + // | } + // | return super.apply(this, arguments); + // | } + // | }); + return {}; // Object + } + =====*/ + + /*===== + Object.getInherited = function(name, args){ + // summary: + // Returns a super method. + // name: String? + // The optional method name. Should be the same as the caller's + // name. Usually "name" is specified in complex dynamic cases, when + // the calling method was dynamically added, undecorated by + // dojo.declare, and it cannot be determined. + // args: Arguments + // The caller supply this argument, which should be the original + // "arguments". + // returns: + // Returns a super method (Function) or "undefined". + // description: + // This method is a convenience method for "this.inherited()". + // It uses the same algorithm but instead of executing a super + // method, it returns it, or "undefined" if not found. + // + // example: + // | var B = dojo.declare(A, { + // | method: function(a, b){ + // | var super = this.getInherited(arguments); + // | // ... + // | if(!super){ + // | console.log("there is no super method"); + // | return 0; + // | } + // | return super.apply(this, arguments); + // | } + // | }); + return {}; // Object + } + =====*/ + + /*===== + Object.isInstanceOf = function(cls){ + // summary: + // Checks the inheritance chain to see if it is inherited from this + // class. + // cls: Function + // Class constructor. + // returns: + // "true", if this object is inherited from this class, "false" + // otherwise. + // description: + // This method is used with instances of classes produced with + // dojo.declare to determine of they support a certain interface or + // not. It models "instanceof" operator. + // + // example: + // | var A = dojo.declare(null, { + // | // constructor, properties, and methods go here + // | // ... + // | }); + // | var B = dojo.declare(null, { + // | // constructor, properties, and methods go here + // | // ... + // | }); + // | var C = dojo.declare([A, B], { + // | // constructor, properties, and methods go here + // | // ... + // | }); + // | var D = dojo.declare(A, { + // | // constructor, properties, and methods go here + // | // ... + // | }); + // | + // | var a = new A(), b = new B(), c = new C(), d = new D(); + // | + // | console.log(a.isInstanceOf(A)); // true + // | console.log(b.isInstanceOf(A)); // false + // | console.log(c.isInstanceOf(A)); // true + // | console.log(d.isInstanceOf(A)); // true + // | + // | console.log(a.isInstanceOf(B)); // false + // | console.log(b.isInstanceOf(B)); // true + // | console.log(c.isInstanceOf(B)); // true + // | console.log(d.isInstanceOf(B)); // false + // | + // | console.log(a.isInstanceOf(C)); // false + // | console.log(b.isInstanceOf(C)); // false + // | console.log(c.isInstanceOf(C)); // true + // | console.log(d.isInstanceOf(C)); // false + // | + // | console.log(a.isInstanceOf(D)); // false + // | console.log(b.isInstanceOf(D)); // false + // | console.log(c.isInstanceOf(D)); // false + // | console.log(d.isInstanceOf(D)); // true + return {}; // Object + } + =====*/ + + /*===== + Object.extend = function(source){ + // summary: + // Adds all properties and methods of source to constructor's + // prototype, making them available to all instances created with + // constructor. This method is specific to constructors created with + // dojo.declare. + // source: Object + // Source object which properties are going to be copied to the + // constructor's prototype. + // description: + // Adds source properties to the constructor's prototype. It can + // override existing properties. + // + // This method is similar to dojo.extend function, but it is specific + // to constructors produced by dojo.declare. It is implemented + // using dojo.safeMixin, and it skips a constructor property, + // and properly decorates copied functions. + // + // example: + // | var A = dojo.declare(null, { + // | m1: function(){}, + // | s1: "Popokatepetl" + // | }); + // | A.extend({ + // | m1: function(){}, + // | m2: function(){}, + // | f1: true, + // | d1: 42 + // | }); + }; + =====*/ })(); + } -- cgit v1.2.3