Subversion Repositories Applications.papyrus

Rev

Blame | Last modification | View Log | RSS feed

if(!dojo._hasResource["dojo.parser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.parser"] = true;
dojo.provide("dojo.parser");
dojo.require("dojo.date.stamp");

dojo.parser = new function(){

        var d = dojo;

        function val2type(/*Object*/ value){
                // summary:
                //              Returns name of type of given value.

                if(d.isString(value)){ return "string"; }
                if(typeof value == "number"){ return "number"; }
                if(typeof value == "boolean"){ return "boolean"; }
                if(d.isFunction(value)){ return "function"; }
                if(d.isArray(value)){ return "array"; } // typeof [] == "object"
                if(value instanceof Date) { return "date"; } // assume timestamp
                if(value instanceof d._Url){ return "url"; }
                return "object";
        }

        function str2obj(/*String*/ value, /*String*/ type){
                // summary:
                //              Convert given string value to given type
                switch(type){
                        case "string":
                                return value;
                        case "number":
                                return value.length ? Number(value) : NaN;
                        case "boolean":
                                // for checked/disabled value might be "" or "checked".  interpret as true.
                                return typeof value == "boolean" ? value : !(value.toLowerCase()=="false");
                        case "function":
                                if(d.isFunction(value)){
                                        // IE gives us a function, even when we say something like onClick="foo"
                                        // (in which case it gives us an invalid function "function(){ foo }"). 
                                        //  Therefore, convert to string
                                        value=value.toString();
                                        value=d.trim(value.substring(value.indexOf('{')+1, value.length-1));
                                }
                                try{
                                        if(value.search(/[^\w\.]+/i) != -1){
                                                // TODO: "this" here won't work
                                                value = d.parser._nameAnonFunc(new Function(value), this);
                                        }
                                        return d.getObject(value, false);
                                }catch(e){ return new Function(); }
                        case "array":
                                return value.split(/\s*,\s*/);
                        case "date":
                                switch(value){
                                        case "": return new Date("");   // the NaN of dates
                                        case "now": return new Date();  // current date
                                        default: return d.date.stamp.fromISOString(value);
                                }
                        case "url":
                                return d.baseUrl + value;
                        default:
                                return d.fromJson(value);
                }
        }

        var instanceClasses = {
                // map from fully qualified name (like "dijit.Button") to structure like
                // { cls: dijit.Button, params: {label: "string", disabled: "boolean"} }
        };
        
        function getClassInfo(/*String*/ className){
                // className:
                //              fully qualified name (like "dijit.Button")
                // returns:
                //              structure like
                //                      { 
                //                              cls: dijit.Button, 
                //                              params: { label: "string", disabled: "boolean"}
                //                      }

                if(!instanceClasses[className]){
                        // get pointer to widget class
                        var cls = d.getObject(className);
                        if(!d.isFunction(cls)){
                                throw new Error("Could not load class '" + className +
                                        "'. Did you spell the name correctly and use a full path, like 'dijit.form.Button'?");
                        }
                        var proto = cls.prototype;
        
                        // get table of parameter names & types
                        var params={};
                        for(var name in proto){
                                if(name.charAt(0)=="_"){ continue; }    // skip internal properties
                                var defVal = proto[name];
                                params[name]=val2type(defVal);
                        }

                        instanceClasses[className] = { cls: cls, params: params };
                }
                return instanceClasses[className];
        }

        this._functionFromScript = function(script){
                var preamble = "";
                var suffix = "";
                var argsStr = script.getAttribute("args");
                if(argsStr){
                        d.forEach(argsStr.split(/\s*,\s*/), function(part, idx){
                                preamble += "var "+part+" = arguments["+idx+"]; ";
                        });
                }
                var withStr = script.getAttribute("with");
                if(withStr && withStr.length){
                        d.forEach(withStr.split(/\s*,\s*/), function(part){
                                preamble += "with("+part+"){";
                                suffix += "}";
                        });
                }
                return new Function(preamble+script.innerHTML+suffix);
        }

        this.instantiate = function(/* Array */nodes){
                // summary:
                //              Takes array of nodes, and turns them into class instances and
                //              potentially calls a layout method to allow them to connect with
                //              any children            
                var thelist = [];
                d.forEach(nodes, function(node){
                        if(!node){ return; }
                        var type = node.getAttribute("dojoType");
                        if((!type)||(!type.length)){ return; }
                        var clsInfo = getClassInfo(type);
                        var clazz = clsInfo.cls;
                        var ps = clazz._noScript||clazz.prototype._noScript;

                        // read parameters (ie, attributes).
                        // clsInfo.params lists expected params like {"checked": "boolean", "n": "number"}
                        var params = {};
                        var attributes = node.attributes;
                        for(var name in clsInfo.params){
                                var item = attributes.getNamedItem(name);
                                if(!item || (!item.specified && (!dojo.isIE || name.toLowerCase()!="value"))){ continue; }
                                var value = item.value;
                                // Deal with IE quirks for 'class' and 'style'
                                switch(name){
                                case "class":
                                        value = node.className;
                                        break;
                                case "style":
                                        value = node.style && node.style.cssText; // FIXME: Opera?
                                }
                                var _type = clsInfo.params[name];
                                params[name] = str2obj(value, _type);
                        }

                        // Process <script type="dojo/*"> script tags
                        // <script type="dojo/method" event="foo"> tags are added to params, and passed to
                        // the widget on instantiation.
                        // <script type="dojo/method"> tags (with no event) are executed after instantiation
                        // <script type="dojo/connect" event="foo"> tags are dojo.connected after instantiation
                        if(!ps){
                                var connects = [],      // functions to connect after instantiation
                                        calls = [];             // functions to call after instantiation

                                d.query("> script[type^='dojo/']", node).orphan().forEach(function(script){
                                        var event = script.getAttribute("event"),
                                                type = script.getAttribute("type"),
                                                nf = d.parser._functionFromScript(script);
                                        if(event){
                                                if(type == "dojo/connect"){
                                                        connects.push({event: event, func: nf});
                                                }else{
                                                        params[event] = nf;
                                                }
                                        }else{
                                                calls.push(nf);
                                        }
                                });
                        }

                        var markupFactory = clazz["markupFactory"];
                        if(!markupFactory && clazz["prototype"]){
                                markupFactory = clazz.prototype["markupFactory"];
                        }
                        // create the instance
                        var instance = markupFactory ? markupFactory(params, node, clazz) : new clazz(params, node);
                        thelist.push(instance);

                        // map it to the JS namespace if that makes sense
                        var jsname = node.getAttribute("jsId");
                        if(jsname){
                                d.setObject(jsname, instance);
                        }

                        // process connections and startup functions
                        if(!ps){
                                dojo.forEach(connects, function(connect){
                                        dojo.connect(instance, connect.event, null, connect.func);
                                });
                                dojo.forEach(calls, function(func){
                                        func.call(instance);
                                });
                        }
                });

                // Call startup on each top level instance if it makes sense (as for
                // widgets).  Parent widgets will recursively call startup on their
                // (non-top level) children
                d.forEach(thelist, function(instance){
                        if(     instance  && 
                                (instance.startup) && 
                                ((!instance.getParent) || (!instance.getParent()))
                        ){
                                instance.startup();
                        }
                });
                return thelist;
        };

        this.parse = function(/*DomNode?*/ rootNode){
                // summary:
                //              Search specified node (or root node) recursively for class instances,
                //              and instantiate them Searches for
                //              dojoType="qualified.class.name"
                var list = d.query('[dojoType]', rootNode);
                // go build the object instances
                var instances = this.instantiate(list);
                return instances;
        };
}();

//Register the parser callback. It should be the first callback
//after the a11y test.

(function(){
        var parseRunner = function(){ 
                if(djConfig["parseOnLoad"] == true){
                        dojo.parser.parse(); 
                }
        };

        // FIXME: need to clobber cross-dependency!!
        if(dojo.exists("dijit.wai.onload") && (dijit.wai.onload === dojo._loaders[0])){
                dojo._loaders.splice(1, 0, parseRunner);
        }else{
                dojo._loaders.unshift(parseRunner);
        }
})();

//TODO: ported from 0.4.x Dojo.  Can we reduce this?
dojo.parser._anonCtr = 0;
dojo.parser._anon = {}; // why is this property required?
dojo.parser._nameAnonFunc = function(/*Function*/anonFuncPtr, /*Object*/thisObj){
        // summary:
        //              Creates a reference to anonFuncPtr in thisObj with a completely
        //              unique name. The new name is returned as a String. 
        var jpn = "$joinpoint";
        var nso = (thisObj|| dojo.parser._anon);
        if(dojo.isIE){
                var cn = anonFuncPtr["__dojoNameCache"];
                if(cn && nso[cn] === anonFuncPtr){
                        return anonFuncPtr["__dojoNameCache"];
                }
        }
        var ret = "__"+dojo.parser._anonCtr++;
        while(typeof nso[ret] != "undefined"){
                ret = "__"+dojo.parser._anonCtr++;
        }
        nso[ret] = anonFuncPtr;
        return ret; // String
}

}