/tags/release/7020-RC6/aipo/war/src/main/webapp/javascript/dojo/parser.xd.js

http://aipo.googlecode.com/ · JavaScript · 277 lines · 200 code · 26 blank · 51 comment · 48 complexity · 7aa74b706f7ef1e2890e9f8a4b943a4f MD5 · raw file

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