123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733 |
- if (!dojo._hasResource["dojox.dtl.html"]) { // _hasResource checks added by
- // build. Do not use _hasResource
- // directly in your code.
- dojo._hasResource["dojox.dtl.html"] = true;
- dojo.provide("dojox.dtl.html");
- dojo.require("dojox.dtl._base");
- dojox.dtl.ObjectMap = function() {
- this.contents = [];
- }
- dojo.extend(dojox.dtl.ObjectMap, {
- get : function(key) {
- var contents = this.contents;
- for (var i = 0, content; content = contents[i]; i++) {
- if (content[0] === key) {
- return content[1];
- }
- }
- },
- put : function(key, value) {
- var contents = this.contents;
- for (var i = 0, content; content = contents[i]; i++) {
- if (content[0] === key) {
- if (arguments.length == 1) {
- contents.splice(i, 1);
- return;
- }
- content[1] = value;
- return;
- }
- }
- contents.push([key, value]);
- },
- toString : function() {
- return "dojox.dtl.ObjectMap";
- }
- });
- dojox.dtl.html = {
- types : dojo.mixin({
- change : -11,
- attr : -12,
- elem : 1,
- text : 3
- }, dojox.dtl.text.types),
- _attributes : {},
- _re : /(^\s+|\s+$)/g,
- _re2 : /\b([a-zA-Z]+)="/g,
- _re3 : /<!--({({|%).*?(%|})})-->/g,
- _re4 : /^function anonymous\(\)\s*{\s*(.*)\s*}$/,
- _trim : function(/* String */str) {
- return str.replace(this._re, "");
- },
- getTemplate : function(text) {
- if (typeof this._commentable == "undefined") {
- // Check to see if the browser can handle comments
- this._commentable = false;
- var div = document.createElement("div");
- div.innerHTML = "<!--Test comment handling, and long comments, using comments whenever possible.-->";
- if (div.childNodes.length && div.childNodes[0].nodeType == 8
- && div.childNodes[0].data == "comment") {
- this._commentable = true;
- }
- }
- if (!this._commentable) {
- // Strip comments
- text = text.replace(this._re3, "$1");
- }
- var match;
- while (match = this._re2.exec(text)) {
- this._attributes[match[1]] = true;
- }
- var div = document.createElement("div");
- div.innerHTML = text;
- var output = {
- pres : [],
- posts : []
- }
- while (div.childNodes.length) {
- if (!output.node && div.childNodes[0].nodeType == 1) {
- output.node = div.removeChild(div.childNodes[0]);
- } else if (!output.node) {
- output.pres.push(div.removeChild(div.childNodes[0]));
- } else {
- output.posts.push(div.removeChild(div.childNodes[0]));
- }
- }
- if (!output.node) {
- throw new Error("Template did not provide any content");
- }
- return output;
- },
- tokenize : function(/* Node */node, /* Array? */tokens, /* Array? */
- preNodes, /* Array? */postNodes) {
- tokens = tokens || [];
- var first = !tokens.length;
- var types = this.types;
- var children = [];
- for (var i = 0, child; child = node.childNodes[i]; i++) {
- children.push(child);
- }
- if (preNodes) {
- for (var i = 0, child; child = preNodes[i]; i++) {
- this._tokenize(node, child, tokens);
- }
- }
- tokens.push([types.elem, node]);
- tokens.push([types.change, node]);
- for (var key in this._attributes) {
- var value = "";
- if (key == "class") {
- value = node.className || value;
- } else if (key == "for") {
- value = node.htmlFor || value;
- } else if (node.getAttribute) {
- value = node.getAttribute(key, 2) || value;
- if (key == "href" || key == "src") {
- if (dojo.isIE) {
- var hash = location.href.lastIndexOf(location.hash);
- var href = location.href.substring(0, hash)
- .split("/");
- href.pop();
- href = href.join("/") + "/";
- if (value.indexOf(href) == 0) {
- value = value.replace(href, "");
- }
- value = value.replace(/%20/g, " ").replace(/%7B/g,
- "{").replace(/%7D/g, "}").replace(/%25/g,
- "%");
- }
- if (value.indexOf("{%") != -1
- || value.indexOf("{{") != -1) {
- node.setAttribute(key, "");
- }
- }
- }
- if (typeof value == "function") {
- value = value.toString().replace(this._re4, "$1");
- }
- if (typeof value == "string"
- && (value.indexOf("{%") != -1
- || value.indexOf("{{") != -1 || (value && dojox.dtl.text
- .getTag("attr:" + key, true)))) {
- tokens.push([types.attr, node, key, value]);
- }
- }
- if (!children.length) {
- tokens.push([types.change, node.parentNode, true]);
- if (postNodes) {
- for (var i = 0, child; child = postNodes[i]; i++) {
- this._tokenize(node, child, tokens);
- }
- }
- return tokens;
- }
- for (var i = 0, child; child = children[i]; i++) {
- this._tokenize(node, child, tokens);
- }
- if (node.parentNode && node.parentNode.tagName) {
- tokens.push([types.change, node.parentNode, true]);
- node.parentNode.removeChild(node);
- }
- if (postNodes) {
- for (var i = 0, child; child = postNodes[i]; i++) {
- this._tokenize(node, child, tokens);
- }
- }
- if (first) {
- tokens.push([types.change, node, true]);
- }
- return tokens;
- },
- _tokenize : function(parent, child, tokens) {
- var types = this.types;
- var data = child.data;
- switch (child.nodeType) {
- case 1 :
- this.tokenize(child, tokens);
- break;
- case 3 :
- if (data.match(/[^\s\n]/)) {
- if (data.indexOf("{{") != -1
- || data.indexOf("{%") != -1) {
- var texts = dojox.dtl.text.tokenize(data);
- for (var j = 0, text; text = texts[j]; j++) {
- if (typeof text == "string") {
- tokens.push([types.text, text]);
- } else {
- tokens.push(text);
- }
- }
- } else {
- tokens.push([child.nodeType, child]);
- }
- }
- if (child.parentNode)
- child.parentNode.removeChild(child);
- break;
- case 8 :
- if (data.indexOf("{%") == 0) {
- tokens
- .push([
- types.tag,
- this._trim(data.substring(2,
- data.length - 3))]);
- }
- if (data.indexOf("{{") == 0) {
- tokens
- .push([
- types.varr,
- this._trim(data.substring(2,
- data.length - 3))]);
- }
- if (child.parentNode)
- child.parentNode.removeChild(child);
- break;
- }
- }
- }
- dojox.dtl.HtmlTemplate = function(/* String|dojo._Url */obj) {
- // summary: Use this object for HTML templating
- var dd = dojox.dtl;
- var ddh = dd.html;
- if (!obj.node) {
- if (typeof obj == "object") {
- obj = dojox.dtl.text.getTemplateString(obj);
- }
- obj = ddh.getTemplate(obj);
- }
- var tokens = ddh.tokenize(obj.node, [], obj.pres, obj.posts);
- var parser = new dd.HtmlParser(tokens);
- this.nodelist = parser.parse();
- }
- dojo.extend(dojox.dtl.HtmlTemplate, {
- _count : 0,
- _re : /\bdojo:([a-zA-Z0-9_]+)\b/g,
- setClass : function(str) {
- this.getRootNode().className = str;
- },
- getRootNode : function() {
- return this.rootNode;
- },
- getBuffer : function() {
- return new dojox.dtl.HtmlBuffer();
- },
- render : function(context, buffer) {
- buffer = buffer || this.getBuffer();
- this.rootNode = null;
- var onSetParent = dojo.connect(buffer, "onSetParent", this,
- function(node) {
- if (!this.rootNode) {
- this.rootNode = node || true;
- }
- });
- var output = this.nodelist.render(context
- || new dojox.dtl.Context({}), buffer);
- dojo.disconnect(onSetParent);
- buffer._flushCache();
- return output;
- },
- unrender : function(context, buffer) {
- return this.nodelist.unrender(context, buffer);
- },
- toString : function() {
- return "dojox.dtl.HtmlTemplate";
- }
- });
- dojox.dtl.HtmlBuffer = function(/* Node */parent) {
- // summary: Allows the manipulation of DOM
- // description:
- // Use this to append a child, change the parent, or
- // change the attribute of the current node.
- this._parent = parent;
- this._cache = [];
- }
- dojo.extend(dojox.dtl.HtmlBuffer, {
- concat : function(/* DOMNode */node) {
- if (!this._parent)
- return this;
- if (node.nodeType) {
- var caches = this._getCache(this._parent);
- if (node.parentNode === this._parent) {
- // If we reach a node that already existed, fill in the
- // cache for this same parent
- var i = 0;
- for (var i = 0, cache; cache = caches[i]; i++) {
- this.onAddNode(node);
- this._parent.insertBefore(cache, node);
- }
- caches.length = 0;
- }
- if (!node.parentNode || !node.parentNode.tagName) {
- if (!this._parent.childNodes.length) {
- this.onAddNode(node);
- this._parent.appendChild(node);
- } else {
- caches.push(node);
- }
- }
- }
- return this;
- },
- remove : function(obj) {
- if (typeof obj == "string") {
- this._parent.removeAttribute(obj);
- } else {
- if (obj.parentNode === this._parent) {
- this.onRemoveNode();
- this._parent.removeChild(obj);
- }
- }
- return this;
- },
- setAttribute : function(key, value) {
- if (key == "class") {
- this._parent.className = value;
- } else if (key == "for") {
- this._parent.htmlFor = value;
- } else if (this._parent.setAttribute) {
- this._parent.setAttribute(key, value);
- }
- return this;
- },
- setParent : function(node, /* Boolean? */up) {
- if (!this._parent)
- this._parent = node;
- var caches = this._getCache(this._parent);
- if (caches && caches.length && up) {
- for (var i = 0, cache; cache = caches[i]; i++) {
- if (cache !== this._parent
- && (!cache.parentNode || !cache.parentNode.tagName)) {
- this.onAddNode(cache);
- this._parent.appendChild(cache);
- }
- }
- caches.length = 0;
- }
- this.onSetParent(node, up);
- this._parent = node;
- return this;
- },
- getParent : function() {
- return this._parent;
- },
- onSetParent : function() {
- // summary: Stub called when setParent is used.
- },
- onAddNode : function() {
- // summary: Stub called when new nodes are added
- },
- onRemoveNode : function() {
- // summary: Stub called when nodes are removed
- },
- _getCache : function(node) {
- for (var i = 0, cache; cache = this._cache[i]; i++) {
- if (cache[0] === node) {
- return cache[1];
- }
- }
- var arr = [];
- this._cache.push([node, arr]);
- return arr;
- },
- _flushCache : function(node) {
- for (var i = 0, cache; cache = this._cache[i]; i++) {
- if (!cache[1].length) {
- this._cache.splice(i--, 1);
- }
- }
- },
- toString : function() {
- return "dojox.dtl.HtmlBuffer";
- }
- });
- dojox.dtl.HtmlNode = function(node) {
- // summary: Places a node into DOM
- this.contents = node;
- }
- dojo.extend(dojox.dtl.HtmlNode, {
- render : function(context, buffer) {
- return buffer.concat(this.contents);
- },
- unrender : function(context, buffer) {
- return buffer.remove(this.contents);
- },
- clone : function(buffer) {
- return new dojox.dtl.HtmlNode(this.contents);
- },
- toString : function() {
- return "dojox.dtl.HtmlNode";
- }
- });
- dojox.dtl.HtmlNodeList = function(/* Node[] */nodes) {
- // summary: A list of any HTML-specific node object
- // description:
- // Any object that's used in the constructor or added
- // through the push function much implement the
- // render, unrender, and clone functions.
- this.contents = nodes || [];
- }
- dojo.extend(dojox.dtl.HtmlNodeList, {
- parents : new dojox.dtl.ObjectMap(),
- push : function(node) {
- this.contents.push(node);
- },
- unshift : function(node) {
- this.contents.unshift(node);
- },
- render : function(context, buffer, /* Node */instance) {
- if (instance) {
- var parent = buffer.getParent();
- }
- for (var i = 0; i < this.contents.length; i++) {
- buffer = this.contents[i].render(context, buffer);
- if (!buffer)
- throw new Error("Template node render functions must return their buffer");
- }
- if (parent) {
- buffer.setParent(parent, true);
- }
- return buffer;
- },
- unrender : function(context, buffer) {
- for (var i = 0; i < this.contents.length; i++) {
- buffer = this.contents[i].unrender(context, buffer);
- if (!buffer)
- throw new Error("Template node render functions must return their buffer");
- }
- return buffer;
- },
- clone : function(buffer) {
- // summary:
- // Used to create an identical copy of a NodeList, useful for things
- // like the for tag.
- var dd = dojox.dtl;
- var ddh = dd.html;
- var parent = buffer.getParent();
- var contents = this.contents;
- var nodelist = new dd.HtmlNodeList();
- var cloned = [];
- for (var i = 0; i < contents.length; i++) {
- var clone = contents[i].clone(buffer);
- if (clone instanceof dd.ChangeNode
- || clone instanceof dd.HtmlNode) {
- var item = this.parents.get(clone.contents);
- if (item) {
- clone.contents = item;
- } else if (parent !== clone.contents
- && clone instanceof dd.HtmlNode) {
- var node = clone.contents;
- clone.contents = clone.contents.cloneNode(false);
- cloned.push(node);
- this.parents.put(node, clone.contents);
- }
- }
- nodelist.push(clone);
- }
- for (var i = 0, clone; clone = cloned[i]; i++) {
- this.parents.put(clone);
- }
- return nodelist;
- },
- toString : function() {
- return "dojox.dtl.HtmlNodeList";
- }
- });
- dojox.dtl.HtmlVarNode = function(str) {
- // summary: A node to be processed as a variable
- // description:
- // Will render an object that supports the render function
- // and the getRootNode function
- this.contents = new dojox.dtl.Filter(str);
- this._lists = {};
- }
- dojo.extend(dojox.dtl.HtmlVarNode, {
- render : function(context, buffer) {
- this._rendered = true;
- var dd = dojox.dtl;
- var ddh = dd.html;
- var str = this.contents.resolve(context);
- if (str && str.render && str.getRootNode) {
- var root = this._curr = str.getRootNode();
- var lists = this._lists;
- var list = lists[root];
- if (!list) {
- list = lists[root] = new dd.HtmlNodeList();
- list.push(new dd.ChangeNode(buffer.getParent()));
- list.push(new dd.HtmlNode(root));
- list.push(str);
- list.push(new dd.ChangeNode(buffer.getParent(),
- true));
- }
- return list.render(context, buffer);
- } else {
- if (!this._txt)
- this._txt = document.createTextNode(str);
- if (this._txt.data != str)
- this._txt.data = str;
- return buffer.concat(this._txt);
- }
- return buffer;
- },
- unrender : function(context, buffer) {
- if (this._rendered) {
- this._rendered = false;
- if (this._curr) {
- return this._lists[this._curr].unrender(context,
- buffer);
- } else if (this._txt) {
- return buffer.remove(this._txt);
- }
- }
- return buffer;
- },
- clone : function() {
- return new dojox.dtl.HtmlVarNode(this.contents.contents);
- },
- toString : function() {
- return "dojox.dtl.HtmlVarNode";
- }
- });
- dojox.dtl.ChangeNode = function(node, /* Boolean? */up) {
- // summary: Changes the parent during render/unrender
- this.contents = node;
- this._up = up;
- }
- dojo.extend(dojox.dtl.ChangeNode, {
- render : function(context, buffer) {
- return buffer.setParent(this.contents, this._up);
- },
- unrender : function(context, buffer) {
- return buffer.setParent(this.contents);
- },
- clone : function(buffer) {
- return new dojox.dtl.ChangeNode(this.contents, this._up);
- },
- toString : function() {
- return "dojox.dtl.ChangeNode";
- }
- });
- dojox.dtl.AttributeNode = function(key, value) {
- // summary: Works on attributes
- this._key = key;
- this._value = value;
- this._tpl = new dojox.dtl.Template(value);
- this.contents = "";
- }
- dojo.extend(dojox.dtl.AttributeNode, {
- render : function(context, buffer) {
- var key = this._key;
- var value = this._tpl.render(context);
- if (this._rendered) {
- if (value != this.contents) {
- this.contents = value;
- return buffer.setAttribute(key, value);
- }
- } else {
- this._rendered = true;
- this.contents = value;
- return buffer.setAttribute(key, value);
- }
- return buffer;
- },
- unrender : function(context, buffer) {
- if (this._rendered) {
- this._rendered = false;
- this.contents = "";
- return buffer.remove(this.contents);
- }
- return buffer;
- },
- clone : function() {
- return new dojox.dtl.AttributeNode(this._key, this._value);
- },
- toString : function() {
- return "dojox.dtl.AttributeNode";
- }
- });
- dojox.dtl.HtmlTextNode = function(str) {
- // summary: Adds a straight text node without any processing
- this.contents = document.createTextNode(str);
- }
- dojo.extend(dojox.dtl.HtmlTextNode, {
- render : function(context, buffer) {
- return buffer.concat(this.contents);
- },
- unrender : function(context, buffer) {
- return buffer.remove(this.contents);
- },
- clone : function() {
- return new dojox.dtl.HtmlTextNode(this.contents.data);
- },
- toString : function() {
- return "dojox.dtl.HtmlTextNode";
- }
- });
- dojox.dtl.HtmlParser = function(tokens) {
- // summary: Turn a simple array into a set of objects
- // description:
- // This is also used by all tags to move through
- // the list of nodes.
- this.contents = tokens;
- }
- dojo.extend(dojox.dtl.HtmlParser, {
- parse : function(/* Array? */stop_at) {
- var dd = dojox.dtl;
- var ddh = dd.html;
- var types = ddh.types;
- var terminators = {};
- var tokens = this.contents;
- if (!stop_at) {
- stop_at = [];
- }
- for (var i = 0; i < stop_at.length; i++) {
- terminators[stop_at[i]] = true;
- }
- var nodelist = new dd.HtmlNodeList();
- while (tokens.length) {
- var token = tokens.shift();
- var type = token[0];
- var value = token[1];
- if (type == types.change) {
- nodelist.push(new dd.ChangeNode(value, token[2]));
- } else if (type == types.attr) {
- var fn = dojox.dtl.text.getTag("attr:" + token[2], true);
- if (fn) {
- nodelist.push(fn(null, token[2] + " " + token[3]));
- } else {
- nodelist.push(new dd.AttributeNode(token[2], token[3]));
- }
- } else if (type == types.elem) {
- var fn = dojox.dtl.text.getTag("node:"
- + value.tagName.toLowerCase(), true);
- if (fn) {
- // TODO: We need to move this to tokenization so that
- // it's before the
- // node and the parser can be passed here instead of
- // null
- nodelist.push(fn(null, value, value.tagName
- .toLowerCase()));
- }
- nodelist.push(new dd.HtmlNode(value));
- } else if (type == types.varr) {
- nodelist.push(new dd.HtmlVarNode(value));
- } else if (type == types.text) {
- nodelist.push(new dd.HtmlTextNode(value.data || value));
- } else if (type == types.tag) {
- if (terminators[value]) {
- tokens.unshift(token);
- return nodelist;
- }
- var cmd = value.split(/\s+/g);
- if (cmd.length) {
- cmd = cmd[0];
- var fn = dojox.dtl.text.getTag(cmd);
- if (typeof fn != "function") {
- throw new Error("Function not found for ", cmd);
- }
- var tpl = fn(this, value);
- if (tpl) {
- nodelist.push(tpl);
- }
- }
- }
- }
- if (stop_at.length) {
- throw new Error("Could not find closing tag(s): "
- + stop_at.toString());
- }
- return nodelist;
- },
- next : function() {
- // summary: Used by tags to discover what token was found
- var token = this.contents.shift();
- return {
- type : token[0],
- text : token[1]
- };
- },
- skipPast : function(endtag) {
- return dojox.dtl.Parser.prototype.skipPast.call(this, endtag);
- },
- getVarNode : function() {
- return dojox.dtl.HtmlVarNode;
- },
- getTextNode : function() {
- return dojox.dtl.HtmlTextNode;
- },
- getTemplate : function(/* String */loc) {
- return new dojox.dtl.HtmlTemplate(dojox.dtl.html.getTemplate(loc));
- },
- toString : function() {
- return "dojox.dtl.HtmlParser";
- }
- });
- dojox.dtl.register.tag("dojox.dtl.tag.event", "dojox.dtl.tag.event", [[
- /(attr:)?on(click|key(up))/i, "on"]]);
- dojox.dtl.register.tag("dojox.dtl.tag.html", "dojox.dtl.tag.html", ["html",
- "attr:attach", "attr:tstyle"]);
- }
|