Subversion Repositories Applications.papyrus

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2150 mathias 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
dojox.dtl.Context = function(dict){
9
	dojo.mixin(this, dict || {});
10
	this._dicts = [];
11
	this._this = {};
12
}
13
dojo.extend(dojox.dtl.Context, {
14
	_dicts: [],
15
	_this: {},
16
	extend: function(/*dojox.dtl.Context|Object*/ obj){
17
		// summary: Returns a clone of this context object, with the items from the
18
		//		passed objecct mixed in.
19
		var context = new dojox.dtl.Context();
20
		var keys = this.getKeys();
21
		for(var i = 0, key; key = keys[i]; i++){
22
			if(typeof obj[key] != "undefined"){
23
				context[key] = obj[key];
24
			}else{
25
				context[key] = this[key];
26
			}
27
		}
28
 
29
		if(obj instanceof dojox.dtl.Context){
30
			keys = obj.getKeys();
31
		}else if(typeof obj == "object"){
32
			keys = [];
33
			for(var key in obj){
34
				keys.push(key);
35
			}
36
		}
37
 
38
		for(var i = 0, key; key = keys[i]; i++){
39
			context[key] = obj[key];
40
		}
41
 
42
		return context;
43
	},
44
	filter: function(/*dojox.dtl.Context|Object|String...*/ filter){
45
		// summary: Returns a clone of this context, only containing the items
46
		//		defined in the filter.
47
		var context = new dojox.dtl.Context();
48
		var keys = [];
49
		if(filter instanceof dojox.dtl.Context){
50
			keys = filter.getKeys();
51
		}else if(typeof filter == "object"){
52
			for(var key in filter){
53
				keys.push(key);
54
			}
55
		}else{
56
			for(var i = 0, arg; arg = arguments[i]; i++){
57
				if(typeof arg == "string"){
58
					keys.push(arg);
59
				}
60
			}
61
		}
62
 
63
		for(var i = 0, key; key = keys[i]; i++){
64
			context[key] = this[key];
65
		}
66
 
67
		return context;
68
	},
69
	setThis: function(/*Object*/ _this){
70
		this._this = _this;
71
	},
72
	getThis: function(){
73
		return this._this;
74
	},
75
	push: function(){
76
		var dict = {};
77
		var keys = this.getKeys();
78
		for(var i = 0, key; key = keys[i]; i++){
79
			dict[key] = this[key];
80
			delete this[key];
81
		}
82
		this._dicts.unshift(dict);
83
	},
84
	pop: function(){
85
		if(!this._dicts.length){
86
			throw new Error("pop() has been called more times than push() on the Context");
87
		}
88
		var dict = this._dicts.shift();
89
		dojo.mixin(this, dict);
90
	},
91
	hasKey: function(key){
92
		if(typeof this[key] != "undefined"){
93
			return true;
94
		}
95
 
96
		for(var i = 0, dict; dict = this._dicts[i]; i++){
97
			if(typeof dict[key] != "undefined"){
98
				return true;
99
			}
100
		}
101
 
102
		return false;
103
	},
104
	getKeys: function(){
105
		var keys = [];
106
		for(var key in this){
107
			if(isNaN(key)){
108
				var found = false;
109
				for(var protoKey in dojox.dtl.Context.prototype){
110
					if(key == protoKey){
111
						found = true;
112
						break;
113
					}
114
				}
115
				if(!found){
116
					keys.push(key);
117
				}
118
			}
119
		}
120
		return keys;
121
	},
122
	get: function(key, otherwise){
123
		if(typeof this[key] != "undefined"){
124
			return this[key];
125
		}
126
 
127
		for(var i = 0, dict; dict = this._dicts[i]; i++){
128
			if(typeof dict[key] != "undefined"){
129
				return dict[key];
130
			}
131
		}
132
 
133
		return otherwise;
134
	},
135
	update: function(dict){
136
		this.push();
137
		if(dict){
138
			dojo.mixin(this, dict);
139
		}
140
	},
141
	toString: function(){ return "dojox.dtl.Context"; }
142
});
143
 
144
dojox.dtl.text = {
145
	types: {tag: -1, varr: -2,	text: 3},
146
	pySplit: function(str){
147
		// summary: Split a string according to Python's split function
148
		str = str.replace(/^\s+|\s+$/, "");
149
		if(!str.length){
150
			return [];
151
		}
152
		return str.split(/\s+/g);
153
	},
154
	urlquote: function(/*String*/ url, /*String?*/ safe){
155
		if(!safe){
156
			safe = "/";
157
		}
158
		return dojox.string.tokenize(url, /([^\w-_.])/g, function(token){
159
			if(safe.indexOf(token) == -1){
160
				if(token == " "){
161
					return "+";
162
				}else{
163
					return "%" + token.charCodeAt(0).toString(16).toUpperCase();
164
				}
165
			}
166
			return token;
167
		}).join("");
168
	},
169
	_get: function(module, name, errorless){
170
		// summary: Used to find both tags and filters
171
		var params = dojox.dtl.register.get(module, name, errorless);
172
		if(!params) return;
173
 
174
		var require = params.getRequire();
175
		var obj = params.getObj();
176
		var fn = params.getFn();
177
 
178
		if(fn.indexOf(":") != -1){
179
			var parts = fn.split(":");
180
			fn = parts.pop();
181
		}
182
 
183
		dojo.requireIf(true, require);
184
 
185
		var parent = window;
186
		var parts = obj.split(".");
187
		for(var i = 0, part; part = parts[i]; i++){
188
			if(!parent[part]) return;
189
			parent = parent[part];
190
		}
191
		return parent[fn || name] || parent[name + "_"];
192
	},
193
	getTag: function(name, errorless){
194
		return dojox.dtl.text._get("tag", name, errorless);
195
	},
196
	getFilter: function(name, errorless){
197
		return dojox.dtl.text._get("filter", name, errorless);
198
	},
199
	getTemplate: function(file){
200
		return new dojox.dtl.Template(dojox.dtl.getTemplateString(file));
201
	},
202
	getTemplateString: function(file){
203
		return dojo._getText(file.toString()) || "";
204
	},
205
	_re: /(?:\{\{\s*(.+?)\s*\}\}|\{%\s*(.+?)\s*%\})/g,
206
	tokenize: function(str){
207
		return dojox.string.tokenize(str, dojox.dtl.text._re, dojox.dtl.text._parseDelims);
208
	},
209
	_parseDelims: function(varr, tag){
210
		var types = dojox.dtl.text.types;
211
		if(varr){
212
			return [types.varr, varr];
213
		}else{
214
			return [types.tag, tag];
215
		}
216
	}
217
}
218
 
219
dojox.dtl.Template = function(str){
220
	var st = dojox.dtl;
221
	var tokens = st.text.tokenize(str);
222
	var parser = new st.Parser(tokens);
223
	this.nodelist = parser.parse();
224
}
225
dojo.extend(dojox.dtl.Template, {
226
	render: function(context, /*concatenatable?*/ buffer){
227
		context = context || new dojox.dtl.Context({});
228
		if(!buffer){
229
			dojo.require("dojox.string.Builder");
230
			buffer = new dojox.string.Builder();
231
		}
232
		return this.nodelist.render(context, buffer) + "";
233
	},
234
	toString: function(){ return "dojox.dtl.Template"; }
235
});
236
 
237
dojox.dtl.Filter = function(token){
238
	// summary: Uses a string to find (and manipulate) a variable
239
	if(!token) throw new Error("Filter must be called with variable name");
240
	this.contents = token;
241
	var key = null;
242
	var re = this._re;
243
	var matches, filter, arg, fn;
244
	var filters = [];
245
	while(matches = re.exec(token)){
246
		if(key === null){
247
			if(this._exists(matches, 3)){
248
				// variable
249
				key = matches[3];
250
			}else if(this._exists(matches, 1)){
251
				// _("text")
252
				key = '"' + matches[1] + '"';
253
			}else if(this._exists(matches, 2)){
254
				// "text"
255
				key = '"' + matches[2] + '"';
256
			}else if(this._exists(matches, 9)){
257
				// 'text'
258
				key = '"' + matches[9] + '"';
259
			}
260
		}else{
261
			if(this._exists(matches, 7)){
262
				// :variable
263
				arg = [true, matches[7]];
264
			}else if(this._exists(matches, 5)){
265
				// :_("text")
266
				arg = [false, dojox.dtl.replace(matches[5], '\\"', '"')];
267
			}else if(this._exists(matches, 6)){
268
				// :"text"
269
				arg = [false, dojox.dtl.replace(matches[6], '\\"', '"')];
270
			}else if(this._exists(matches, 8)){
271
				// :"text"
272
				arg = [false, dojox.dtl.replace(matches[8], "\\'", "'")];
273
			}
274
			// Get a named filter
275
			fn = dojox.dtl.text.getFilter(matches[4]);
276
			if(typeof fn != "function") throw new Error(matches[4] + " is not registered as a filter");
277
			filters.push([fn, arg]);
278
		}
279
	}
280
 
281
	this.key = key;
282
	this.filters = filters;
283
}
284
dojo.extend(dojox.dtl.Filter, {
285
	_re: /(?:^_\("([^\\"]*(?:\\.[^\\"])*)"\)|^"([^\\"]*(?:\\.[^\\"]*)*)"|^([a-zA-Z0-9_.]+)|\|(\w+)(?::(?:_\("([^\\"]*(?:\\.[^\\"])*)"\)|"([^\\"]*(?:\\.[^\\"]*)*)"|([a-zA-Z0-9_.]+)|'([^\\']*(?:\\.[^\\']*)*)'))?|^'([^\\']*(?:\\.[^\\']*)*)')/g,
286
	_exists: function(arr, index){
287
		if(typeof arr[index] != "undefined" && arr[index] !== ""){
288
			return true;
289
		}
290
		return false;
291
	},
292
	resolve: function(context){
293
		var str = this.resolvePath(this.key, context);
294
		for(var i = 0, filter; filter = this.filters[i]; i++){
295
			// Each filter has the function in [0], a boolean in [1][0] of whether it's a variable or a string
296
			// and [1][1] is either the variable name of the string content.
297
			if(filter[1]){
298
				if(filter[1][0]){
299
					str = filter[0](str, this.resolvePath(filter[1][1], context));
300
				}else{
301
					str = filter[0](str, filter[1][1]);
302
				}
303
			}else{
304
				str = filter[0](str);
305
			}
306
		}
307
		return str;
308
	},
309
	resolvePath: function(path, context){
310
		var current, parts;
311
		var first = path.charAt(0);
312
		var last = path.charAt(path.length - 1);
313
		if(!isNaN(parseInt(first))){
314
			current = (path.indexOf(".") == -1) ? parseInt(path) : parseFloat(path);
315
		}else if(first == '"' && first == last){
316
			current = path.substring(1, path.length - 1);
317
		}else{;
318
			if(path == "true") return true;
319
			if(path == "false") return false;
320
			if(path == "null" || path == "None") return null;
321
			parts = path.split(".");
322
			current = context.get(parts.shift());
323
			while(parts.length){
324
				if(current && typeof current[parts[0]] != "undefined"){
325
					current = current[parts[0]];
326
					if(typeof current == "function"){
327
						if(current.alters_data){
328
							current = "";
329
						}else{
330
							current = current();
331
						}
332
					}
333
				}else{
334
					return "";
335
				}
336
				parts.shift();
337
			}
338
		}
339
		return current;
340
	},
341
	toString: function(){ return "dojox.dtl.Filter"; }
342
});
343
 
344
dojox.dtl.Node = function(/*Object*/ obj){
345
	// summary: Basic catch-all node
346
	this.contents = obj;
347
}
348
dojo.extend(dojox.dtl.Node, {
349
	render: function(context, buffer){
350
		// summary: Adds content onto the buffer
351
		return buffer.concat(this.contents);
352
	},
353
	toString: function(){ return "dojox.dtl.Node"; }
354
});
355
 
356
dojox.dtl.NodeList = function(/*Node[]*/ nodes){
357
	// summary: Allows us to render a group of nodes
358
	this.contents = nodes || [];
359
}
360
dojo.extend(dojox.dtl.NodeList, {
361
	push: function(node){
362
		// summary: Add a new node to the list
363
		this.contents.push(node);
364
	},
365
	render: function(context, buffer){
366
		// summary: Adds all content onto the buffer
367
		for(var i = 0; i < this.contents.length; i++){
368
			buffer = this.contents[i].render(context, buffer);
369
			if(!buffer) throw new Error("Template node render functions must return their buffer");
370
		}
371
		return buffer;
372
	},
373
	unrender: function(context, buffer){ return buffer; },
374
	clone: function(){ return this; },
375
	toString: function(){ return "dojox.dtl.NodeList"; }
376
});
377
 
378
dojox.dtl.TextNode = dojox.dtl.Node;
379
 
380
dojox.dtl.VarNode = function(str){
381
	// summary: A node to be processed as a variable
382
	this.contents = new dojox.dtl.Filter(str);
383
}
384
dojo.extend(dojox.dtl.VarNode, {
385
	render: function(context, buffer){
386
		var str = this.contents.resolve(context);
387
		return buffer.concat(str);
388
	},
389
	toString: function(){ return "dojox.dtl.VarNode"; }
390
});
391
 
392
dojox.dtl.Parser = function(tokens){
393
	// summary: Parser used during initialization and for tag groups.
394
	this.contents = tokens;
395
}
396
dojo.extend(dojox.dtl.Parser, {
397
	parse: function(/*Array?*/ stop_at){
398
		// summary: Turns tokens into nodes
399
		// description: Steps into tags are they're found. Blocks use the parse object
400
		//		to find their closing tag (the stop_at array). stop_at is inclusive, it
401
		//		returns the node that matched.
402
		var st = dojox.dtl;
403
		var types = st.text.types;
404
		var terminators = {};
405
		var tokens = this.contents;
406
		stop_at = stop_at || [];
407
		for(var i = 0; i < stop_at.length; i++){
408
			terminators[stop_at[i]] = true;
409
		}
410
 
411
		var nodelist = new st.NodeList();
412
		while(tokens.length){
413
			token = tokens.shift();
414
			if(typeof token == "string"){
415
				nodelist.push(new st.TextNode(token));
416
			}else{
417
				var type = token[0];
418
				var text = token[1];
419
				if(type == types.varr){
420
					nodelist.push(new st.VarNode(text));
421
				}else if(type == types.tag){
422
					if(terminators[text]){
423
						tokens.unshift(token);
424
						return nodelist;
425
					}
426
					var cmd = text.split(/\s+/g);
427
					if(cmd.length){
428
						cmd = cmd[0];
429
						var fn = dojox.dtl.text.getTag(cmd);
430
						if(fn){
431
							nodelist.push(fn(this, text));
432
						}
433
					}
434
				}
435
			}
436
		}
437
 
438
		if(stop_at.length){
439
			throw new Error("Could not find closing tag(s): " + stop_at.toString());
440
		}
441
 
442
		return nodelist;
443
	},
444
	next: function(){
445
		// summary: Returns the next token in the list.
446
		var token = this.contents.shift();
447
		return {type: token[0], text: token[1]};
448
	},
449
	skipPast: function(endtag){
450
		var types = dojox.dtl.text.types;
451
		while(this.contents.length){
452
			var token = this.contents.shift();
453
			if(token[0] == types.tag && token[1] == endtag){
454
				return;
455
			}
456
		}
457
		throw new Error("Unclosed tag found when looking for " + endtag);
458
	},
459
	getVarNode: function(){
460
		return dojox.dtl.VarNode;
461
	},
462
	getTextNode: function(){
463
		return dojox.dtl.TextNode;
464
	},
465
	getTemplate: function(file){
466
		return new dojox.dtl.Template(file);
467
	},
468
	toString: function(){ return "dojox.dtl.Parser"; }
469
});
470
 
471
dojox.dtl.register = function(module, cols, args, /*Function*/ normalize){
472
	// summary: Used to create dojox.dtl.register[module] function, and as a namespace
473
	// expand: Used if the call structure is reformatted for a more compact view.
474
	//		Should return an array of normalized arguments.
475
	// description: The function produced will accept a "name"
476
	//		as the first parameter and all other parameters will
477
	//		be associated with the parameter names listed in cols.
478
	var ddr = dojox.dtl.register;
479
	var registry = ddr._mod[module] = {
480
		params: [],
481
		Getter: function(params){
482
			ddr._params = params || {};
483
		}
484
	};
485
 
486
	cols.unshift("name");
487
	for(var i = 0, col; col = cols[i]; i++){
488
		registry.Getter.prototype["get" + col.substring(0, 1).toUpperCase() + col.substring(1, col.length)] = ddr._ret(i);
489
	}
490
 
491
	ddr[module] = function(/*String*/ name, /*mixed...*/ parameters){
492
		if(normalize){
493
			var normalized = normalize(arguments);
494
		}else{
495
			var normalized = [arguments];
496
		}
497
 
498
		for(var i = 0, args; args = normalized[i]; i++){
499
			var params = [];
500
			for(var j = 0; j < cols.length; j++){
501
				params.push(args[j] || null);
502
			}
503
			if(typeof args[0] == "string"){
504
				// Strings before regexes for speed
505
				registry.params.unshift(params);
506
			}else{
507
				// break
508
				// module RegExp
509
				registry.params.push(params);
510
			}
511
		}
512
	}
513
 
514
	ddr[module].apply(null, args);
515
}
516
dojo.mixin(dojox.dtl.register, {
517
	_mod: {},
518
	_ret: function(i){
519
		// summary: Just lets use i and _params within a closure
520
		return function(){
521
			return dojox.dtl.register._params[i] || "";
522
		}
523
	},
524
	get: function(/*String*/ module, /*String*/ name, /*Boolean*/ errorless){
525
		// summary: Returns a "Getter", based on the registry
526
		// description: The getter functions correspond with the registered cols
527
		//		used in dojo.register
528
		var registry = this._mod[module] || {};
529
		if(registry.params){
530
			for(var i = 0, param; param = registry.params[i]; i++){
531
				var search = param[0];
532
				if(typeof search == "string"){
533
					if(search == name){
534
						return new registry.Getter(param);
535
					}
536
				}else if(name.match(search)){
537
					var matches = search.exec(name);
538
					var mixin = [];
539
					dojo.mixin(mixin, param);
540
					mixin[0] = matches[1];
541
					return new registry.Getter(param);
542
				}
543
			}
544
		}
545
		if(!errorless) throw new Error("'" + module + "' of name '" + name + "' does not exist");
546
	},
547
	_normalize: function(args){
548
		// summary:
549
		//		Translates to the signature (/*String*/ name, /*String*/ require, /*String*/ obj, /*String*/ fn)
550
		var items = args[2];
551
		var output = [];
552
		for(var i = 0, item; item = items[i]; i++){
553
			if(typeof item == "string"){
554
				output.push([item, args[0], args[1], item]);
555
			}else{
556
				output.push([item[0], args[0], args[1], item[1]]);
557
			}
558
		}
559
		return output;
560
	},
561
 	tag: function(/*String*/ require, /*String*/ obj, /*String[]|[RegExp, String][]*/ fns){
562
		// summary:
563
		//		Specify the location of a given tag function.
564
		// require:
565
		//		The file this function is in
566
		// obj:
567
		//		The base object to use for lookups
568
		// fn:
569
		//		List of functions within obj to use
570
		// description:
571
		//		When we are looking up a tag as specified in a template, we either use a
572
		//		string in the fns array, or the RegExp item of the [RegExp, String] pair.
573
		//		When that string is found, it requires the file specified in the require
574
		//		parameter, uses the base object as a starting point and checks for obj.fn
575
		//		or obj.fn_ in case fn is a reserved word.
576
		this("tag", ["require", "obj", "fn"], arguments, this._normalize);
577
	},
578
	filter: function(/*String*/ require, /*String*/ obj, /*String[]|[RegExp, String][]*/ fns){
579
		// summary:
580
		//		Specify the location of a given filter function.
581
		// require:
582
		//		The file this function is in
583
		// obj:
584
		//		The base object to use for lookups
585
		// fn:
586
		//		List of functions within obj to use
587
		// description:
588
		//		When we are looking up a tag as specified in a template, we either use a
589
		//		string in the fns array, or the RegExp item of the [RegExp, String] pair.
590
		//		When that string is found, it requires the file specified in the require
591
		//		parameter, uses the base object as a starting point and checks for obj.fn
592
		//		or obj.fn_ in case fn is a reserved word.
593
		this("filter", ["require", "obj", "fn"], arguments, this._normalize);
594
	}
595
});
596
 
597
(function(){
598
	var register = dojox.dtl.register;
599
	var dtt = "dojox.dtl.tag";
600
	register.tag(dtt + ".logic", dtt + ".logic", ["if", "for"]);
601
	register.tag(dtt + ".loader", dtt + ".loader", ["extends", "block"]);
602
	register.tag(dtt + ".misc", dtt + ".misc", ["comment", "debug", "filter"]);
603
	register.tag(dtt + ".loop", dtt + ".loop", ["cycle"]);
604
 
605
	var dtf = "dojox.dtl.filter";
606
	register.filter(dtf + ".dates", dtf + ".dates", ["date", "time", "timesince", "timeuntil"]);
607
	register.filter(dtf + ".htmlstrings", dtf + ".htmlstrings", ["escape", "linebreaks", "linebreaksbr", "removetags", "striptags"]);
608
	register.filter(dtf + ".integers", dtf + ".integers", ["add", "get_digit"]);
609
	register.filter(dtf + ".lists", dtf + ".lists", ["dictsort", "dictsortreversed", "first", "join", "length", "length_is", "random", "slice", "unordered_list"]);
610
	register.filter(dtf + ".logic", dtf + ".logic", ["default", "default_if_none", "divisibleby", "yesno"]);
611
	register.filter(dtf + ".misc", dtf + ".misc", ["filesizeformat", "pluralize", "phone2numeric", "pprint"]);
612
	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"]);
613
})();
614
 
615
dojox.dtl.replace = function(str, token, repl){
616
	repl = repl || "";
617
	var pos, len = token.length;
618
	while(1){
619
		pos = str.indexOf(token);
620
		if(pos == -1) break;
621
		str = str.substring(0, pos) + repl + str.substring(pos + len);
622
	}
623
	return str;
624
}
625
 
626
dojox.dtl.resolveVariable = function(token, context){
627
	// summary: Quickly resolve a variables
628
	var filter = new dojox.dtl.Filter(token);
629
	return filter.resolve(context);
630
}
631
 
632
}