New file |
0,0 → 1,632 |
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"); |
|
dojox.dtl.Context = function(dict){ |
dojo.mixin(this, dict || {}); |
this._dicts = []; |
this._this = {}; |
} |
dojo.extend(dojox.dtl.Context, { |
_dicts: [], |
_this: {}, |
extend: function(/*dojox.dtl.Context|Object*/ obj){ |
// summary: Returns a clone of this context object, with the items from the |
// passed objecct mixed in. |
var context = new dojox.dtl.Context(); |
var keys = this.getKeys(); |
for(var i = 0, key; key = keys[i]; i++){ |
if(typeof obj[key] != "undefined"){ |
context[key] = obj[key]; |
}else{ |
context[key] = this[key]; |
} |
} |
|
if(obj instanceof dojox.dtl.Context){ |
keys = obj.getKeys(); |
}else if(typeof obj == "object"){ |
keys = []; |
for(var key in obj){ |
keys.push(key); |
} |
} |
|
for(var i = 0, key; key = keys[i]; i++){ |
context[key] = obj[key]; |
} |
|
return context; |
}, |
filter: function(/*dojox.dtl.Context|Object|String...*/ filter){ |
// summary: Returns a clone of this context, only containing the items |
// defined in the filter. |
var context = new dojox.dtl.Context(); |
var keys = []; |
if(filter instanceof dojox.dtl.Context){ |
keys = filter.getKeys(); |
}else if(typeof filter == "object"){ |
for(var key in filter){ |
keys.push(key); |
} |
}else{ |
for(var i = 0, arg; arg = arguments[i]; i++){ |
if(typeof arg == "string"){ |
keys.push(arg); |
} |
} |
} |
|
for(var i = 0, key; key = keys[i]; i++){ |
context[key] = this[key]; |
} |
|
return context; |
}, |
setThis: function(/*Object*/ _this){ |
this._this = _this; |
}, |
getThis: function(){ |
return this._this; |
}, |
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() has been called more times than push() on the Context"); |
} |
var dict = this._dicts.shift(); |
dojo.mixin(this, dict); |
}, |
hasKey: function(key){ |
if(typeof this[key] != "undefined"){ |
return true; |
} |
|
for(var i = 0, dict; dict = this._dicts[i]; i++){ |
if(typeof dict[key] != "undefined"){ |
return true; |
} |
} |
|
return false; |
}, |
getKeys: function(){ |
var keys = []; |
for(var key in this){ |
if(isNaN(key)){ |
var found = false; |
for(var protoKey in dojox.dtl.Context.prototype){ |
if(key == protoKey){ |
found = true; |
break; |
} |
} |
if(!found){ |
keys.push(key); |
} |
} |
} |
return keys; |
}, |
get: function(key, otherwise){ |
if(typeof this[key] != "undefined"){ |
return this[key]; |
} |
|
for(var i = 0, dict; dict = this._dicts[i]; i++){ |
if(typeof dict[key] != "undefined"){ |
return dict[key]; |
} |
} |
|
return otherwise; |
}, |
update: function(dict){ |
this.push(); |
if(dict){ |
dojo.mixin(this, dict); |
} |
}, |
toString: function(){ return "dojox.dtl.Context"; } |
}); |
|
dojox.dtl.text = { |
types: {tag: -1, varr: -2, text: 3}, |
pySplit: function(str){ |
// summary: Split a string according to Python's split function |
str = str.replace(/^\s+|\s+$/, ""); |
if(!str.length){ |
return []; |
} |
return str.split(/\s+/g); |
}, |
urlquote: function(/*String*/ url, /*String?*/ safe){ |
if(!safe){ |
safe = "/"; |
} |
return dojox.string.tokenize(url, /([^\w-_.])/g, function(token){ |
if(safe.indexOf(token) == -1){ |
if(token == " "){ |
return "+"; |
}else{ |
return "%" + token.charCodeAt(0).toString(16).toUpperCase(); |
} |
} |
return token; |
}).join(""); |
}, |
_get: function(module, name, errorless){ |
// summary: Used to find both tags and filters |
var params = dojox.dtl.register.get(module, name, errorless); |
if(!params) return; |
|
var require = params.getRequire(); |
var obj = params.getObj(); |
var fn = params.getFn(); |
|
if(fn.indexOf(":") != -1){ |
var parts = fn.split(":"); |
fn = parts.pop(); |
} |
|
dojo.requireIf(true, require); |
|
var parent = window; |
var parts = obj.split("."); |
for(var i = 0, part; part = parts[i]; i++){ |
if(!parent[part]) return; |
parent = parent[part]; |
} |
return parent[fn || name] || parent[name + "_"]; |
}, |
getTag: function(name, errorless){ |
return dojox.dtl.text._get("tag", name, errorless); |
}, |
getFilter: function(name, errorless){ |
return dojox.dtl.text._get("filter", name, errorless); |
}, |
getTemplate: function(file){ |
return new dojox.dtl.Template(dojox.dtl.getTemplateString(file)); |
}, |
getTemplateString: function(file){ |
return dojo._getText(file.toString()) || ""; |
}, |
_re: /(?:\{\{\s*(.+?)\s*\}\}|\{%\s*(.+?)\s*%\})/g, |
tokenize: function(str){ |
return dojox.string.tokenize(str, dojox.dtl.text._re, dojox.dtl.text._parseDelims); |
}, |
_parseDelims: function(varr, tag){ |
var types = dojox.dtl.text.types; |
if(varr){ |
return [types.varr, varr]; |
}else{ |
return [types.tag, tag]; |
} |
} |
} |
|
dojox.dtl.Template = function(str){ |
var st = dojox.dtl; |
var tokens = st.text.tokenize(str); |
var parser = new st.Parser(tokens); |
this.nodelist = parser.parse(); |
} |
dojo.extend(dojox.dtl.Template, { |
render: function(context, /*concatenatable?*/ buffer){ |
context = context || new dojox.dtl.Context({}); |
if(!buffer){ |
dojo.require("dojox.string.Builder"); |
buffer = new dojox.string.Builder(); |
} |
return this.nodelist.render(context, buffer) + ""; |
}, |
toString: function(){ return "dojox.dtl.Template"; } |
}); |
|
dojox.dtl.Filter = 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 key = null; |
var re = this._re; |
var matches, filter, arg, fn; |
var filters = []; |
while(matches = re.exec(token)){ |
if(key === null){ |
if(this._exists(matches, 3)){ |
// variable |
key = matches[3]; |
}else if(this._exists(matches, 1)){ |
// _("text") |
key = '"' + matches[1] + '"'; |
}else if(this._exists(matches, 2)){ |
// "text" |
key = '"' + matches[2] + '"'; |
}else if(this._exists(matches, 9)){ |
// 'text' |
key = '"' + matches[9] + '"'; |
} |
}else{ |
if(this._exists(matches, 7)){ |
// :variable |
arg = [true, matches[7]]; |
}else if(this._exists(matches, 5)){ |
// :_("text") |
arg = [false, dojox.dtl.replace(matches[5], '\\"', '"')]; |
}else if(this._exists(matches, 6)){ |
// :"text" |
arg = [false, dojox.dtl.replace(matches[6], '\\"', '"')]; |
}else if(this._exists(matches, 8)){ |
// :"text" |
arg = [false, dojox.dtl.replace(matches[8], "\\'", "'")]; |
} |
// Get a named filter |
fn = dojox.dtl.text.getFilter(matches[4]); |
if(typeof fn != "function") throw new Error(matches[4] + " is not registered as a filter"); |
filters.push([fn, arg]); |
} |
} |
|
this.key = key; |
this.filters = filters; |
} |
dojo.extend(dojox.dtl.Filter, { |
_re: /(?:^_\("([^\\"]*(?:\\.[^\\"])*)"\)|^"([^\\"]*(?:\\.[^\\"]*)*)"|^([a-zA-Z0-9_.]+)|\|(\w+)(?::(?:_\("([^\\"]*(?:\\.[^\\"])*)"\)|"([^\\"]*(?:\\.[^\\"]*)*)"|([a-zA-Z0-9_.]+)|'([^\\']*(?:\\.[^\\']*)*)'))?|^'([^\\']*(?:\\.[^\\']*)*)')/g, |
_exists: function(arr, index){ |
if(typeof arr[index] != "undefined" && arr[index] !== ""){ |
return true; |
} |
return false; |
}, |
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.charAt(path.length - 1); |
if(!isNaN(parseInt(first))){ |
current = (path.indexOf(".") == -1) ? parseInt(path) : parseFloat(path); |
}else if(first == '"' && first == last){ |
current = path.substring(1, path.length - 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.shift()); |
while(parts.length){ |
if(current && typeof current[parts[0]] != "undefined"){ |
current = current[parts[0]]; |
if(typeof current == "function"){ |
if(current.alters_data){ |
current = ""; |
}else{ |
current = current(); |
} |
} |
}else{ |
return ""; |
} |
parts.shift(); |
} |
} |
return current; |
}, |
toString: function(){ return "dojox.dtl.Filter"; } |
}); |
|
dojox.dtl.Node = function(/*Object*/ obj){ |
// summary: Basic catch-all node |
this.contents = obj; |
} |
dojo.extend(dojox.dtl.Node, { |
render: function(context, buffer){ |
// summary: Adds content onto the buffer |
return buffer.concat(this.contents); |
}, |
toString: function(){ return "dojox.dtl.Node"; } |
}); |
|
dojox.dtl.NodeList = function(/*Node[]*/ nodes){ |
// summary: Allows us to render a group of nodes |
this.contents = nodes || []; |
} |
dojo.extend(dojox.dtl.NodeList, { |
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 node render functions must return their buffer"); |
} |
return buffer; |
}, |
unrender: function(context, buffer){ return buffer; }, |
clone: function(){ return this; }, |
toString: function(){ return "dojox.dtl.NodeList"; } |
}); |
|
dojox.dtl.TextNode = dojox.dtl.Node; |
|
dojox.dtl.VarNode = function(str){ |
// summary: A node to be processed as a variable |
this.contents = new dojox.dtl.Filter(str); |
} |
dojo.extend(dojox.dtl.VarNode, { |
render: function(context, buffer){ |
var str = this.contents.resolve(context); |
return buffer.concat(str); |
}, |
toString: function(){ return "dojox.dtl.VarNode"; } |
}); |
|
dojox.dtl.Parser = function(tokens){ |
// summary: Parser used during initialization and for tag groups. |
this.contents = tokens; |
} |
dojo.extend(dojox.dtl.Parser, { |
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 st = dojox.dtl; |
var types = st.text.types; |
var terminators = {}; |
var tokens = this.contents; |
stop_at = stop_at || []; |
for(var i = 0; i < stop_at.length; i++){ |
terminators[stop_at[i]] = true; |
} |
|
var nodelist = new st.NodeList(); |
while(tokens.length){ |
token = tokens.shift(); |
if(typeof token == "string"){ |
nodelist.push(new st.TextNode(token)); |
}else{ |
var type = token[0]; |
var text = token[1]; |
if(type == types.varr){ |
nodelist.push(new st.VarNode(text)); |
}else if(type == types.tag){ |
if(terminators[text]){ |
tokens.unshift(token); |
return nodelist; |
} |
var cmd = text.split(/\s+/g); |
if(cmd.length){ |
cmd = cmd[0]; |
var fn = dojox.dtl.text.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()); |
} |
|
return nodelist; |
}, |
next: function(){ |
// summary: Returns the next token in the list. |
var token = this.contents.shift(); |
return {type: token[0], text: token[1]}; |
}, |
skipPast: function(endtag){ |
var types = dojox.dtl.text.types; |
while(this.contents.length){ |
var token = this.contents.shift(); |
if(token[0] == types.tag && token[1] == endtag){ |
return; |
} |
} |
throw new Error("Unclosed tag found when looking for " + endtag); |
}, |
getVarNode: function(){ |
return dojox.dtl.VarNode; |
}, |
getTextNode: function(){ |
return dojox.dtl.TextNode; |
}, |
getTemplate: function(file){ |
return new dojox.dtl.Template(file); |
}, |
toString: function(){ return "dojox.dtl.Parser"; } |
}); |
|
dojox.dtl.register = function(module, cols, args, /*Function*/ normalize){ |
// summary: Used to create dojox.dtl.register[module] function, and as a namespace |
// expand: Used if the call structure is reformatted for a more compact view. |
// Should return an array of normalized arguments. |
// description: The function produced will accept a "name" |
// as the first parameter and all other parameters will |
// be associated with the parameter names listed in cols. |
var ddr = dojox.dtl.register; |
var registry = ddr._mod[module] = { |
params: [], |
Getter: function(params){ |
ddr._params = params || {}; |
} |
}; |
|
cols.unshift("name"); |
for(var i = 0, col; col = cols[i]; i++){ |
registry.Getter.prototype["get" + col.substring(0, 1).toUpperCase() + col.substring(1, col.length)] = ddr._ret(i); |
} |
|
ddr[module] = function(/*String*/ name, /*mixed...*/ parameters){ |
if(normalize){ |
var normalized = normalize(arguments); |
}else{ |
var normalized = [arguments]; |
} |
|
for(var i = 0, args; args = normalized[i]; i++){ |
var params = []; |
for(var j = 0; j < cols.length; j++){ |
params.push(args[j] || null); |
} |
if(typeof args[0] == "string"){ |
// Strings before regexes for speed |
registry.params.unshift(params); |
}else{ |
// break |
// module RegExp |
registry.params.push(params); |
} |
} |
} |
|
ddr[module].apply(null, args); |
} |
dojo.mixin(dojox.dtl.register, { |
_mod: {}, |
_ret: function(i){ |
// summary: Just lets use i and _params within a closure |
return function(){ |
return dojox.dtl.register._params[i] || ""; |
} |
}, |
get: function(/*String*/ module, /*String*/ name, /*Boolean*/ errorless){ |
// summary: Returns a "Getter", based on the registry |
// description: The getter functions correspond with the registered cols |
// used in dojo.register |
var registry = this._mod[module] || {}; |
if(registry.params){ |
for(var i = 0, param; param = registry.params[i]; i++){ |
var search = param[0]; |
if(typeof search == "string"){ |
if(search == name){ |
return new registry.Getter(param); |
} |
}else if(name.match(search)){ |
var matches = search.exec(name); |
var mixin = []; |
dojo.mixin(mixin, param); |
mixin[0] = matches[1]; |
return new registry.Getter(param); |
} |
} |
} |
if(!errorless) throw new Error("'" + module + "' of name '" + name + "' does not exist"); |
}, |
_normalize: function(args){ |
// summary: |
// Translates to the signature (/*String*/ name, /*String*/ require, /*String*/ obj, /*String*/ fn) |
var items = args[2]; |
var output = []; |
for(var i = 0, item; item = items[i]; i++){ |
if(typeof item == "string"){ |
output.push([item, args[0], args[1], item]); |
}else{ |
output.push([item[0], args[0], args[1], item[1]]); |
} |
} |
return output; |
}, |
tag: function(/*String*/ require, /*String*/ obj, /*String[]|[RegExp, String][]*/ fns){ |
// summary: |
// Specify the location of a given tag function. |
// require: |
// The file this function is in |
// obj: |
// The base object to use for lookups |
// fn: |
// List of functions within obj to use |
// description: |
// When we are looking up a tag as specified in a template, we either use a |
// string in the fns array, or the RegExp item of the [RegExp, String] pair. |
// When that string is found, it requires the file specified in the require |
// parameter, uses the base object as a starting point and checks for obj.fn |
// or obj.fn_ in case fn is a reserved word. |
this("tag", ["require", "obj", "fn"], arguments, this._normalize); |
}, |
filter: function(/*String*/ require, /*String*/ obj, /*String[]|[RegExp, String][]*/ fns){ |
// summary: |
// Specify the location of a given filter function. |
// require: |
// The file this function is in |
// obj: |
// The base object to use for lookups |
// fn: |
// List of functions within obj to use |
// description: |
// When we are looking up a tag as specified in a template, we either use a |
// string in the fns array, or the RegExp item of the [RegExp, String] pair. |
// When that string is found, it requires the file specified in the require |
// parameter, uses the base object as a starting point and checks for obj.fn |
// or obj.fn_ in case fn is a reserved word. |
this("filter", ["require", "obj", "fn"], arguments, this._normalize); |
} |
}); |
|
(function(){ |
var register = dojox.dtl.register; |
var dtt = "dojox.dtl.tag"; |
register.tag(dtt + ".logic", dtt + ".logic", ["if", "for"]); |
register.tag(dtt + ".loader", dtt + ".loader", ["extends", "block"]); |
register.tag(dtt + ".misc", dtt + ".misc", ["comment", "debug", "filter"]); |
register.tag(dtt + ".loop", dtt + ".loop", ["cycle"]); |
|
var dtf = "dojox.dtl.filter"; |
register.filter(dtf + ".dates", dtf + ".dates", ["date", "time", "timesince", "timeuntil"]); |
register.filter(dtf + ".htmlstrings", dtf + ".htmlstrings", ["escape", "linebreaks", "linebreaksbr", "removetags", "striptags"]); |
register.filter(dtf + ".integers", dtf + ".integers", ["add", "get_digit"]); |
register.filter(dtf + ".lists", dtf + ".lists", ["dictsort", "dictsortreversed", "first", "join", "length", "length_is", "random", "slice", "unordered_list"]); |
register.filter(dtf + ".logic", dtf + ".logic", ["default", "default_if_none", "divisibleby", "yesno"]); |
register.filter(dtf + ".misc", dtf + ".misc", ["filesizeformat", "pluralize", "phone2numeric", "pprint"]); |
register.filter(dtf + ".strings", dtf + ".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"]); |
})(); |
|
dojox.dtl.replace = function(str, token, repl){ |
repl = repl || ""; |
var pos, len = token.length; |
while(1){ |
pos = str.indexOf(token); |
if(pos == -1) break; |
str = str.substring(0, pos) + repl + str.substring(pos + len); |
} |
return str; |
} |
|
dojox.dtl.resolveVariable = function(token, context){ |
// summary: Quickly resolve a variables |
var filter = new dojox.dtl.Filter(token); |
return filter.resolve(context); |
} |
|
} |