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