if(!dojo._hasResource["dojox.dtl._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["dojox.dtl._base"] = true; dojo.provide("dojox.dtl._base"); dojo.require("dojox.string.Builder"); dojo.require("dojox.string.tokenize"); (function(){ var dd = dojox.dtl; dd._Context = dojo.extend(function(dict){ // summary: Pass one of these when rendering a template to tell the template what values to use. dojo.mixin(this, dict || {}); this._dicts = []; }, { push: function(){ var dict = {}; var keys = this.getKeys(); for(var i = 0, key; key = keys[i]; i++){ dict[key] = this[key]; delete this[key]; } this._dicts.unshift(dict); }, pop: function(){ if(!this._dicts.length){ throw new Error("pop() called on empty Context"); } var dict = this._dicts.shift(); dojo.mixin(this, dict); }, getKeys: function(){ var keys = []; for(var key in this){ if(this.hasOwnProperty(key) && key != "_dicts" && key != "_this"){ keys.push(key); } } return keys; }, get: function(key, otherwise){ if(typeof this[key] != "undefined"){ return this._normalize(this[key]); } for(var i = 0, dict; dict = this._dicts[i]; i++){ if(typeof dict[key] != "undefined"){ return this._normalize(dict[key]); } } return otherwise; }, _normalize: function(value){ if(value instanceof Date){ value.year = value.getFullYear(); value.month = value.getMonth() + 1; value.day = value.getDate(); value.date = value.year + "-" + ("0" + value.month).slice(-2) + "-" + ("0" + value.day).slice(-2); value.hour = value.getHours(); value.minute = value.getMinutes(); value.second = value.getSeconds(); value.microsecond = value.getMilliseconds(); } return value; }, update: function(dict){ this.push(); if(dict){ dojo.mixin(this, dict); } } }); var ddt = dd.text = { types: {tag: -1, varr: -2, text: 3}, pySplit: function(str){ // summary: Split a string according to Python's split function str = dojo.trim(str); return (!str.length) ? [] : str.split(/\s+/g); }, _get: function(module, name, errorless){ // summary: Used to find both tags and filters var params = dd.register.get(module, name.toLowerCase(), errorless); if(!params){ if(!errorless){ throw new Error("No tag found for " + name); } return null; } var fn = params[1]; var require = params[2]; var parts; if(fn.indexOf(":") != -1){ parts = fn.split(":"); fn = parts.pop(); } dojo["require"](require); var parent = dojo.getObject(require); return parent[fn || name] || parent[name + "_"]; }, getTag: function(name, errorless){ return ddt._get("tag", name, errorless); }, getFilter: function(name, errorless){ return ddt._get("filter", name, errorless); }, getTemplate: function(file){ return new dd.Template(dd.getTemplateString(file)); }, getTemplateString: function(file){ return dojo._getText(file.toString()) || ""; }, _resolveLazy: function(location, sync, json){ if(sync){ if(json){ return dojo.fromJson(dojo._getText(location)) || {}; }else{ return dd.text.getTemplateString(location); } }else{ return dojo.xhrGet({ handleAs: (json) ? "json" : "text", url: location }); } }, _resolveTemplateArg: function(arg, sync){ if(ddt._isTemplate(arg)){ if(!sync){ var d = new dojo.Deferred(); d.callback(arg); return d; } return arg; } return ddt._resolveLazy(arg, sync); }, _isTemplate: function(arg){ return (typeof arg == "undefined") || (dojo.isString(arg) && (arg.match(/^\s*[<{]/) || arg.indexOf(" ") != -1)); }, _resolveContextArg: function(arg, sync){ if(arg.constructor == Object){ if(!sync){ var d = new dojo.Deferred; d.callback(arg); return d; } return arg; } return ddt._resolveLazy(arg, sync, true); }, _re: /(?:\{\{\s*(.+?)\s*\}\}|\{%\s*(load\s*)?(.+?)\s*%\})/g, tokenize: function(str){ return dojox.string.tokenize(str, ddt._re, ddt._parseDelims); }, _parseDelims: function(varr, load, tag){ var types = ddt.types; if(varr){ return [types.varr, varr]; }else if(load){ var parts = dd.text.pySplit(tag); for(var i = 0, part; part = parts[i]; i++){ dojo["require"](part); } }else{ return [types.tag, tag]; } } } dd.Template = dojo.extend(function(/*String|dojo._Url*/ template){ // template: // The string or location of the string to // use as a template var str = ddt._resolveTemplateArg(template, true) || ""; var tokens = ddt.tokenize(str); var parser = new dd._Parser(tokens); this.nodelist = parser.parse(); }, { update: function(node, context){ // node: DOMNode|String|dojo.NodeList // A node reference or set of nodes // context: dojo._Url|String|Object // The context object or location return ddt._resolveContextArg(context).addCallback(this, function(contextObject){ var content = this.render(new dd._Context(contextObject)); if(node.forEach){ node.forEach(function(item){ item.innerHTML = content; }); }else{ dojo.byId(node).innerHTML = content; } return this; }); }, render: function(context, /*concatenatable?*/ buffer){ buffer = buffer || this.getBuffer(); context = context || new dd._Context({}); return this.nodelist.render(context, buffer) + ""; }, getBuffer: function(){ dojo.require("dojox.string.Builder"); return new dojox.string.Builder(); } }); dd._Filter = dojo.extend(function(token){ // summary: Uses a string to find (and manipulate) a variable if(!token) throw new Error("Filter must be called with variable name"); this.contents = token; var cache = this._cache[token]; if(cache){ this.key = cache[0]; this.filters = cache[1]; }else{ this.filters = []; dojox.string.tokenize(token, this._re, this._tokenize, this); this._cache[token] = [this.key, this.filters]; } }, { _cache: {}, _re: /(?:^_\("([^\\"]*(?:\\.[^\\"])*)"\)|^"([^\\"]*(?:\\.[^\\"]*)*)"|^([a-zA-Z0-9_.]+)|\|(\w+)(?::(?:_\("([^\\"]*(?:\\.[^\\"])*)"\)|"([^\\"]*(?:\\.[^\\"]*)*)"|([a-zA-Z0-9_.]+)|'([^\\']*(?:\\.[^\\']*)*)'))?|^'([^\\']*(?:\\.[^\\']*)*)')/g, _values: { 0: '"', // _("text") 1: '"', // "text" 2: "", // variable 8: '"' // 'text' }, _args: { 4: '"', // :_("text") 5: '"', // :"text" 6: "", // :variable 7: "'"// :'text' }, _tokenize: function(){ var pos, arg; for(var i = 0, has = []; i < arguments.length; i++){ has[i] = (typeof arguments[i] != "undefined" && dojo.isString(arguments[i]) && arguments[i]); } if(!this.key){ for(pos in this._values){ if(has[pos]){ this.key = this._values[pos] + arguments[pos] + this._values[pos]; break; } } }else{ for(pos in this._args){ if(has[pos]){ var value = arguments[pos]; if(this._args[pos] == "'"){ value = value.replace(/\\'/g, "'"); }else if(this._args[pos] == '"'){ value = value.replace(/\\"/g, '"'); } arg = [!this._args[pos], value]; break; } } // Get a named filter var fn = ddt.getFilter(arguments[3]); if(!dojo.isFunction(fn)) throw new Error(arguments[3] + " is not registered as a filter"); this.filters.push([fn, arg]); } }, getExpression: function(){ return this.contents; }, resolve: function(context){ var str = this.resolvePath(this.key, context); for(var i = 0, filter; filter = this.filters[i]; i++){ // Each filter has the function in [0], a boolean in [1][0] of whether it's a variable or a string // and [1][1] is either the variable name of the string content. if(filter[1]){ if(filter[1][0]){ str = filter[0](str, this.resolvePath(filter[1][1], context)); }else{ str = filter[0](str, filter[1][1]); } }else{ str = filter[0](str); } } return str; }, resolvePath: function(path, context){ var current, parts; var first = path.charAt(0); var last = path.slice(-1); if(!isNaN(parseInt(first))){ current = (path.indexOf(".") == -1) ? parseInt(path) : parseFloat(path); }else if(first == '"' && first == last){ current = path.slice(1, -1); }else{ if(path == "true"){ return true; } if(path == "false"){ return false; } if(path == "null" || path == "None"){ return null; } parts = path.split("."); current = context.get(parts[0]); for(var i = 1; i < parts.length; i++){ var part = parts[i]; if(current){ if(dojo.isObject(current) && part == "items" && typeof current[part] == "undefined"){ var items = []; for(var key in current){ items.push([key, current[key]]); } current = items; continue; } if(current.get && dojo.isFunction(current.get)){ current = current.get(part); }else if(typeof current[part] == "undefined"){ current = current[part]; break; }else{ current = current[part]; } if(dojo.isFunction(current)){ if(current.alters_data){ current = ""; }else{ current = current(); } } }else{ return ""; } } } return current; } }); dd._TextNode = dd._Node = dojo.extend(function(/*Object*/ obj){ // summary: Basic catch-all node this.contents = obj; }, { set: function(data){ this.contents = data; }, render: function(context, buffer){ // summary: Adds content onto the buffer return buffer.concat(this.contents); } }); dd._NodeList = dojo.extend(function(/*Node[]*/ nodes){ // summary: Allows us to render a group of nodes this.contents = nodes || []; this.last = ""; }, { push: function(node){ // summary: Add a new node to the list this.contents.push(node); }, render: function(context, buffer){ // summary: Adds all content onto the buffer for(var i = 0; i < this.contents.length; i++){ buffer = this.contents[i].render(context, buffer); if(!buffer) throw new Error("Template must return buffer"); } return buffer; }, dummyRender: function(context){ return this.render(context, dd.Template.prototype.getBuffer()).toString(); }, unrender: function(){ return arguments[1]; }, clone: function(){ return this; } }); dd._VarNode = dojo.extend(function(str){ // summary: A node to be processed as a variable this.contents = new dd._Filter(str); }, { render: function(context, buffer){ var str = this.contents.resolve(context); return buffer.concat(str); } }); dd._noOpNode = new function(){ // summary: Adds a no-op node. Useful in custom tags this.render = this.unrender = function(){ return arguments[1]; } this.clone = function(){ return this; } } dd._Parser = dojo.extend(function(tokens){ // summary: Parser used during initialization and for tag groups. this.contents = tokens; }, { i: 0, parse: function(/*Array?*/ stop_at){ // summary: Turns tokens into nodes // description: Steps into tags are they're found. Blocks use the parse object // to find their closing tag (the stop_at array). stop_at is inclusive, it // returns the node that matched. var types = ddt.types; var terminators = {}; stop_at = stop_at || []; for(var i = 0; i < stop_at.length; i++){ terminators[stop_at[i]] = true; } var nodelist = new dd._NodeList(); while(this.i < this.contents.length){ token = this.contents[this.i++]; if(dojo.isString(token)){ nodelist.push(new dd._TextNode(token)); }else{ var type = token[0]; var text = token[1]; if(type == types.varr){ nodelist.push(new dd._VarNode(text)); }else if(type == types.tag){ if(terminators[text]){ --this.i; return nodelist; } var cmd = text.split(/\s+/g); if(cmd.length){ cmd = cmd[0]; var fn = ddt.getTag(cmd); if(fn){ nodelist.push(fn(this, text)); } } } } } if(stop_at.length){ throw new Error("Could not find closing tag(s): " + stop_at.toString()); } this.contents.length = 0; return nodelist; }, next: function(){ // summary: Returns the next token in the list. var token = this.contents[this.i++]; return {type: token[0], text: token[1]}; }, skipPast: function(endtag){ var types = ddt.types; while(this.i < this.contents.length){ var token = this.contents[this.i++]; if(token[0] == types.tag && token[1] == endtag){ return; } } throw new Error("Unclosed tag found when looking for " + endtag); }, getVarNodeConstructor: function(){ return dd._VarNode; }, getTextNodeConstructor: function(){ return dd._TextNode; }, getTemplate: function(file){ return new dd.Template(file); } }); dd.register = { _registry: { attributes: [], tags: [], filters: [] }, get: function(/*String*/ module, /*String*/ name){ var registry = dd.register._registry[module + "s"]; for(var i = 0, entry; entry = registry[i]; i++){ if(dojo.isString(entry[0])){ if(entry[0] == name){ return entry; } }else if(name.match(entry[0])){ return entry; } } }, getAttributeTags: function(){ var tags = []; var registry = dd.register._registry.attributes; for(var i = 0, entry; entry = registry[i]; i++){ if(entry.length == 3){ tags.push(entry); }else{ var fn = dojo.getObject(entry[1]); if(fn && dojo.isFunction(fn)){ entry.push(fn); tags.push(entry); } } } return tags; }, _any: function(type, base, locations){ for(var path in locations){ for(var i = 0, fn; fn = locations[path][i]; i++){ var key = fn; if(dojo.isArray(fn)){ key = fn[0]; fn = fn[1]; } if(dojo.isString(key)){ if(key.substr(0, 5) == "attr:"){ var attr = fn; if(attr.substr(0, 5) == "attr:"){ attr = attr.slice(5); } dd.register._registry.attributes.push([attr, base + "." + path + "." + attr]); } key = key.toLowerCase(); } dd.register._registry[type].push([ key, fn, base + "." + path ]); } } }, tags: function(/*String*/ base, /*Object*/ locations){ dd.register._any("tags", base, locations); }, filters: function(/*String*/ base, /*Object*/ locations){ dd.register._any("filters", base, locations); } } dd.register.tags("dojox.dtl.tag", { "date": ["now"], "logic": ["if", "for", "ifequal", "ifnotequal"], "loader": ["extends", "block", "include", "load", "ssi"], "misc": ["comment", "debug", "filter", "firstof", "spaceless", "templatetag", "widthratio", "with"], "loop": ["cycle", "ifchanged", "regroup"] }); dd.register.filters("dojox.dtl.filter", { "dates": ["date", "time", "timesince", "timeuntil"], "htmlstrings": ["escape", "linebreaks", "linebreaksbr", "removetags", "striptags"], "integers": ["add", "get_digit"], "lists": ["dictsort", "dictsortreversed", "first", "join", "length", "length_is", "random", "slice", "unordered_list"], "logic": ["default", "default_if_none", "divisibleby", "yesno"], "misc": ["filesizeformat", "pluralize", "phone2numeric", "pprint"], "strings": ["addslashes", "capfirst", "center", "cut", "fix_ampersands", "floatformat", "iriencode", "linenumbers", "ljust", "lower", "make_list", "rjust", "slugify", "stringformat", "title", "truncatewords", "truncatewords_html", "upper", "urlencode", "urlize", "urlizetrunc", "wordcount", "wordwrap"] }); })(); }