html.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. if (!dojo._hasResource["dojox.dtl.html"]) { // _hasResource checks added by
  2. // build. Do not use _hasResource
  3. // directly in your code.
  4. dojo._hasResource["dojox.dtl.html"] = true;
  5. dojo.provide("dojox.dtl.html");
  6. dojo.require("dojox.dtl._base");
  7. dojox.dtl.ObjectMap = function() {
  8. this.contents = [];
  9. }
  10. dojo.extend(dojox.dtl.ObjectMap, {
  11. get : function(key) {
  12. var contents = this.contents;
  13. for (var i = 0, content; content = contents[i]; i++) {
  14. if (content[0] === key) {
  15. return content[1];
  16. }
  17. }
  18. },
  19. put : function(key, value) {
  20. var contents = this.contents;
  21. for (var i = 0, content; content = contents[i]; i++) {
  22. if (content[0] === key) {
  23. if (arguments.length == 1) {
  24. contents.splice(i, 1);
  25. return;
  26. }
  27. content[1] = value;
  28. return;
  29. }
  30. }
  31. contents.push([key, value]);
  32. },
  33. toString : function() {
  34. return "dojox.dtl.ObjectMap";
  35. }
  36. });
  37. dojox.dtl.html = {
  38. types : dojo.mixin({
  39. change : -11,
  40. attr : -12,
  41. elem : 1,
  42. text : 3
  43. }, dojox.dtl.text.types),
  44. _attributes : {},
  45. _re : /(^\s+|\s+$)/g,
  46. _re2 : /\b([a-zA-Z]+)="/g,
  47. _re3 : /<!--({({|%).*?(%|})})-->/g,
  48. _re4 : /^function anonymous\(\)\s*{\s*(.*)\s*}$/,
  49. _trim : function(/* String */str) {
  50. return str.replace(this._re, "");
  51. },
  52. getTemplate : function(text) {
  53. if (typeof this._commentable == "undefined") {
  54. // Check to see if the browser can handle comments
  55. this._commentable = false;
  56. var div = document.createElement("div");
  57. div.innerHTML = "<!--Test comment handling, and long comments, using comments whenever possible.-->";
  58. if (div.childNodes.length && div.childNodes[0].nodeType == 8
  59. && div.childNodes[0].data == "comment") {
  60. this._commentable = true;
  61. }
  62. }
  63. if (!this._commentable) {
  64. // Strip comments
  65. text = text.replace(this._re3, "$1");
  66. }
  67. var match;
  68. while (match = this._re2.exec(text)) {
  69. this._attributes[match[1]] = true;
  70. }
  71. var div = document.createElement("div");
  72. div.innerHTML = text;
  73. var output = {
  74. pres : [],
  75. posts : []
  76. }
  77. while (div.childNodes.length) {
  78. if (!output.node && div.childNodes[0].nodeType == 1) {
  79. output.node = div.removeChild(div.childNodes[0]);
  80. } else if (!output.node) {
  81. output.pres.push(div.removeChild(div.childNodes[0]));
  82. } else {
  83. output.posts.push(div.removeChild(div.childNodes[0]));
  84. }
  85. }
  86. if (!output.node) {
  87. throw new Error("Template did not provide any content");
  88. }
  89. return output;
  90. },
  91. tokenize : function(/* Node */node, /* Array? */tokens, /* Array? */
  92. preNodes, /* Array? */postNodes) {
  93. tokens = tokens || [];
  94. var first = !tokens.length;
  95. var types = this.types;
  96. var children = [];
  97. for (var i = 0, child; child = node.childNodes[i]; i++) {
  98. children.push(child);
  99. }
  100. if (preNodes) {
  101. for (var i = 0, child; child = preNodes[i]; i++) {
  102. this._tokenize(node, child, tokens);
  103. }
  104. }
  105. tokens.push([types.elem, node]);
  106. tokens.push([types.change, node]);
  107. for (var key in this._attributes) {
  108. var value = "";
  109. if (key == "class") {
  110. value = node.className || value;
  111. } else if (key == "for") {
  112. value = node.htmlFor || value;
  113. } else if (node.getAttribute) {
  114. value = node.getAttribute(key, 2) || value;
  115. if (key == "href" || key == "src") {
  116. if (dojo.isIE) {
  117. var hash = location.href.lastIndexOf(location.hash);
  118. var href = location.href.substring(0, hash)
  119. .split("/");
  120. href.pop();
  121. href = href.join("/") + "/";
  122. if (value.indexOf(href) == 0) {
  123. value = value.replace(href, "");
  124. }
  125. value = value.replace(/%20/g, " ").replace(/%7B/g,
  126. "{").replace(/%7D/g, "}").replace(/%25/g,
  127. "%");
  128. }
  129. if (value.indexOf("{%") != -1
  130. || value.indexOf("{{") != -1) {
  131. node.setAttribute(key, "");
  132. }
  133. }
  134. }
  135. if (typeof value == "function") {
  136. value = value.toString().replace(this._re4, "$1");
  137. }
  138. if (typeof value == "string"
  139. && (value.indexOf("{%") != -1
  140. || value.indexOf("{{") != -1 || (value && dojox.dtl.text
  141. .getTag("attr:" + key, true)))) {
  142. tokens.push([types.attr, node, key, value]);
  143. }
  144. }
  145. if (!children.length) {
  146. tokens.push([types.change, node.parentNode, true]);
  147. if (postNodes) {
  148. for (var i = 0, child; child = postNodes[i]; i++) {
  149. this._tokenize(node, child, tokens);
  150. }
  151. }
  152. return tokens;
  153. }
  154. for (var i = 0, child; child = children[i]; i++) {
  155. this._tokenize(node, child, tokens);
  156. }
  157. if (node.parentNode && node.parentNode.tagName) {
  158. tokens.push([types.change, node.parentNode, true]);
  159. node.parentNode.removeChild(node);
  160. }
  161. if (postNodes) {
  162. for (var i = 0, child; child = postNodes[i]; i++) {
  163. this._tokenize(node, child, tokens);
  164. }
  165. }
  166. if (first) {
  167. tokens.push([types.change, node, true]);
  168. }
  169. return tokens;
  170. },
  171. _tokenize : function(parent, child, tokens) {
  172. var types = this.types;
  173. var data = child.data;
  174. switch (child.nodeType) {
  175. case 1 :
  176. this.tokenize(child, tokens);
  177. break;
  178. case 3 :
  179. if (data.match(/[^\s\n]/)) {
  180. if (data.indexOf("{{") != -1
  181. || data.indexOf("{%") != -1) {
  182. var texts = dojox.dtl.text.tokenize(data);
  183. for (var j = 0, text; text = texts[j]; j++) {
  184. if (typeof text == "string") {
  185. tokens.push([types.text, text]);
  186. } else {
  187. tokens.push(text);
  188. }
  189. }
  190. } else {
  191. tokens.push([child.nodeType, child]);
  192. }
  193. }
  194. if (child.parentNode)
  195. child.parentNode.removeChild(child);
  196. break;
  197. case 8 :
  198. if (data.indexOf("{%") == 0) {
  199. tokens
  200. .push([
  201. types.tag,
  202. this._trim(data.substring(2,
  203. data.length - 3))]);
  204. }
  205. if (data.indexOf("{{") == 0) {
  206. tokens
  207. .push([
  208. types.varr,
  209. this._trim(data.substring(2,
  210. data.length - 3))]);
  211. }
  212. if (child.parentNode)
  213. child.parentNode.removeChild(child);
  214. break;
  215. }
  216. }
  217. }
  218. dojox.dtl.HtmlTemplate = function(/* String|dojo._Url */obj) {
  219. // summary: Use this object for HTML templating
  220. var dd = dojox.dtl;
  221. var ddh = dd.html;
  222. if (!obj.node) {
  223. if (typeof obj == "object") {
  224. obj = dojox.dtl.text.getTemplateString(obj);
  225. }
  226. obj = ddh.getTemplate(obj);
  227. }
  228. var tokens = ddh.tokenize(obj.node, [], obj.pres, obj.posts);
  229. var parser = new dd.HtmlParser(tokens);
  230. this.nodelist = parser.parse();
  231. }
  232. dojo.extend(dojox.dtl.HtmlTemplate, {
  233. _count : 0,
  234. _re : /\bdojo:([a-zA-Z0-9_]+)\b/g,
  235. setClass : function(str) {
  236. this.getRootNode().className = str;
  237. },
  238. getRootNode : function() {
  239. return this.rootNode;
  240. },
  241. getBuffer : function() {
  242. return new dojox.dtl.HtmlBuffer();
  243. },
  244. render : function(context, buffer) {
  245. buffer = buffer || this.getBuffer();
  246. this.rootNode = null;
  247. var onSetParent = dojo.connect(buffer, "onSetParent", this,
  248. function(node) {
  249. if (!this.rootNode) {
  250. this.rootNode = node || true;
  251. }
  252. });
  253. var output = this.nodelist.render(context
  254. || new dojox.dtl.Context({}), buffer);
  255. dojo.disconnect(onSetParent);
  256. buffer._flushCache();
  257. return output;
  258. },
  259. unrender : function(context, buffer) {
  260. return this.nodelist.unrender(context, buffer);
  261. },
  262. toString : function() {
  263. return "dojox.dtl.HtmlTemplate";
  264. }
  265. });
  266. dojox.dtl.HtmlBuffer = function(/* Node */parent) {
  267. // summary: Allows the manipulation of DOM
  268. // description:
  269. // Use this to append a child, change the parent, or
  270. // change the attribute of the current node.
  271. this._parent = parent;
  272. this._cache = [];
  273. }
  274. dojo.extend(dojox.dtl.HtmlBuffer, {
  275. concat : function(/* DOMNode */node) {
  276. if (!this._parent)
  277. return this;
  278. if (node.nodeType) {
  279. var caches = this._getCache(this._parent);
  280. if (node.parentNode === this._parent) {
  281. // If we reach a node that already existed, fill in the
  282. // cache for this same parent
  283. var i = 0;
  284. for (var i = 0, cache; cache = caches[i]; i++) {
  285. this.onAddNode(node);
  286. this._parent.insertBefore(cache, node);
  287. }
  288. caches.length = 0;
  289. }
  290. if (!node.parentNode || !node.parentNode.tagName) {
  291. if (!this._parent.childNodes.length) {
  292. this.onAddNode(node);
  293. this._parent.appendChild(node);
  294. } else {
  295. caches.push(node);
  296. }
  297. }
  298. }
  299. return this;
  300. },
  301. remove : function(obj) {
  302. if (typeof obj == "string") {
  303. this._parent.removeAttribute(obj);
  304. } else {
  305. if (obj.parentNode === this._parent) {
  306. this.onRemoveNode();
  307. this._parent.removeChild(obj);
  308. }
  309. }
  310. return this;
  311. },
  312. setAttribute : function(key, value) {
  313. if (key == "class") {
  314. this._parent.className = value;
  315. } else if (key == "for") {
  316. this._parent.htmlFor = value;
  317. } else if (this._parent.setAttribute) {
  318. this._parent.setAttribute(key, value);
  319. }
  320. return this;
  321. },
  322. setParent : function(node, /* Boolean? */up) {
  323. if (!this._parent)
  324. this._parent = node;
  325. var caches = this._getCache(this._parent);
  326. if (caches && caches.length && up) {
  327. for (var i = 0, cache; cache = caches[i]; i++) {
  328. if (cache !== this._parent
  329. && (!cache.parentNode || !cache.parentNode.tagName)) {
  330. this.onAddNode(cache);
  331. this._parent.appendChild(cache);
  332. }
  333. }
  334. caches.length = 0;
  335. }
  336. this.onSetParent(node, up);
  337. this._parent = node;
  338. return this;
  339. },
  340. getParent : function() {
  341. return this._parent;
  342. },
  343. onSetParent : function() {
  344. // summary: Stub called when setParent is used.
  345. },
  346. onAddNode : function() {
  347. // summary: Stub called when new nodes are added
  348. },
  349. onRemoveNode : function() {
  350. // summary: Stub called when nodes are removed
  351. },
  352. _getCache : function(node) {
  353. for (var i = 0, cache; cache = this._cache[i]; i++) {
  354. if (cache[0] === node) {
  355. return cache[1];
  356. }
  357. }
  358. var arr = [];
  359. this._cache.push([node, arr]);
  360. return arr;
  361. },
  362. _flushCache : function(node) {
  363. for (var i = 0, cache; cache = this._cache[i]; i++) {
  364. if (!cache[1].length) {
  365. this._cache.splice(i--, 1);
  366. }
  367. }
  368. },
  369. toString : function() {
  370. return "dojox.dtl.HtmlBuffer";
  371. }
  372. });
  373. dojox.dtl.HtmlNode = function(node) {
  374. // summary: Places a node into DOM
  375. this.contents = node;
  376. }
  377. dojo.extend(dojox.dtl.HtmlNode, {
  378. render : function(context, buffer) {
  379. return buffer.concat(this.contents);
  380. },
  381. unrender : function(context, buffer) {
  382. return buffer.remove(this.contents);
  383. },
  384. clone : function(buffer) {
  385. return new dojox.dtl.HtmlNode(this.contents);
  386. },
  387. toString : function() {
  388. return "dojox.dtl.HtmlNode";
  389. }
  390. });
  391. dojox.dtl.HtmlNodeList = function(/* Node[] */nodes) {
  392. // summary: A list of any HTML-specific node object
  393. // description:
  394. // Any object that's used in the constructor or added
  395. // through the push function much implement the
  396. // render, unrender, and clone functions.
  397. this.contents = nodes || [];
  398. }
  399. dojo.extend(dojox.dtl.HtmlNodeList, {
  400. parents : new dojox.dtl.ObjectMap(),
  401. push : function(node) {
  402. this.contents.push(node);
  403. },
  404. unshift : function(node) {
  405. this.contents.unshift(node);
  406. },
  407. render : function(context, buffer, /* Node */instance) {
  408. if (instance) {
  409. var parent = buffer.getParent();
  410. }
  411. for (var i = 0; i < this.contents.length; i++) {
  412. buffer = this.contents[i].render(context, buffer);
  413. if (!buffer)
  414. throw new Error("Template node render functions must return their buffer");
  415. }
  416. if (parent) {
  417. buffer.setParent(parent, true);
  418. }
  419. return buffer;
  420. },
  421. unrender : function(context, buffer) {
  422. for (var i = 0; i < this.contents.length; i++) {
  423. buffer = this.contents[i].unrender(context, buffer);
  424. if (!buffer)
  425. throw new Error("Template node render functions must return their buffer");
  426. }
  427. return buffer;
  428. },
  429. clone : function(buffer) {
  430. // summary:
  431. // Used to create an identical copy of a NodeList, useful for things
  432. // like the for tag.
  433. var dd = dojox.dtl;
  434. var ddh = dd.html;
  435. var parent = buffer.getParent();
  436. var contents = this.contents;
  437. var nodelist = new dd.HtmlNodeList();
  438. var cloned = [];
  439. for (var i = 0; i < contents.length; i++) {
  440. var clone = contents[i].clone(buffer);
  441. if (clone instanceof dd.ChangeNode
  442. || clone instanceof dd.HtmlNode) {
  443. var item = this.parents.get(clone.contents);
  444. if (item) {
  445. clone.contents = item;
  446. } else if (parent !== clone.contents
  447. && clone instanceof dd.HtmlNode) {
  448. var node = clone.contents;
  449. clone.contents = clone.contents.cloneNode(false);
  450. cloned.push(node);
  451. this.parents.put(node, clone.contents);
  452. }
  453. }
  454. nodelist.push(clone);
  455. }
  456. for (var i = 0, clone; clone = cloned[i]; i++) {
  457. this.parents.put(clone);
  458. }
  459. return nodelist;
  460. },
  461. toString : function() {
  462. return "dojox.dtl.HtmlNodeList";
  463. }
  464. });
  465. dojox.dtl.HtmlVarNode = function(str) {
  466. // summary: A node to be processed as a variable
  467. // description:
  468. // Will render an object that supports the render function
  469. // and the getRootNode function
  470. this.contents = new dojox.dtl.Filter(str);
  471. this._lists = {};
  472. }
  473. dojo.extend(dojox.dtl.HtmlVarNode, {
  474. render : function(context, buffer) {
  475. this._rendered = true;
  476. var dd = dojox.dtl;
  477. var ddh = dd.html;
  478. var str = this.contents.resolve(context);
  479. if (str && str.render && str.getRootNode) {
  480. var root = this._curr = str.getRootNode();
  481. var lists = this._lists;
  482. var list = lists[root];
  483. if (!list) {
  484. list = lists[root] = new dd.HtmlNodeList();
  485. list.push(new dd.ChangeNode(buffer.getParent()));
  486. list.push(new dd.HtmlNode(root));
  487. list.push(str);
  488. list.push(new dd.ChangeNode(buffer.getParent(),
  489. true));
  490. }
  491. return list.render(context, buffer);
  492. } else {
  493. if (!this._txt)
  494. this._txt = document.createTextNode(str);
  495. if (this._txt.data != str)
  496. this._txt.data = str;
  497. return buffer.concat(this._txt);
  498. }
  499. return buffer;
  500. },
  501. unrender : function(context, buffer) {
  502. if (this._rendered) {
  503. this._rendered = false;
  504. if (this._curr) {
  505. return this._lists[this._curr].unrender(context,
  506. buffer);
  507. } else if (this._txt) {
  508. return buffer.remove(this._txt);
  509. }
  510. }
  511. return buffer;
  512. },
  513. clone : function() {
  514. return new dojox.dtl.HtmlVarNode(this.contents.contents);
  515. },
  516. toString : function() {
  517. return "dojox.dtl.HtmlVarNode";
  518. }
  519. });
  520. dojox.dtl.ChangeNode = function(node, /* Boolean? */up) {
  521. // summary: Changes the parent during render/unrender
  522. this.contents = node;
  523. this._up = up;
  524. }
  525. dojo.extend(dojox.dtl.ChangeNode, {
  526. render : function(context, buffer) {
  527. return buffer.setParent(this.contents, this._up);
  528. },
  529. unrender : function(context, buffer) {
  530. return buffer.setParent(this.contents);
  531. },
  532. clone : function(buffer) {
  533. return new dojox.dtl.ChangeNode(this.contents, this._up);
  534. },
  535. toString : function() {
  536. return "dojox.dtl.ChangeNode";
  537. }
  538. });
  539. dojox.dtl.AttributeNode = function(key, value) {
  540. // summary: Works on attributes
  541. this._key = key;
  542. this._value = value;
  543. this._tpl = new dojox.dtl.Template(value);
  544. this.contents = "";
  545. }
  546. dojo.extend(dojox.dtl.AttributeNode, {
  547. render : function(context, buffer) {
  548. var key = this._key;
  549. var value = this._tpl.render(context);
  550. if (this._rendered) {
  551. if (value != this.contents) {
  552. this.contents = value;
  553. return buffer.setAttribute(key, value);
  554. }
  555. } else {
  556. this._rendered = true;
  557. this.contents = value;
  558. return buffer.setAttribute(key, value);
  559. }
  560. return buffer;
  561. },
  562. unrender : function(context, buffer) {
  563. if (this._rendered) {
  564. this._rendered = false;
  565. this.contents = "";
  566. return buffer.remove(this.contents);
  567. }
  568. return buffer;
  569. },
  570. clone : function() {
  571. return new dojox.dtl.AttributeNode(this._key, this._value);
  572. },
  573. toString : function() {
  574. return "dojox.dtl.AttributeNode";
  575. }
  576. });
  577. dojox.dtl.HtmlTextNode = function(str) {
  578. // summary: Adds a straight text node without any processing
  579. this.contents = document.createTextNode(str);
  580. }
  581. dojo.extend(dojox.dtl.HtmlTextNode, {
  582. render : function(context, buffer) {
  583. return buffer.concat(this.contents);
  584. },
  585. unrender : function(context, buffer) {
  586. return buffer.remove(this.contents);
  587. },
  588. clone : function() {
  589. return new dojox.dtl.HtmlTextNode(this.contents.data);
  590. },
  591. toString : function() {
  592. return "dojox.dtl.HtmlTextNode";
  593. }
  594. });
  595. dojox.dtl.HtmlParser = function(tokens) {
  596. // summary: Turn a simple array into a set of objects
  597. // description:
  598. // This is also used by all tags to move through
  599. // the list of nodes.
  600. this.contents = tokens;
  601. }
  602. dojo.extend(dojox.dtl.HtmlParser, {
  603. parse : function(/* Array? */stop_at) {
  604. var dd = dojox.dtl;
  605. var ddh = dd.html;
  606. var types = ddh.types;
  607. var terminators = {};
  608. var tokens = this.contents;
  609. if (!stop_at) {
  610. stop_at = [];
  611. }
  612. for (var i = 0; i < stop_at.length; i++) {
  613. terminators[stop_at[i]] = true;
  614. }
  615. var nodelist = new dd.HtmlNodeList();
  616. while (tokens.length) {
  617. var token = tokens.shift();
  618. var type = token[0];
  619. var value = token[1];
  620. if (type == types.change) {
  621. nodelist.push(new dd.ChangeNode(value, token[2]));
  622. } else if (type == types.attr) {
  623. var fn = dojox.dtl.text.getTag("attr:" + token[2], true);
  624. if (fn) {
  625. nodelist.push(fn(null, token[2] + " " + token[3]));
  626. } else {
  627. nodelist.push(new dd.AttributeNode(token[2], token[3]));
  628. }
  629. } else if (type == types.elem) {
  630. var fn = dojox.dtl.text.getTag("node:"
  631. + value.tagName.toLowerCase(), true);
  632. if (fn) {
  633. // TODO: We need to move this to tokenization so that
  634. // it's before the
  635. // node and the parser can be passed here instead of
  636. // null
  637. nodelist.push(fn(null, value, value.tagName
  638. .toLowerCase()));
  639. }
  640. nodelist.push(new dd.HtmlNode(value));
  641. } else if (type == types.varr) {
  642. nodelist.push(new dd.HtmlVarNode(value));
  643. } else if (type == types.text) {
  644. nodelist.push(new dd.HtmlTextNode(value.data || value));
  645. } else if (type == types.tag) {
  646. if (terminators[value]) {
  647. tokens.unshift(token);
  648. return nodelist;
  649. }
  650. var cmd = value.split(/\s+/g);
  651. if (cmd.length) {
  652. cmd = cmd[0];
  653. var fn = dojox.dtl.text.getTag(cmd);
  654. if (typeof fn != "function") {
  655. throw new Error("Function not found for ", cmd);
  656. }
  657. var tpl = fn(this, value);
  658. if (tpl) {
  659. nodelist.push(tpl);
  660. }
  661. }
  662. }
  663. }
  664. if (stop_at.length) {
  665. throw new Error("Could not find closing tag(s): "
  666. + stop_at.toString());
  667. }
  668. return nodelist;
  669. },
  670. next : function() {
  671. // summary: Used by tags to discover what token was found
  672. var token = this.contents.shift();
  673. return {
  674. type : token[0],
  675. text : token[1]
  676. };
  677. },
  678. skipPast : function(endtag) {
  679. return dojox.dtl.Parser.prototype.skipPast.call(this, endtag);
  680. },
  681. getVarNode : function() {
  682. return dojox.dtl.HtmlVarNode;
  683. },
  684. getTextNode : function() {
  685. return dojox.dtl.HtmlTextNode;
  686. },
  687. getTemplate : function(/* String */loc) {
  688. return new dojox.dtl.HtmlTemplate(dojox.dtl.html.getTemplate(loc));
  689. },
  690. toString : function() {
  691. return "dojox.dtl.HtmlParser";
  692. }
  693. });
  694. dojox.dtl.register.tag("dojox.dtl.tag.event", "dojox.dtl.tag.event", [[
  695. /(attr:)?on(click|key(up))/i, "on"]]);
  696. dojox.dtl.register.tag("dojox.dtl.tag.html", "dojox.dtl.tag.html", ["html",
  697. "attr:attach", "attr:tstyle"]);
  698. }