From e44a7e37b6c7b5961adaffc62b9042b8d442938e Mon Sep 17 00:00:00 2001 From: mensonge Date: Thu, 13 Nov 2008 09:49:11 +0000 Subject: New feature: basic Ajax suggestion for tags and implementation of Dojo toolkit git-svn-id: https://semanticscuttle.svn.sourceforge.net/svnroot/semanticscuttle/trunk@151 b3834d28-1941-0410-a4f8-b48e95affb8f --- includes/js/dojox/dtl/tag/date.js | 29 ++++ includes/js/dojox/dtl/tag/loader.js | 277 ++++++++++++++++++++++++++++++++++ includes/js/dojox/dtl/tag/logic.js | 272 +++++++++++++++++++++++++++++++++ includes/js/dojox/dtl/tag/loop.js | 196 ++++++++++++++++++++++++ includes/js/dojox/dtl/tag/misc.js | 291 ++++++++++++++++++++++++++++++++++++ 5 files changed, 1065 insertions(+) create mode 100644 includes/js/dojox/dtl/tag/date.js create mode 100644 includes/js/dojox/dtl/tag/loader.js create mode 100644 includes/js/dojox/dtl/tag/logic.js create mode 100644 includes/js/dojox/dtl/tag/loop.js create mode 100644 includes/js/dojox/dtl/tag/misc.js (limited to 'includes/js/dojox/dtl/tag') diff --git a/includes/js/dojox/dtl/tag/date.js b/includes/js/dojox/dtl/tag/date.js new file mode 100644 index 0000000..fba4089 --- /dev/null +++ b/includes/js/dojox/dtl/tag/date.js @@ -0,0 +1,29 @@ +if(!dojo._hasResource["dojox.dtl.tag.date"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.tag.date"] = true; +dojo.provide("dojox.dtl.tag.date"); + +dojo.require("dojox.dtl._base"); +dojo.require("dojox.dtl.utils.date"); + +dojox.dtl.tag.date.NowNode = function(format, TextNode){ + this.format = new dojox.dtl.utils.date.DateFormat(format); + this.contents = new TextNode(""); +} +dojo.extend(dojox.dtl.tag.date.NowNode, { + render: function(context, buffer){ + this.contents.set(this.format.format(new Date())); + return this.contents.render(context, buffer); + } +}); + +dojox.dtl.tag.date.now = function(parser, text){ + // Split by either :" or :' + var parts = text.split((text.substring(0, 5) == "now '") ? "'" : '"'); + if(parts.length != 3){ + throw new Error("'now' statement takes one argument"); + } + var format = parts[1]; + return new dojox.dtl.tag.date.NowNode(format, parser.getTextNodeConstructor()); +} + +} diff --git a/includes/js/dojox/dtl/tag/loader.js b/includes/js/dojox/dtl/tag/loader.js new file mode 100644 index 0000000..36c81bc --- /dev/null +++ b/includes/js/dojox/dtl/tag/loader.js @@ -0,0 +1,277 @@ +if(!dojo._hasResource["dojox.dtl.tag.loader"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.tag.loader"] = true; +dojo.provide("dojox.dtl.tag.loader"); + +dojo.require("dojox.dtl._base"); + +(function(){ + var dd = dojox.dtl; + var ddtl = dd.tag.loader; + + ddtl.BlockNode = dojo.extend(function(name, nodelist){ + this.name = name; + this.nodelist = nodelist; // Can be overridden + }, + { + render: function(context, buffer){ + var name = this.name; + var nodelist = this.nodelist; + if(buffer.blocks){ + var block = buffer.blocks[name]; + if(block){ + nodelist = block.nodelist; + block.used = true; + } + } + this.rendered = nodelist; + return nodelist.render(context, buffer, this); + }, + unrender: function(context, buffer){ + return this.rendered.unrender(context, buffer); + }, + clone: function(buffer){ + return new this.constructor(this.name, this.nodelist.clone(buffer)); + }, + setOverride: function(nodelist){ + // summary: In a shared parent, we override, not overwrite + if(!this.override){ + this.override = nodelist; + } + }, + toString: function(){ return "dojox.dtl.tag.loader.BlockNode"; } + }); + + ddtl.ExtendsNode = dojo.extend(function(getTemplate, nodelist, shared, parent, key){ + this.getTemplate = getTemplate; + this.nodelist = nodelist; + this.shared = shared; + this.parent = parent; + this.key = key; + }, + { + parents: {}, + getParent: function(context){ + if(!this.parent){ + this.parent = context.get(this.key, false); + if(!this.parent){ + throw new Error("extends tag used a variable that did not resolve"); + } + if(typeof this.parent == "object"){ + if(this.parent.url){ + if(this.parent.shared){ + this.shared = true; + } + this.parent = this.parent.url.toString(); + }else{ + this.parent = this.parent.toString(); + } + } + if(this.parent && this.parent.indexOf("shared:") == 0){ + this.shared = true; + this.parent = this.parent.substring(7, parent.length); + } + } + var parent = this.parent; + if(!parent){ + throw new Error("Invalid template name in 'extends' tag."); + } + if(parent.render){ + return parent; + } + if(this.parents[parent]){ + return this.parents[parent]; + } + this.parent = this.getTemplate(dojox.dtl.text.getTemplateString(parent)); + if(this.shared){ + this.parents[parent] = this.parent; + } + return this.parent; + }, + render: function(context, buffer){ + var parent = this.getParent(context); + + buffer.blocks = buffer.blocks || {}; + + // The parent won't always be in the default parent's nodelist + for(var i = 0, node; node = this.nodelist.contents[i]; i++){ + if(node instanceof dojox.dtl.tag.loader.BlockNode){ + buffer.blocks[node.name] = { + shared: this.shared, + nodelist: node.nodelist, + used: false + } + } + } + + this.rendered = parent; + buffer = parent.nodelist.render(context, buffer, this); + + var rerender = false; + for(var name in buffer.blocks){ + var block = buffer.blocks[name]; + if(!block.used){ + rerender = true; + parent.nodelist[0].nodelist.append(block.nodelist); + } + } + + if(rerender){ + buffer = parent.nodelist.render(context, buffer, this); + } + + return buffer; + }, + unrender: function(context, buffer){ + return this.rendered.unrender(context, buffer, this); + }, + toString: function(){ return "dojox.dtl.block.ExtendsNode"; } + }); + + ddtl.IncludeNode = dojo.extend(function(path, constant, getTemplate, TextNode, parsed){ + this._path = path; + this.constant = constant; + this.path = (constant) ? path : new dd._Filter(path); + this.getTemplate = getTemplate; + this.TextNode = TextNode; + this.parsed = (arguments.length == 5) ? parsed : true; + }, + { + _cache: [{}, {}], + render: function(context, buffer){ + var location = ((this.constant) ? this.path : this.path.resolve(context)).toString(); + var parsed = Number(this.parsed); + var dirty = false; + if(location != this.last){ + dirty = true; + if(this.last){ + buffer = this.unrender(context, buffer); + } + this.last = location; + } + + var cache = this._cache[parsed]; + + if(parsed){ + if(!cache[location]){ + cache[location] = dd.text._resolveTemplateArg(location, true); + } + if(dirty){ + var template = this.getTemplate(cache[location]); + this.rendered = template.nodelist; + } + return this.rendered.render(context, buffer, this); + }else{ + if(this.TextNode == dd._TextNode){ + if(dirty){ + this.rendered = new this.TextNode(""); + this.rendered.set(dd.text._resolveTemplateArg(location, true)); + } + return this.rendered.render(context, buffer); + }else{ + if(!cache[location]){ + var nodelist = []; + var div = document.createElement("div"); + div.innerHTML = dd.text._resolveTemplateArg(location, true); + var children = div.childNodes; + while(children.length){ + var removed = div.removeChild(children[0]); + nodelist.push(removed); + } + cache[location] = nodelist; + } + if(dirty){ + this.nodelist = []; + var exists = true; + for(var i = 0, child; child = cache[location][i]; i++){ + this.nodelist.push(child.cloneNode(true)); + } + } + for(var i = 0, node; node = this.nodelist[i]; i++){ + buffer = buffer.concat(node); + } + } + } + return buffer; + }, + unrender: function(context, buffer){ + if(this.rendered){ + buffer = this.rendered.unrender(context, buffer); + } + if(this.nodelist){ + for(var i = 0, node; node = this.nodelist[i]; i++){ + buffer = buffer.remove(node); + } + } + return buffer; + }, + clone: function(buffer){ + return new this.constructor(this._path, this.constant, this.getTemplate, this.TextNode, this.parsed); + } + }); + + dojo.mixin(ddtl, { + block: function(parser, text){ + var parts = text.split(" "); + var name = parts[1]; + + parser._blocks = parser._blocks || {}; + parser._blocks[name] = parser._blocks[name] || []; + parser._blocks[name].push(name); + + var nodelist = parser.parse(["endblock", "endblock " + name]); + parser.next(); + return new dojox.dtl.tag.loader.BlockNode(name, nodelist); + }, + extends_: function(parser, text){ + var parts = text.split(" "); + var shared = false; + var parent = null; + var key = null; + if(parts[1].charAt(0) == '"' || parts[1].charAt(0) == "'"){ + parent = parts[1].substring(1, parts[1].length - 1); + }else{ + key = parts[1]; + } + if(parent && parent.indexOf("shared:") == 0){ + shared = true; + parent = parent.substring(7, parent.length); + } + var nodelist = parser.parse(); + return new dojox.dtl.tag.loader.ExtendsNode(parser.getTemplate, nodelist, shared, parent, key); + }, + include: function(parser, token){ + var parts = dd.text.pySplit(token); + if(parts.length != 2){ + throw new Error(parts[0] + " tag takes one argument: the name of the template to be included"); + } + var path = parts[1]; + var constant = false; + if((path.charAt(0) == '"' || path.slice(-1) == "'") && path.charAt(0) == path.slice(-1)){ + path = path.slice(1, -1); + constant = true; + } + return new ddtl.IncludeNode(path, constant, parser.getTemplate, parser.getTextNodeConstructor()); + }, + ssi: function(parser, token){ + // We're going to treat things a little differently here. + // First of all, this tag is *not* portable, so I'm not + // concerned about it being a "drop in" replacement. + + // Instead, we'll just replicate the include tag, but with that + // optional "parsed" parameter. + var parts = dd.text.pySplit(token); + var parsed = false; + if(parts.length == 3){ + parsed = (parts.pop() == "parsed"); + if(!parsed){ + throw new Error("Second (optional) argument to ssi tag must be 'parsed'"); + } + } + var node = ddtl.include(parser, parts.join(" ")); + node.parsed = parsed; + return node; + } + }); +})(); + +} diff --git a/includes/js/dojox/dtl/tag/logic.js b/includes/js/dojox/dtl/tag/logic.js new file mode 100644 index 0000000..90909ce --- /dev/null +++ b/includes/js/dojox/dtl/tag/logic.js @@ -0,0 +1,272 @@ +if(!dojo._hasResource["dojox.dtl.tag.logic"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.tag.logic"] = true; +dojo.provide("dojox.dtl.tag.logic"); + +dojo.require("dojox.dtl._base"); + +(function(){ + var dd = dojox.dtl; + var ddt = dd.text; + var ddtl = dd.tag.logic; + + ddtl.IfNode = dojo.extend(function(bools, trues, falses, type){ + this.bools = bools; + this.trues = trues; + this.falses = falses; + this.type = type; + }, + { + render: function(context, buffer){ + var i, bool, ifnot, filter, value; + if(this.type == "or"){ + for(i = 0; bool = this.bools[i]; i++){ + ifnot = bool[0]; + filter = bool[1]; + value = filter.resolve(context); + if((value && !ifnot) || (ifnot && !value)){ + if(this.falses){ + buffer = this.falses.unrender(context, buffer); + } + return (this.trues) ? this.trues.render(context, buffer, this) : buffer; + } + } + if(this.trues){ + buffer = this.trues.unrender(context, buffer); + } + return (this.falses) ? this.falses.render(context, buffer, this) : buffer; + }else{ + for(i = 0; bool = this.bools[i]; i++){ + ifnot = bool[0]; + filter = bool[1]; + value = filter.resolve(context); + // If we ever encounter a false value + if(value == ifnot){ + if(this.trues){ + buffer = this.trues.unrender(context, buffer); + } + return (this.falses) ? this.falses.render(context, buffer, this) : buffer; + } + } + if(this.falses){ + buffer = this.falses.unrender(context, buffer); + } + return (this.trues) ? this.trues.render(context, buffer, this) : buffer; + } + return buffer; + }, + unrender: function(context, buffer){ + buffer = (this.trues) ? this.trues.unrender(context, buffer) : buffer; + buffer = (this.falses) ? this.falses.unrender(context, buffer) : buffer; + return buffer; + }, + clone: function(buffer){ + var trues = (this.trues) ? this.trues.clone(buffer) : null; + var falses = (this.falses) ? this.falses.clone(buffer) : null; + return new this.constructor(this.bools, trues, falses, this.type); + } + }); + + ddtl.IfEqualNode = dojo.extend(function(var1, var2, trues, falses, negate){ + this.var1 = new dd._Filter(var1); + this.var2 = new dd._Filter(var2); + this.trues = trues; + this.falses = falses; + this.negate = negate; + }, + { + render: function(context, buffer){ + var var1 = this.var1.resolve(context); + var var2 = this.var2.resolve(context); + if((this.negate && var1 != var2) || (!this.negate && var1 == var2)){ + if(this.falses){ + buffer = this.falses.unrender(context, buffer); + } + return (this.trues) ? this.trues.render(context, buffer, this) : buffer; + } + if(this.trues){ + buffer = this.trues.unrender(context, buffer); + } + return (this.falses) ? this.falses.render(context, buffer, this) : buffer; + }, + unrender: function(context, buffer){ + return ddtl.IfNode.prototype.unrender.call(this, context, buffer); + }, + clone: function(buffer){ + return new this.constructor(this.var1.getExpression(), this.var2.getExpression(), this.trues.clone(buffer), this.falses.clone(buffer), this.negate); + } + }); + + ddtl.ForNode = dojo.extend(function(assign, loop, reversed, nodelist){ + this.assign = assign; + this.loop = new dd._Filter(loop); + this.reversed = reversed; + this.nodelist = nodelist; + this.pool = []; + }, + { + render: function(context, buffer){ + var i, j, k; + var dirty = false; + var assign = this.assign; + + for(k = 0; k < assign.length; k++){ + if(typeof context[assign[k]] != "undefined"){ + dirty = true; + context.push(); + break; + } + } + + var items = this.loop.resolve(context) || []; + for(i = items.length; i < this.pool.length; i++){ + this.pool[i].unrender(context, buffer); + } + if(this.reversed){ + items = items.slice(0).reverse(); + } + + var isObject = dojo.isObject(items) && !dojo.isArrayLike(items); + var arred = []; + if(isObject){ + for(var key in items){ + arred.push(items[key]); + } + }else{ + arred = items; + } + + var forloop = context.forloop = { + parentloop: context.forloop || {} + }; + var j = 0; + for(i = 0; i < arred.length; i++){ + var item = arred[i]; + + forloop.counter0 = j; + forloop.counter = j + 1; + forloop.revcounter0 = arred.length - j - 1; + forloop.revcounter = arred.length - j; + forloop.first = !j; + forloop.last = (j == arred.length - 1); + + if(assign.length > 1 && dojo.isArrayLike(item)){ + if(!dirty){ + dirty = true; + context.push(); + } + var zipped = {}; + for(k = 0; k < item.length && k < assign.length; k++){ + zipped[assign[k]] = item[k]; + } + context.update(zipped); + }else{ + context[assign[0]] = item; + } + + if(j + 1 > this.pool.length){ + this.pool.push(this.nodelist.clone(buffer)); + } + buffer = this.pool[j].render(context, buffer, this); + ++j; + } + + delete context.forloop; + for(k = 0; k < assign.length; k++){ + delete context[assign[k]]; + } + if(dirty){ + context.pop(); + } + return buffer; + }, + unrender: function(context, buffer){ + for(var i = 0, pool; pool = this.pool[i]; i++){ + buffer = pool.unrender(context, buffer); + } + return buffer; + }, + clone: function(buffer){ + return new this.constructor(this.assign, this.loop.getExpression(), this.reversed, this.nodelist.clone(buffer)); + } + }); + + dojo.mixin(ddtl, { + if_: function(parser, text){ + var i, part, type, bools = [], parts = ddt.pySplit(text); + parts.shift(); + text = parts.join(" "); + parts = text.split(" and "); + if(parts.length == 1){ + type = "or"; + parts = text.split(" or "); + }else{ + type = "and"; + for(i = 0; i < parts.length; i++){ + if(parts[i].indexOf(" or ") != -1){ + // Note, since we split by and, this is the only place we need to error check + throw new Error("'if' tags can't mix 'and' and 'or'"); + } + } + } + for(i = 0; part = parts[i]; i++){ + var not = false; + if(part.indexOf("not ") == 0){ + part = part.slice(4); + not = true; + } + bools.push([not, new dd._Filter(part)]); + } + var trues = parser.parse(["else", "endif"]); + var falses = false; + var token = parser.next(); + if(token.text == "else"){ + falses = parser.parse(["endif"]); + parser.next(); + } + return new ddtl.IfNode(bools, trues, falses, type); + }, + _ifequal: function(parser, text, negate){ + var parts = ddt.pySplit(text); + if(parts.length != 3){ + throw new Error(parts[0] + " takes two arguments"); + } + var end = 'end' + parts[0]; + var trues = parser.parse(["else", end]); + var falses = false; + var token = parser.next(); + if(token.text == "else"){ + falses = parser.parse([end]); + parser.next(); + } + return new ddtl.IfEqualNode(parts[1], parts[2], trues, falses, negate); + }, + ifequal: function(parser, text){ + return ddtl._ifequal(parser, text); + }, + ifnotequal: function(parser, text){ + return ddtl._ifequal(parser, text, true); + }, + for_: function(parser, text){ + var parts = ddt.pySplit(text); + if(parts.length < 4){ + throw new Error("'for' statements should have at least four words: " + text); + } + var reversed = parts[parts.length - 1] == "reversed"; + var index = (reversed) ? -3 : -2; + if(parts[parts.length + index] != "in"){ + throw new Error("'for' tag received an invalid argument: " + text); + } + var loopvars = parts.slice(1, index).join(" ").split(/ *, */); + for(var i = 0; i < loopvars.length; i++){ + if(!loopvars[i] || loopvars[i].indexOf(" ") != -1){ + throw new Error("'for' tag received an invalid argument: " + text); + } + } + var nodelist = parser.parse(["endfor"]); + parser.next(); + return new ddtl.ForNode(loopvars, parts[parts.length + index + 1], reversed, nodelist); + } + }); +})(); + +} diff --git a/includes/js/dojox/dtl/tag/loop.js b/includes/js/dojox/dtl/tag/loop.js new file mode 100644 index 0000000..3626c52 --- /dev/null +++ b/includes/js/dojox/dtl/tag/loop.js @@ -0,0 +1,196 @@ +if(!dojo._hasResource["dojox.dtl.tag.loop"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.tag.loop"] = true; +dojo.provide("dojox.dtl.tag.loop"); + +dojo.require("dojox.dtl._base"); +dojo.require("dojox.string.tokenize"); + +(function(){ + var dd = dojox.dtl; + var ddtl = dd.tag.loop; + + ddtl.CycleNode = dojo.extend(function(cyclevars, name, TextNode, shared){ + this.cyclevars = cyclevars; + this.name = name; + this.TextNode = TextNode; + this.shared = shared || {counter: -1, map: {}}; + }, + { + render: function(context, buffer){ + if(context.forloop && !context.forloop.counter0){ + this.shared.counter = -1; + } + + ++this.shared.counter; + var value = this.cyclevars[this.shared.counter % this.cyclevars.length]; + + var map = this.shared.map; + if(!map[value]){ + map[value] = new dd._Filter(value); + } + value = map[value].resolve(context, buffer); + + if(this.name){ + context[this.name] = value; + } + if(!this.contents){ + this.contents = new this.TextNode(""); + } + this.contents.set(value); + return this.contents.render(context, buffer); + }, + unrender: function(context, buffer){ + return this.contents.unrender(context, buffer); + }, + clone: function(){ + return new this.constructor(this.cyclevars, this.name, this.TextNode, this.shared); + } + }); + + ddtl.IfChangedNode = dojo.extend(function(nodes, vars, shared){ + this.nodes = nodes; + this._vars = vars; + this.shared = shared || {last: null}; + this.vars = dojo.map(vars, function(item){ + return new dojox.dtl._Filter(item); + }); + }, { + render: function(context, buffer){ + if(context.forloop && context.forloop.first){ + this.shared.last = null; + } + + var change; + if(this.vars.length){ + change = dojo.toJson(dojo.map(this.vars, function(item){ + return item.resolve(context); + })); + }else{ + change = this.nodes.dummyRender(context, buffer); + } + + if(change != this.shared.last){ + var firstloop = (this.shared.last === null); + this.shared.last = change; + context.push(); + context.ifchanged = {firstloop: firstloop} + buffer = this.nodes.render(context, buffer); + context.pop(); + } + return buffer; + }, + unrender: function(context, buffer){ + this.nodes.unrender(context, buffer); + }, + clone: function(buffer){ + return new this.constructor(this.nodes.clone(buffer), this._vars, this.shared); + } + }); + + ddtl.RegroupNode = dojo.extend(function(expression, key, alias){ + this._expression = expression; + this.expression = new dd._Filter(expression); + this.key = key; + this.alias = alias; + }, + { + _push: function(container, grouper, stack){ + if(stack.length){ + container.push({ grouper: grouper, list: stack }) + } + }, + render: function(context, buffer){ + context[this.alias] = []; + var list = this.expression.resolve(context); + if(list){ + var last = null; + var stack = []; + for(var i = 0; i < list.length; i++){ + var id = list[i][this.key]; + if(last !== id){ + this._push(context[this.alias], last, stack); + last = id; + stack = [list[i]]; + }else{ + stack.push(list[i]); + } + } + this._push(context[this.alias], last, stack); + } + return buffer; + }, + unrender: function(context, buffer){ + return buffer; + }, + clone: function(context, buffer){ + return this; + } + }); + + dojo.mixin(ddtl, { + cycle: function(parser, text){ + // summary: Cycle among the given strings each time this tag is encountered + var args = text.split(" "); + + if(args.length < 2){ + throw new Error("'cycle' tag requires at least two arguments"); + } + + if(args[1].indexOf(",") != -1){ + var vars = args[1].split(","); + args = [args[0]]; + for(var i = 0; i < vars.length; i++){ + args.push('"' + vars[i] + '"'); + } + } + + if(args.length == 2){ + var name = args[args.length - 1]; + + if(!parser._namedCycleNodes){ + throw new Error("No named cycles in template: '" + name + "' is not defined"); + } + if(!parser._namedCycleNodes[name]){ + throw new Error("Named cycle '" + name + "' does not exist"); + } + + return parser._namedCycleNodes[name]; + } + + if(args.length > 4 && args[args.length - 2] == "as"){ + var name = args[args.length - 1]; + + var node = new ddtl.CycleNode(args.slice(1, args.length - 2), name, parser.getTextNodeConstructor()); + + if(!parser._namedCycleNodes){ + parser._namedCycleNodes = {}; + } + parser._namedCycleNodes[name] = node; + }else{ + node = new ddtl.CycleNode(args.slice(1), null, parser.getTextNodeConstructor()); + } + + return node; + }, + ifchanged: function(parser, text){ + var parts = dojox.dtl.text.pySplit(text); + var nodes = parser.parse(["endifchanged"]); + parser.next(); + return new ddtl.IfChangedNode(nodes, parts.slice(1)); + }, + regroup: function(parser, text){ + var tokens = dojox.string.tokenize(dojo.trim(text), /(\s+)/g, function(spaces){ + return spaces; + }); + if(tokens.length < 11 || tokens[tokens.length - 3] != "as" || tokens[tokens.length - 7] != "by"){ + throw new Error("Expected the format: regroup list by key as newList"); + } + var expression = tokens.slice(2, -8).join(""); + var key = tokens[tokens.length - 5]; + var alias = tokens[tokens.length - 1]; + return new ddtl.RegroupNode(expression, key, alias); + } + }); +})(); + +} diff --git a/includes/js/dojox/dtl/tag/misc.js b/includes/js/dojox/dtl/tag/misc.js new file mode 100644 index 0000000..31610d7 --- /dev/null +++ b/includes/js/dojox/dtl/tag/misc.js @@ -0,0 +1,291 @@ +if(!dojo._hasResource["dojox.dtl.tag.misc"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.dtl.tag.misc"] = true; +dojo.provide("dojox.dtl.tag.misc"); +dojo.require("dojox.dtl._base"); + +(function(){ + var dd = dojox.dtl; + var ddtm = dd.tag.misc; + + ddtm.DebugNode = dojo.extend(function(TextNode){ + this._TextNode = TextNode; + }, + { + render: function(context, buffer){ + var keys = context.getKeys(); + var debug = ""; + for(var i = 0, key; key = keys[i]; i++){ + console.debug("DEBUG", key, ":", context[key]); + debug += key + ": " + dojo.toJson(context[key]) + "\n\n"; + } + return new this._TextNode(debug).render(context, buffer, this); + }, + unrender: function(context, buffer){ + return buffer; + }, + clone: function(buffer){ + return new this.constructor(this._TextNode); + }, + toString: function(){ return "ddtm.DebugNode"; } + }); + + ddtm.FilterNode = dojo.extend(function(varnode, nodelist){ + this._varnode = varnode; + this._nodelist = nodelist; + }, + { + render: function(context, buffer){ + // Doing this in HTML requires a different buffer with a fake root node + var output = this._nodelist.render(context, new dojox.string.Builder()); + context.update({ "var": output.toString() }); + var filtered = this._varnode.render(context, buffer); + context.pop(); + return buffer; + }, + unrender: function(context, buffer){ + return buffer; + }, + clone: function(buffer){ + return new this.constructor(this._expression, this._nodelist.clone(buffer)); + } + }); + + ddtm.FirstOfNode = dojo.extend(function(vars, TextNode){ + this._vars = vars; + this.vars = dojo.map(vars, function(item){ + return new dojox.dtl._Filter(item); + }); + this.contents = new TextNode(""); + }, + { + render: function(context, buffer){ + for(var i = 0, item; item = this.vars[i]; i++){ + var resolved = item.resolve(context); + if(typeof resolved != "undefined"){ + if(resolved === null){ + resolved = "null"; + } + this.contents.set(resolved); + return this.contents.render(context, buffer); + } + } + return this.contents.unrender(context, buffer); + }, + unrender: function(context, buffer){ + return this.contents.unrender(context, buffer); + }, + clone: function(buffer){ + return new this.constructor(this._vars, this.contents.constructor); + } + }); + + ddtm.SpacelessNode = dojo.extend(function(nodelist, TextNode){ + this.nodelist = nodelist; + this.TextNode = TextNode; + }, + { + render: function(context, buffer){ + if(buffer.onAddNodeComplete){ + // Unfortunately, we have to branch here + var watch = [ + dojo.connect(buffer, "onAddNodeComplete", this, "_watch"), + dojo.connect(buffer, "onSetParent", this, "_watchParent") + ]; + buffer = this.nodelist.render(context, buffer); + dojo.disconnect(watch[0]); + dojo.disconnect(watch[1]); + }else{ + if(!this.contents){ + this.contents = new this.TextNode(""); + } + var value = this.nodelist.dummyRender(context); + this.contents.set(value.replace(/>\s+<')); + buffer = this.contents.render(context, buffer); + } + return buffer; + }, + unrender: function(context, buffer){ + return this.nodelist.unrender(context, buffer); + }, + clone: function(buffer){ + return new this.constructor(this.nodelist.clone(buffer)); + }, + _isEmpty: function(node){ + return (node.nodeType == 3 && !node.data.match(/[^\s\n]/)); + }, + _watch: function(node){ + if(this._isEmpty(node)){ + var remove = false; + if(node.parentNode.firstChild == node){ + node.parentNode.removeChild(node); + } + }else{ + var children = node.parentNode.childNodes; + if(node.nodeType == 1 && children.length > 2){ + for(var i = 2, child; child = children[i]; i++){ + if(children[i - 2].nodeType == 1 && this._isEmpty(children[i - 1])){ + node.parentNode.removeChild(children[i - 1]); + return; + } + } + } + } + }, + _watchParent: function(node){ + var children = node.childNodes; + if(children.length){ + while(node.childNodes.length){ + var last = node.childNodes[node.childNodes.length - 1]; + if(!this._isEmpty(last)){ + return; + } + node.removeChild(last); + } + } + } + }); + + ddtm.TemplateTagNode = dojo.extend(function(tag, TextNode){ + this.tag = tag; + this.contents = new TextNode(""); + }, + { + mapping: { + openblock: "{%", + closeblock: "%}", + openvariable: "{{", + closevariable: "}}", + openbrace: "{", + closebrace: "}", + opencomment: "{#", + closecomment: "#}" + }, + render: function(context, buffer){ + this.contents.set(this.mapping[this.tag]); + return this.contents.render(context, buffer); + }, + unrender: function(context, buffer){ + return this.contents.unrender(context, buffer); + }, + clone: function(buffer){ + return new this.constructor(this.tag, this.contents.constructor); + } + }); + + ddtm.WidthRatioNode = dojo.extend(function(current, max, width, TextNode){ + this.current = new dd._Filter(current); + this.max = new dd._Filter(max); + this.width = width; + this.contents = new TextNode(""); + }, + { + render: function(context, buffer){ + var current = +this.current.resolve(context); + var max = +this.max.resolve(context); + if(typeof current != "number" || typeof max != "number" || !max){ + this.contents.set(""); + }else{ + this.contents.set("" + Math.round((current / max) * this.width)); + } + return this.contents.render(context, buffer); + }, + unrender: function(context, buffer){ + return this.contents.unrender(context, buffer); + }, + clone: function(buffer){ + return new this.constructor(this.current.getExpression(), this.max.getExpression(), this.width, this.contents.constructor); + } + }); + + ddtm.WithNode = dojo.extend(function(target, alias, nodelist){ + this.target = new dd._Filter(target); + this.alias = alias; + this.nodelist = nodelist; + }, + { + render: function(context, buffer){ + var target = this.target.resolve(context); + context.push(); + context[this.alias] = target; + buffer = this.nodelist.render(context, buffer); + context.pop(); + return buffer; + }, + unrender: function(context, buffer){ + return buffer; + }, + clone: function(buffer){ + return new this.constructor(this.target.getExpression(), this.alias, this.nodelist.clone(buffer)); + } + }); + + dojo.mixin(ddtm, { + comment: function(parser, text){ + // summary: Ignore everything between {% comment %} and {% endcomment %} + parser.skipPast("endcomment"); + return dd._noOpNode; + }, + debug: function(parser, text){ + // summary: Output the current context, maybe add more stuff later. + return new ddtm.DebugNode(parser.getTextNodeConstructor()); + }, + filter: function(parser, text){ + // summary: Filter the contents of the blog through variable filters. + var parts = text.split(" ", 2); + var varnode = new (parser.getVarNodeConstructor())("var|" + parts[1]); + var nodelist = parser.parse(["endfilter"]); + parser.next(); + return new ddtm.FilterNode(varnode, nodelist); + }, + firstof: function(parser, text){ + var parts = dojox.dtl.text.pySplit(text).slice(1); + if(!parts.length){ + throw new Error("'firstof' statement requires at least one argument"); + } + return new ddtm.FirstOfNode(parts, parser.getTextNodeConstructor()); + }, + spaceless: function(parser, text){ + var nodelist = parser.parse(["endspaceless"]); + parser.next(); + return new ddtm.SpacelessNode(nodelist, parser.getTextNodeConstructor()); + }, + templatetag: function(parser, text){ + var parts = dd.text.pySplit(text); + if(parts.length != 2){ + throw new Error("'templatetag' statement takes one argument"); + } + var tag = parts[1]; + var mapping = ddtm.TemplateTagNode.prototype.mapping; + if(!mapping[tag]){ + var keys = []; + for(var key in mapping){ + keys.push(key); + } + throw new Error("Invalid templatetag argument: '" + tag + "'. Must be one of: " + keys.join(", ")); + } + return new ddtm.TemplateTagNode(tag, parser.getTextNodeConstructor()); + }, + widthratio: function(parser, text){ + var parts = dd.text.pySplit(text); + if(parts.length != 4){ + throw new Error("widthratio takes three arguments"); + } + var width = +parts[3]; + if(typeof width != "number"){ + throw new Error("widthratio final argument must be an integer"); + } + return new ddtm.WidthRatioNode(parts[1], parts[2], width, parser.getTextNodeConstructor()); + }, + with_: function(parser, text){ + var parts = dd.text.pySplit(text); + if(parts.length != 4 || parts[2] != "as"){ + throw new Error("do_width expected format as 'with value as name'"); + } + var nodelist = parser.parse(["endwith"]); + parser.next(); + return new ddtm.WithNode(parts[1], parts[3], nodelist); + } + }); +})(); + +} -- cgit v1.2.3-54-g00ecf