cacert-testmgr/external/ZendFramework-1.9.5/externals/dojo/dojox/lang/oo/declare.js

248 lines
7.8 KiB
JavaScript
Raw Permalink Normal View History

dojo.provide("dojox.lang.oo.declare");
dojo.experimental("dojox.lang.oo.mixin");
// a copy of the version #7 (with makeDeclare() yet a drop-in replacement for dojo.declare())
(function(){
var d = dojo, oo = dojox.lang.oo, op = Object.prototype,
isF = d.isFunction, xtor = function(){}, extraNames, i,
each = function(a, f){ for(var i = 0, l = a.length; i < l; ++i){ f(a[i]); } },
error = function(cond, msg){ if(cond){ throw new Error("declare: " + msg); } },
mix = function(target, source, name){
var t = target[name], s = source[name];
return t !== s && s !== op[name] ? target[name] = s : 0;
},
mixName = function(target, source, name){
var t = mix(target, source, name);
if(isF(t)){ t.nom = name; }
},
mixer = function(target, source, mix){
for(var name in source){ mix(target, source, name); }
each(extraNames, function(name){ if(name in source) mix(target, source, name); });
},
collect = function(meta, base){
var m = base._meta, mb = meta.bases;
m && mb.push(m.bases);
mb.push(base);
};
for(i in {toString: 1}){ extraNames = []; break; }
extraNames = extraNames || ["hasOwnProperty", "valueOf", "isPrototypeOf",
"propertyIsEnumerable", "toLocaleString", "toString"];
oo.makeDeclare = function(before, after){
var chains = {constructor: "after"},
buildMethodList = function(meta, name){
var fs = [], mb = meta.bases, i, l, t, c, m, h;
for(i = 0, l = mb.length; i < l; ++i){
// the assignment on the next line is intentional
(t = (c = mb[i]) && (m = c._meta) && (h = m.hidden) ?
(name in h) && h[name] : c.prototype[name]) && fs.push(t);
}
// the assignment on the next line is intentional
(t = meta.hidden[name]) && fs.push(t);
// the next line works for inherited methods too
return chains[name] === "after" ? fs : fs.reverse();
},
inherited = function(name, args, a){
var c = this.constructor, m = c._meta, cache = c._cache, caller,
i, l, f, n, ch, s, x;
// crack arguments
if(typeof name != "string"){
a = args;
args = name;
name = "";
}
caller = inherited.caller;
n = caller.nom;
error(n && name && n !== name, "calling inherited() with a different name: " + name);
name = name || n;
ch = cache[name];
// get the cached method list
if(!ch){
error(!name, "can't deduce a name to call inherited()");
error(typeof chains[name] == "string", "chained method: " + name);
ch = cache[name] = buildMethodList(m, name);
}
// check the stack
do{
s = this._inherited, n = s.length - 1;
if(n >= 0){
x = s[n];
if(x.name === name && ch[x.pos] === caller && caller.caller === inherited){
break;
}
}
// find the caller
for(i = 0, l = ch.length; i < l && ch[i] !== caller; ++i);
if(i == l){
// the assignment on the next line is intentional
this[name] === caller && (i = -1) || error(1, "can't find the caller for inherited()");
}
// the assignment on the next line is intentional
s.push(x = {name: name, start: i, pos: i});
}while(false);
f = ch[++x.pos];
try{
return f ? f.apply(this, a || args) : undefined;
}finally{
x.start == --x.pos && s.pop();
}
};
before = before || [];
each(before, function(name){ chains[name] = "before"; });
after = after || [];
each(after, function(name){ chains[name] = "after"; });
return function(className, superclass, props){
var mixins, proto, i, l, t, f, ctor, hidden = {}, meta = {bases: []};
// crack parameters
if(typeof className != "string"){
props = superclass;
superclass = className;
className = "";
}
if(d.isArray(superclass)){
mixins = superclass;
superclass = mixins[0];
}
// build a prototype
if(superclass){
collect(meta, superclass);
if(mixins){
for(i = 1, l = mixins.length; i < l; ++i){
// the assignment on the next line is intentional
error(!(t = mixins[i]), "mixin #" + i + " is null");
collect(meta, t);
// delegation
xtor.prototype = superclass.prototype;
proto = new xtor;
mixer(proto, t.prototype, mix);
(ctor = function(){}).superclass = superclass;
ctor.prototype = proto;
superclass = proto.constructor = ctor;
}
}
// add props
xtor.prototype = superclass.prototype;
proto = new xtor;
}else{
proto = {};
}
// add props
// the assignment on the next line is intentional
mixer(proto, (meta.hidden = props || {}), mixName);
// flatten the base list and collect our chain instructions
meta.bases = meta.bases.concat.apply([], meta.bases);
// build chains and add them to the prototype
each(after.concat(before), function(name){
// the assignment on the next line is intentional
(proto[name] = function(){
var c = this.constructor, t = buildMethodList(c._meta, name), l = t.length,
f = function(){ for(var i = 0; i < l; ++i){ t[i].apply(this, arguments); } };
f.nom = name;
// the assignment on the next line is intentional
(c.prototype[name] = f).apply(this, arguments);
}).nom = name;
});
// add inherited to the prototype
proto.inherited = inherited;
// build ctor
t = buildMethodList(meta, "constructor");
ctor = function(){
this._inherited = [];
// perform the shaman's rituals of the original dojo.declare()
// 1) call two types of the preamble
var a = arguments, args = a, a0 = a[0], f, i, l;
// the assignment on the next line is intentional
a = a0 && (f = a0.preamble) && f.apply(this, a) || a;
// the assignment on the next line is intentional
a = (f = this.preamble) && f.apply(this, a) || a;
// 2) call the constructor with different parameters
for(i = 0, l = t.length - 1; i < l; ++i){
t[i].apply(this, a);
}
l >= 0 && t[i].apply(this, t[i] === ctor._meta.hidden.constructor ? args : a);
// 3) continue the original ritual: call the postscript
// the assignment on the next line is intentional
(f = this.postscript) && f.apply(this, args);
};
// build metadata on the constructor
ctor._meta = meta;
ctor._cache = {};
ctor.superclass = superclass && superclass.prototype;
proto.constructor = ctor;
ctor.prototype = proto;
// the assignment on the next line is intentional
className && d.setObject(proto.declaredClass = className, ctor);
return ctor; // Function
};
};
/*=====
// 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
// superclass: Function|Function[]:
// May be null, a Function, or an Array of Functions. If an array,
// the first element is used as the prototypical ancestor and
// any following Functions become mixin ancestors.
// props: Object:
// An object whose properties are copied to the created prototype.
// Add an instance-initialization function by making it a property
// named "constructor".
// 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.
//
// "className" is cached in "declaredClass" property of the new class.
//
// example:
// | dojox.lang.oo.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();
// | }
// | });
=====*/
oo.declare = oo.makeDeclare();
})();