parser.js 25 KB

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