Subversion Repositories Applications.papyrus

Rev

Blame | Last modification | View Log | RSS feed

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");

// this file courtesy of the TurboAjax group, licensed under a Dojo CLA

dojo.declare = function(/*String*/ className, /*Function|Function[]*/ superclass, /*Object*/ props){
        //      summary: 
        //              Create a feature-rich constructor from compact notation
        //      className:
        //              The name of the constructor (loosely, a "class")
        //              stored in the "declaredClass" property in the created prototype
        //      superclass:
        //              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:
        //              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. 
        //
        //              All superclasses (including mixins) must be Functions (not simple Objects).
        //
        //              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:
        //      |       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(); 
        //      |               }
        //      |       );

        // argument juggling (deprecated)
        if(dojo.isFunction(props)||(arguments.length>3)){ 
                dojo.deprecated("dojo.declare: for class '" + className + "' pass initializer function as 'constructor' property instead of as a separate argument.", "", "1.0");
                var c = props;
                props = arguments[3] || {};
                props.constructor = c;
        }
        // process superclass argument
        // var dd=dojo.declare, mixins=null;
        var dd=arguments.callee, mixins=null;
        if(dojo.isArray(superclass)){
                mixins = superclass;
                superclass = mixins.shift();
        }
        // construct intermediate classes for mixins
        if(mixins){
                for(var i=0, m; i<mixins.length; i++){
                        m = mixins[i];
                        if(!m){throw("Mixin #" + i + " to declaration of " + className + " is null. It's likely a required module is not loaded.")};
                        superclass = dd._delegate(superclass, m);
                }
        }
        // prepare values
        var init=(props||0).constructor, ctor=dd._delegate(superclass), fn;
        // name methods (experimental)
        for(var i in props){if(dojo.isFunction(fn=props[i])&&(!0[i])){fn.nom=i;}}
        // decorate prototype
        dojo.extend(ctor, {declaredClass: className, _constructor: init, preamble: null}, props||0); 
        // special help for IE
        ctor.prototype.constructor = ctor;
        // create named reference
        return dojo.setObject(className, ctor); // Function
}

dojo.mixin(dojo.declare, {
        _delegate: function(base, mixin){
                var bp = (base||0).prototype, mp = (mixin||0).prototype;
                // fresh constructor, fresh prototype
                var ctor = dojo.declare._makeCtor();
                // cache ancestry
                dojo.mixin(ctor, {superclass: bp, mixin: mp, extend: dojo.declare._extend});
                // chain prototypes
                if(base){ctor.prototype = dojo._delegate(bp);}
                // add mixin and core
                dojo.extend(ctor, dojo.declare._core, mp||0, {_constructor: null, preamble: null});
                // special help for IE
                ctor.prototype.constructor = ctor;
                // name this class for debugging
                ctor.prototype.declaredClass = (bp||0).declaredClass + '_' + (mp||0).declaredClass;
                return ctor;
        },
        _extend: function(props){
                for(var i in props){if(dojo.isFunction(fn=props[i])&&(!0[i])){fn.nom=i;}}
                dojo.extend(this, props);
        },
        _makeCtor: function(){
                // we have to make a function, but don't want to close over anything
                return function(){ this._construct(arguments); }
        },
        _core: { 
                _construct: function(args){
                        var c=args.callee, s=c.superclass, ct=s&&s.constructor, m=c.mixin, mct=m&&m.constructor, a=args, ii, fn;
                        // side-effect of = used on purpose here, lint may complain, don't try this at home
                        if(a[0]){ 
                                // FIXME: preambles for each mixin should be allowed
                                // FIXME: 
                                //              should we allow the preamble here NOT to modify the
                                //              default args, but instead to act on each mixin
                                //              independently of the class instance being constructed
                                //              (for impdedence matching)?

                                // allow any first argument w/ a "preamble" property to act as a
                                // class preamble (not exclusive of the prototype preamble)
                                if(/*dojo.isFunction*/(fn = a[0]["preamble"])){ 
                                        a = fn.apply(this, a) || a; 
                                }
                        } 
                        // prototype preamble
                        if(fn=c.prototype.preamble){a = fn.apply(this, a) || a;}
                        // FIXME: 
                        //              need to provide an optional prototype-settable
                        //              "_explicitSuper" property which disables this
                        // initialize superclass
                        if(ct&&ct.apply){ct.apply(this, a);}
                        // initialize mixin
                        if(mct&&mct.apply){mct.apply(this, a);}
                        // initialize self
                        if(ii=c.prototype._constructor){ii.apply(this, args);}
                        // post construction
                        if(this.constructor.prototype==c.prototype && (ct=this.postscript)){ct.apply(this, args)};
                },
                _findMixin: function(mixin){
                        var c = this.constructor, p, m;
                        while(c){
                                p = c.superclass;
                                m = c.mixin;
                                if(m==mixin || (m instanceof mixin.constructor)){return p;}
                                if(m && (m=m._findMixin(mixin))){return m;}
                                c = p && p.constructor;
                        }
                },
                _findMethod: function(name, method, ptype, has){
                        // consciously trading readability for bytes and speed in this low-level method
                        var p=ptype, c, m, f;
                        do{
                                c = p.constructor;
                                m = c.mixin;
                                // find method by name in our mixin ancestor
                                if(m && (m=this._findMethod(name, method, m, has))){return m};
                                // if we found a named method that either exactly-is or exactly-is-not 'method'
                                if((f=p[name])&&(has==(f==method))){return p};
                                // ascend chain
                                p = c.superclass;
                        }while(p);
                        // if we couldn't find an ancestor in our primary chain, try a mixin chain
                        return !has && (p=this._findMixin(ptype)) && this._findMethod(name, method, p, has);
                },
                inherited: function(name, args, newArgs){
                        // optionalize name argument (experimental)
                        var a = arguments;
                        if(!dojo.isString(a[0])){newArgs=args; args=name; name=args.callee.nom;}
                        var c=args.callee, p=this.constructor.prototype, a=newArgs||args, fn, mp;
                        // if not an instance override 
                        if(this[name]!=c || p[name]==c){
                                mp = this._findMethod(name, c, p, true);
                                if(!mp){throw(this.declaredClass + ': name argument ("' + name + '") to inherited must match callee (declare.js)');}
                                p = this._findMethod(name, c, mp, false);
                        }
                        fn = p && p[name];
                        // FIXME: perhaps we should throw here? 
                        if(!fn){console.debug(mp.declaredClass + ': no inherited "' + name + '" was found (declare.js)'); return;}
                        // if the function exists, invoke it in our scope
                        return fn.apply(this, a);
                }
        }
});

}