]> git.pond.sub.org Git - eow/blob - static/dojo-release-1.1.1/dojox/dtl/_base.js
add Dojo 1.1.1
[eow] / static / dojo-release-1.1.1 / dojox / dtl / _base.js
1 if(!dojo._hasResource["dojox.dtl._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2 dojo._hasResource["dojox.dtl._base"] = true;
3 dojo.provide("dojox.dtl._base");
4
5 dojo.require("dojox.string.Builder");
6 dojo.require("dojox.string.tokenize");
7
8 (function(){
9         var dd = dojox.dtl;
10
11         dd._Context = dojo.extend(function(dict){
12                 // summary: Pass one of these when rendering a template to tell the template what values to use.
13                 dojo.mixin(this, dict || {});
14                 this._dicts = [];
15         },
16         {
17                 push: function(){
18                         var dict = {};
19                         var keys = this.getKeys();
20                         for(var i = 0, key; key = keys[i]; i++){
21                                 dict[key] = this[key];
22                                 delete this[key];
23                         }
24                         this._dicts.unshift(dict);
25                 },
26                 pop: function(){
27                         if(!this._dicts.length){
28                                 throw new Error("pop() called on empty Context");
29                         }
30                         var dict = this._dicts.shift();
31                         dojo.mixin(this, dict);
32                 },
33                 getKeys: function(){
34                         var keys = [];
35                         for(var key in this){
36                                 if(this.hasOwnProperty(key) && key != "_dicts" && key != "_this"){
37                                         keys.push(key);
38                                 }
39                         }
40                         return keys;
41                 },
42                 get: function(key, otherwise){
43                         if(typeof this[key] != "undefined"){
44                                 return this._normalize(this[key]);
45                         }
46
47                         for(var i = 0, dict; dict = this._dicts[i]; i++){
48                                 if(typeof dict[key] != "undefined"){
49                                         return this._normalize(dict[key]);
50                                 }
51                         }
52
53                         return otherwise;
54                 },
55                 _normalize: function(value){
56                         if(value instanceof Date){
57                                 value.year = value.getFullYear();
58                                 value.month = value.getMonth() + 1;
59                                 value.day = value.getDate();
60                                 value.date = value.year + "-" + ("0" + value.month).slice(-2) + "-" + ("0" + value.day).slice(-2);
61                                 value.hour = value.getHours();
62                                 value.minute = value.getMinutes();
63                                 value.second = value.getSeconds();
64                                 value.microsecond = value.getMilliseconds();
65                         }
66                         return value;
67                 },
68                 update: function(dict){
69                         this.push();
70                         if(dict){
71                                 dojo.mixin(this, dict);
72                         }
73                 }
74         });
75
76         var ddt = dd.text = {
77                 types: {tag: -1, varr: -2, text: 3},
78                 pySplit: function(str){
79                         // summary: Split a string according to Python's split function
80                         str = dojo.trim(str);
81                         return (!str.length) ? [] : str.split(/\s+/g);
82                 },
83                 _get: function(module, name, errorless){
84                         // summary: Used to find both tags and filters
85                         var params = dd.register.get(module, name.toLowerCase(), errorless);
86                         if(!params){
87                                 if(!errorless){
88                                         throw new Error("No tag found for " + name);
89                                 }
90                                 return null;
91                         }
92
93                         var fn = params[1];
94                         var require = params[2];
95
96                         var parts;
97                         if(fn.indexOf(":") != -1){
98                                 parts = fn.split(":");
99                                 fn = parts.pop();
100                         }
101
102                         dojo["require"](require);
103
104                         var parent = dojo.getObject(require);
105
106                         return parent[fn || name] || parent[name + "_"];
107                 },
108                 getTag: function(name, errorless){
109                         return ddt._get("tag", name, errorless);
110                 },
111                 getFilter: function(name, errorless){
112                         return ddt._get("filter", name, errorless);
113                 },
114                 getTemplate: function(file){
115                         return new dd.Template(dd.getTemplateString(file));
116                 },
117                 getTemplateString: function(file){
118                         return dojo._getText(file.toString()) || "";
119                 },
120                 _resolveLazy: function(location, sync, json){
121                         if(sync){
122                                 if(json){
123                                         return dojo.fromJson(dojo._getText(location)) || {};
124                                 }else{
125                                         return dd.text.getTemplateString(location);
126                                 }
127                         }else{
128                                 return dojo.xhrGet({
129                                         handleAs: (json) ? "json" : "text",
130                                         url: location
131                                 });
132                         }
133                 },
134                 _resolveTemplateArg: function(arg, sync){
135                         if(ddt._isTemplate(arg)){
136                                 if(!sync){
137                                         var d = new dojo.Deferred();
138                                         d.callback(arg);
139                                         return d;
140                                 }
141                                 return arg;
142                         }
143                         return ddt._resolveLazy(arg, sync);
144                 },
145                 _isTemplate: function(arg){
146                         return (typeof arg == "undefined") || (dojo.isString(arg) && (arg.match(/^\s*[<{]/) || arg.indexOf(" ") != -1));
147                 },
148                 _resolveContextArg: function(arg, sync){
149                         if(arg.constructor == Object){
150                                 if(!sync){
151                                         var d = new dojo.Deferred;
152                                         d.callback(arg);
153                                         return d;
154                                 }
155                                 return arg;
156                         }
157                         return ddt._resolveLazy(arg, sync, true);
158                 },
159                 _re: /(?:\{\{\s*(.+?)\s*\}\}|\{%\s*(load\s*)?(.+?)\s*%\})/g,
160                 tokenize: function(str){
161                         return dojox.string.tokenize(str, ddt._re, ddt._parseDelims);
162                 },
163                 _parseDelims: function(varr, load, tag){
164                         var types = ddt.types;
165                         if(varr){
166                                 return [types.varr, varr];
167                         }else if(load){
168                                 var parts = dd.text.pySplit(tag);
169                                 for(var i = 0, part; part = parts[i]; i++){
170                                         dojo["require"](part);
171                                 }
172                         }else{
173                                 return [types.tag, tag];
174                         }
175                 }
176         }
177
178         dd.Template = dojo.extend(function(/*String|dojo._Url*/ template){
179                 // template:
180                 //              The string or location of the string to
181                 //              use as a template
182                 var str = ddt._resolveTemplateArg(template, true) || "";
183                 var tokens = ddt.tokenize(str);
184                 var parser = new dd._Parser(tokens);
185                 this.nodelist = parser.parse();
186         },
187         {
188                 update: function(node, context){
189                         // node: DOMNode|String|dojo.NodeList
190                         //              A node reference or set of nodes
191                         // context: dojo._Url|String|Object
192                         //              The context object or location
193                         return ddt._resolveContextArg(context).addCallback(this, function(contextObject){
194                                 var content = this.render(new dd._Context(contextObject));
195                                 if(node.forEach){
196                                         node.forEach(function(item){
197                                                 item.innerHTML = content;
198                                         });
199                                 }else{
200                                         dojo.byId(node).innerHTML = content;
201                                 }
202                                 return this;
203                         });
204                 },
205                 render: function(context, /*concatenatable?*/ buffer){
206                         buffer = buffer || this.getBuffer();
207                         context = context || new dd._Context({});
208                         return this.nodelist.render(context, buffer) + "";
209                 },
210                 getBuffer: function(){
211                         dojo.require("dojox.string.Builder");
212                         return new dojox.string.Builder();
213                 }
214         });
215
216         dd._Filter = dojo.extend(function(token){
217                 // summary: Uses a string to find (and manipulate) a variable
218                 if(!token) throw new Error("Filter must be called with variable name");
219                 this.contents = token;
220
221                 var cache = this._cache[token];
222                 if(cache){
223                         this.key = cache[0];
224                         this.filters = cache[1];
225                 }else{
226                         this.filters = [];
227                         dojox.string.tokenize(token, this._re, this._tokenize, this);
228                         this._cache[token] = [this.key, this.filters];
229                 }
230         },
231         {
232                 _cache: {},
233                 _re: /(?:^_\("([^\\"]*(?:\\.[^\\"])*)"\)|^"([^\\"]*(?:\\.[^\\"]*)*)"|^([a-zA-Z0-9_.]+)|\|(\w+)(?::(?:_\("([^\\"]*(?:\\.[^\\"])*)"\)|"([^\\"]*(?:\\.[^\\"]*)*)"|([a-zA-Z0-9_.]+)|'([^\\']*(?:\\.[^\\']*)*)'))?|^'([^\\']*(?:\\.[^\\']*)*)')/g,
234                 _values: {
235                         0: '"', // _("text")
236                         1: '"', // "text"
237                         2: "", // variable
238                         8: '"' // 'text'
239                 },
240                 _args: {
241                         4: '"', // :_("text")
242                         5: '"', // :"text"
243                         6: "", // :variable
244                         7: "'"// :'text'
245                 },
246                 _tokenize: function(){
247                         var pos, arg;
248
249                         for(var i = 0, has = []; i < arguments.length; i++){
250                                 has[i] = (typeof arguments[i] != "undefined" && dojo.isString(arguments[i]) && arguments[i]);
251                         }
252
253                         if(!this.key){
254                                 for(pos in this._values){
255                                         if(has[pos]){
256                                                 this.key = this._values[pos] + arguments[pos] + this._values[pos];
257                                                 break;
258                                         }
259                                 }
260                         }else{
261                                 for(pos in this._args){
262                                         if(has[pos]){
263                                                 var value = arguments[pos];
264                                                 if(this._args[pos] == "'"){
265                                                         value = value.replace(/\\'/g, "'");
266                                                 }else if(this._args[pos] == '"'){
267                                                         value = value.replace(/\\"/g, '"');
268                                                 }
269                                                 arg = [!this._args[pos], value];
270                                                 break;
271                                         }
272                                 }
273                                 // Get a named filter
274                                 var fn = ddt.getFilter(arguments[3]);
275                                 if(!dojo.isFunction(fn)) throw new Error(arguments[3] + " is not registered as a filter");
276                                 this.filters.push([fn, arg]);
277                         }
278                 },
279                 getExpression: function(){
280                         return this.contents;
281                 },
282                 resolve: function(context){
283                         var str = this.resolvePath(this.key, context);
284                         for(var i = 0, filter; filter = this.filters[i]; i++){
285                                 // Each filter has the function in [0], a boolean in [1][0] of whether it's a variable or a string
286                                 // and [1][1] is either the variable name of the string content.
287                                 if(filter[1]){
288                                         if(filter[1][0]){
289                                                 str = filter[0](str, this.resolvePath(filter[1][1], context));
290                                         }else{
291                                                 str = filter[0](str, filter[1][1]);
292                                         }
293                                 }else{
294                                         str = filter[0](str);
295                                 }
296                         }
297                         return str;
298                 },
299                 resolvePath: function(path, context){
300                         var current, parts;
301                         var first = path.charAt(0);
302                         var last = path.slice(-1);
303                         if(!isNaN(parseInt(first))){
304                                 current = (path.indexOf(".") == -1) ? parseInt(path) : parseFloat(path);
305                         }else if(first == '"' && first == last){
306                                 current = path.slice(1, -1);
307                         }else{
308                                 if(path == "true"){ return true; }
309                                 if(path == "false"){ return false; }
310                                 if(path == "null" || path == "None"){ return null; }
311                                 parts = path.split(".");
312                                 current = context.get(parts[0]);
313                                 for(var i = 1; i < parts.length; i++){
314                                         var part = parts[i];
315                                         if(current){
316                                                 if(dojo.isObject(current) && part == "items" && typeof current[part] == "undefined"){
317                                                         var items = [];
318                                                         for(var key in current){
319                                                                 items.push([key, current[key]]);
320                                                         }
321                                                         current = items;
322                                                         continue;
323                                                 }
324
325                                                 if(current.get && dojo.isFunction(current.get)){
326                                                         current = current.get(part);
327                                                 }else if(typeof current[part] == "undefined"){
328                                                         current = current[part];
329                                                         break;
330                                                 }else{
331                                                         current = current[part];
332                                                 }
333
334                                                 if(dojo.isFunction(current)){
335                                                         if(current.alters_data){
336                                                                 current = "";
337                                                         }else{
338                                                                 current = current();
339                                                         }
340                                                 }
341                                         }else{
342                                                 return "";
343                                         }
344                                 }
345                         }
346                         return current;
347                 }
348         });
349
350         dd._TextNode = dd._Node = dojo.extend(function(/*Object*/ obj){
351                 // summary: Basic catch-all node
352                 this.contents = obj;
353         },
354         {
355                 set: function(data){
356                         this.contents = data;
357                 },
358                 render: function(context, buffer){
359                         // summary: Adds content onto the buffer
360                         return buffer.concat(this.contents);
361                 }
362         });
363
364         dd._NodeList = dojo.extend(function(/*Node[]*/ nodes){
365                 // summary: Allows us to render a group of nodes
366                 this.contents = nodes || [];
367                 this.last = "";
368         },
369         {
370                 push: function(node){
371                         // summary: Add a new node to the list
372                         this.contents.push(node);
373                 },
374                 render: function(context, buffer){
375                         // summary: Adds all content onto the buffer
376                         for(var i = 0; i < this.contents.length; i++){
377                                 buffer = this.contents[i].render(context, buffer);
378                                 if(!buffer) throw new Error("Template must return buffer");
379                         }
380                         return buffer;
381                 },
382                 dummyRender: function(context){
383                         return this.render(context, dd.Template.prototype.getBuffer()).toString();
384                 },
385                 unrender: function(){ return arguments[1]; },
386                 clone: function(){ return this; }
387         });
388
389         dd._VarNode = dojo.extend(function(str){
390                 // summary: A node to be processed as a variable
391                 this.contents = new dd._Filter(str);
392         },
393         {
394                 render: function(context, buffer){
395                         var str = this.contents.resolve(context);
396                         return buffer.concat(str);
397                 }
398         });
399
400         dd._noOpNode = new function(){
401                 // summary: Adds a no-op node. Useful in custom tags
402                 this.render = this.unrender = function(){ return arguments[1]; }
403                 this.clone = function(){ return this; }
404         }
405
406         dd._Parser = dojo.extend(function(tokens){
407                 // summary: Parser used during initialization and for tag groups.
408                 this.contents = tokens;
409         },
410         {
411                 i: 0,
412                 parse: function(/*Array?*/ stop_at){
413                         // summary: Turns tokens into nodes
414                         // description: Steps into tags are they're found. Blocks use the parse object
415                         //              to find their closing tag (the stop_at array). stop_at is inclusive, it
416                         //              returns the node that matched.
417                         var types = ddt.types;
418                         var terminators = {};
419                         stop_at = stop_at || [];
420                         for(var i = 0; i < stop_at.length; i++){
421                                 terminators[stop_at[i]] = true;
422                         }
423
424                         var nodelist = new dd._NodeList();
425                         while(this.i < this.contents.length){
426                                 token = this.contents[this.i++];
427                                 if(dojo.isString(token)){
428                                         nodelist.push(new dd._TextNode(token));
429                                 }else{
430                                         var type = token[0];
431                                         var text = token[1];
432                                         if(type == types.varr){
433                                                 nodelist.push(new dd._VarNode(text));
434                                         }else if(type == types.tag){
435                                                 if(terminators[text]){
436                                                         --this.i;
437                                                         return nodelist;
438                                                 }
439                                                 var cmd = text.split(/\s+/g);
440                                                 if(cmd.length){
441                                                         cmd = cmd[0];
442                                                         var fn = ddt.getTag(cmd);
443                                                         if(fn){
444                                                                 nodelist.push(fn(this, text));
445                                                         }
446                                                 }
447                                         }
448                                 }
449                         }
450
451                         if(stop_at.length){
452                                 throw new Error("Could not find closing tag(s): " + stop_at.toString());
453                         }
454
455                         this.contents.length = 0;
456                         return nodelist;
457                 },
458                 next: function(){
459                         // summary: Returns the next token in the list.
460                         var token = this.contents[this.i++];
461                         return {type: token[0], text: token[1]};
462                 },
463                 skipPast: function(endtag){
464                         var types = ddt.types;
465                         while(this.i < this.contents.length){
466                                 var token = this.contents[this.i++];
467                                 if(token[0] == types.tag && token[1] == endtag){
468                                         return;
469                                 }
470                         }
471                         throw new Error("Unclosed tag found when looking for " + endtag);
472                 },
473                 getVarNodeConstructor: function(){
474                         return dd._VarNode;
475                 },
476                 getTextNodeConstructor: function(){
477                         return dd._TextNode;
478                 },
479                 getTemplate: function(file){
480                         return new dd.Template(file);
481                 }
482         });
483
484         dd.register = {
485                 _registry: {
486                         attributes: [],
487                         tags: [],
488                         filters: []
489                 },
490                 get: function(/*String*/ module, /*String*/ name){
491                         var registry = dd.register._registry[module + "s"];
492                         for(var i = 0, entry; entry = registry[i]; i++){
493                                 if(dojo.isString(entry[0])){
494                                         if(entry[0] == name){
495                                                 return entry;
496                                         }
497                                 }else if(name.match(entry[0])){
498                                         return entry;
499                                 }
500                         }
501                 },
502                 getAttributeTags: function(){
503                         var tags = [];
504                         var registry = dd.register._registry.attributes;
505                         for(var i = 0, entry; entry = registry[i]; i++){
506                                 if(entry.length == 3){
507                                         tags.push(entry);
508                                 }else{
509                                         var fn = dojo.getObject(entry[1]);
510                                         if(fn && dojo.isFunction(fn)){
511                                                 entry.push(fn);
512                                                 tags.push(entry);
513                                         }
514                                 }
515                         }
516                         return tags;
517                 },
518                 _any: function(type, base, locations){
519                         for(var path in locations){
520                                 for(var i = 0, fn; fn = locations[path][i]; i++){
521                                         var key = fn;
522                                         if(dojo.isArray(fn)){
523                                                 key = fn[0];
524                                                 fn = fn[1];
525                                         }
526                                         if(dojo.isString(key)){
527                                                 if(key.substr(0, 5) == "attr:"){
528                                                         var attr = fn;
529                                                         if(attr.substr(0, 5) == "attr:"){
530                                                                 attr = attr.slice(5);
531                                                         }
532                                                         dd.register._registry.attributes.push([attr, base + "." + path + "." + attr]);
533                                                 }
534                                                 key = key.toLowerCase();
535                                         }
536                                         dd.register._registry[type].push([
537                                                 key,
538                                                 fn,
539                                                 base + "." + path
540                                         ]);
541                                 }
542                         }
543                 },
544                 tags: function(/*String*/ base, /*Object*/ locations){
545                         dd.register._any("tags", base, locations);
546                 },
547                 filters: function(/*String*/ base, /*Object*/ locations){
548                         dd.register._any("filters", base, locations);
549                 }
550         }
551
552         dd.register.tags("dojox.dtl.tag", {
553                 "date": ["now"],
554                 "logic": ["if", "for", "ifequal", "ifnotequal"],
555                 "loader": ["extends", "block", "include", "load", "ssi"],
556                 "misc": ["comment", "debug", "filter", "firstof", "spaceless", "templatetag", "widthratio", "with"],
557                 "loop": ["cycle", "ifchanged", "regroup"]
558         });
559         dd.register.filters("dojox.dtl.filter", {
560                 "dates": ["date", "time", "timesince", "timeuntil"],
561                 "htmlstrings": ["escape", "linebreaks", "linebreaksbr", "removetags", "striptags"],
562                 "integers": ["add", "get_digit"],
563                 "lists": ["dictsort", "dictsortreversed", "first", "join", "length", "length_is", "random", "slice", "unordered_list"],
564                 "logic": ["default", "default_if_none", "divisibleby", "yesno"],
565                 "misc": ["filesizeformat", "pluralize", "phone2numeric", "pprint"],
566                 "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"]
567         });
568 })();
569
570 }