]>
git.wh0rd.org - tt-rss.git/blob - lib/dojo/parser.js.uncompressed.js
2 "dojo/parser", ["require", "./_base/kernel", "./_base/lang", "./_base/array", "./_base/config", "./_base/html", "./_base/window",
3 "./_base/url", "./_base/json", "./aspect", "./date/stamp", "./Deferred", "./has", "./query", "./on", "./ready"],
4 function(require
, dojo
, dlang
, darray
, config
, dhtml
, dwindow
, _Url
, djson
, aspect
, dates
, Deferred
, has
, query
, don
, ready
){
9 new Date("X"); // workaround for #11279, new Date("") == NaN
12 // Widgets like BorderContainer add properties to _Widget via dojo.extend().
13 // If BorderContainer is loaded after _Widget's parameter list has been cached,
14 // we need to refresh that parameter list (for _Widget and all widgets that extend _Widget).
16 aspect
.after(dlang
, "extend", function(){
20 function getNameMap(ctor
){
22 // Returns map from lowercase name to attribute name in class, ex: {onclick: "onClick"}
23 var map
= ctor
._nameCaseMap
, proto
= ctor
.prototype;
25 // Create the map if it's undefined.
26 // Refresh the map if a superclass was possibly extended with new methods since the map was created.
27 if(!map
|| map
._extendCnt
< extendCnt
){
28 map
= ctor
._nameCaseMap
= {};
29 for(var name
in proto
){
30 if(name
.charAt(0) === "_"){ continue; } // skip internal properties
31 map
[name
.toLowerCase()] = name
;
33 map
._extendCnt
= extendCnt
;
38 // Map from widget name or list of widget names(ex: "dijit/form/Button,acme/MyMixin") to a constructor.
41 function getCtor(/*String[]*/ types
){
43 // Retrieves a constructor. If the types array contains more than one class/MID then the
44 // subsequent classes will be mixed into the first class and a unique constructor will be
45 // returned for that array.
47 var ts
= types
.join();
50 for(var i
= 0, l
= types
.length
; i
< l
; i
++){
52 // TODO: Consider swapping getObject and require in the future
53 mixins
[mixins
.length
] = (_ctorMap
[t
] = _ctorMap
[t
] || (dlang
.getObject(t
) || (~t
.indexOf('/') && require(t
))));
55 var ctor
= mixins
.shift();
56 _ctorMap
[ts
] = mixins
.length
? (ctor
.createSubclass
? ctor
.createSubclass(mixins
) : ctor
.extend
.apply(ctor
, mixins
)) : ctor
;
64 // The Dom/Widget parsing package
66 _clearCache: function(){
68 // Clear cached data. Used mainly for benchmarking.
73 _functionFromScript: function(script
, attrData
){
75 // Convert a `<script type="dojo/method" args="a, b, c"> ... </script>`
78 // The `<script>` DOMNode
80 // For HTML5 compliance, searches for attrData + "args" (typically
81 // "data-dojo-args") instead of "args"
84 argsStr
= (script
.getAttribute(attrData
+ "args") || script
.getAttribute("args")),
85 withStr
= script
.getAttribute("with");
87 // Convert any arguments supplied in script tag into an array to be passed to the
88 var fnArgs
= (argsStr
|| "").split(/\s*,\s*/);
90 if(withStr
&& withStr
.length
){
91 darray
.forEach(withStr
.split(/\s*,\s*/), function(part
){
92 preamble
+= "with("+part
+"){";
97 return new Function(fnArgs
, preamble
+ script
.innerHTML
+ suffix
);
100 instantiate: function(nodes
, mixin
, options
){
102 // Takes array of nodes, and turns them into class instances and
103 // potentially calls a startup method to allow them to connect with
106 // Array of DOM nodes
108 // An object that will be mixed in with each node in the array.
109 // Values in the mixin will override values in the node, if they
112 // An object used to hold kwArgs for instantiation.
113 // See parse.options argument for details.
116 options
= options
|| {};
118 var dojoType
= (options
.scope
|| dojo
._scopeName
) + "Type", // typically "dojoType"
119 attrData
= "data-" + (options
.scope
|| dojo
._scopeName
) + "-",// typically "data-dojo-"
120 dataDojoType
= attrData
+ "type", // typically "data-dojo-type"
121 dataDojoMixins
= attrData
+ "mixins"; // typically "data-dojo-mixins"
124 darray
.forEach(nodes
, function(node
){
125 var type
= dojoType
in mixin
? mixin
[dojoType
] : node
.getAttribute(dataDojoType
) || node
.getAttribute(dojoType
);
127 var mixinsValue
= node
.getAttribute(dataDojoMixins
),
128 types
= mixinsValue
? [type
].concat(mixinsValue
.split(/\s*,\s*/)) : [type
];
137 // Instantiate the nodes and return the objects
138 return this._instantiate(list
, mixin
, options
);
141 _instantiate: function(nodes
, mixin
, options
){
143 // Takes array of objects representing nodes, and turns them into class instances and
144 // potentially calls a startup method to allow them to connect with
147 // Array of objects like
149 // | ctor: Function (may be null)
150 // | types: ["dijit/form/Button", "acme/MyMixin"] (used if ctor not specified)
152 // | scripts: [ ... ], // array of <script type="dojo/..."> children of node
153 // | inherited: { ... } // settings inherited from ancestors like dir, theme, etc.
156 // An object that will be mixed in with each node in the array.
157 // Values in the mixin will override values in the node, if they
160 // An options object used to hold kwArgs for instantiation.
161 // See parse.options argument for details.
163 // Call widget constructors
164 var thelist
= darray
.map(nodes
, function(obj
){
165 var ctor
= obj
.ctor
|| getCtor(obj
.types
);
166 // If we still haven't resolved a ctor, it is fatal now
168 throw new Error("Unable to resolve constructor for: '" + obj
.types
.join() + "'");
170 return this.construct(ctor
, obj
.node
, mixin
, options
, obj
.scripts
, obj
.inherited
);
173 // Call startup on each top level instance if it makes sense (as for
174 // widgets). Parent widgets will recursively call startup on their
175 // (non-top level) children
176 if(!mixin
._started
&& !options
.noStart
){
177 darray
.forEach(thelist
, function(instance
){
178 if(typeof instance
.startup
=== "function" && !instance
._started
){
187 construct: function(ctor
, node
, mixin
, options
, scripts
, inherited
){
189 // Calls new ctor(params, node), where params is the hash of parameters specified on the node,
190 // excluding data-dojo-type and data-dojo-mixins. Does not call startup(). Returns the widget.
192 // Widget constructor.
194 // This node will be replaced/attached to by the widget. It also specifies the arguments to pass to ctor.
196 // Attributes in this object will be passed as parameters to ctor,
197 // overriding attributes specified on the node.
199 // An options object used to hold kwArgs for instantiation. See parse.options argument for details.
200 // scripts: DomNode[]?
201 // Array of `<script type="dojo/*">` DOMNodes. If not specified, will search for `<script>` tags inside node.
202 // inherited: Object?
203 // Settings from dir=rtl or lang=... on a node above this node. Overrides options.inherited.
205 var proto
= ctor
&& ctor
.prototype;
206 options
= options
|| {};
208 // Setup hash to hold parameter settings for this widget. Start with the parameter
209 // settings inherited from ancestors ("dir" and "lang").
210 // Inherited setting may later be overridden by explicit settings on node itself.
213 if(options
.defaults
){
214 // settings for the document itself (or whatever subtree is being parsed)
215 dlang
.mixin(params
, options
.defaults
);
218 // settings from dir=rtl or lang=... on a node above this node
219 dlang
.mixin(params
, inherited
);
222 // Get list of attributes explicitly listed in the markup
224 if(has("dom-attributes-explicit")){
225 // Standard path to get list of user specified attributes
226 attributes
= node
.attributes
;
227 }else if(has("dom-attributes-specified-flag")){
228 // Special processing needed for IE8, to skip a few faux values in attributes[]
229 attributes
= darray
.filter(node
.attributes
, function(a
){ return a
.specified
;});
231 // Special path for IE6-7, avoid (sometimes >100) bogus entries in node.attributes
232 var clone
= /^input$|^img$/i.test(node
.nodeName
) ? node
: node
.cloneNode(false),
233 attrs
= clone
.outerHTML
.replace(/=[^\s"']+|="[^"]*"|='[^']*'/g, "").replace(/^\s*<[a-zA-Z0-9]*\s*/, "").replace(/\s*>.*$/, "");
235 attributes
= darray
.map(attrs
.split(/\s+/), function(name
){
236 var lcName
= name
.toLowerCase();
239 // getAttribute() doesn't work for button.value, returns innerHTML of button.
240 // but getAttributeNode().value doesn't work for the form.encType or li.value
241 value
: (node
.nodeName
== "LI" && name
== "value") || lcName
== "enctype" ?
242 node
.getAttribute(lcName
) : node
.getAttributeNode(lcName
).value
247 // Hash to convert scoped attribute name (ex: data-dojo17-params) to something friendly (ex: data-dojo-params)
248 // TODO: remove scope for 2.0
249 var scope
= options
.scope
|| dojo
._scopeName
,
250 attrData
= "data-" + scope
+ "-", // typically "data-dojo-"
252 if(scope
!== "dojo"){
253 hash
[attrData
+ "props"] = "data-dojo-props";
254 hash
[attrData
+ "type"] = "data-dojo-type";
255 hash
[attrData
+ "mixins"] = "data-dojo-mixins";
256 hash
[scope
+ "type"] = "dojoType";
257 hash
[attrData
+ "id"] = "data-dojo-id";
260 // Read in attributes and process them, including data-dojo-props, data-dojo-type,
261 // dojoAttachPoint, etc., as well as normal foo=bar attributes.
262 var i
=0, item
, funcAttrs
=[], jsname
, extra
;
263 while(item
= attributes
[i
++]){
264 var name
= item
.name
,
265 lcName
= name
.toLowerCase(),
268 switch(hash
[lcName
] || lcName
){
269 // Already processed, just ignore
270 case "data-dojo-type":
272 case "data-dojo-mixins":
275 // Data-dojo-props. Save for later to make sure it overrides direct foo=bar settings
276 case "data-dojo-props":
280 // data-dojo-id or jsId. TODO: drop jsId in 2.0
286 // For the benefit of _Templated
287 case "data-dojo-attach-point":
288 case "dojoattachpoint":
289 params
.dojoAttachPoint
= value
;
291 case "data-dojo-attach-event":
292 case "dojoattachevent":
293 params
.dojoAttachEvent
= value
;
296 // Special parameter handling needed for IE
298 params
["class"] = node
.className
;
301 params
["style"] = node
.style
&& node
.style
.cssText
;
304 // Normal attribute, ex: value="123"
306 // Find attribute in widget corresponding to specified name.
307 // May involve case conversion, ex: onclick --> onClick
308 if(!(name
in proto
)){
309 var map
= getNameMap(ctor
);
310 name
= map
[lcName
] || name
;
313 // Set params[name] to value, doing type conversion
315 switch(typeof proto
[name
]){
317 params
[name
] = value
;
320 params
[name
] = value
.length
? Number(value
) : NaN
;
323 // for checked/disabled value might be "" or "checked". interpret as true.
324 params
[name
] = value
.toLowerCase() != "false";
327 if(value
=== "" || value
.search(/[^\w\.]+/i) != -1){
328 // The user has specified some text for a function like "return x+5"
329 params
[name
] = new Function(value
);
331 // The user has specified the name of a global function like "myOnClick"
332 // or a single word function "return"
333 params
[name
] = dlang
.getObject(value
, false) || new Function(value
);
335 funcAttrs
.push(name
); // prevent "double connect", see #15026
338 var pVal
= proto
[name
];
340 (pVal
&& "length" in pVal
) ? (value
? value
.split(/\s*,\s*/) : []) : // array
341 (pVal
instanceof Date
) ?
342 (value
== "" ? new Date("") : // the NaN of dates
343 value
== "now" ? new Date() : // current date
344 dates
.fromISOString(value
)) :
345 (pVal
instanceof _Url
) ? (dojo
.baseUrl
+ value
) :
346 djson
.fromJson(value
);
349 params
[name
] = value
;
354 // Remove function attributes from DOMNode to prevent "double connect" problem, see #15026.
355 // Do this as a separate loop since attributes[] is often a live collection (depends on the browser though).
356 for(var j
=0; j
<funcAttrs
.length
; j
++){
357 var lcfname
= funcAttrs
[j
].toLowerCase();
358 node
.removeAttribute(lcfname
);
359 node
[lcfname
] = null;
362 // Mix things found in data-dojo-props into the params, overriding any direct settings
365 extra
= djson
.fromJson
.call(options
.propsThis
, "{" + extra
+ "}");
366 dlang
.mixin(params
, extra
);
368 // give the user a pointer to their invalid parameters. FIXME: can we kill this in production?
369 throw new Error(e
.toString() + " in data-dojo-props='" + extra
+ "'");
373 // Any parameters specified in "mixin" override everything else.
374 dlang
.mixin(params
, mixin
);
376 // Get <script> nodes associated with this widget, if they weren't specified explicitly
378 scripts
= (ctor
&& (ctor
._noScript
|| proto
._noScript
) ? [] : query("> script[type^='dojo/']", node
));
381 // Process <script type="dojo/*"> script tags
382 // <script type="dojo/method" event="foo"> tags are added to params, and passed to
383 // the widget on instantiation.
384 // <script type="dojo/method"> tags (with no event) are executed after instantiation
385 // <script type="dojo/connect" data-dojo-event="foo"> tags are dojo.connected after instantiation
386 // <script type="dojo/watch" data-dojo-prop="foo"> tags are dojo.watch after instantiation
387 // <script type="dojo/on" data-dojo-event="foo"> tags are dojo.on after instantiation
388 // note: dojo/* script tags cannot exist in self closing widgets, like <input />
389 var aspects
= [], // aspects to connect after instantiation
390 calls
= [], // functions to call after instantiation
391 watches
= [], // functions to watch after instantiation
392 ons
= []; // functions to on after instantiation
395 for(i
=0; i
<scripts
.length
; i
++){
396 var script
= scripts
[i
];
397 node
.removeChild(script
);
398 // FIXME: drop event="" support in 2.0. use data-dojo-event="" instead
399 var event
= (script
.getAttribute(attrData
+ "event") || script
.getAttribute("event")),
400 prop
= script
.getAttribute(attrData
+ "prop"),
401 method
= script
.getAttribute(attrData
+ "method"),
402 advice
= script
.getAttribute(attrData
+ "advice"),
403 scriptType
= script
.getAttribute("type"),
404 nf
= this._functionFromScript(script
, attrData
);
406 if(scriptType
== "dojo/connect"){
407 aspects
.push({ method
: event
, func
: nf
});
408 }else if(scriptType
== "dojo/on"){
409 ons
.push({ event
: event
, func
: nf
});
413 }else if(scriptType
== "dojo/aspect"){
414 aspects
.push({ method
: method
, advice
: advice
, func
: nf
});
415 }else if(scriptType
== "dojo/watch"){
416 watches
.push({ prop
: prop
, func
: nf
});
423 // create the instance
424 var markupFactory
= ctor
.markupFactory
|| proto
.markupFactory
;
425 var instance
= markupFactory
? markupFactory(params
, node
, ctor
) : new ctor(params
, node
);
427 // map it to the JS namespace if that makes sense
429 dlang
.setObject(jsname
, instance
);
432 // process connections and startup functions
433 for(i
=0; i
<aspects
.length
; i
++){
434 aspect
[aspects
[i
].advice
|| "after"](instance
, aspects
[i
].method
, dlang
.hitch(instance
, aspects
[i
].func
), true);
436 for(i
=0; i
<calls
.length
; i
++){
437 calls
[i
].call(instance
);
439 for(i
=0; i
<watches
.length
; i
++){
440 instance
.watch(watches
[i
].prop
, watches
[i
].func
);
442 for(i
=0; i
<ons
.length
; i
++){
443 don(instance
, ons
[i
].event
, ons
[i
].func
);
449 scan: function(root
, options
){
451 // Scan a DOM tree and return an array of objects representing the DOMNodes
452 // that need to be turned into widgets.
454 // Search specified node (or document root node) recursively for class instances
455 // and return an array of objects that represent potential widgets to be
456 // instantiated. Searches for either data-dojo-type="MID" or dojoType="MID" where
457 // "MID" is a module ID like "dijit/form/Button" or a fully qualified Class name
458 // like "dijit/form/Button". If the MID is not currently available, scan will
459 // attempt to require() in the module.
461 // See parser.parse() for details of markup.
463 // A default starting root node from which to start the parsing. Can be
464 // omitted, defaulting to the entire document. If omitted, the `options`
465 // object can be passed in this place. If the `options` object has a
466 // `rootNode` member, that is used.
468 // a kwArgs options object, see parse() for details
471 // A promise that is resolved with the nodes that have been parsed.
473 var list
= [], // Output List
474 mids
= [], // An array of modules that are not yet loaded
475 midsHash
= {}; // Used to keep the mids array unique
477 var dojoType
= (options
.scope
|| dojo
._scopeName
) + "Type", // typically "dojoType"
478 attrData
= "data-" + (options
.scope
|| dojo
._scopeName
) + "-", // typically "data-dojo-"
479 dataDojoType
= attrData
+ "type", // typically "data-dojo-type"
480 dataDojoTextDir
= attrData
+ "textdir", // typically "data-dojo-textdir"
481 dataDojoMixins
= attrData
+ "mixins"; // typically "data-dojo-mixins"
483 // Info on DOMNode currently being processed
484 var node
= root
.firstChild
;
486 // Info on parent of DOMNode currently being processed
487 // - inherited: dir, lang, and textDir setting of parent, or inherited by parent
488 // - parent: pointer to identical structure for my parent (or null if no parent)
489 // - scripts: if specified, collects <script type="dojo/..."> type nodes from children
490 var inherited
= options
.inherited
;
492 function findAncestorAttr(node
, attr
){
493 return (node
.getAttribute
&& node
.getAttribute(attr
)) ||
494 (node
.parentNode
&& findAncestorAttr(node
.parentNode
, attr
));
497 dir
: findAncestorAttr(root
, "dir"),
498 lang
: findAncestorAttr(root
, "lang"),
499 textDir
: findAncestorAttr(root
, dataDojoTextDir
)
501 for(var key
in inherited
){
502 if(!inherited
[key
]){ delete inherited
[key
]; }
506 // Metadata about parent node
511 // For collecting <script type="dojo/..."> type nodes (when null, we don't need to collect)
514 // when true, only look for <script type="dojo/..."> tags, and don't recurse to children
517 function getEffective(parent
){
519 // Get effective dir, lang, textDir settings for specified obj
520 // (matching "parent" object structure above), and do caching.
521 // Take care not to return null entries.
522 if(!parent
.inherited
){
523 parent
.inherited
= {};
524 var node
= parent
.node
,
525 grandparent
= getEffective(parent
.parent
);
527 dir
: node
.getAttribute("dir") || grandparent
.dir
,
528 lang
: node
.getAttribute("lang") || grandparent
.lang
,
529 textDir
: node
.getAttribute(dataDojoTextDir
) || grandparent
.textDir
531 for(var key
in inherited
){
533 parent
.inherited
[key
] = inherited
[key
];
537 return parent
.inherited
;
540 // DFS on DOM tree, collecting nodes with data-dojo-type specified.
543 // Finished this level, continue to parent's next sibling
544 if(!parent
|| !parent
.node
){
547 node
= parent
.node
.nextSibling
;
549 parent
= parent
.parent
;
550 scripts
= parent
.scripts
;
554 if(node
.nodeType
!= 1){
555 // Text or comment node, skip to next sibling
556 node
= node
.nextSibling
;
560 if(scripts
&& node
.nodeName
.toLowerCase() == "script"){
561 // Save <script type="dojo/..."> for parent, then continue to next sibling
562 type
= node
.getAttribute("type");
563 if(type
&& /^dojo\/\w/i.test(type
)){
566 node
= node
.nextSibling
;
570 // scriptsOnly flag is set, we have already collected scripts if the parent wants them, so now we shouldn't
571 // continue further analysis of the node and will continue to the next sibling
572 node
= node
.nextSibling
;
576 // Check for data-dojo-type attribute, fallback to backward compatible dojoType
577 // TODO: Remove dojoType in 2.0
578 var type
= node
.getAttribute(dataDojoType
) || node
.getAttribute(dojoType
);
580 // Short circuit for leaf nodes containing nothing [but text]
581 var firstChild
= node
.firstChild
;
582 if(!type
&& (!firstChild
|| (firstChild
.nodeType
== 3 && !firstChild
.nextSibling
))){
583 node
= node
.nextSibling
;
587 // Meta data about current node
592 // If dojoType/data-dojo-type specified, add to output array of nodes to instantiate.
593 var mixinsValue
= node
.getAttribute(dataDojoMixins
),
594 types
= mixinsValue
? [type
].concat(mixinsValue
.split(/\s*,\s*/)) : [type
];
596 // Note: won't find classes declared via dojo/Declaration or any modules that haven't been
597 // loaded yet so use try/catch to avoid throw from require()
599 ctor
= getCtor(types
);
602 // If the constructor was not found, check to see if it has modules that can be loaded
604 darray
.forEach(types
, function(t
){
605 if(~t
.indexOf('/') && !midsHash
[t
]){
606 // If the type looks like a MID and it currently isn't in the array of MIDs to load, add it.
608 mids
[mids
.length
] = t
;
613 var childScripts
= ctor
&& !ctor
.prototype._noScript
? [] : null; // <script> nodes that are parent's children
615 // Setup meta data about this widget node, and save it to list of nodes to instantiate
621 scripts
: childScripts
623 current
.inherited
= getEffective(current
); // dir & lang settings for current node, explicit or inherited
626 // Meta data about this non-widget node
634 // Recurse, collecting <script type="dojo/..."> children, and also looking for
635 // descendant nodes with dojoType specified (unless the widget has the stopParser flag).
636 // When finished with children, go to my next sibling.
638 scripts
= childScripts
;
639 scriptsOnly
= ctor
&& ctor
.prototype.stopParser
&& !(options
.template
);
643 var d
= new Deferred();
645 // If there are modules to load then require them in
647 // Warn that there are modules being auto-required
648 if(has("dojo-debug-messages")){
649 console
.warn("WARNING: Modules being Auto-Required: " + mids
.join(", "));
651 require(mids
, function(){
652 // Go through list of widget nodes, filling in missing constructors, and filtering out nodes that shouldn't
653 // be instantiated due to a stopParser flag on an ancestor that we belatedly learned about due to
654 // auto-require of a module like ContentPane. Assumes list is in DFS order.
655 d
.resolve(darray
.filter(list
, function(widget
){
657 // Attempt to find the constructor again. Still won't find classes defined via
658 // dijit/Declaration so need to try/catch.
660 widget
.ctor
= getCtor(widget
.types
);
664 // Get the parent widget
665 var parent
= widget
.parent
;
666 while(parent
&& !parent
.types
){
667 parent
= parent
.parent
;
670 // Return false if this node should be skipped due to stopParser on an ancestor.
671 // Since list[] is in DFS order, this loop will always set parent.instantiateChildren before
672 // trying to compute widget.instantiate.
673 var proto
= widget
.ctor
&& widget
.ctor
.prototype;
674 widget
.instantiateChildren
= !(proto
&& proto
.stopParser
&& !(options
.template
));
675 widget
.instantiate
= !parent
|| (parent
.instantiate
&& parent
.instantiateChildren
);
676 return widget
.instantiate
;
680 // There were no modules to load, so just resolve with the parsed nodes. This separate code path is for
681 // efficiency, to avoid running the require() and the callback code above.
685 // Return the promise
689 _require: function(/*DOMNode*/ script
){
691 // Helper for _scanAMD(). Takes a `<script type=dojo/require>bar: "acme/bar", ...</script>` node,
692 // calls require() to load the specified modules and (asynchronously) assign them to the specified global
693 // variables, and returns a Promise for when that operation completes.
695 // In the example above, it is effectively doing a require(["acme/bar", ...], function(a){ bar = a; }).
697 var hash
= djson
.fromJson("{" + script
.innerHTML
+ "}"),
702 for(var name
in hash
){
704 mids
.push(hash
[name
]);
707 require(mids
, function(){
708 for(var i
=0; i
<vars
.length
; i
++){
709 dlang
.setObject(vars
[i
], arguments
[i
]);
711 d
.resolve(arguments
);
717 _scanAmd: function(root
){
719 // Scans the DOM for any declarative requires and returns their values.
721 // Looks for `<script type=dojo/require>bar: "acme/bar", ...</script>` node, calls require() to load the
722 // specified modules and (asynchronously) assign them to the specified global variables,
723 // and returns a Promise for when those operations complete.
725 // The node to base the scan from.
727 // Promise that resolves when all the <script type=dojo/require> nodes have finished loading.
728 var deferred
= new Deferred(),
729 promise
= deferred
.promise
;
730 deferred
.resolve(true);
733 query("script[type='dojo/require']", root
).forEach(function(node
){
734 // Fire off require() call for specified modules. Chain this require to fire after
735 // any previous requires complete, so that layers can be loaded before individual module require()'s fire.
736 promise
= promise
.then(function(){ return self
._require(node
); });
738 // Remove from DOM so it isn't seen again
739 node
.parentNode
.removeChild(node
);
745 parse: function(rootNode
, options
){
747 // Scan the DOM for class instances, and instantiate them.
749 // Search specified node (or root node) recursively for class instances,
750 // and instantiate them. Searches for either data-dojo-type="Class" or
751 // dojoType="Class" where "Class" is a a fully qualified class name,
752 // like `dijit/form/Button`
754 // Using `data-dojo-type`:
755 // Attributes using can be mixed into the parameters used to instantiate the
756 // Class by using a `data-dojo-props` attribute on the node being converted.
757 // `data-dojo-props` should be a string attribute to be converted from JSON.
760 // Attributes are read from the original domNode and converted to appropriate
761 // types by looking up the Class prototype values. This is the default behavior
762 // from Dojo 1.0 to Dojo 1.5. `dojoType` support is deprecated, and will
763 // go away in Dojo 2.0.
764 // rootNode: DomNode?
765 // A default starting root node from which to start the parsing. Can be
766 // omitted, defaulting to the entire document. If omitted, the `options`
767 // object can be passed in this place. If the `options` object has a
768 // `rootNode` member, that is used.
770 // A hash of options.
772 // - noStart: Boolean?:
773 // when set will prevent the parser from calling .startup()
774 // when locating the nodes.
775 // - rootNode: DomNode?:
776 // identical to the function's `rootNode` argument, though
777 // allowed to be passed in via this `options object.
778 // - template: Boolean:
779 // If true, ignores ContentPane's stopParser flag and parses contents inside of
780 // a ContentPane inside of a template. This allows dojoAttachPoint on widgets/nodes
781 // nested inside the ContentPane to work.
782 // - inherited: Object:
783 // Hash possibly containing dir and lang settings to be applied to
784 // parsed widgets, unless there's another setting on a sub-node that overrides
786 // Root for attribute names to search for. If scopeName is dojo,
787 // will search for data-dojo-type (or dojoType). For backwards compatibility
788 // reasons defaults to dojo._scopeName (which is "dojo" except when
789 // multi-version support is used, when it will be something like dojo16, dojo20, etc.)
790 // - propsThis: Object:
791 // If specified, "this" referenced from data-dojo-props will refer to propsThis.
792 // Intended for use from the widgets-in-template feature of `dijit._WidgetsInTemplateMixin`
794 // Returns a blended object that is an array of the instantiated objects, but also can include
795 // a promise that is resolved with the instantiated objects. This is done for backwards
796 // compatibility. If the parser auto-requires modules, it will always behave in a promise
797 // fashion and `parser.parse().then(function(instances){...})` should be used.
799 // Parse all widgets on a page:
802 // Parse all classes within the node with id="foo"
803 // | parser.parse(dojo.byId('foo'));
805 // Parse all classes in a page, but do not call .startup() on any
807 // | parser.parse({ noStart: true })
809 // Parse all classes in a node, but do not call .startup()
810 // | parser.parse(someNode, { noStart:true });
812 // | parser.parse({ noStart:true, rootNode: someNode });
814 // determine the root node and options based on the passed arguments.
816 if(!options
&& rootNode
&& rootNode
.rootNode
){
818 root
= options
.rootNode
;
819 }else if(rootNode
&& dlang
.isObject(rootNode
) && !("nodeType" in rootNode
)){
824 root
= root
? dhtml
.byId(root
) : dwindow
.body();
826 options
= options
|| {};
828 var mixin
= options
.template
? { template
: true } : {},
832 // First scan for any <script type=dojo/require> nodes, and execute.
833 // Then scan for all nodes with data-dojo-type, and load any unloaded modules.
834 // Then build the object instances. Add instances to already existing (but empty) instances[] array,
835 // which may already have been returned to caller. Also, use otherwise to collect and throw any errors
836 // that occur during the parse().
838 this._scanAmd(root
, options
).then(function(){
839 return self
.scan(root
, options
);
840 }).then(function(parsedNodes
){
841 return instances
= instances
.concat(self
._instantiate(parsedNodes
, mixin
, options
));
842 }).otherwise(function(e
){
843 // TODO Modify to follow better pattern for promise error managment when available
844 console
.error("dojo/parser::parse() error", e
);
848 // Blend the array with the promise
849 dlang
.mixin(instances
, p
);
855 dojo
.parser
= parser
;
858 // Register the parser callback. It should be the first callback
859 // after the a11y test.
860 if(config
.parseOnLoad
){
861 ready(100, parser
, "parse");