]>
Commit | Line | Data |
---|---|---|
1354d172 AD |
1 | define( |
2 | "dojo/parser", ["./_base/kernel", "./_base/lang", "./_base/array", "./_base/html", "./_base/window", "./_base/url", | |
3 | "./_base/json", "./aspect", "./date/stamp", "./query", "./on", "./ready"], | |
4 | function(dojo, dlang, darray, dhtml, dwindow, _Url, djson, aspect, dates, query, don){ | |
5 | ||
6 | // module: | |
7 | // dojo/parser | |
8 | // summary: | |
9 | // The Dom/Widget parsing package | |
10 | ||
11 | new Date("X"); // workaround for #11279, new Date("") == NaN | |
12 | ||
13 | var features = { | |
14 | // Feature detection for when node.attributes only lists the attributes specified in the markup | |
15 | // rather than old IE/quirks behavior where it lists every default value too | |
16 | "dom-attributes-explicit": document.createElement("div").attributes.length < 40 | |
17 | }; | |
18 | function has(feature){ | |
19 | return features[feature]; | |
20 | } | |
21 | ||
22 | ||
23 | dojo.parser = new function(){ | |
24 | // summary: | |
25 | // The Dom/Widget parsing package | |
26 | ||
27 | var _nameMap = { | |
28 | // Map from widget name (ex: "dijit.form.Button") to structure mapping | |
29 | // lowercase version of attribute names to the version in the widget ex: | |
30 | // { | |
31 | // label: "label", | |
32 | // onclick: "onClick" | |
33 | // } | |
34 | }; | |
35 | function getNameMap(proto){ | |
36 | // summary: | |
37 | // Returns map from lowercase name to attribute name in class, ex: {onclick: "onClick"} | |
38 | var map = {}; | |
39 | for(var name in proto){ | |
40 | if(name.charAt(0)=="_"){ continue; } // skip internal properties | |
41 | map[name.toLowerCase()] = name; | |
42 | } | |
43 | return map; | |
44 | } | |
45 | // Widgets like BorderContainer add properties to _Widget via dojo.extend(). | |
46 | // If BorderContainer is loaded after _Widget's parameter list has been cached, | |
47 | // we need to refresh that parameter list (for _Widget and all widgets that extend _Widget). | |
48 | aspect.after(dlang, "extend", function(){ | |
49 | _nameMap = {}; | |
50 | }, true); | |
51 | ||
52 | // Map from widget name (ex: "dijit.form.Button") to constructor | |
53 | var _ctorMap = {}; | |
54 | ||
55 | this._functionFromScript = function(script, attrData){ | |
56 | // summary: | |
57 | // Convert a <script type="dojo/method" args="a, b, c"> ... </script> | |
58 | // into a function | |
59 | // script: DOMNode | |
60 | // The <script> DOMNode | |
61 | // attrData: String | |
62 | // For HTML5 compliance, searches for attrData + "args" (typically | |
63 | // "data-dojo-args") instead of "args" | |
64 | var preamble = ""; | |
65 | var suffix = ""; | |
66 | var argsStr = (script.getAttribute(attrData + "args") || script.getAttribute("args")); | |
67 | if(argsStr){ | |
68 | darray.forEach(argsStr.split(/\s*,\s*/), function(part, idx){ | |
69 | preamble += "var "+part+" = arguments["+idx+"]; "; | |
70 | }); | |
71 | } | |
72 | var withStr = script.getAttribute("with"); | |
73 | if(withStr && withStr.length){ | |
74 | darray.forEach(withStr.split(/\s*,\s*/), function(part){ | |
75 | preamble += "with("+part+"){"; | |
76 | suffix += "}"; | |
77 | }); | |
78 | } | |
79 | return new Function(preamble+script.innerHTML+suffix); | |
80 | }; | |
81 | ||
82 | this.instantiate = /*====== dojo.parser.instantiate= ======*/function(nodes, mixin, args){ | |
83 | // summary: | |
84 | // Takes array of nodes, and turns them into class instances and | |
85 | // potentially calls a startup method to allow them to connect with | |
86 | // any children. | |
87 | // nodes: Array | |
88 | // Array of nodes or objects like | |
89 | // | { | |
90 | // | type: "dijit.form.Button", | |
91 | // | node: DOMNode, | |
92 | // | scripts: [ ... ], // array of <script type="dojo/..."> children of node | |
93 | // | inherited: { ... } // settings inherited from ancestors like dir, theme, etc. | |
94 | // | } | |
95 | // mixin: Object? | |
96 | // An object that will be mixed in with each node in the array. | |
97 | // Values in the mixin will override values in the node, if they | |
98 | // exist. | |
99 | // args: Object? | |
100 | // An object used to hold kwArgs for instantiation. | |
101 | // See parse.args argument for details. | |
102 | ||
103 | var thelist = [], | |
104 | mixin = mixin||{}; | |
105 | args = args||{}; | |
106 | ||
107 | // Precompute names of special attributes we are looking for | |
108 | // TODO: for 2.0 default to data-dojo- regardless of scopeName (or maybe scopeName won't exist in 2.0) | |
109 | var dojoType = (args.scope || dojo._scopeName) + "Type", // typically "dojoType" | |
110 | attrData = "data-" + (args.scope || dojo._scopeName) + "-",// typically "data-dojo-" | |
111 | dataDojoType = attrData + "type", // typically "data-dojo-type" | |
112 | dataDojoProps = attrData + "props", // typically "data-dojo-props" | |
113 | dataDojoAttachPoint = attrData + "attach-point", | |
114 | dataDojoAttachEvent = attrData + "attach-event", | |
115 | dataDojoId = attrData + "id"; | |
116 | ||
117 | // And make hash to quickly check if a given attribute is special, and to map the name to something friendly | |
118 | var specialAttrs = {}; | |
119 | darray.forEach([dataDojoProps, dataDojoType, dojoType, dataDojoId, "jsId", dataDojoAttachPoint, | |
120 | dataDojoAttachEvent, "dojoAttachPoint", "dojoAttachEvent", "class", "style"], function(name){ | |
121 | specialAttrs[name.toLowerCase()] = name.replace(args.scope, "dojo"); | |
122 | }); | |
123 | ||
124 | darray.forEach(nodes, function(obj){ | |
125 | if(!obj){ return; } | |
126 | ||
127 | var node = obj.node || obj, | |
128 | type = dojoType in mixin ? mixin[dojoType] : obj.node ? obj.type : (node.getAttribute(dataDojoType) || node.getAttribute(dojoType)), | |
129 | ctor = _ctorMap[type] || (_ctorMap[type] = dlang.getObject(type)), | |
130 | proto = ctor && ctor.prototype; | |
131 | if(!ctor){ | |
132 | throw new Error("Could not load class '" + type); | |
133 | } | |
134 | ||
135 | // Setup hash to hold parameter settings for this widget. Start with the parameter | |
136 | // settings inherited from ancestors ("dir" and "lang"). | |
137 | // Inherited setting may later be overridden by explicit settings on node itself. | |
138 | var params = {}; | |
139 | ||
140 | if(args.defaults){ | |
141 | // settings for the document itself (or whatever subtree is being parsed) | |
142 | dlang.mixin(params, args.defaults); | |
143 | } | |
144 | if(obj.inherited){ | |
145 | // settings from dir=rtl or lang=... on a node above this node | |
146 | dlang.mixin(params, obj.inherited); | |
147 | } | |
148 | ||
149 | // Get list of attributes explicitly listed in the markup | |
150 | var attributes; | |
151 | if(has("dom-attributes-explicit")){ | |
152 | // Standard path to get list of user specified attributes | |
153 | attributes = node.attributes; | |
154 | }else{ | |
155 | // Special path for IE, avoid (sometimes >100) bogus entries in node.attributes | |
156 | var clone = /^input$|^img$/i.test(node.nodeName) ? node : node.cloneNode(false), | |
157 | attrs = clone.outerHTML.replace(/=[^\s"']+|="[^"]*"|='[^']*'/g, "").replace(/^\s*<[a-zA-Z0-9]*/, "").replace(/>.*$/, ""); | |
158 | ||
159 | attributes = darray.map(attrs.split(/\s+/), function(name){ | |
160 | var lcName = name.toLowerCase(); | |
161 | return { | |
162 | name: name, | |
163 | // getAttribute() doesn't work for button.value, returns innerHTML of button. | |
164 | // but getAttributeNode().value doesn't work for the form.encType or li.value | |
165 | value: (node.nodeName == "LI" && name == "value") || lcName == "enctype" ? | |
166 | node.getAttribute(lcName) : node.getAttributeNode(lcName).value, | |
167 | specified: true | |
168 | }; | |
169 | }); | |
170 | } | |
171 | ||
172 | // Read in attributes and process them, including data-dojo-props, data-dojo-type, | |
173 | // dojoAttachPoint, etc., as well as normal foo=bar attributes. | |
174 | var i=0, item; | |
175 | while(item = attributes[i++]){ | |
176 | if(!item || !item.specified){ | |
177 | continue; | |
178 | } | |
179 | ||
180 | var name = item.name, | |
181 | lcName = name.toLowerCase(), | |
182 | value = item.value; | |
183 | ||
184 | if(lcName in specialAttrs){ | |
185 | switch(specialAttrs[lcName]){ | |
186 | ||
187 | // Data-dojo-props. Save for later to make sure it overrides direct foo=bar settings | |
188 | case "data-dojo-props": | |
189 | var extra = value; | |
190 | break; | |
191 | ||
192 | // data-dojo-id or jsId. TODO: drop jsId in 2.0 | |
193 | case "data-dojo-id": | |
194 | case "jsId": | |
195 | var jsname = value; | |
196 | break; | |
197 | ||
198 | // For the benefit of _Templated | |
199 | case "data-dojo-attach-point": | |
200 | case "dojoAttachPoint": | |
201 | params.dojoAttachPoint = value; | |
202 | break; | |
203 | case "data-dojo-attach-event": | |
204 | case "dojoAttachEvent": | |
205 | params.dojoAttachEvent = value; | |
206 | break; | |
207 | ||
208 | // Special parameter handling needed for IE | |
209 | case "class": | |
210 | params["class"] = node.className; | |
211 | break; | |
212 | case "style": | |
213 | params["style"] = node.style && node.style.cssText; | |
214 | break; | |
215 | } | |
216 | }else{ | |
217 | // Normal attribute, ex: value="123" | |
218 | ||
219 | // Find attribute in widget corresponding to specified name. | |
220 | // May involve case conversion, ex: onclick --> onClick | |
221 | if(!(name in proto)){ | |
222 | var map = (_nameMap[type] || (_nameMap[type] = getNameMap(proto))); | |
223 | name = map[lcName] || name; | |
224 | } | |
225 | ||
226 | // Set params[name] to value, doing type conversion | |
227 | if(name in proto){ | |
228 | switch(typeof proto[name]){ | |
229 | case "string": | |
230 | params[name] = value; | |
231 | break; | |
232 | case "number": | |
233 | params[name] = value.length ? Number(value) : NaN; | |
234 | break; | |
235 | case "boolean": | |
236 | // for checked/disabled value might be "" or "checked". interpret as true. | |
237 | params[name] = value.toLowerCase() != "false"; | |
238 | break; | |
239 | case "function": | |
240 | if(value === "" || value.search(/[^\w\.]+/i) != -1){ | |
241 | // The user has specified some text for a function like "return x+5" | |
242 | params[name] = new Function(value); | |
243 | }else{ | |
244 | // The user has specified the name of a function like "myOnClick" | |
245 | // or a single word function "return" | |
246 | params[name] = dlang.getObject(value, false) || new Function(value); | |
247 | } | |
248 | break; | |
249 | default: | |
250 | var pVal = proto[name]; | |
251 | params[name] = | |
252 | (pVal && "length" in pVal) ? (value ? value.split(/\s*,\s*/) : []) : // array | |
253 | (pVal instanceof Date) ? | |
254 | (value == "" ? new Date("") : // the NaN of dates | |
255 | value == "now" ? new Date() : // current date | |
256 | dates.fromISOString(value)) : | |
257 | (pVal instanceof dojo._Url) ? (dojo.baseUrl + value) : | |
258 | djson.fromJson(value); | |
259 | } | |
260 | }else{ | |
261 | params[name] = value; | |
262 | } | |
263 | } | |
264 | } | |
265 | ||
266 | // Mix things found in data-dojo-props into the params, overriding any direct settings | |
267 | if(extra){ | |
268 | try{ | |
269 | extra = djson.fromJson.call(args.propsThis, "{" + extra + "}"); | |
270 | dlang.mixin(params, extra); | |
271 | }catch(e){ | |
272 | // give the user a pointer to their invalid parameters. FIXME: can we kill this in production? | |
273 | throw new Error(e.toString() + " in data-dojo-props='" + extra + "'"); | |
274 | } | |
275 | } | |
276 | ||
277 | // Any parameters specified in "mixin" override everything else. | |
278 | dlang.mixin(params, mixin); | |
279 | ||
280 | var scripts = obj.node ? obj.scripts : (ctor && (ctor._noScript || proto._noScript) ? [] : | |
281 | query("> script[type^='dojo/']", node)); | |
282 | ||
283 | // Process <script type="dojo/*"> script tags | |
284 | // <script type="dojo/method" event="foo"> tags are added to params, and passed to | |
285 | // the widget on instantiation. | |
286 | // <script type="dojo/method"> tags (with no event) are executed after instantiation | |
287 | // <script type="dojo/connect" data-dojo-event="foo"> tags are dojo.connected after instantiation | |
288 | // <script type="dojo/watch" data-dojo-prop="foo"> tags are dojo.watch after instantiation | |
289 | // <script type="dojo/on" data-dojo-event="foo"> tags are dojo.on after instantiation | |
290 | // note: dojo/* script tags cannot exist in self closing widgets, like <input /> | |
291 | var connects = [], // functions to connect after instantiation | |
292 | calls = [], // functions to call after instantiation | |
293 | watch = [], //functions to watch after instantiation | |
294 | on = []; //functions to on after instantiation | |
295 | ||
296 | if(scripts){ | |
297 | for(i=0; i<scripts.length; i++){ | |
298 | var script = scripts[i]; | |
299 | node.removeChild(script); | |
300 | // FIXME: drop event="" support in 2.0. use data-dojo-event="" instead | |
301 | var event = (script.getAttribute(attrData + "event") || script.getAttribute("event")), | |
302 | prop = script.getAttribute(attrData + "prop"), | |
303 | type = script.getAttribute("type"), | |
304 | nf = this._functionFromScript(script, attrData); | |
305 | if(event){ | |
306 | if(type == "dojo/connect"){ | |
307 | connects.push({event: event, func: nf}); | |
308 | }else if(type == "dojo/on"){ | |
309 | on.push({event: event, func: nf}); | |
310 | }else{ | |
311 | params[event] = nf; | |
312 | } | |
313 | }else if(type == "dojo/watch"){ | |
314 | watch.push({prop: prop, func: nf}); | |
315 | }else{ | |
316 | calls.push(nf); | |
317 | } | |
318 | } | |
319 | } | |
320 | ||
321 | // create the instance | |
322 | var markupFactory = ctor.markupFactory || proto.markupFactory; | |
323 | var instance = markupFactory ? markupFactory(params, node, ctor) : new ctor(params, node); | |
324 | thelist.push(instance); | |
325 | ||
326 | // map it to the JS namespace if that makes sense | |
327 | if(jsname){ | |
328 | dlang.setObject(jsname, instance); | |
329 | } | |
330 | ||
331 | // process connections and startup functions | |
332 | for(i=0; i<connects.length; i++){ | |
333 | aspect.after(instance, connects[i].event, dojo.hitch(instance, connects[i].func), true); | |
334 | } | |
335 | for(i=0; i<calls.length; i++){ | |
336 | calls[i].call(instance); | |
337 | } | |
338 | for(i=0; i<watch.length; i++){ | |
339 | instance.watch(watch[i].prop, watch[i].func); | |
340 | } | |
341 | for(i=0; i<on.length; i++){ | |
342 | don(instance, on[i].event, on[i].func); | |
343 | } | |
344 | }, this); | |
345 | ||
346 | // Call startup on each top level instance if it makes sense (as for | |
347 | // widgets). Parent widgets will recursively call startup on their | |
348 | // (non-top level) children | |
349 | if(!mixin._started){ | |
350 | darray.forEach(thelist, function(instance){ | |
351 | if( !args.noStart && instance && | |
352 | dlang.isFunction(instance.startup) && | |
353 | !instance._started | |
354 | ){ | |
355 | instance.startup(); | |
356 | } | |
357 | }); | |
358 | } | |
359 | return thelist; | |
360 | }; | |
361 | ||
362 | this.parse = /*====== dojo.parser.parse= ======*/ function(rootNode, args){ | |
363 | // summary: | |
364 | // Scan the DOM for class instances, and instantiate them. | |
365 | // | |
366 | // description: | |
367 | // Search specified node (or root node) recursively for class instances, | |
368 | // and instantiate them. Searches for either data-dojo-type="Class" or | |
369 | // dojoType="Class" where "Class" is a a fully qualified class name, | |
370 | // like `dijit.form.Button` | |
371 | // | |
372 | // Using `data-dojo-type`: | |
373 | // Attributes using can be mixed into the parameters used to instantiate the | |
374 | // Class by using a `data-dojo-props` attribute on the node being converted. | |
375 | // `data-dojo-props` should be a string attribute to be converted from JSON. | |
376 | // | |
377 | // Using `dojoType`: | |
378 | // Attributes are read from the original domNode and converted to appropriate | |
379 | // types by looking up the Class prototype values. This is the default behavior | |
380 | // from Dojo 1.0 to Dojo 1.5. `dojoType` support is deprecated, and will | |
381 | // go away in Dojo 2.0. | |
382 | // | |
383 | // rootNode: DomNode? | |
384 | // A default starting root node from which to start the parsing. Can be | |
385 | // omitted, defaulting to the entire document. If omitted, the `args` | |
386 | // object can be passed in this place. If the `args` object has a | |
387 | // `rootNode` member, that is used. | |
388 | // | |
389 | // args: Object | |
390 | // a kwArgs object passed along to instantiate() | |
391 | // | |
392 | // * noStart: Boolean? | |
393 | // when set will prevent the parser from calling .startup() | |
394 | // when locating the nodes. | |
395 | // * rootNode: DomNode? | |
396 | // identical to the function's `rootNode` argument, though | |
397 | // allowed to be passed in via this `args object. | |
398 | // * template: Boolean | |
399 | // If true, ignores ContentPane's stopParser flag and parses contents inside of | |
400 | // a ContentPane inside of a template. This allows dojoAttachPoint on widgets/nodes | |
401 | // nested inside the ContentPane to work. | |
402 | // * inherited: Object | |
403 | // Hash possibly containing dir and lang settings to be applied to | |
404 | // parsed widgets, unless there's another setting on a sub-node that overrides | |
405 | // * scope: String | |
406 | // Root for attribute names to search for. If scopeName is dojo, | |
407 | // will search for data-dojo-type (or dojoType). For backwards compatibility | |
408 | // reasons defaults to dojo._scopeName (which is "dojo" except when | |
409 | // multi-version support is used, when it will be something like dojo16, dojo20, etc.) | |
410 | // * propsThis: Object | |
411 | // If specified, "this" referenced from data-dojo-props will refer to propsThis. | |
412 | // Intended for use from the widgets-in-template feature of `dijit._WidgetsInTemplateMixin` | |
413 | // | |
414 | // example: | |
415 | // Parse all widgets on a page: | |
416 | // | dojo.parser.parse(); | |
417 | // | |
418 | // example: | |
419 | // Parse all classes within the node with id="foo" | |
420 | // | dojo.parser.parse(dojo.byId('foo')); | |
421 | // | |
422 | // example: | |
423 | // Parse all classes in a page, but do not call .startup() on any | |
424 | // child | |
425 | // | dojo.parser.parse({ noStart: true }) | |
426 | // | |
427 | // example: | |
428 | // Parse all classes in a node, but do not call .startup() | |
429 | // | dojo.parser.parse(someNode, { noStart:true }); | |
430 | // | // or | |
431 | // | dojo.parser.parse({ noStart:true, rootNode: someNode }); | |
432 | ||
433 | // determine the root node based on the passed arguments. | |
434 | var root; | |
435 | if(!args && rootNode && rootNode.rootNode){ | |
436 | args = rootNode; | |
437 | root = args.rootNode; | |
438 | }else{ | |
439 | root = rootNode; | |
440 | } | |
441 | root = root ? dhtml.byId(root) : dwindow.body(); | |
442 | args = args || {}; | |
443 | ||
444 | var dojoType = (args.scope || dojo._scopeName) + "Type", // typically "dojoType" | |
445 | attrData = "data-" + (args.scope || dojo._scopeName) + "-", // typically "data-dojo-" | |
446 | dataDojoType = attrData + "type", // typically "data-dojo-type" | |
447 | dataDojoTextDir = attrData + "textdir"; // typically "data-dojo-textdir" | |
448 | ||
449 | // List of all nodes on page w/dojoType specified | |
450 | var list = []; | |
451 | ||
452 | // Info on DOMNode currently being processed | |
453 | var node = root.firstChild; | |
454 | ||
455 | // Info on parent of DOMNode currently being processed | |
456 | // - inherited: dir, lang, and textDir setting of parent, or inherited by parent | |
457 | // - parent: pointer to identical structure for my parent (or null if no parent) | |
458 | // - scripts: if specified, collects <script type="dojo/..."> type nodes from children | |
459 | var inherited = args && args.inherited; | |
460 | if(!inherited){ | |
461 | function findAncestorAttr(node, attr){ | |
462 | return (node.getAttribute && node.getAttribute(attr)) || | |
463 | (node !== dwindow.doc && node !== dwindow.doc.documentElement && node.parentNode ? findAncestorAttr(node.parentNode, attr) : null); | |
464 | } | |
465 | inherited = { | |
466 | dir: findAncestorAttr(root, "dir"), | |
467 | lang: findAncestorAttr(root, "lang"), | |
468 | textDir: findAncestorAttr(root, dataDojoTextDir) | |
469 | }; | |
470 | for(var key in inherited){ | |
471 | if(!inherited[key]){ delete inherited[key]; } | |
472 | } | |
473 | } | |
474 | var parent = { | |
475 | inherited: inherited | |
476 | }; | |
477 | ||
478 | // For collecting <script type="dojo/..."> type nodes (when null, we don't need to collect) | |
479 | var scripts; | |
480 | ||
481 | // when true, only look for <script type="dojo/..."> tags, and don't recurse to children | |
482 | var scriptsOnly; | |
483 | ||
484 | function getEffective(parent){ | |
485 | // summary: | |
486 | // Get effective dir, lang, textDir settings for specified obj | |
487 | // (matching "parent" object structure above), and do caching. | |
488 | // Take care not to return null entries. | |
489 | if(!parent.inherited){ | |
490 | parent.inherited = {}; | |
491 | var node = parent.node, | |
492 | grandparent = getEffective(parent.parent); | |
493 | var inherited = { | |
494 | dir: node.getAttribute("dir") || grandparent.dir, | |
495 | lang: node.getAttribute("lang") || grandparent.lang, | |
496 | textDir: node.getAttribute(dataDojoTextDir) || grandparent.textDir | |
497 | }; | |
498 | for(var key in inherited){ | |
499 | if(inherited[key]){ | |
500 | parent.inherited[key] = inherited[key]; | |
501 | } | |
502 | } | |
503 | } | |
504 | return parent.inherited; | |
505 | } | |
506 | ||
507 | // DFS on DOM tree, collecting nodes with data-dojo-type specified. | |
508 | while(true){ | |
509 | if(!node){ | |
510 | // Finished this level, continue to parent's next sibling | |
511 | if(!parent || !parent.node){ | |
512 | break; | |
513 | } | |
514 | node = parent.node.nextSibling; | |
515 | scripts = parent.scripts; | |
516 | scriptsOnly = false; | |
517 | parent = parent.parent; | |
518 | continue; | |
519 | } | |
520 | ||
521 | if(node.nodeType != 1){ | |
522 | // Text or comment node, skip to next sibling | |
523 | node = node.nextSibling; | |
524 | continue; | |
525 | } | |
526 | ||
527 | if(scripts && node.nodeName.toLowerCase() == "script"){ | |
528 | // Save <script type="dojo/..."> for parent, then continue to next sibling | |
529 | type = node.getAttribute("type"); | |
530 | if(type && /^dojo\/\w/i.test(type)){ | |
531 | scripts.push(node); | |
532 | } | |
533 | node = node.nextSibling; | |
534 | continue; | |
535 | } | |
536 | if(scriptsOnly){ | |
537 | node = node.nextSibling; | |
538 | continue; | |
539 | } | |
540 | ||
541 | // Check for data-dojo-type attribute, fallback to backward compatible dojoType | |
542 | var type = node.getAttribute(dataDojoType) || node.getAttribute(dojoType); | |
543 | ||
544 | // Short circuit for leaf nodes containing nothing [but text] | |
545 | var firstChild = node.firstChild; | |
546 | if(!type && (!firstChild || (firstChild.nodeType == 3 && !firstChild.nextSibling))){ | |
547 | node = node.nextSibling; | |
548 | continue; | |
549 | } | |
550 | ||
551 | // Setup data structure to save info on current node for when we return from processing descendant nodes | |
552 | var current = { | |
553 | node: node, | |
554 | scripts: scripts, | |
555 | parent: parent | |
556 | }; | |
557 | ||
558 | // If dojoType/data-dojo-type specified, add to output array of nodes to instantiate | |
559 | var ctor = type && (_ctorMap[type] || (_ctorMap[type] = dlang.getObject(type))), // note: won't find classes declared via dojo.Declaration | |
560 | childScripts = ctor && !ctor.prototype._noScript ? [] : null; // <script> nodes that are parent's children | |
561 | if(type){ | |
562 | list.push({ | |
563 | "type": type, | |
564 | node: node, | |
565 | scripts: childScripts, | |
566 | inherited: getEffective(current) // dir & lang settings for current node, explicit or inherited | |
567 | }); | |
568 | } | |
569 | ||
570 | // Recurse, collecting <script type="dojo/..."> children, and also looking for | |
571 | // descendant nodes with dojoType specified (unless the widget has the stopParser flag). | |
572 | // When finished with children, go to my next sibling. | |
573 | node = firstChild; | |
574 | scripts = childScripts; | |
575 | scriptsOnly = ctor && ctor.prototype.stopParser && !(args && args.template); | |
576 | parent = current; | |
577 | ||
578 | } | |
579 | ||
580 | // go build the object instances | |
581 | var mixin = args && args.template ? {template: true} : null; | |
582 | return this.instantiate(list, mixin, args); // Array | |
583 | }; | |
584 | }(); | |
585 | ||
586 | ||
587 | //Register the parser callback. It should be the first callback | |
588 | //after the a11y test. | |
589 | if(dojo.config.parseOnLoad){ | |
590 | dojo.ready(100, dojo.parser, "parse"); | |
591 | } | |
592 | ||
593 | return dojo.parser; | |
594 | }); |