]> git.pond.sub.org Git - eow/blob - static/dojo-release-1.1.1/dojo/parser.js
Comment class stub
[eow] / static / dojo-release-1.1.1 / dojo / parser.js
1 if(!dojo._hasResource["dojo.parser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2 dojo._hasResource["dojo.parser"] = true;
3 dojo.provide("dojo.parser");
4 dojo.require("dojo.date.stamp");
5
6 dojo.parser = new function(){
7         // summary: The Dom/Widget parsing package
8
9         var d = dojo;
10         var dtName = d._scopeName + "Type";
11         var qry = "[" + dtName + "]";
12
13         function val2type(/*Object*/ value){
14                 // summary:
15                 //              Returns name of type of given value.
16
17                 if(d.isString(value)){ return "string"; }
18                 if(typeof value == "number"){ return "number"; }
19                 if(typeof value == "boolean"){ return "boolean"; }
20                 if(d.isFunction(value)){ return "function"; }
21                 if(d.isArray(value)){ return "array"; } // typeof [] == "object"
22                 if(value instanceof Date) { return "date"; } // assume timestamp
23                 if(value instanceof d._Url){ return "url"; }
24                 return "object";
25         }
26
27         function str2obj(/*String*/ value, /*String*/ type){
28                 // summary:
29                 //              Convert given string value to given type
30                 switch(type){
31                         case "string":
32                                 return value;
33                         case "number":
34                                 return value.length ? Number(value) : NaN;
35                         case "boolean":
36                                 // for checked/disabled value might be "" or "checked".  interpret as true.
37                                 return typeof value == "boolean" ? value : !(value.toLowerCase()=="false");
38                         case "function":
39                                 if(d.isFunction(value)){
40                                         // IE gives us a function, even when we say something like onClick="foo"
41                                         // (in which case it gives us an invalid function "function(){ foo }"). 
42                                         //  Therefore, convert to string
43                                         value=value.toString();
44                                         value=d.trim(value.substring(value.indexOf('{')+1, value.length-1));
45                                 }
46                                 try{
47                                         if(value.search(/[^\w\.]+/i) != -1){
48                                                 // TODO: "this" here won't work
49                                                 value = d.parser._nameAnonFunc(new Function(value), this);
50                                         }
51                                         return d.getObject(value, false);
52                                 }catch(e){ return new Function(); }
53                         case "array":
54                                 return value.split(/\s*,\s*/);
55                         case "date":
56                                 switch(value){
57                                         case "": return new Date("");   // the NaN of dates
58                                         case "now": return new Date();  // current date
59                                         default: return d.date.stamp.fromISOString(value);
60                                 }
61                         case "url":
62                                 return d.baseUrl + value;
63                         default:
64                                 return d.fromJson(value);
65                 }
66         }
67
68         var instanceClasses = {
69                 // map from fully qualified name (like "dijit.Button") to structure like
70                 // { cls: dijit.Button, params: {label: "string", disabled: "boolean"} }
71         };
72         
73         function getClassInfo(/*String*/ className){
74                 // className:
75                 //              fully qualified name (like "dijit.Button")
76                 // returns:
77                 //              structure like
78                 //                      { 
79                 //                              cls: dijit.Button, 
80                 //                              params: { label: "string", disabled: "boolean"}
81                 //                      }
82
83                 if(!instanceClasses[className]){
84                         // get pointer to widget class
85                         var cls = d.getObject(className);
86                         if(!d.isFunction(cls)){
87                                 throw new Error("Could not load class '" + className +
88                                         "'. Did you spell the name correctly and use a full path, like 'dijit.form.Button'?");
89                         }
90                         var proto = cls.prototype;
91         
92                         // get table of parameter names & types
93                         var params={};
94                         for(var name in proto){
95                                 if(name.charAt(0)=="_"){ continue; }    // skip internal properties
96                                 var defVal = proto[name];
97                                 params[name]=val2type(defVal);
98                         }
99
100                         instanceClasses[className] = { cls: cls, params: params };
101                 }
102                 return instanceClasses[className];
103         }
104
105         this._functionFromScript = function(script){
106                 var preamble = "";
107                 var suffix = "";
108                 var argsStr = script.getAttribute("args");
109                 if(argsStr){
110                         d.forEach(argsStr.split(/\s*,\s*/), function(part, idx){
111                                 preamble += "var "+part+" = arguments["+idx+"]; ";
112                         });
113                 }
114                 var withStr = script.getAttribute("with");
115                 if(withStr && withStr.length){
116                         d.forEach(withStr.split(/\s*,\s*/), function(part){
117                                 preamble += "with("+part+"){";
118                                 suffix += "}";
119                         });
120                 }
121                 return new Function(preamble+script.innerHTML+suffix);
122         }
123
124         this.instantiate = function(/* Array */nodes){
125                 // summary:
126                 //              Takes array of nodes, and turns them into class instances and
127                 //              potentially calls a layout method to allow them to connect with
128                 //              any children            
129                 var thelist = [];
130                 d.forEach(nodes, function(node){
131                         if(!node){ return; }
132                         var type = node.getAttribute(dtName);
133                         if((!type)||(!type.length)){ return; }
134                         var clsInfo = getClassInfo(type);
135                         var clazz = clsInfo.cls;
136                         var ps = clazz._noScript||clazz.prototype._noScript;
137
138                         // read parameters (ie, attributes).
139                         // clsInfo.params lists expected params like {"checked": "boolean", "n": "number"}
140                         var params = {};
141                         var attributes = node.attributes;
142                         for(var name in clsInfo.params){
143                                 var item = attributes.getNamedItem(name);
144                                 if(!item || (!item.specified && (!dojo.isIE || name.toLowerCase()!="value"))){ continue; }
145                                 var value = item.value;
146                                 // Deal with IE quirks for 'class' and 'style'
147                                 switch(name){
148                                 case "class":
149                                         value = node.className;
150                                         break;
151                                 case "style":
152                                         value = node.style && node.style.cssText; // FIXME: Opera?
153                                 }
154                                 var _type = clsInfo.params[name];
155                                 params[name] = str2obj(value, _type);
156                         }
157
158                         // Process <script type="dojo/*"> script tags
159                         // <script type="dojo/method" event="foo"> tags are added to params, and passed to
160                         // the widget on instantiation.
161                         // <script type="dojo/method"> tags (with no event) are executed after instantiation
162                         // <script type="dojo/connect" event="foo"> tags are dojo.connected after instantiation
163                         // note: dojo/* script tags cannot exist in self closing widgets, like <input />
164                         if(!ps){
165                                 var connects = [],      // functions to connect after instantiation
166                                         calls = [];             // functions to call after instantiation
167
168                                 d.query("> script[type^='dojo/']", node).orphan().forEach(function(script){
169                                         var event = script.getAttribute("event"),
170                                                 type = script.getAttribute("type"),
171                                                 nf = d.parser._functionFromScript(script);
172                                         if(event){
173                                                 if(type == "dojo/connect"){
174                                                         connects.push({event: event, func: nf});
175                                                 }else{
176                                                         params[event] = nf;
177                                                 }
178                                         }else{
179                                                 calls.push(nf);
180                                         }
181                                 });
182                         }
183
184                         var markupFactory = clazz["markupFactory"];
185                         if(!markupFactory && clazz["prototype"]){
186                                 markupFactory = clazz.prototype["markupFactory"];
187                         }
188                         // create the instance
189                         var instance = markupFactory ? markupFactory(params, node, clazz) : new clazz(params, node);
190                         thelist.push(instance);
191
192                         // map it to the JS namespace if that makes sense
193                         var jsname = node.getAttribute("jsId");
194                         if(jsname){
195                                 d.setObject(jsname, instance);
196                         }
197
198                         // process connections and startup functions
199                         if(!ps){
200                                 d.forEach(connects, function(connect){
201                                         d.connect(instance, connect.event, null, connect.func);
202                                 });
203                                 d.forEach(calls, function(func){
204                                         func.call(instance);
205                                 });
206                         }
207                 });
208
209                 // Call startup on each top level instance if it makes sense (as for
210                 // widgets).  Parent widgets will recursively call startup on their
211                 // (non-top level) children
212                 d.forEach(thelist, function(instance){
213                         if(     instance  && 
214                                 instance.startup &&
215                                 !instance._started && 
216                                 (!instance.getParent || !instance.getParent())
217                         ){
218                                 instance.startup();
219                         }
220                 });
221                 return thelist;
222         };
223
224         this.parse = function(/*DomNode?*/ rootNode){
225                 // summary:
226                 //              Search specified node (or root node) recursively for class instances,
227                 //              and instantiate them Searches for
228                 //              dojoType="qualified.class.name"
229                 var list = d.query(qry, rootNode);
230                 // go build the object instances
231                 var instances = this.instantiate(list);
232                 return instances;
233         };
234 }();
235
236 //Register the parser callback. It should be the first callback
237 //after the a11y test.
238
239 (function(){
240         var parseRunner = function(){ 
241                 if(dojo.config["parseOnLoad"] == true){
242                         dojo.parser.parse(); 
243                 }
244         };
245
246         // FIXME: need to clobber cross-dependency!!
247         if(dojo.exists("dijit.wai.onload") && (dijit.wai.onload === dojo._loaders[0])){
248                 dojo._loaders.splice(1, 0, parseRunner);
249         }else{
250                 dojo._loaders.unshift(parseRunner);
251         }
252 })();
253
254 //TODO: ported from 0.4.x Dojo.  Can we reduce this?
255 dojo.parser._anonCtr = 0;
256 dojo.parser._anon = {}; // why is this property required?
257 dojo.parser._nameAnonFunc = function(/*Function*/anonFuncPtr, /*Object*/thisObj){
258         // summary:
259         //              Creates a reference to anonFuncPtr in thisObj with a completely
260         //              unique name. The new name is returned as a String. 
261         var jpn = "$joinpoint";
262         var nso = (thisObj|| dojo.parser._anon);
263         if(dojo.isIE){
264                 var cn = anonFuncPtr["__dojoNameCache"];
265                 if(cn && nso[cn] === anonFuncPtr){
266                         return anonFuncPtr["__dojoNameCache"];
267                 }
268         }
269         var ret = "__"+dojo.parser._anonCtr++;
270         while(typeof nso[ret] != "undefined"){
271                 ret = "__"+dojo.parser._anonCtr++;
272         }
273         nso[ret] = anonFuncPtr;
274         return ret; // String
275 }
276
277 }