root / trunk / web / dojo / dojox / dtl.js.uncompressed.js
History | View | Annotate | Download (78.9 KB)
1 |
/*
|
---|---|
2 |
Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
|
3 |
Available via Academic Free License >= 2.1 OR the modified BSD license.
|
4 |
see: http://dojotoolkit.org/license for details
|
5 |
*/
|
6 |
|
7 |
/*
|
8 |
This is an optimized version of Dojo, built for deployment and not for
|
9 |
development. To get sources and documentation, please visit:
|
10 |
|
11 |
http://dojotoolkit.org
|
12 |
*/
|
13 |
|
14 |
if(!dojo._hasResource["dojox.string.Builder"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
15 |
dojo._hasResource["dojox.string.Builder"] = true; |
16 |
dojo.provide("dojox.string.Builder");
|
17 |
|
18 |
dojox.string.Builder = function(/*String?*/str){ |
19 |
// summary:
|
20 |
// A fast buffer for creating large strings.
|
21 |
//
|
22 |
// length: Number
|
23 |
// The current length of the internal string.
|
24 |
|
25 |
// N.B. the public nature of the internal buffer is no longer
|
26 |
// needed because the IE-specific fork is no longer needed--TRT.
|
27 |
var b = ""; |
28 |
this.length = 0; |
29 |
|
30 |
this.append = function(/* String... */s){ |
31 |
// summary: Append all arguments to the end of the buffer
|
32 |
if(arguments.length>1){ |
33 |
/*
|
34 |
This is a loop unroll was designed specifically for Firefox;
|
35 |
it would seem that static index access on an Arguments
|
36 |
object is a LOT faster than doing dynamic index access.
|
37 |
Therefore, we create a buffer string and take advantage
|
38 |
of JS's switch fallthrough. The peformance of this method
|
39 |
comes very close to straight up string concatenation (+=).
|
40 |
|
41 |
If the arguments object length is greater than 9, we fall
|
42 |
back to standard dynamic access.
|
43 |
|
44 |
This optimization seems to have no real effect on either
|
45 |
Safari or Opera, so we just use it for all.
|
46 |
|
47 |
It turns out also that this loop unroll can increase performance
|
48 |
significantly with Internet Explorer, particularly when
|
49 |
as many arguments are provided as possible.
|
50 |
|
51 |
Loop unroll per suggestion from Kris Zyp, implemented by
|
52 |
Tom Trenka.
|
53 |
|
54 |
Note: added empty string to force a string cast if needed.
|
55 |
*/
|
56 |
var tmp="", l=arguments.length; |
57 |
switch(l){
|
58 |
case 9: tmp=""+arguments[8]+tmp; |
59 |
case 8: tmp=""+arguments[7]+tmp; |
60 |
case 7: tmp=""+arguments[6]+tmp; |
61 |
case 6: tmp=""+arguments[5]+tmp; |
62 |
case 5: tmp=""+arguments[4]+tmp; |
63 |
case 4: tmp=""+arguments[3]+tmp; |
64 |
case 3: tmp=""+arguments[2]+tmp; |
65 |
case 2: { |
66 |
b+=""+arguments[0]+arguments[1]+tmp; |
67 |
break;
|
68 |
} |
69 |
default: {
|
70 |
var i=0; |
71 |
while(i<arguments.length){ |
72 |
tmp += arguments[i++];
|
73 |
} |
74 |
b += tmp; |
75 |
} |
76 |
} |
77 |
} else {
|
78 |
b += s; |
79 |
} |
80 |
this.length = b.length;
|
81 |
return this; // dojox.string.Builder |
82 |
}; |
83 |
|
84 |
this.concat = function(/*String...*/s){ |
85 |
// summary:
|
86 |
// Alias for append.
|
87 |
return this.append.apply(this, arguments); // dojox.string.Builder |
88 |
}; |
89 |
|
90 |
this.appendArray = function(/*Array*/strings) { |
91 |
// summary:
|
92 |
// Append an array of items to the internal buffer.
|
93 |
|
94 |
// Changed from String.prototype.concat.apply because of IE.
|
95 |
return this.append.apply(this, strings); // dojox.string.Builder |
96 |
}; |
97 |
|
98 |
this.clear = function(){ |
99 |
// summary:
|
100 |
// Remove all characters from the buffer.
|
101 |
b = "";
|
102 |
this.length = 0; |
103 |
return this; // dojox.string.Builder |
104 |
}; |
105 |
|
106 |
this.replace = function(/* String */oldStr, /* String */ newStr){ |
107 |
// summary:
|
108 |
// Replace instances of one string with another in the buffer.
|
109 |
b = b.replace(oldStr,newStr); |
110 |
this.length = b.length;
|
111 |
return this; // dojox.string.Builder |
112 |
}; |
113 |
|
114 |
this.remove = function(/* Number */start, /* Number? */len){ |
115 |
// summary:
|
116 |
// Remove len characters starting at index start. If len
|
117 |
// is not provided, the end of the string is assumed.
|
118 |
if(len===undefined){ len = b.length; } |
119 |
if(len == 0){ return this; } |
120 |
b = b.substr(0, start) + b.substr(start+len);
|
121 |
this.length = b.length;
|
122 |
return this; // dojox.string.Builder |
123 |
}; |
124 |
|
125 |
this.insert = function(/* Number */index, /* String */str){ |
126 |
// summary:
|
127 |
// Insert string str starting at index.
|
128 |
if(index == 0){ |
129 |
b = str + b; |
130 |
}else{
|
131 |
b = b.slice(0, index) + str + b.slice(index);
|
132 |
} |
133 |
this.length = b.length;
|
134 |
return this; // dojox.string.Builder |
135 |
}; |
136 |
|
137 |
this.toString = function(){ |
138 |
// summary:
|
139 |
// Return the string representation of the internal buffer.
|
140 |
return b; // String |
141 |
}; |
142 |
|
143 |
// initialize the buffer.
|
144 |
if(str){ this.append(str); } |
145 |
}; |
146 |
|
147 |
} |
148 |
|
149 |
if(!dojo._hasResource["dojox.string.tokenize"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
150 |
dojo._hasResource["dojox.string.tokenize"] = true; |
151 |
dojo.provide("dojox.string.tokenize");
|
152 |
|
153 |
dojox.string.tokenize = function(/*String*/ str, /*RegExp*/ re, /*Function?*/ parseDelim, /*Object?*/ instance){ |
154 |
// summary:
|
155 |
// Split a string by a regular expression with the ability to capture the delimeters
|
156 |
// parseDelim:
|
157 |
// Each group (excluding the 0 group) is passed as a parameter. If the function returns
|
158 |
// a value, it's added to the list of tokens.
|
159 |
// instance:
|
160 |
// Used as the "this" instance when calling parseDelim
|
161 |
var tokens = [];
|
162 |
var match, content, lastIndex = 0; |
163 |
while(match = re.exec(str)){
|
164 |
content = str.slice(lastIndex, re.lastIndex - match[0].length);
|
165 |
if(content.length){
|
166 |
tokens.push(content); |
167 |
} |
168 |
if(parseDelim){
|
169 |
if(dojo.isOpera){
|
170 |
var copy = match.slice(0); |
171 |
while(copy.length < match.length){
|
172 |
copy.push(null);
|
173 |
} |
174 |
match = copy; |
175 |
} |
176 |
var parsed = parseDelim.apply(instance, match.slice(1).concat(tokens.length)); |
177 |
if(typeof parsed != "undefined"){ |
178 |
tokens.push(parsed); |
179 |
} |
180 |
} |
181 |
lastIndex = re.lastIndex; |
182 |
} |
183 |
content = str.slice(lastIndex); |
184 |
if(content.length){
|
185 |
tokens.push(content); |
186 |
} |
187 |
return tokens;
|
188 |
} |
189 |
|
190 |
} |
191 |
|
192 |
if(!dojo._hasResource["dojox.dtl._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
193 |
dojo._hasResource["dojox.dtl._base"] = true; |
194 |
dojo.provide("dojox.dtl._base");
|
195 |
|
196 |
|
197 |
|
198 |
|
199 |
dojo.experimental("dojox.dtl");
|
200 |
|
201 |
(function(){
|
202 |
var dd = dojox.dtl;
|
203 |
|
204 |
dd.TOKEN_BLOCK = -1;
|
205 |
dd.TOKEN_VAR = -2;
|
206 |
dd.TOKEN_COMMENT = -3;
|
207 |
dd.TOKEN_TEXT = 3;
|
208 |
|
209 |
dd._Context = dojo.extend(function(dict){
|
210 |
// summary: Pass one of these when rendering a template to tell the template what values to use.
|
211 |
if(dict){
|
212 |
dojo._mixin(this, dict);
|
213 |
if(dict.get){
|
214 |
// Preserve passed getter and restore prototype get
|
215 |
this._getter = dict.get;
|
216 |
delete this.get; |
217 |
} |
218 |
} |
219 |
}, |
220 |
{ |
221 |
push: function(){ |
222 |
var last = this; |
223 |
var context = dojo.delegate(this); |
224 |
context.pop = function(){ return last; } |
225 |
return context;
|
226 |
}, |
227 |
pop: function(){ |
228 |
throw new Error("pop() called on empty Context"); |
229 |
}, |
230 |
get: function(key, otherwise){ |
231 |
var n = this._normalize; |
232 |
|
233 |
if(this._getter){ |
234 |
var got = this._getter(key); |
235 |
if(typeof got != "undefined"){ |
236 |
return n(got);
|
237 |
} |
238 |
} |
239 |
|
240 |
if(typeof this[key] != "undefined"){ |
241 |
return n(this[key]); |
242 |
} |
243 |
|
244 |
return otherwise;
|
245 |
}, |
246 |
_normalize: function(value){ |
247 |
if(value instanceof Date){ |
248 |
value.year = value.getFullYear(); |
249 |
value.month = value.getMonth() + 1;
|
250 |
value.day = value.getDate(); |
251 |
value.date = value.year + "-" + ("0" + value.month).slice(-2) + "-" + ("0" + value.day).slice(-2); |
252 |
value.hour = value.getHours(); |
253 |
value.minute = value.getMinutes(); |
254 |
value.second = value.getSeconds(); |
255 |
value.microsecond = value.getMilliseconds(); |
256 |
} |
257 |
return value;
|
258 |
}, |
259 |
update: function(dict){ |
260 |
var context = this.push(); |
261 |
if(dict){
|
262 |
dojo._mixin(this, dict);
|
263 |
} |
264 |
return context;
|
265 |
} |
266 |
}); |
267 |
|
268 |
var smart_split_re = /("(?:[^"\\]*(?:\\.[^"\\]*)*)"|'(?:[^'\\]*(?:\\.[^'\\]*)*)'|[^\s]+)/g; |
269 |
var split_re = /\s+/g; |
270 |
var split = function(/*String|RegExp?*/ splitter, /*Integer?*/ limit){ |
271 |
splitter = splitter || split_re; |
272 |
if(!(splitter instanceof RegExp)){ |
273 |
splitter = new RegExp(splitter, "g"); |
274 |
} |
275 |
if(!splitter.global){
|
276 |
throw new Error("You must use a globally flagged RegExp with split " + splitter); |
277 |
} |
278 |
splitter.exec(""); // Reset the global |
279 |
|
280 |
var part, parts = [], lastIndex = 0, i = 0; |
281 |
while(part = splitter.exec(this)){ |
282 |
parts.push(this.slice(lastIndex, splitter.lastIndex - part[0].length)); |
283 |
lastIndex = splitter.lastIndex; |
284 |
if(limit && (++i > limit - 1)){ |
285 |
break;
|
286 |
} |
287 |
} |
288 |
parts.push(this.slice(lastIndex));
|
289 |
return parts;
|
290 |
} |
291 |
|
292 |
dd.Token = function(token_type, contents){ |
293 |
this.token_type = token_type;
|
294 |
this.contents = new String(dojo.trim(contents)); |
295 |
this.contents.split = split;
|
296 |
this.split = function(){ |
297 |
return String.prototype.split.apply(this.contents, arguments); |
298 |
} |
299 |
} |
300 |
dd.Token.prototype.split_contents = function(/*Integer?*/ limit){ |
301 |
var bit, bits = [], i = 0; |
302 |
limit = limit || 999;
|
303 |
while(i++ < limit && (bit = smart_split_re.exec(this.contents))){ |
304 |
bit = bit[0];
|
305 |
if(bit.charAt(0) == '"' && bit.slice(-1) == '"'){ |
306 |
bits.push('"' + bit.slice(1, -1).replace('\\"', '"').replace('\\\\', '\\') + '"'); |
307 |
}else if(bit.charAt(0) == "'" && bit.slice(-1) == "'"){ |
308 |
bits.push("'" + bit.slice(1, -1).replace("\\'", "'").replace('\\\\', '\\') + "'"); |
309 |
}else{
|
310 |
bits.push(bit); |
311 |
} |
312 |
} |
313 |
return bits;
|
314 |
} |
315 |
|
316 |
var ddt = dd.text = {
|
317 |
_get: function(module, name, errorless){ |
318 |
// summary: Used to find both tags and filters
|
319 |
var params = dd.register.get(module, name.toLowerCase(), errorless);
|
320 |
if(!params){
|
321 |
if(!errorless){
|
322 |
throw new Error("No tag found for " + name); |
323 |
} |
324 |
return null; |
325 |
} |
326 |
|
327 |
var fn = params[1]; |
328 |
var require = params[2]; |
329 |
|
330 |
var parts;
|
331 |
if(fn.indexOf(":") != -1){ |
332 |
parts = fn.split(":");
|
333 |
fn = parts.pop(); |
334 |
} |
335 |
|
336 |
dojo["require"](require);
|
337 |
|
338 |
var parent = dojo.getObject(require);
|
339 |
|
340 |
return parent[fn || name] || parent[name + "_"] || parent[fn + "_"]; |
341 |
}, |
342 |
getTag: function(name, errorless){ |
343 |
return ddt._get("tag", name, errorless); |
344 |
}, |
345 |
getFilter: function(name, errorless){ |
346 |
return ddt._get("filter", name, errorless); |
347 |
}, |
348 |
getTemplate: function(file){ |
349 |
return new dd.Template(ddt.getTemplateString(file)); |
350 |
}, |
351 |
getTemplateString: function(file){ |
352 |
return dojo._getText(file.toString()) || ""; |
353 |
}, |
354 |
_resolveLazy: function(location, sync, json){ |
355 |
if(sync){
|
356 |
if(json){
|
357 |
return dojo.fromJson(dojo._getText(location)) || {};
|
358 |
}else{
|
359 |
return dd.text.getTemplateString(location);
|
360 |
} |
361 |
}else{
|
362 |
return dojo.xhrGet({
|
363 |
handleAs: (json) ? "json" : "text", |
364 |
url: location
|
365 |
}); |
366 |
} |
367 |
}, |
368 |
_resolveTemplateArg: function(arg, sync){ |
369 |
if(ddt._isTemplate(arg)){
|
370 |
if(!sync){
|
371 |
var d = new dojo.Deferred(); |
372 |
d.callback(arg); |
373 |
return d;
|
374 |
} |
375 |
return arg;
|
376 |
} |
377 |
return ddt._resolveLazy(arg, sync);
|
378 |
}, |
379 |
_isTemplate: function(arg){ |
380 |
return (typeof arg == "undefined") || (typeof arg == "string" && (arg.match(/^\s*[<{]/) || arg.indexOf(" ") != -1)); |
381 |
}, |
382 |
_resolveContextArg: function(arg, sync){ |
383 |
if(arg.constructor == Object){
|
384 |
if(!sync){
|
385 |
var d = new dojo.Deferred; |
386 |
d.callback(arg); |
387 |
return d;
|
388 |
} |
389 |
return arg;
|
390 |
} |
391 |
return ddt._resolveLazy(arg, sync, true); |
392 |
}, |
393 |
_re: /(?:\{\{\s*(.+?)\s*\}\}|\{%\s*(load\s*)?(.+?)\s*%\})/g, |
394 |
tokenize: function(str){ |
395 |
return dojox.string.tokenize(str, ddt._re, ddt._parseDelims);
|
396 |
}, |
397 |
_parseDelims: function(varr, load, tag){ |
398 |
if(varr){
|
399 |
return [dd.TOKEN_VAR, varr];
|
400 |
}else if(load){ |
401 |
var parts = dojo.trim(tag).split(/\s+/g); |
402 |
for(var i = 0, part; part = parts[i]; i++){ |
403 |
dojo["require"](part);
|
404 |
} |
405 |
}else{
|
406 |
return [dd.TOKEN_BLOCK, tag];
|
407 |
} |
408 |
} |
409 |
} |
410 |
|
411 |
dd.Template = dojo.extend(function(/*String|dojo._Url*/ template, /*Boolean*/ isString){ |
412 |
// template:
|
413 |
// The string or location of the string to
|
414 |
// use as a template
|
415 |
var str = isString ? template : ddt._resolveTemplateArg(template, true) || ""; |
416 |
var tokens = ddt.tokenize(str);
|
417 |
var parser = new dd._Parser(tokens); |
418 |
this.nodelist = parser.parse();
|
419 |
}, |
420 |
{ |
421 |
update: function(node, context){ |
422 |
// node: DOMNode|String|dojo.NodeList
|
423 |
// A node reference or set of nodes
|
424 |
// context: dojo._Url|String|Object
|
425 |
// The context object or location
|
426 |
return ddt._resolveContextArg(context).addCallback(this, function(contextObject){ |
427 |
var content = this.render(new dd._Context(contextObject)); |
428 |
if(node.forEach){
|
429 |
node.forEach(function(item){
|
430 |
item.innerHTML = content; |
431 |
}); |
432 |
}else{
|
433 |
dojo.byId(node).innerHTML = content; |
434 |
} |
435 |
return this; |
436 |
}); |
437 |
}, |
438 |
render: function(context, /*concatenatable?*/ buffer){ |
439 |
buffer = buffer || this.getBuffer();
|
440 |
context = context || new dd._Context({});
|
441 |
return this.nodelist.render(context, buffer) + ""; |
442 |
}, |
443 |
getBuffer: function(){ |
444 |
|
445 |
return new dojox.string.Builder(); |
446 |
} |
447 |
}); |
448 |
|
449 |
var qfRe = /\{\{\s*(.+?)\s*\}\}/g; |
450 |
dd.quickFilter = function(str){ |
451 |
if(!str){
|
452 |
return new dd._NodeList(); |
453 |
} |
454 |
|
455 |
if(str.indexOf("{%") == -1){ |
456 |
return new dd._QuickNodeList(dojox.string.tokenize(str, qfRe, function(token){ |
457 |
return new dd._Filter(token); |
458 |
})); |
459 |
} |
460 |
} |
461 |
|
462 |
dd._QuickNodeList = dojo.extend(function(contents){
|
463 |
this.contents = contents;
|
464 |
}, |
465 |
{ |
466 |
render: function(context, buffer){ |
467 |
for(var i=0, l=this.contents.length; i<l; i++){ |
468 |
if(this.contents[i].resolve){ |
469 |
buffer = buffer.concat(this.contents[i].resolve(context));
|
470 |
}else{
|
471 |
buffer = buffer.concat(this.contents[i]);
|
472 |
} |
473 |
} |
474 |
return buffer;
|
475 |
}, |
476 |
dummyRender: function(context){ return this.render(context, dd.Template.prototype.getBuffer()).toString(); }, |
477 |
clone: function(buffer){ return this; } |
478 |
}); |
479 |
|
480 |
dd._Filter = dojo.extend(function(token){
|
481 |
// summary: Uses a string to find (and manipulate) a variable
|
482 |
if(!token) throw new Error("Filter must be called with variable name"); |
483 |
this.contents = token;
|
484 |
|
485 |
var cache = this._cache[token]; |
486 |
if(cache){
|
487 |
this.key = cache[0]; |
488 |
this.filters = cache[1]; |
489 |
}else{
|
490 |
this.filters = [];
|
491 |
dojox.string.tokenize(token, this._re, this._tokenize, this); |
492 |
this._cache[token] = [this.key, this.filters]; |
493 |
} |
494 |
}, |
495 |
{ |
496 |
_cache: {},
|
497 |
_re: /(?:^_\("([^\\"]*(?:\\.[^\\"])*)"\)|^"([^\\"]*(?:\\.[^\\"]*)*)"|^([a-zA-Z0-9_.]+)|\|(\w+)(?::(?:_\("([^\\"]*(?:\\.[^\\"])*)"\)|"([^\\"]*(?:\\.[^\\"]*)*)"|([a-zA-Z0-9_.]+)|'([^\\']*(?:\\.[^\\']*)*)'))?|^'([^\\']*(?:\\.[^\\']*)*)')/g, |
498 |
_values: {
|
499 |
0: '"', // _("text") |
500 |
1: '"', // "text" |
501 |
2: "", // variable |
502 |
8: '"' // 'text' |
503 |
}, |
504 |
_args: {
|
505 |
4: '"', // :_("text") |
506 |
5: '"', // :"text" |
507 |
6: "", // :variable |
508 |
7: "'"// :'text' |
509 |
}, |
510 |
_tokenize: function(){ |
511 |
var pos, arg;
|
512 |
|
513 |
for(var i = 0, has = []; i < arguments.length; i++){ |
514 |
has[i] = (typeof arguments[i] != "undefined" && typeof arguments[i] == "string" && arguments[i]); |
515 |
} |
516 |
|
517 |
if(!this.key){ |
518 |
for(pos in this._values){ |
519 |
if(has[pos]){
|
520 |
this.key = this._values[pos] + arguments[pos] + this._values[pos]; |
521 |
break;
|
522 |
} |
523 |
} |
524 |
}else{
|
525 |
for(pos in this._args){ |
526 |
if(has[pos]){
|
527 |
var value = arguments[pos]; |
528 |
if(this._args[pos] == "'"){ |
529 |
value = value.replace(/\\'/g, "'"); |
530 |
}else if(this._args[pos] == '"'){ |
531 |
value = value.replace(/\\"/g, '"'); |
532 |
} |
533 |
arg = [!this._args[pos], value];
|
534 |
break;
|
535 |
} |
536 |
} |
537 |
// Get a named filter
|
538 |
var fn = ddt.getFilter(arguments[3]); |
539 |
if(!dojo.isFunction(fn)) throw new Error(arguments[3] + " is not registered as a filter"); |
540 |
this.filters.push([fn, arg]);
|
541 |
} |
542 |
}, |
543 |
getExpression: function(){ |
544 |
return this.contents; |
545 |
}, |
546 |
resolve: function(context){ |
547 |
if(typeof this.key == "undefined"){ |
548 |
return ""; |
549 |
} |
550 |
|
551 |
var str = this.resolvePath(this.key, context); |
552 |
|
553 |
for(var i = 0, filter; filter = this.filters[i]; i++){ |
554 |
// Each filter has the function in [0], a boolean in [1][0] of whether it's a variable or a string
|
555 |
// and [1][1] is either the variable name of the string content.
|
556 |
if(filter[1]){ |
557 |
if(filter[1][0]){ |
558 |
str = filter[0](str, this.resolvePath(filter[1][1], context)); |
559 |
}else{
|
560 |
str = filter[0](str, filter[1][1]); |
561 |
} |
562 |
}else{
|
563 |
str = filter[0](str);
|
564 |
} |
565 |
} |
566 |
|
567 |
return str;
|
568 |
}, |
569 |
resolvePath: function(path, context){ |
570 |
var current, parts;
|
571 |
var first = path.charAt(0); |
572 |
var last = path.slice(-1); |
573 |
if(!isNaN(parseInt(first))){
|
574 |
current = (path.indexOf(".") == -1) ? parseInt(path) : parseFloat(path); |
575 |
}else if(first == '"' && first == last){ |
576 |
current = path.slice(1, -1); |
577 |
}else{
|
578 |
if(path == "true"){ return true; } |
579 |
if(path == "false"){ return false; } |
580 |
if(path == "null" || path == "None"){ return null; } |
581 |
parts = path.split(".");
|
582 |
current = context.get(parts[0]);
|
583 |
|
584 |
if(dojo.isFunction(current)){
|
585 |
var self = context.getThis && context.getThis();
|
586 |
if(current.alters_data){
|
587 |
current = "";
|
588 |
}else if(self){ |
589 |
current = current.call(self); |
590 |
}else{
|
591 |
current = "";
|
592 |
} |
593 |
} |
594 |
|
595 |
for(var i = 1; i < parts.length; i++){ |
596 |
var part = parts[i];
|
597 |
if(current){
|
598 |
var base = current;
|
599 |
if(dojo.isObject(current) && part == "items" && typeof current[part] == "undefined"){ |
600 |
var items = [];
|
601 |
for(var key in current){ |
602 |
items.push([key, current[key]]); |
603 |
} |
604 |
current = items; |
605 |
continue;
|
606 |
} |
607 |
|
608 |
if(current.get && dojo.isFunction(current.get) && current.get.safe){
|
609 |
current = current.get(part); |
610 |
}else if(typeof current[part] == "undefined"){ |
611 |
current = current[part]; |
612 |
break;
|
613 |
}else{
|
614 |
current = current[part]; |
615 |
} |
616 |
|
617 |
if(dojo.isFunction(current)){
|
618 |
if(current.alters_data){
|
619 |
current = "";
|
620 |
}else{
|
621 |
current = current.call(base); |
622 |
} |
623 |
}else if(current instanceof Date){ |
624 |
current = dd._Context.prototype._normalize(current); |
625 |
} |
626 |
}else{
|
627 |
return ""; |
628 |
} |
629 |
} |
630 |
} |
631 |
return current;
|
632 |
} |
633 |
}); |
634 |
|
635 |
dd._TextNode = dd._Node = dojo.extend(function(/*Object*/ obj){ |
636 |
// summary: Basic catch-all node
|
637 |
this.contents = obj;
|
638 |
}, |
639 |
{ |
640 |
set: function(data){ |
641 |
this.contents = data;
|
642 |
return this; |
643 |
}, |
644 |
render: function(context, buffer){ |
645 |
// summary: Adds content onto the buffer
|
646 |
return buffer.concat(this.contents); |
647 |
}, |
648 |
isEmpty: function(){ |
649 |
return !dojo.trim(this.contents); |
650 |
}, |
651 |
clone: function(){ return this; } |
652 |
}); |
653 |
|
654 |
dd._NodeList = dojo.extend(function(/*Node[]*/ nodes){ |
655 |
// summary: Allows us to render a group of nodes
|
656 |
this.contents = nodes || [];
|
657 |
this.last = ""; |
658 |
}, |
659 |
{ |
660 |
push: function(node){ |
661 |
// summary: Add a new node to the list
|
662 |
this.contents.push(node);
|
663 |
return this; |
664 |
}, |
665 |
concat: function(nodes){ |
666 |
this.contents = this.contents.concat(nodes); |
667 |
return this; |
668 |
}, |
669 |
render: function(context, buffer){ |
670 |
// summary: Adds all content onto the buffer
|
671 |
for(var i = 0; i < this.contents.length; i++){ |
672 |
buffer = this.contents[i].render(context, buffer);
|
673 |
if(!buffer) throw new Error("Template must return buffer"); |
674 |
} |
675 |
return buffer;
|
676 |
}, |
677 |
dummyRender: function(context){ |
678 |
return this.render(context, dd.Template.prototype.getBuffer()).toString(); |
679 |
}, |
680 |
unrender: function(){ return arguments[1]; }, |
681 |
clone: function(){ return this; }, |
682 |
rtrim: function(){ |
683 |
while(1){ |
684 |
i = this.contents.length - 1; |
685 |
if(this.contents[i] instanceof dd._TextNode && this.contents[i].isEmpty()){ |
686 |
this.contents.pop();
|
687 |
}else{
|
688 |
break;
|
689 |
} |
690 |
} |
691 |
|
692 |
return this; |
693 |
} |
694 |
}); |
695 |
|
696 |
dd._VarNode = dojo.extend(function(str){
|
697 |
// summary: A node to be processed as a variable
|
698 |
this.contents = new dd._Filter(str); |
699 |
}, |
700 |
{ |
701 |
render: function(context, buffer){ |
702 |
var str = this.contents.resolve(context); |
703 |
if(!str.safe){
|
704 |
str = dd._base.escape("" + str);
|
705 |
} |
706 |
return buffer.concat(str);
|
707 |
} |
708 |
}); |
709 |
|
710 |
dd._noOpNode = new function(){ |
711 |
// summary: Adds a no-op node. Useful in custom tags
|
712 |
this.render = this.unrender = function(){ return arguments[1]; } |
713 |
this.clone = function(){ return this; } |
714 |
} |
715 |
|
716 |
dd._Parser = dojo.extend(function(tokens){
|
717 |
// summary: Parser used during initialization and for tag groups.
|
718 |
this.contents = tokens;
|
719 |
}, |
720 |
{ |
721 |
i: 0, |
722 |
parse: function(/*Array?*/ stop_at){ |
723 |
// summary: Turns tokens into nodes
|
724 |
// description: Steps into tags are they're found. Blocks use the parse object
|
725 |
// to find their closing tag (the stop_at array). stop_at is inclusive, it
|
726 |
// returns the node that matched.
|
727 |
var terminators = {}, token;
|
728 |
stop_at = stop_at || []; |
729 |
for(var i = 0; i < stop_at.length; i++){ |
730 |
terminators[stop_at[i]] = true;
|
731 |
} |
732 |
|
733 |
var nodelist = new dd._NodeList(); |
734 |
while(this.i < this.contents.length){ |
735 |
token = this.contents[this.i++]; |
736 |
if(typeof token == "string"){ |
737 |
nodelist.push(new dd._TextNode(token));
|
738 |
}else{
|
739 |
var type = token[0]; |
740 |
var text = token[1]; |
741 |
if(type == dd.TOKEN_VAR){
|
742 |
nodelist.push(new dd._VarNode(text));
|
743 |
}else if(type == dd.TOKEN_BLOCK){ |
744 |
if(terminators[text]){
|
745 |
--this.i;
|
746 |
return nodelist;
|
747 |
} |
748 |
var cmd = text.split(/\s+/g); |
749 |
if(cmd.length){
|
750 |
cmd = cmd[0];
|
751 |
var fn = ddt.getTag(cmd);
|
752 |
if(fn){
|
753 |
nodelist.push(fn(this, new dd.Token(type, text))); |
754 |
} |
755 |
} |
756 |
} |
757 |
} |
758 |
} |
759 |
|
760 |
if(stop_at.length){
|
761 |
throw new Error("Could not find closing tag(s): " + stop_at.toString()); |
762 |
} |
763 |
|
764 |
this.contents.length = 0; |
765 |
return nodelist;
|
766 |
}, |
767 |
next_token: function(){ |
768 |
// summary: Returns the next token in the list.
|
769 |
var token = this.contents[this.i++]; |
770 |
return new dd.Token(token[0], token[1]); |
771 |
}, |
772 |
delete_first_token: function(){ |
773 |
this.i++;
|
774 |
}, |
775 |
skip_past: function(endtag){ |
776 |
while(this.i < this.contents.length){ |
777 |
var token = this.contents[this.i++]; |
778 |
if(token[0] == dd.TOKEN_BLOCK && token[1] == endtag){ |
779 |
return;
|
780 |
} |
781 |
} |
782 |
throw new Error("Unclosed tag found when looking for " + endtag); |
783 |
}, |
784 |
create_variable_node: function(expr){ |
785 |
return new dd._VarNode(expr); |
786 |
}, |
787 |
create_text_node: function(expr){ |
788 |
return new dd._TextNode(expr || ""); |
789 |
}, |
790 |
getTemplate: function(file){ |
791 |
return new dd.Template(file); |
792 |
} |
793 |
}); |
794 |
|
795 |
dd.register = { |
796 |
_registry: {
|
797 |
attributes: [],
|
798 |
tags: [],
|
799 |
filters: []
|
800 |
}, |
801 |
get: function(/*String*/ module, /*String*/ name){ |
802 |
var registry = dd.register._registry[module + "s"]; |
803 |
for(var i = 0, entry; entry = registry[i]; i++){ |
804 |
if(typeof entry[0] == "string"){ |
805 |
if(entry[0] == name){ |
806 |
return entry;
|
807 |
} |
808 |
}else if(name.match(entry[0])){ |
809 |
return entry;
|
810 |
} |
811 |
} |
812 |
}, |
813 |
getAttributeTags: function(){ |
814 |
var tags = [];
|
815 |
var registry = dd.register._registry.attributes;
|
816 |
for(var i = 0, entry; entry = registry[i]; i++){ |
817 |
if(entry.length == 3){ |
818 |
tags.push(entry); |
819 |
}else{
|
820 |
var fn = dojo.getObject(entry[1]); |
821 |
if(fn && dojo.isFunction(fn)){
|
822 |
entry.push(fn); |
823 |
tags.push(entry); |
824 |
} |
825 |
} |
826 |
} |
827 |
return tags;
|
828 |
}, |
829 |
_any: function(type, base, locations){ |
830 |
for(var path in locations){ |
831 |
for(var i = 0, fn; fn = locations[path][i]; i++){ |
832 |
var key = fn;
|
833 |
if(dojo.isArray(fn)){
|
834 |
key = fn[0];
|
835 |
fn = fn[1];
|
836 |
} |
837 |
if(typeof key == "string"){ |
838 |
if(key.substr(0, 5) == "attr:"){ |
839 |
var attr = fn;
|
840 |
if(attr.substr(0, 5) == "attr:"){ |
841 |
attr = attr.slice(5);
|
842 |
} |
843 |
dd.register._registry.attributes.push([attr.toLowerCase(), base + "." + path + "." + attr]); |
844 |
} |
845 |
key = key.toLowerCase() |
846 |
} |
847 |
dd.register._registry[type].push([ |
848 |
key, |
849 |
fn, |
850 |
base + "." + path
|
851 |
]); |
852 |
} |
853 |
} |
854 |
}, |
855 |
tags: function(/*String*/ base, /*Object*/ locations){ |
856 |
dd.register._any("tags", base, locations);
|
857 |
}, |
858 |
filters: function(/*String*/ base, /*Object*/ locations){ |
859 |
dd.register._any("filters", base, locations);
|
860 |
} |
861 |
} |
862 |
|
863 |
var escapeamp = /&/g; |
864 |
var escapelt = /</g; |
865 |
var escapegt = />/g; |
866 |
var escapeqt = /'/g; |
867 |
var escapedblqt = /"/g; |
868 |
dd._base.escape = function(value){ |
869 |
// summary: Escapes a string's HTML
|
870 |
return dd.mark_safe(value.replace(escapeamp, '&').replace(escapelt, '<').replace(escapegt, '>').replace(escapedblqt, '"').replace(escapeqt, ''')); |
871 |
} |
872 |
|
873 |
dd._base.safe = function(value){ |
874 |
if(typeof value == "string"){ |
875 |
value = new String(value);
|
876 |
} |
877 |
if(typeof value == "object"){ |
878 |
value.safe = true;
|
879 |
} |
880 |
return value;
|
881 |
} |
882 |
dd.mark_safe = dd._base.safe; |
883 |
|
884 |
dd.register.tags("dojox.dtl.tag", {
|
885 |
"date": ["now"], |
886 |
"logic": ["if", "for", "ifequal", "ifnotequal"], |
887 |
"loader": ["extends", "block", "include", "load", "ssi"], |
888 |
"misc": ["comment", "debug", "filter", "firstof", "spaceless", "templatetag", "widthratio", "with"], |
889 |
"loop": ["cycle", "ifchanged", "regroup"] |
890 |
}); |
891 |
dd.register.filters("dojox.dtl.filter", {
|
892 |
"dates": ["date", "time", "timesince", "timeuntil"], |
893 |
"htmlstrings": ["linebreaks", "linebreaksbr", "removetags", "striptags"], |
894 |
"integers": ["add", "get_digit"], |
895 |
"lists": ["dictsort", "dictsortreversed", "first", "join", "length", "length_is", "random", "slice", "unordered_list"], |
896 |
"logic": ["default", "default_if_none", "divisibleby", "yesno"], |
897 |
"misc": ["filesizeformat", "pluralize", "phone2numeric", "pprint"], |
898 |
"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"] |
899 |
}); |
900 |
dd.register.filters("dojox.dtl", {
|
901 |
"_base": ["escape", "safe"] |
902 |
}); |
903 |
})(); |
904 |
|
905 |
} |
906 |
|
907 |
if(!dojo._hasResource["dojox.dtl"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
908 |
dojo._hasResource["dojox.dtl"] = true; |
909 |
dojo.provide("dojox.dtl");
|
910 |
|
911 |
|
912 |
} |
913 |
|
914 |
if(!dojo._hasResource["dojox.dtl.Context"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
915 |
dojo._hasResource["dojox.dtl.Context"] = true; |
916 |
dojo.provide("dojox.dtl.Context");
|
917 |
|
918 |
|
919 |
dojox.dtl.Context = dojo.extend(function(dict){
|
920 |
this._this = {};
|
921 |
dojox.dtl._Context.call(this, dict);
|
922 |
}, dojox.dtl._Context.prototype, |
923 |
{ |
924 |
getKeys: function(){ |
925 |
var keys = [];
|
926 |
for(var key in this){ |
927 |
if(this.hasOwnProperty(key) && key != "_this"){ |
928 |
keys.push(key); |
929 |
} |
930 |
} |
931 |
return keys;
|
932 |
}, |
933 |
extend: function(/*dojox.dtl.Context|Object*/ obj){ |
934 |
// summary: Returns a clone of this context object, with the items from the
|
935 |
// passed objecct mixed in.
|
936 |
return dojo.delegate(this, obj); |
937 |
}, |
938 |
filter: function(/*dojox.dtl.Context|Object|String...*/ filter){ |
939 |
// summary: Returns a clone of this context, only containing the items
|
940 |
// defined in the filter.
|
941 |
var context = new dojox.dtl.Context(); |
942 |
var keys = [];
|
943 |
var i, arg;
|
944 |
if(filter instanceof dojox.dtl.Context){ |
945 |
keys = filter.getKeys(); |
946 |
}else if(typeof filter == "object"){ |
947 |
for(var key in filter){ |
948 |
keys.push(key); |
949 |
} |
950 |
}else{
|
951 |
for(i = 0; arg = arguments[i]; i++){ |
952 |
if(typeof arg == "string"){ |
953 |
keys.push(arg); |
954 |
} |
955 |
} |
956 |
} |
957 |
|
958 |
for(i = 0, key; key = keys[i]; i++){ |
959 |
context[key] = this[key];
|
960 |
} |
961 |
|
962 |
return context;
|
963 |
}, |
964 |
setThis: function(/*Object*/ _this){ |
965 |
this._this = _this;
|
966 |
}, |
967 |
getThis: function(){ |
968 |
return this._this; |
969 |
}, |
970 |
hasKey: function(key){ |
971 |
if(this._getter){ |
972 |
var got = this._getter(key); |
973 |
if(typeof got != "undefined"){ |
974 |
return true; |
975 |
} |
976 |
} |
977 |
|
978 |
if(typeof this[key] != "undefined"){ |
979 |
return true; |
980 |
} |
981 |
|
982 |
return false; |
983 |
} |
984 |
}); |
985 |
|
986 |
} |
987 |
|
988 |
if(!dojo._hasResource["dojox.dtl.tag.logic"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
989 |
dojo._hasResource["dojox.dtl.tag.logic"] = true; |
990 |
dojo.provide("dojox.dtl.tag.logic");
|
991 |
|
992 |
|
993 |
|
994 |
(function(){
|
995 |
var dd = dojox.dtl;
|
996 |
var ddt = dd.text;
|
997 |
var ddtl = dd.tag.logic;
|
998 |
|
999 |
ddtl.IfNode = dojo.extend(function(bools, trues, falses, type){
|
1000 |
this.bools = bools;
|
1001 |
this.trues = trues;
|
1002 |
this.falses = falses;
|
1003 |
this.type = type;
|
1004 |
}, |
1005 |
{ |
1006 |
render: function(context, buffer){ |
1007 |
var i, bool, ifnot, filter, value;
|
1008 |
if(this.type == "or"){ |
1009 |
for(i = 0; bool = this.bools[i]; i++){ |
1010 |
ifnot = bool[0];
|
1011 |
filter = bool[1];
|
1012 |
value = filter.resolve(context); |
1013 |
if((value && !ifnot) || (ifnot && !value)){
|
1014 |
if(this.falses){ |
1015 |
buffer = this.falses.unrender(context, buffer);
|
1016 |
} |
1017 |
return (this.trues) ? this.trues.render(context, buffer, this) : buffer; |
1018 |
} |
1019 |
} |
1020 |
if(this.trues){ |
1021 |
buffer = this.trues.unrender(context, buffer);
|
1022 |
} |
1023 |
return (this.falses) ? this.falses.render(context, buffer, this) : buffer; |
1024 |
}else{
|
1025 |
for(i = 0; bool = this.bools[i]; i++){ |
1026 |
ifnot = bool[0];
|
1027 |
filter = bool[1];
|
1028 |
value = filter.resolve(context); |
1029 |
// If we ever encounter a false value
|
1030 |
if(value == ifnot){
|
1031 |
if(this.trues){ |
1032 |
buffer = this.trues.unrender(context, buffer);
|
1033 |
} |
1034 |
return (this.falses) ? this.falses.render(context, buffer, this) : buffer; |
1035 |
} |
1036 |
} |
1037 |
if(this.falses){ |
1038 |
buffer = this.falses.unrender(context, buffer);
|
1039 |
} |
1040 |
return (this.trues) ? this.trues.render(context, buffer, this) : buffer; |
1041 |
} |
1042 |
return buffer;
|
1043 |
}, |
1044 |
unrender: function(context, buffer){ |
1045 |
buffer = (this.trues) ? this.trues.unrender(context, buffer) : buffer; |
1046 |
buffer = (this.falses) ? this.falses.unrender(context, buffer) : buffer; |
1047 |
return buffer;
|
1048 |
}, |
1049 |
clone: function(buffer){ |
1050 |
var trues = (this.trues) ? this.trues.clone(buffer) : null; |
1051 |
var falses = (this.falses) ? this.falses.clone(buffer) : null; |
1052 |
return new this.constructor(this.bools, trues, falses, this.type); |
1053 |
} |
1054 |
}); |
1055 |
|
1056 |
ddtl.IfEqualNode = dojo.extend(function(var1, var2, trues, falses, negate){
|
1057 |
this.var1 = new dd._Filter(var1); |
1058 |
this.var2 = new dd._Filter(var2); |
1059 |
this.trues = trues;
|
1060 |
this.falses = falses;
|
1061 |
this.negate = negate;
|
1062 |
}, |
1063 |
{ |
1064 |
render: function(context, buffer){ |
1065 |
var var1 = this.var1.resolve(context); |
1066 |
var var2 = this.var2.resolve(context); |
1067 |
var1 = (typeof var1 != "undefined") ? var1 : ""; |
1068 |
var2 = (typeof var1 != "undefined") ? var2 : ""; |
1069 |
if((this.negate && var1 != var2) || (!this.negate && var1 == var2)){ |
1070 |
if(this.falses){ |
1071 |
buffer = this.falses.unrender(context, buffer, this); |
1072 |
} |
1073 |
return (this.trues) ? this.trues.render(context, buffer, this) : buffer; |
1074 |
} |
1075 |
if(this.trues){ |
1076 |
buffer = this.trues.unrender(context, buffer, this); |
1077 |
} |
1078 |
return (this.falses) ? this.falses.render(context, buffer, this) : buffer; |
1079 |
}, |
1080 |
unrender: function(context, buffer){ |
1081 |
return ddtl.IfNode.prototype.unrender.call(this, context, buffer); |
1082 |
}, |
1083 |
clone: function(buffer){ |
1084 |
var trues = this.trues ? this.trues.clone(buffer) : null; |
1085 |
var falses = this.falses ? this.falses.clone(buffer) : null; |
1086 |
return new this.constructor(this.var1.getExpression(), this.var2.getExpression(), trues, falses, this.negate); |
1087 |
} |
1088 |
}); |
1089 |
|
1090 |
ddtl.ForNode = dojo.extend(function(assign, loop, reversed, nodelist){
|
1091 |
this.assign = assign;
|
1092 |
this.loop = new dd._Filter(loop); |
1093 |
this.reversed = reversed;
|
1094 |
this.nodelist = nodelist;
|
1095 |
this.pool = [];
|
1096 |
}, |
1097 |
{ |
1098 |
render: function(context, buffer){ |
1099 |
var i, j, k;
|
1100 |
var dirty = false; |
1101 |
var assign = this.assign; |
1102 |
|
1103 |
for(k = 0; k < assign.length; k++){ |
1104 |
if(typeof context[assign[k]] != "undefined"){ |
1105 |
dirty = true;
|
1106 |
context = context.push(); |
1107 |
break;
|
1108 |
} |
1109 |
} |
1110 |
if(!dirty && context.forloop){
|
1111 |
dirty = true;
|
1112 |
context = context.push(); |
1113 |
} |
1114 |
|
1115 |
var items = this.loop.resolve(context) || []; |
1116 |
for(i = items.length; i < this.pool.length; i++){ |
1117 |
this.pool[i].unrender(context, buffer, this); |
1118 |
} |
1119 |
if(this.reversed){ |
1120 |
items = items.slice(0).reverse();
|
1121 |
} |
1122 |
|
1123 |
var isObject = dojo.isObject(items) && !dojo.isArrayLike(items);
|
1124 |
var arred = [];
|
1125 |
if(isObject){
|
1126 |
for(var key in items){ |
1127 |
arred.push(items[key]); |
1128 |
} |
1129 |
}else{
|
1130 |
arred = items; |
1131 |
} |
1132 |
|
1133 |
var forloop = context.forloop = {
|
1134 |
parentloop: context.get("forloop", {}) |
1135 |
}; |
1136 |
var j = 0; |
1137 |
for(i = 0; i < arred.length; i++){ |
1138 |
var item = arred[i];
|
1139 |
|
1140 |
forloop.counter0 = j; |
1141 |
forloop.counter = j + 1;
|
1142 |
forloop.revcounter0 = arred.length - j - 1;
|
1143 |
forloop.revcounter = arred.length - j; |
1144 |
forloop.first = !j; |
1145 |
forloop.last = (j == arred.length - 1);
|
1146 |
|
1147 |
if(assign.length > 1 && dojo.isArrayLike(item)){ |
1148 |
if(!dirty){
|
1149 |
dirty = true;
|
1150 |
context = context.push(); |
1151 |
} |
1152 |
var zipped = {};
|
1153 |
for(k = 0; k < item.length && k < assign.length; k++){ |
1154 |
zipped[assign[k]] = item[k]; |
1155 |
} |
1156 |
dojo.mixin(context, zipped); |
1157 |
}else{
|
1158 |
context[assign[0]] = item;
|
1159 |
} |
1160 |
|
1161 |
if(j + 1 > this.pool.length){ |
1162 |
this.pool.push(this.nodelist.clone(buffer)); |
1163 |
} |
1164 |
buffer = this.pool[j++].render(context, buffer, this); |
1165 |
} |
1166 |
|
1167 |
delete context.forloop;
|
1168 |
if(dirty){
|
1169 |
context = context.pop(); |
1170 |
}else{
|
1171 |
for(k = 0; k < assign.length; k++){ |
1172 |
delete context[assign[k]];
|
1173 |
} |
1174 |
} |
1175 |
return buffer;
|
1176 |
}, |
1177 |
unrender: function(context, buffer){ |
1178 |
for(var i = 0, pool; pool = this.pool[i]; i++){ |
1179 |
buffer = pool.unrender(context, buffer); |
1180 |
} |
1181 |
return buffer;
|
1182 |
}, |
1183 |
clone: function(buffer){ |
1184 |
return new this.constructor(this.assign, this.loop.getExpression(), this.reversed, this.nodelist.clone(buffer)); |
1185 |
} |
1186 |
}); |
1187 |
|
1188 |
dojo.mixin(ddtl, { |
1189 |
if_: function(parser, token){ |
1190 |
var i, part, type, bools = [], parts = token.contents.split();
|
1191 |
parts.shift(); |
1192 |
token = parts.join(" ");
|
1193 |
parts = token.split(" and ");
|
1194 |
if(parts.length == 1){ |
1195 |
type = "or";
|
1196 |
parts = token.split(" or ");
|
1197 |
}else{
|
1198 |
type = "and";
|
1199 |
for(i = 0; i < parts.length; i++){ |
1200 |
if(parts[i].indexOf(" or ") != -1){ |
1201 |
// Note, since we split by and, this is the only place we need to error check
|
1202 |
throw new Error("'if' tags can't mix 'and' and 'or'"); |
1203 |
} |
1204 |
} |
1205 |
} |
1206 |
for(i = 0; part = parts[i]; i++){ |
1207 |
var not = false; |
1208 |
if(part.indexOf("not ") == 0){ |
1209 |
part = part.slice(4);
|
1210 |
not = true;
|
1211 |
} |
1212 |
bools.push([not, new dd._Filter(part)]);
|
1213 |
} |
1214 |
var trues = parser.parse(["else", "endif"]); |
1215 |
var falses = false; |
1216 |
var token = parser.next_token();
|
1217 |
if(token.contents == "else"){ |
1218 |
falses = parser.parse(["endif"]);
|
1219 |
parser.next_token(); |
1220 |
} |
1221 |
return new ddtl.IfNode(bools, trues, falses, type); |
1222 |
}, |
1223 |
_ifequal: function(parser, token, negate){ |
1224 |
var parts = token.split_contents();
|
1225 |
if(parts.length != 3){ |
1226 |
throw new Error(parts[0] + " takes two arguments"); |
1227 |
} |
1228 |
var end = 'end' + parts[0]; |
1229 |
var trues = parser.parse(["else", end]); |
1230 |
var falses = false; |
1231 |
var token = parser.next_token();
|
1232 |
if(token.contents == "else"){ |
1233 |
falses = parser.parse([end]); |
1234 |
parser.next_token(); |
1235 |
} |
1236 |
return new ddtl.IfEqualNode(parts[1], parts[2], trues, falses, negate); |
1237 |
}, |
1238 |
ifequal: function(parser, token){ |
1239 |
return ddtl._ifequal(parser, token);
|
1240 |
}, |
1241 |
ifnotequal: function(parser, token){ |
1242 |
return ddtl._ifequal(parser, token, true); |
1243 |
}, |
1244 |
for_: function(parser, token){ |
1245 |
var parts = token.contents.split();
|
1246 |
if(parts.length < 4){ |
1247 |
throw new Error("'for' statements should have at least four words: " + token.contents); |
1248 |
} |
1249 |
var reversed = parts[parts.length - 1] == "reversed"; |
1250 |
var index = (reversed) ? -3 : -2; |
1251 |
if(parts[parts.length + index] != "in"){ |
1252 |
throw new Error("'for' tag received an invalid argument: " + token.contents); |
1253 |
} |
1254 |
var loopvars = parts.slice(1, index).join(" ").split(/ *, */); |
1255 |
for(var i = 0; i < loopvars.length; i++){ |
1256 |
if(!loopvars[i] || loopvars[i].indexOf(" ") != -1){ |
1257 |
throw new Error("'for' tag received an invalid argument: " + token.contents); |
1258 |
} |
1259 |
} |
1260 |
var nodelist = parser.parse(["endfor"]); |
1261 |
parser.next_token(); |
1262 |
return new ddtl.ForNode(loopvars, parts[parts.length + index + 1], reversed, nodelist); |
1263 |
} |
1264 |
}); |
1265 |
})(); |
1266 |
|
1267 |
} |
1268 |
|
1269 |
if(!dojo._hasResource["dojox.dtl.tag.loop"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
1270 |
dojo._hasResource["dojox.dtl.tag.loop"] = true; |
1271 |
dojo.provide("dojox.dtl.tag.loop");
|
1272 |
|
1273 |
|
1274 |
|
1275 |
|
1276 |
(function(){
|
1277 |
var dd = dojox.dtl;
|
1278 |
var ddtl = dd.tag.loop;
|
1279 |
|
1280 |
ddtl.CycleNode = dojo.extend(function(cyclevars, name, text, shared){
|
1281 |
this.cyclevars = cyclevars;
|
1282 |
this.name = name;
|
1283 |
this.contents = text;
|
1284 |
this.shared = shared || {counter: -1, map: {}}; |
1285 |
}, |
1286 |
{ |
1287 |
render: function(context, buffer){ |
1288 |
if(context.forloop && !context.forloop.counter0){
|
1289 |
this.shared.counter = -1; |
1290 |
} |
1291 |
|
1292 |
++this.shared.counter;
|
1293 |
var value = this.cyclevars[this.shared.counter % this.cyclevars.length]; |
1294 |
|
1295 |
var map = this.shared.map; |
1296 |
if(!map[value]){
|
1297 |
map[value] = new dd._Filter(value);
|
1298 |
} |
1299 |
value = map[value].resolve(context, buffer); |
1300 |
|
1301 |
if(this.name){ |
1302 |
context[this.name] = value;
|
1303 |
} |
1304 |
this.contents.set(value);
|
1305 |
return this.contents.render(context, buffer); |
1306 |
}, |
1307 |
unrender: function(context, buffer){ |
1308 |
return this.contents.unrender(context, buffer); |
1309 |
}, |
1310 |
clone: function(buffer){ |
1311 |
return new this.constructor(this.cyclevars, this.name, this.contents.clone(buffer), this.shared); |
1312 |
} |
1313 |
}); |
1314 |
|
1315 |
ddtl.IfChangedNode = dojo.extend(function(nodes, vars, shared){
|
1316 |
this.nodes = nodes;
|
1317 |
this._vars = vars;
|
1318 |
this.shared = shared || {last: null, counter: 0}; |
1319 |
this.vars = dojo.map(vars, function(item){ |
1320 |
return new dojox.dtl._Filter(item); |
1321 |
}); |
1322 |
}, { |
1323 |
render: function(context, buffer){ |
1324 |
if(context.forloop){
|
1325 |
if(context.forloop.counter <= this.shared.counter){ |
1326 |
this.shared.last = null; |
1327 |
} |
1328 |
this.shared.counter = context.forloop.counter;
|
1329 |
} |
1330 |
|
1331 |
var change;
|
1332 |
if(this.vars.length){ |
1333 |
change = dojo.toJson(dojo.map(this.vars, function(item){ |
1334 |
return item.resolve(context);
|
1335 |
})); |
1336 |
}else{
|
1337 |
change = this.nodes.dummyRender(context, buffer);
|
1338 |
} |
1339 |
|
1340 |
if(change != this.shared.last){ |
1341 |
var firstloop = (this.shared.last === null); |
1342 |
this.shared.last = change;
|
1343 |
context = context.push(); |
1344 |
context.ifchanged = {firstloop: firstloop};
|
1345 |
buffer = this.nodes.render(context, buffer);
|
1346 |
context = context.pop(); |
1347 |
}else{
|
1348 |
buffer = this.nodes.unrender(context, buffer);
|
1349 |
} |
1350 |
return buffer;
|
1351 |
}, |
1352 |
unrender: function(context, buffer){ |
1353 |
return this.nodes.unrender(context, buffer); |
1354 |
}, |
1355 |
clone: function(buffer){ |
1356 |
return new this.constructor(this.nodes.clone(buffer), this._vars, this.shared); |
1357 |
} |
1358 |
}); |
1359 |
|
1360 |
ddtl.RegroupNode = dojo.extend(function(expression, key, alias){
|
1361 |
this._expression = expression;
|
1362 |
this.expression = new dd._Filter(expression); |
1363 |
this.key = key;
|
1364 |
this.alias = alias;
|
1365 |
}, |
1366 |
{ |
1367 |
_push: function(container, grouper, stack){ |
1368 |
if(stack.length){
|
1369 |
container.push({ grouper: grouper, list: stack }); |
1370 |
} |
1371 |
}, |
1372 |
render: function(context, buffer){ |
1373 |
context[this.alias] = [];
|
1374 |
var list = this.expression.resolve(context); |
1375 |
if(list){
|
1376 |
var last = null; |
1377 |
var stack = [];
|
1378 |
for(var i = 0; i < list.length; i++){ |
1379 |
var id = list[i][this.key]; |
1380 |
if(last !== id){
|
1381 |
this._push(context[this.alias], last, stack); |
1382 |
last = id; |
1383 |
stack = [list[i]]; |
1384 |
}else{
|
1385 |
stack.push(list[i]); |
1386 |
} |
1387 |
} |
1388 |
this._push(context[this.alias], last, stack); |
1389 |
} |
1390 |
return buffer;
|
1391 |
}, |
1392 |
unrender: function(context, buffer){ |
1393 |
return buffer;
|
1394 |
}, |
1395 |
clone: function(context, buffer){ |
1396 |
return this; |
1397 |
} |
1398 |
}); |
1399 |
|
1400 |
dojo.mixin(ddtl, { |
1401 |
cycle: function(parser, token){ |
1402 |
// summary: Cycle among the given strings each time this tag is encountered
|
1403 |
var args = token.split_contents();
|
1404 |
|
1405 |
if(args.length < 2){ |
1406 |
throw new Error("'cycle' tag requires at least two arguments"); |
1407 |
} |
1408 |
|
1409 |
if(args[1].indexOf(",") != -1){ |
1410 |
var vars = args[1].split(","); |
1411 |
args = [args[0]];
|
1412 |
for(var i = 0; i < vars.length; i++){ |
1413 |
args.push('"' + vars[i] + '"'); |
1414 |
} |
1415 |
} |
1416 |
|
1417 |
if(args.length == 2){ |
1418 |
var name = args[args.length - 1]; |
1419 |
|
1420 |
if(!parser._namedCycleNodes){
|
1421 |
throw new Error("No named cycles in template: '" + name + "' is not defined"); |
1422 |
} |
1423 |
if(!parser._namedCycleNodes[name]){
|
1424 |
throw new Error("Named cycle '" + name + "' does not exist"); |
1425 |
} |
1426 |
|
1427 |
return parser._namedCycleNodes[name];
|
1428 |
} |
1429 |
|
1430 |
if(args.length > 4 && args[args.length - 2] == "as"){ |
1431 |
var name = args[args.length - 1]; |
1432 |
|
1433 |
var node = new ddtl.CycleNode(args.slice(1, args.length - 2), name, parser.create_text_node()); |
1434 |
|
1435 |
if(!parser._namedCycleNodes){
|
1436 |
parser._namedCycleNodes = {}; |
1437 |
} |
1438 |
parser._namedCycleNodes[name] = node; |
1439 |
}else{
|
1440 |
node = new ddtl.CycleNode(args.slice(1), null, parser.create_text_node()); |
1441 |
} |
1442 |
|
1443 |
return node;
|
1444 |
}, |
1445 |
ifchanged: function(parser, token){ |
1446 |
var parts = token.contents.split();
|
1447 |
var nodes = parser.parse(["endifchanged"]); |
1448 |
parser.delete_first_token(); |
1449 |
return new ddtl.IfChangedNode(nodes, parts.slice(1)); |
1450 |
}, |
1451 |
regroup: function(parser, token){ |
1452 |
var tokens = dojox.string.tokenize(token.contents, /(\s+)/g, function(spaces){ |
1453 |
return spaces;
|
1454 |
}); |
1455 |
if(tokens.length < 11 || tokens[tokens.length - 3] != "as" || tokens[tokens.length - 7] != "by"){ |
1456 |
throw new Error("Expected the format: regroup list by key as newList"); |
1457 |
} |
1458 |
var expression = tokens.slice(2, -8).join(""); |
1459 |
var key = tokens[tokens.length - 5]; |
1460 |
var alias = tokens[tokens.length - 1]; |
1461 |
return new ddtl.RegroupNode(expression, key, alias); |
1462 |
} |
1463 |
}); |
1464 |
})(); |
1465 |
|
1466 |
} |
1467 |
|
1468 |
if(!dojo._hasResource["dojo.date"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
1469 |
dojo._hasResource["dojo.date"] = true; |
1470 |
dojo.provide("dojo.date");
|
1471 |
|
1472 |
/*=====
|
1473 |
dojo.date = {
|
1474 |
// summary: Date manipulation utilities
|
1475 |
}
|
1476 |
=====*/
|
1477 |
|
1478 |
dojo.date.getDaysInMonth = function(/*Date*/dateObject){ |
1479 |
// summary:
|
1480 |
// Returns the number of days in the month used by dateObject
|
1481 |
var month = dateObject.getMonth();
|
1482 |
var days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; |
1483 |
if(month == 1 && dojo.date.isLeapYear(dateObject)){ return 29; } // Number |
1484 |
return days[month]; // Number |
1485 |
} |
1486 |
|
1487 |
dojo.date.isLeapYear = function(/*Date*/dateObject){ |
1488 |
// summary:
|
1489 |
// Determines if the year of the dateObject is a leap year
|
1490 |
// description:
|
1491 |
// Leap years are years with an additional day YYYY-02-29, where the
|
1492 |
// year number is a multiple of four with the following exception: If
|
1493 |
// a year is a multiple of 100, then it is only a leap year if it is
|
1494 |
// also a multiple of 400. For example, 1900 was not a leap year, but
|
1495 |
// 2000 is one.
|
1496 |
|
1497 |
var year = dateObject.getFullYear();
|
1498 |
return !(year%400) || (!(year%4) && !!(year%100)); // Boolean |
1499 |
} |
1500 |
|
1501 |
// FIXME: This is not localized
|
1502 |
dojo.date.getTimezoneName = function(/*Date*/dateObject){ |
1503 |
// summary:
|
1504 |
// Get the user's time zone as provided by the browser
|
1505 |
// dateObject:
|
1506 |
// Needed because the timezone may vary with time (daylight savings)
|
1507 |
// description:
|
1508 |
// Try to get time zone info from toString or toLocaleString method of
|
1509 |
// the Date object -- UTC offset is not a time zone. See
|
1510 |
// http://www.twinsun.com/tz/tz-link.htm Note: results may be
|
1511 |
// inconsistent across browsers.
|
1512 |
|
1513 |
var str = dateObject.toString(); // Start looking in toString |
1514 |
var tz = ''; // The result -- return empty string if nothing found |
1515 |
var match;
|
1516 |
|
1517 |
// First look for something in parentheses -- fast lookup, no regex
|
1518 |
var pos = str.indexOf('('); |
1519 |
if(pos > -1){ |
1520 |
tz = str.substring(++pos, str.indexOf(')'));
|
1521 |
}else{
|
1522 |
// If at first you don't succeed ...
|
1523 |
// If IE knows about the TZ, it appears before the year
|
1524 |
// Capital letters or slash before a 4-digit year
|
1525 |
// at the end of string
|
1526 |
var pat = /([A-Z\/]+) \d{4}$/; |
1527 |
if((match = str.match(pat))){
|
1528 |
tz = match[1];
|
1529 |
}else{
|
1530 |
// Some browsers (e.g. Safari) glue the TZ on the end
|
1531 |
// of toLocaleString instead of putting it in toString
|
1532 |
str = dateObject.toLocaleString(); |
1533 |
// Capital letters or slash -- end of string,
|
1534 |
// after space
|
1535 |
pat = / ([A-Z\/]+)$/;
|
1536 |
if((match = str.match(pat))){
|
1537 |
tz = match[1];
|
1538 |
} |
1539 |
} |
1540 |
} |
1541 |
|
1542 |
// Make sure it doesn't somehow end up return AM or PM
|
1543 |
return (tz == 'AM' || tz == 'PM') ? '' : tz; // String |
1544 |
} |
1545 |
|
1546 |
// Utility methods to do arithmetic calculations with Dates
|
1547 |
|
1548 |
dojo.date.compare = function(/*Date*/date1, /*Date?*/date2, /*String?*/portion){ |
1549 |
// summary:
|
1550 |
// Compare two date objects by date, time, or both.
|
1551 |
// description:
|
1552 |
// Returns 0 if equal, positive if a > b, else negative.
|
1553 |
// date1:
|
1554 |
// Date object
|
1555 |
// date2:
|
1556 |
// Date object. If not specified, the current Date is used.
|
1557 |
// portion:
|
1558 |
// A string indicating the "date" or "time" portion of a Date object.
|
1559 |
// Compares both "date" and "time" by default. One of the following:
|
1560 |
// "date", "time", "datetime"
|
1561 |
|
1562 |
// Extra step required in copy for IE - see #3112
|
1563 |
date1 = new Date(+date1);
|
1564 |
date2 = new Date(+(date2 || new Date())); |
1565 |
|
1566 |
if(portion == "date"){ |
1567 |
// Ignore times and compare dates.
|
1568 |
date1.setHours(0, 0, 0, 0); |
1569 |
date2.setHours(0, 0, 0, 0); |
1570 |
}else if(portion == "time"){ |
1571 |
// Ignore dates and compare times.
|
1572 |
date1.setFullYear(0, 0, 0); |
1573 |
date2.setFullYear(0, 0, 0); |
1574 |
} |
1575 |
|
1576 |
if(date1 > date2){ return 1; } // int |
1577 |
if(date1 < date2){ return -1; } // int |
1578 |
return 0; // int |
1579 |
}; |
1580 |
|
1581 |
dojo.date.add = function(/*Date*/date, /*String*/interval, /*int*/amount){ |
1582 |
// summary:
|
1583 |
// Add to a Date in intervals of different size, from milliseconds to years
|
1584 |
// date: Date
|
1585 |
// Date object to start with
|
1586 |
// interval:
|
1587 |
// A string representing the interval. One of the following:
|
1588 |
// "year", "month", "day", "hour", "minute", "second",
|
1589 |
// "millisecond", "quarter", "week", "weekday"
|
1590 |
// amount:
|
1591 |
// How much to add to the date.
|
1592 |
|
1593 |
var sum = new Date(+date); // convert to Number before copying to accomodate IE (#3112) |
1594 |
var fixOvershoot = false; |
1595 |
var property = "Date"; |
1596 |
|
1597 |
switch(interval){
|
1598 |
case "day": |
1599 |
break;
|
1600 |
case "weekday": |
1601 |
//i18n FIXME: assumes Saturday/Sunday weekend, but this is not always true. see dojo.cldr.supplemental
|
1602 |
|
1603 |
// Divide the increment time span into weekspans plus leftover days
|
1604 |
// e.g., 8 days is one 5-day weekspan / and two leftover days
|
1605 |
// Can't have zero leftover days, so numbers divisible by 5 get
|
1606 |
// a days value of 5, and the remaining days make up the number of weeks
|
1607 |
var days, weeks;
|
1608 |
var mod = amount % 5; |
1609 |
if(!mod){
|
1610 |
days = (amount > 0) ? 5 : -5; |
1611 |
weeks = (amount > 0) ? ((amount-5)/5) : ((amount+5)/5); |
1612 |
}else{
|
1613 |
days = mod; |
1614 |
weeks = parseInt(amount/5);
|
1615 |
} |
1616 |
// Get weekday value for orig date param
|
1617 |
var strt = date.getDay();
|
1618 |
// Orig date is Sat / positive incrementer
|
1619 |
// Jump over Sun
|
1620 |
var adj = 0; |
1621 |
if(strt == 6 && amount > 0){ |
1622 |
adj = 1;
|
1623 |
}else if(strt == 0 && amount < 0){ |
1624 |
// Orig date is Sun / negative incrementer
|
1625 |
// Jump back over Sat
|
1626 |
adj = -1;
|
1627 |
} |
1628 |
// Get weekday val for the new date
|
1629 |
var trgt = strt + days;
|
1630 |
// New date is on Sat or Sun
|
1631 |
if(trgt == 0 || trgt == 6){ |
1632 |
adj = (amount > 0) ? 2 : -2; |
1633 |
} |
1634 |
// Increment by number of weeks plus leftover days plus
|
1635 |
// weekend adjustments
|
1636 |
amount = (7 * weeks) + days + adj;
|
1637 |
break;
|
1638 |
case "year": |
1639 |
property = "FullYear";
|
1640 |
// Keep increment/decrement from 2/29 out of March
|
1641 |
fixOvershoot = true;
|
1642 |
break;
|
1643 |
case "week": |
1644 |
amount *= 7;
|
1645 |
break;
|
1646 |
case "quarter": |
1647 |
// Naive quarter is just three months
|
1648 |
amount *= 3;
|
1649 |
// fallthrough...
|
1650 |
case "month": |
1651 |
// Reset to last day of month if you overshoot
|
1652 |
fixOvershoot = true;
|
1653 |
property = "Month";
|
1654 |
break;
|
1655 |
// case "hour":
|
1656 |
// case "minute":
|
1657 |
// case "second":
|
1658 |
// case "millisecond":
|
1659 |
default:
|
1660 |
property = "UTC"+interval.charAt(0).toUpperCase() + interval.substring(1) + "s"; |
1661 |
} |
1662 |
|
1663 |
if(property){
|
1664 |
sum["set"+property](sum["get"+property]()+amount); |
1665 |
} |
1666 |
|
1667 |
if(fixOvershoot && (sum.getDate() < date.getDate())){
|
1668 |
sum.setDate(0);
|
1669 |
} |
1670 |
|
1671 |
return sum; // Date |
1672 |
}; |
1673 |
|
1674 |
dojo.date.difference = function(/*Date*/date1, /*Date?*/date2, /*String?*/interval){ |
1675 |
// summary:
|
1676 |
// Get the difference in a specific unit of time (e.g., number of
|
1677 |
// months, weeks, days, etc.) between two dates, rounded to the
|
1678 |
// nearest integer.
|
1679 |
// date1:
|
1680 |
// Date object
|
1681 |
// date2:
|
1682 |
// Date object. If not specified, the current Date is used.
|
1683 |
// interval:
|
1684 |
// A string representing the interval. One of the following:
|
1685 |
// "year", "month", "day", "hour", "minute", "second",
|
1686 |
// "millisecond", "quarter", "week", "weekday"
|
1687 |
// Defaults to "day".
|
1688 |
|
1689 |
date2 = date2 || new Date();
|
1690 |
interval = interval || "day";
|
1691 |
var yearDiff = date2.getFullYear() - date1.getFullYear();
|
1692 |
var delta = 1; // Integer return value |
1693 |
|
1694 |
switch(interval){
|
1695 |
case "quarter": |
1696 |
var m1 = date1.getMonth();
|
1697 |
var m2 = date2.getMonth();
|
1698 |
// Figure out which quarter the months are in
|
1699 |
var q1 = Math.floor(m1/3) + 1; |
1700 |
var q2 = Math.floor(m2/3) + 1; |
1701 |
// Add quarters for any year difference between the dates
|
1702 |
q2 += (yearDiff * 4);
|
1703 |
delta = q2 - q1; |
1704 |
break;
|
1705 |
case "weekday": |
1706 |
var days = Math.round(dojo.date.difference(date1, date2, "day")); |
1707 |
var weeks = parseInt(dojo.date.difference(date1, date2, "week")); |
1708 |
var mod = days % 7; |
1709 |
|
1710 |
// Even number of weeks
|
1711 |
if(mod == 0){ |
1712 |
days = weeks*5;
|
1713 |
}else{
|
1714 |
// Weeks plus spare change (< 7 days)
|
1715 |
var adj = 0; |
1716 |
var aDay = date1.getDay();
|
1717 |
var bDay = date2.getDay();
|
1718 |
|
1719 |
weeks = parseInt(days/7);
|
1720 |
mod = days % 7;
|
1721 |
// Mark the date advanced by the number of
|
1722 |
// round weeks (may be zero)
|
1723 |
var dtMark = new Date(date1); |
1724 |
dtMark.setDate(dtMark.getDate()+(weeks*7));
|
1725 |
var dayMark = dtMark.getDay();
|
1726 |
|
1727 |
// Spare change days -- 6 or less
|
1728 |
if(days > 0){ |
1729 |
switch(true){ |
1730 |
// Range starts on Sat
|
1731 |
case aDay == 6: |
1732 |
adj = -1;
|
1733 |
break;
|
1734 |
// Range starts on Sun
|
1735 |
case aDay == 0: |
1736 |
adj = 0;
|
1737 |
break;
|
1738 |
// Range ends on Sat
|
1739 |
case bDay == 6: |
1740 |
adj = -1;
|
1741 |
break;
|
1742 |
// Range ends on Sun
|
1743 |
case bDay == 0: |
1744 |
adj = -2;
|
1745 |
break;
|
1746 |
// Range contains weekend
|
1747 |
case (dayMark + mod) > 5: |
1748 |
adj = -2;
|
1749 |
} |
1750 |
}else if(days < 0){ |
1751 |
switch(true){ |
1752 |
// Range starts on Sat
|
1753 |
case aDay == 6: |
1754 |
adj = 0;
|
1755 |
break;
|
1756 |
// Range starts on Sun
|
1757 |
case aDay == 0: |
1758 |
adj = 1;
|
1759 |
break;
|
1760 |
// Range ends on Sat
|
1761 |
case bDay == 6: |
1762 |
adj = 2;
|
1763 |
break;
|
1764 |
// Range ends on Sun
|
1765 |
case bDay == 0: |
1766 |
adj = 1;
|
1767 |
break;
|
1768 |
// Range contains weekend
|
1769 |
case (dayMark + mod) < 0: |
1770 |
adj = 2;
|
1771 |
} |
1772 |
} |
1773 |
days += adj; |
1774 |
days -= (weeks*2);
|
1775 |
} |
1776 |
delta = days; |
1777 |
break;
|
1778 |
case "year": |
1779 |
delta = yearDiff; |
1780 |
break;
|
1781 |
case "month": |
1782 |
delta = (date2.getMonth() - date1.getMonth()) + (yearDiff * 12);
|
1783 |
break;
|
1784 |
case "week": |
1785 |
// Truncate instead of rounding
|
1786 |
// Don't use Math.floor -- value may be negative
|
1787 |
delta = parseInt(dojo.date.difference(date1, date2, "day")/7); |
1788 |
break;
|
1789 |
case "day": |
1790 |
delta /= 24;
|
1791 |
// fallthrough
|
1792 |
case "hour": |
1793 |
delta /= 60;
|
1794 |
// fallthrough
|
1795 |
case "minute": |
1796 |
delta /= 60;
|
1797 |
// fallthrough
|
1798 |
case "second": |
1799 |
delta /= 1000;
|
1800 |
// fallthrough
|
1801 |
case "millisecond": |
1802 |
delta *= date2.getTime() - date1.getTime(); |
1803 |
} |
1804 |
|
1805 |
// Round for fractional values and DST leaps
|
1806 |
return Math.round(delta); // Number (integer) |
1807 |
}; |
1808 |
|
1809 |
} |
1810 |
|
1811 |
if(!dojo._hasResource["dojox.date.php"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
1812 |
dojo._hasResource["dojox.date.php"] = true; |
1813 |
dojo.provide("dojox.date.php");
|
1814 |
|
1815 |
|
1816 |
|
1817 |
dojox.date.php.format = function(/*Date*/ date, /*String*/ format){ |
1818 |
// summary: Get a formatted string for a given date object
|
1819 |
var df = new dojox.date.php.DateFormat(format); |
1820 |
return df.format(date);
|
1821 |
} |
1822 |
|
1823 |
dojox.date.php.DateFormat = function(/*String*/ format){ |
1824 |
// summary: Format the internal date object
|
1825 |
if(!this.regex){ |
1826 |
var keys = [];
|
1827 |
for(var key in this.constructor.prototype){ |
1828 |
if(dojo.isString(key) && key.length == 1 && dojo.isFunction(this[key])){ |
1829 |
keys.push(key); |
1830 |
} |
1831 |
} |
1832 |
this.constructor.prototype.regex = new RegExp("(?:(\\\\.)|([" + keys.join("") + "]))", "g"); |
1833 |
} |
1834 |
|
1835 |
var replacements = [];
|
1836 |
|
1837 |
this.tokens = dojox.string.tokenize(format, this.regex, function(escape, token, i){ |
1838 |
if(token){
|
1839 |
replacements.push([i, token]); |
1840 |
return token;
|
1841 |
} |
1842 |
if(escape){
|
1843 |
return escape.charAt(1); |
1844 |
} |
1845 |
}); |
1846 |
|
1847 |
this.replacements = replacements;
|
1848 |
} |
1849 |
dojo.extend(dojox.date.php.DateFormat, { |
1850 |
weekdays: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], |
1851 |
weekdays_3: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], |
1852 |
months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], |
1853 |
months_3: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], |
1854 |
monthdays: [31,28,31,30,31,30,31,31,30,31,30,31], |
1855 |
|
1856 |
format: function(/*Date*/ date){ |
1857 |
this.date = date;
|
1858 |
for(var i = 0, replacement; replacement = this.replacements[i]; i++){ |
1859 |
this.tokens[replacement[0]] = this[replacement[1]](); |
1860 |
} |
1861 |
return this.tokens.join(""); |
1862 |
}, |
1863 |
|
1864 |
// Day
|
1865 |
|
1866 |
d: function(){ |
1867 |
// summary: Day of the month, 2 digits with leading zeros
|
1868 |
var j = this.j(); |
1869 |
return (j.length == 1) ? "0" + j : j; |
1870 |
}, |
1871 |
|
1872 |
D: function(){ |
1873 |
// summary: A textual representation of a day, three letters
|
1874 |
return this.weekdays_3[this.date.getDay()]; |
1875 |
}, |
1876 |
|
1877 |
j: function(){ |
1878 |
// summary: Day of the month without leading zeros
|
1879 |
return this.date.getDate() + ""; |
1880 |
}, |
1881 |
|
1882 |
l: function(){ |
1883 |
// summary: A full textual representation of the day of the week
|
1884 |
return this.weekdays[this.date.getDay()]; |
1885 |
}, |
1886 |
|
1887 |
N: function(){ |
1888 |
// summary: ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0)
|
1889 |
var w = this.w(); |
1890 |
return (!w) ? 7 : w; |
1891 |
}, |
1892 |
|
1893 |
S: function(){ |
1894 |
// summary: English ordinal suffix for the day of the month, 2 characters
|
1895 |
switch(this.date.getDate()){ |
1896 |
case 11: case 12: case 13: return "th"; |
1897 |
case 1: case 21: case 31: return "st"; |
1898 |
case 2: case 22: return "nd"; |
1899 |
case 3: case 23: return "rd"; |
1900 |
default: return "th"; |
1901 |
} |
1902 |
}, |
1903 |
|
1904 |
w: function(){ |
1905 |
// summary: Numeric representation of the day of the week
|
1906 |
return this.date.getDay() + ""; |
1907 |
}, |
1908 |
|
1909 |
z: function(){ |
1910 |
// summary: The day of the year (starting from 0)
|
1911 |
var millis = this.date.getTime() - new Date(this.date.getFullYear(), 0, 1).getTime(); |
1912 |
return Math.floor(millis/86400000) + ""; |
1913 |
}, |
1914 |
|
1915 |
// Week
|
1916 |
|
1917 |
W: function(){ |
1918 |
// summary: ISO-8601 week number of year, weeks starting on Monday (added in PHP 4.1.0)
|
1919 |
var week;
|
1920 |
var jan1_w = new Date(this.date.getFullYear(), 0, 1).getDay() + 1; |
1921 |
var w = this.date.getDay() + 1; |
1922 |
var z = parseInt(this.z()); |
1923 |
|
1924 |
if(z <= (8 - jan1_w) && jan1_w > 4){ |
1925 |
var last_year = new Date(this.date.getFullYear() - 1, this.date.getMonth(), this.date.getDate()); |
1926 |
if(jan1_w == 5 || (jan1_w == 6 && dojo.date.isLeapYear(last_year))){ |
1927 |
week = 53;
|
1928 |
}else{
|
1929 |
week = 52;
|
1930 |
} |
1931 |
}else{
|
1932 |
var i;
|
1933 |
if(Boolean(this.L())){ |
1934 |
i = 366;
|
1935 |
}else{
|
1936 |
i = 365;
|
1937 |
} |
1938 |
if((i - z) < (4 - w)){ |
1939 |
week = 1;
|
1940 |
}else{
|
1941 |
var j = z + (7 - w) + (jan1_w - 1); |
1942 |
week = Math.ceil(j / 7);
|
1943 |
if(jan1_w > 4){ |
1944 |
--week; |
1945 |
} |
1946 |
} |
1947 |
} |
1948 |
|
1949 |
return week;
|
1950 |
}, |
1951 |
|
1952 |
// Month
|
1953 |
|
1954 |
F: function(){ |
1955 |
// summary: A full textual representation of a month, such as January or March
|
1956 |
return this.months[this.date.getMonth()]; |
1957 |
}, |
1958 |
|
1959 |
m: function(){ |
1960 |
// summary: Numeric representation of a month, with leading zeros
|
1961 |
var n = this.n(); |
1962 |
return (n.length == 1) ? "0" + n : n; |
1963 |
}, |
1964 |
|
1965 |
M: function(){ |
1966 |
// summary: A short textual representation of a month, three letters
|
1967 |
return this.months_3[this.date.getMonth()]; |
1968 |
}, |
1969 |
|
1970 |
n: function(){ |
1971 |
// summary: Numeric representation of a month, without leading zeros
|
1972 |
return this.date.getMonth() + 1 + ""; |
1973 |
}, |
1974 |
|
1975 |
t: function(){ |
1976 |
// summary: Number of days in the given month
|
1977 |
return (Boolean(this.L()) && this.date.getMonth() == 1) ? 29 : this.monthdays[this.getMonth()]; |
1978 |
}, |
1979 |
|
1980 |
// Year
|
1981 |
|
1982 |
L: function(){ |
1983 |
// summary: Whether it's a leap year
|
1984 |
return (dojo.date.isLeapYear(this.date)) ? "1" : "0"; |
1985 |
}, |
1986 |
|
1987 |
o: function(){ |
1988 |
// summary:
|
1989 |
// ISO-8601 year number. This has the same value as Y, except that if
|
1990 |
// the ISO week number (W) belongs to the previous or next year, that year is used instead. (added in PHP 5.1.0)
|
1991 |
// TODO: Figure out what this means
|
1992 |
}, |
1993 |
|
1994 |
Y: function(){ |
1995 |
// summary: A full numeric representation of a year, 4 digits
|
1996 |
return this.date.getFullYear() + ""; |
1997 |
}, |
1998 |
|
1999 |
y: function(){ |
2000 |
// summary: A two digit representation of a year
|
2001 |
return this.Y().slice(-2); |
2002 |
}, |
2003 |
|
2004 |
// Time
|
2005 |
|
2006 |
a: function(){ |
2007 |
// summary: Lowercase Ante meridiem and Post meridiem
|
2008 |
return this.date.getHours() >= 12 ? "pm" : "am"; |
2009 |
}, |
2010 |
|
2011 |
b: function(){ |
2012 |
// summary: Uppercase Ante meridiem and Post meridiem
|
2013 |
return this.a().toUpperCase(); |
2014 |
}, |
2015 |
|
2016 |
B: function(){ |
2017 |
// summary:
|
2018 |
// Swatch Internet time
|
2019 |
// A day is 1,000 beats. All time is measured from GMT + 1
|
2020 |
var off = this.date.getTimezoneOffset() + 60; |
2021 |
var secs = (this.date.getHours() * 3600) + (this.date.getMinutes() * 60) + this.getSeconds() + (off * 60); |
2022 |
var beat = Math.abs(Math.floor(secs / 86.4) % 1000) + ""; |
2023 |
while(beat.length < 2) beat = "0" + beat; |
2024 |
return beat;
|
2025 |
}, |
2026 |
|
2027 |
g: function(){ |
2028 |
// summary: 12-hour format of an hour without leading zeros
|
2029 |
return (this.date.getHours() > 12) ? this.date.getHours() - 12 + "" : this.date.getHours() + ""; |
2030 |
}, |
2031 |
|
2032 |
G: function(){ |
2033 |
// summary: 24-hour format of an hour without leading zeros
|
2034 |
return this.date.getHours() + ""; |
2035 |
}, |
2036 |
|
2037 |
h: function(){ |
2038 |
// summary: 12-hour format of an hour with leading zeros
|
2039 |
var g = this.g(); |
2040 |
return (g.length == 1) ? "0" + g : g; |
2041 |
}, |
2042 |
|
2043 |
H: function(){ |
2044 |
// summary: 24-hour format of an hour with leading zeros
|
2045 |
var G = this.G(); |
2046 |
return (G.length == 1) ? "0" + G : G; |
2047 |
}, |
2048 |
|
2049 |
i: function(){ |
2050 |
// summary: Minutes with leading zeros
|
2051 |
var mins = this.date.getMinutes() + ""; |
2052 |
return (mins.length == 1) ? "0" + mins : mins; |
2053 |
}, |
2054 |
|
2055 |
s: function(){ |
2056 |
// summary: Seconds, with leading zeros
|
2057 |
var secs = this.date.getSeconds() + ""; |
2058 |
return (secs.length == 1) ? "0" + secs : secs; |
2059 |
}, |
2060 |
|
2061 |
// Timezone
|
2062 |
|
2063 |
e: function(){ |
2064 |
// summary: Timezone identifier (added in PHP 5.1.0)
|
2065 |
return dojo.date.getTimezoneName(this.date); |
2066 |
}, |
2067 |
|
2068 |
I: function(){ |
2069 |
// summary: Whether or not the date is in daylight saving time
|
2070 |
// TODO: Can dojo.date do this?
|
2071 |
}, |
2072 |
|
2073 |
O: function(){ |
2074 |
// summary: Difference to Greenwich time (GMT) in hours
|
2075 |
var off = Math.abs(this.date.getTimezoneOffset()); |
2076 |
var hours = Math.floor(off / 60) + ""; |
2077 |
var mins = (off % 60) + ""; |
2078 |
if(hours.length == 1) hours = "0" + hours; |
2079 |
if(mins.length == 1) hours = "0" + mins; |
2080 |
return ((this.date.getTimezoneOffset() < 0) ? "+" : "-") + hours + mins; |
2081 |
}, |
2082 |
|
2083 |
P: function(){ |
2084 |
// summary: Difference to Greenwich time (GMT) with colon between hours and minutes (added in PHP 5.1.3)
|
2085 |
var O = this.O(); |
2086 |
return O.substring(0, 2) + ":" + O.substring(2, 4); |
2087 |
}, |
2088 |
|
2089 |
T: function(){ |
2090 |
// summary: Timezone abbreviation
|
2091 |
|
2092 |
// Guess...
|
2093 |
return this.e().substring(0, 3); |
2094 |
}, |
2095 |
|
2096 |
Z: function(){ |
2097 |
// summary:
|
2098 |
// Timezone offset in seconds. The offset for timezones west of UTC is always negative,
|
2099 |
// and for those east of UTC is always positive.
|
2100 |
return this.date.getTimezoneOffset() * -60; |
2101 |
}, |
2102 |
|
2103 |
// Full Date/Time
|
2104 |
|
2105 |
c: function(){ |
2106 |
// summary: ISO 8601 date (added in PHP 5)
|
2107 |
return this.Y() + "-" + this.m() + "-" + this.d() + "T" + this.h() + ":" + this.i() + ":" + this.s() + this.P(); |
2108 |
}, |
2109 |
|
2110 |
r: function(){ |
2111 |
// summary: RFC 2822 formatted date
|
2112 |
return this.D() + ", " + this.d() + " " + this.M() + " " + this.Y() + " " + this.H() + ":" + this.i() + ":" + this.s() + " " + this.O(); |
2113 |
}, |
2114 |
|
2115 |
U: function(){ |
2116 |
// summary: Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)
|
2117 |
return Math.floor(this.date.getTime() / 1000); |
2118 |
} |
2119 |
|
2120 |
}); |
2121 |
|
2122 |
} |
2123 |
|
2124 |
if(!dojo._hasResource["dojox.dtl.utils.date"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
2125 |
dojo._hasResource["dojox.dtl.utils.date"] = true; |
2126 |
dojo.provide("dojox.dtl.utils.date");
|
2127 |
|
2128 |
|
2129 |
|
2130 |
dojox.dtl.utils.date.DateFormat = function(/*String*/ format){ |
2131 |
dojox.date.php.DateFormat.call(this, format);
|
2132 |
} |
2133 |
dojo.extend(dojox.dtl.utils.date.DateFormat, dojox.date.php.DateFormat.prototype, { |
2134 |
f: function(){ |
2135 |
// summary:
|
2136 |
// Time, in 12-hour hours and minutes, with minutes left off if they're zero.
|
2137 |
// description:
|
2138 |
// Examples: '1', '1:30', '2:05', '2'
|
2139 |
// Proprietary extension.
|
2140 |
return (!this.date.getMinutes()) ? this.g() : this.g() + ":" + this.i(); |
2141 |
}, |
2142 |
N: function(){ |
2143 |
// summary: Month abbreviation in Associated Press style. Proprietary extension.
|
2144 |
return dojox.dtl.utils.date._months_ap[this.date.getMonth()]; |
2145 |
}, |
2146 |
P: function(){ |
2147 |
// summary:
|
2148 |
// Time, in 12-hour hours, minutes and 'a.m.'/'p.m.', with minutes left off
|
2149 |
// if they're zero and the strings 'midnight' and 'noon' if appropriate.
|
2150 |
// description:
|
2151 |
// Examples: '1 a.m.', '1:30 p.m.', 'midnight', 'noon', '12:30 p.m.'
|
2152 |
// Proprietary extension.
|
2153 |
if(!this.date.getMinutes() && !this.date.getHours()){ |
2154 |
return 'midnight'; |
2155 |
} |
2156 |
if(!this.date.getMinutes() && this.date.getHours() == 12){ |
2157 |
return 'noon'; |
2158 |
} |
2159 |
return this.f() + " " + this.a(); |
2160 |
} |
2161 |
}); |
2162 |
|
2163 |
dojo.mixin(dojox.dtl.utils.date, { |
2164 |
format: function(/*Date*/ date, /*String*/ format){ |
2165 |
var df = new dojox.dtl.utils.date.DateFormat(format); |
2166 |
return df.format(date);
|
2167 |
}, |
2168 |
timesince: function(d, now){ |
2169 |
// summary:
|
2170 |
// Takes two datetime objects and returns the time between then and now
|
2171 |
// as a nicely formatted string, e.g "10 minutes"
|
2172 |
// description:
|
2173 |
// Adapted from http://blog.natbat.co.uk/archive/2003/Jun/14/time_since
|
2174 |
if(!(d instanceof Date)){ |
2175 |
d = new Date(d.year, d.month, d.day);
|
2176 |
} |
2177 |
if(!now){
|
2178 |
now = new Date();
|
2179 |
} |
2180 |
|
2181 |
var delta = Math.abs(now.getTime() - d.getTime());
|
2182 |
for(var i = 0, chunk; chunk = dojox.dtl.utils.date._chunks[i]; i++){ |
2183 |
var count = Math.floor(delta / chunk[0]); |
2184 |
if(count) break; |
2185 |
} |
2186 |
return count + " " + chunk[1](count); |
2187 |
}, |
2188 |
_chunks: [
|
2189 |
[60 * 60 * 24 * 365 * 1000, function(n){ return (n == 1) ? 'year' : 'years'; }], |
2190 |
[60 * 60 * 24 * 30 * 1000, function(n){ return (n == 1) ? 'month' : 'months'; }], |
2191 |
[60 * 60 * 24 * 7 * 1000, function(n){ return (n == 1) ? 'week' : 'weeks'; }], |
2192 |
[60 * 60 * 24 * 1000, function(n){ return (n == 1) ? 'day' : 'days'; }], |
2193 |
[60 * 60 * 1000, function(n){ return (n == 1) ? 'hour' : 'hours'; }], |
2194 |
[60 * 1000, function(n){ return (n == 1) ? 'minute' : 'minutes'; }] |
2195 |
], |
2196 |
_months_ap: ["Jan.", "Feb.", "March", "April", "May", "June", "July", "Aug.", "Sept.", "Oct.", "Nov.", "Dec."] |
2197 |
}); |
2198 |
|
2199 |
} |
2200 |
|
2201 |
if(!dojo._hasResource["dojox.dtl.tag.date"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
2202 |
dojo._hasResource["dojox.dtl.tag.date"] = true; |
2203 |
dojo.provide("dojox.dtl.tag.date");
|
2204 |
|
2205 |
|
2206 |
|
2207 |
|
2208 |
dojox.dtl.tag.date.NowNode = function(format, node){ |
2209 |
this._format = format;
|
2210 |
this.format = new dojox.dtl.utils.date.DateFormat(format); |
2211 |
this.contents = node;
|
2212 |
} |
2213 |
dojo.extend(dojox.dtl.tag.date.NowNode, { |
2214 |
render: function(context, buffer){ |
2215 |
this.contents.set(this.format.format(new Date())); |
2216 |
return this.contents.render(context, buffer); |
2217 |
}, |
2218 |
unrender: function(context, buffer){ |
2219 |
return this.contents.unrender(context, buffer); |
2220 |
}, |
2221 |
clone: function(buffer){ |
2222 |
return new this.constructor(this._format, this.contents.clone(buffer)); |
2223 |
} |
2224 |
}); |
2225 |
|
2226 |
dojox.dtl.tag.date.now = function(parser, token){ |
2227 |
// Split by either :" or :'
|
2228 |
var parts = token.split_contents();
|
2229 |
if(parts.length != 2){ |
2230 |
throw new Error("'now' statement takes one argument"); |
2231 |
} |
2232 |
return new dojox.dtl.tag.date.NowNode(parts[1].slice(1, -1), parser.create_text_node()); |
2233 |
} |
2234 |
|
2235 |
} |
2236 |
|
2237 |
if(!dojo._hasResource["dojox.dtl.tag.loader"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
2238 |
dojo._hasResource["dojox.dtl.tag.loader"] = true; |
2239 |
dojo.provide("dojox.dtl.tag.loader");
|
2240 |
|
2241 |
|
2242 |
|
2243 |
(function(){
|
2244 |
var dd = dojox.dtl;
|
2245 |
var ddtl = dd.tag.loader;
|
2246 |
|
2247 |
ddtl.BlockNode = dojo.extend(function(name, nodelist){
|
2248 |
this.name = name;
|
2249 |
this.nodelist = nodelist; // Can be overridden |
2250 |
}, |
2251 |
{ |
2252 |
"super": function(){ |
2253 |
if(this.parent){ |
2254 |
var html = this.parent.nodelist.dummyRender(this.context, null, true); |
2255 |
if(typeof html == "string"){ |
2256 |
html = new String(html);
|
2257 |
} |
2258 |
html.safe = true;
|
2259 |
return html;
|
2260 |
} |
2261 |
return ''; |
2262 |
}, |
2263 |
render: function(context, buffer){ |
2264 |
var name = this.name; |
2265 |
var nodelist = this.nodelist; |
2266 |
var parent;
|
2267 |
if(buffer.blocks){
|
2268 |
var block = buffer.blocks[name];
|
2269 |
if(block){
|
2270 |
parent = block.parent; |
2271 |
nodelist = block.nodelist; |
2272 |
block.used = true;
|
2273 |
} |
2274 |
} |
2275 |
|
2276 |
this.rendered = nodelist;
|
2277 |
|
2278 |
context = context.push(); |
2279 |
this.context = context;
|
2280 |
this.parent = null; |
2281 |
if(nodelist != this.nodelist){ |
2282 |
this.parent = this; |
2283 |
} |
2284 |
context.block = this;
|
2285 |
|
2286 |
if(buffer.getParent){
|
2287 |
var bufferParent = buffer.getParent();
|
2288 |
var setParent = dojo.connect(buffer, "onSetParent", function(node, up, root){ |
2289 |
if(up && root){
|
2290 |
buffer.setParent(bufferParent); |
2291 |
} |
2292 |
}); |
2293 |
} |
2294 |
buffer = nodelist.render(context, buffer, this);
|
2295 |
setParent && dojo.disconnect(setParent); |
2296 |
context = context.pop(); |
2297 |
return buffer;
|
2298 |
}, |
2299 |
unrender: function(context, buffer){ |
2300 |
return this.rendered.unrender(context, buffer); |
2301 |
}, |
2302 |
clone: function(buffer){ |
2303 |
return new this.constructor(this.name, this.nodelist.clone(buffer)); |
2304 |
}, |
2305 |
toString: function(){ return "dojox.dtl.tag.loader.BlockNode"; } |
2306 |
}); |
2307 |
|
2308 |
ddtl.ExtendsNode = dojo.extend(function(getTemplate, nodelist, shared, parent, key){
|
2309 |
this.getTemplate = getTemplate;
|
2310 |
this.nodelist = nodelist;
|
2311 |
this.shared = shared;
|
2312 |
this.parent = parent;
|
2313 |
this.key = key;
|
2314 |
}, |
2315 |
{ |
2316 |
parents: {},
|
2317 |
getParent: function(context){ |
2318 |
var parent = this.parent; |
2319 |
if(!parent){
|
2320 |
var string;
|
2321 |
parent = this.parent = context.get(this.key, false); |
2322 |
if(!parent){
|
2323 |
throw new Error("extends tag used a variable that did not resolve"); |
2324 |
} |
2325 |
if(typeof parent == "object"){ |
2326 |
var url = parent.url || parent.templatePath;
|
2327 |
if(parent.shared){
|
2328 |
this.shared = true; |
2329 |
} |
2330 |
if(url){
|
2331 |
parent = this.parent = url.toString();
|
2332 |
}else if(parent.templateString){ |
2333 |
// Allow the builder's string interning to work
|
2334 |
string = parent.templateString; |
2335 |
parent = this.parent = " "; |
2336 |
}else{
|
2337 |
parent = this.parent = this.parent.toString(); |
2338 |
} |
2339 |
} |
2340 |
if(parent && parent.indexOf("shared:") === 0){ |
2341 |
this.shared = true; |
2342 |
parent = this.parent = parent.substring(7, parent.length); |
2343 |
} |
2344 |
} |
2345 |
if(!parent){
|
2346 |
throw new Error("Invalid template name in 'extends' tag."); |
2347 |
} |
2348 |
if(parent.render){
|
2349 |
return parent;
|
2350 |
} |
2351 |
if(this.parents[parent]){ |
2352 |
return this.parents[parent]; |
2353 |
} |
2354 |
this.parent = this.getTemplate(string || dojox.dtl.text.getTemplateString(parent)); |
2355 |
if(this.shared){ |
2356 |
this.parents[parent] = this.parent; |
2357 |
} |
2358 |
return this.parent; |
2359 |
}, |
2360 |
render: function(context, buffer){ |
2361 |
var parent = this.getParent(context); |
2362 |
|
2363 |
parent.blocks = parent.blocks || {}; |
2364 |
buffer.blocks = buffer.blocks || {}; |
2365 |
|
2366 |
for(var i = 0, node; node = this.nodelist.contents[i]; i++){ |
2367 |
if(node instanceof dojox.dtl.tag.loader.BlockNode){ |
2368 |
var old = parent.blocks[node.name];
|
2369 |
if(old && old.nodelist != node.nodelist){
|
2370 |
// In a shared template, the individual blocks might change
|
2371 |
buffer = old.nodelist.unrender(context, buffer); |
2372 |
} |
2373 |
parent.blocks[node.name] = buffer.blocks[node.name] = { |
2374 |
shared: this.shared, |
2375 |
nodelist: node.nodelist,
|
2376 |
used: false |
2377 |
} |
2378 |
} |
2379 |
} |
2380 |
|
2381 |
this.rendered = parent;
|
2382 |
return parent.nodelist.render(context, buffer, this); |
2383 |
}, |
2384 |
unrender: function(context, buffer){ |
2385 |
return this.rendered.unrender(context, buffer, this); |
2386 |
}, |
2387 |
toString: function(){ return "dojox.dtl.block.ExtendsNode"; } |
2388 |
}); |
2389 |
|
2390 |
ddtl.IncludeNode = dojo.extend(function(path, constant, getTemplate, text, parsed){
|
2391 |
this._path = path;
|
2392 |
this.constant = constant;
|
2393 |
this.path = (constant) ? path : new dd._Filter(path); |
2394 |
this.getTemplate = getTemplate;
|
2395 |
this.text = text;
|
2396 |
this.parsed = (arguments.length == 5) ? parsed : true; |
2397 |
}, |
2398 |
{ |
2399 |
_cache: [{}, {}],
|
2400 |
render: function(context, buffer){ |
2401 |
var location = ((this.constant) ? this.path : this.path.resolve(context)).toString(); |
2402 |
var parsed = Number(this.parsed); |
2403 |
var dirty = false; |
2404 |
if(location != this.last){ |
2405 |
dirty = true;
|
2406 |
if(this.last){ |
2407 |
buffer = this.unrender(context, buffer);
|
2408 |
} |
2409 |
this.last = location;
|
2410 |
} |
2411 |
|
2412 |
var cache = this._cache[parsed]; |
2413 |
|
2414 |
if(parsed){
|
2415 |
if(!cache[location]){
|
2416 |
cache[location] = dd.text._resolveTemplateArg(location, true);
|
2417 |
} |
2418 |
if(dirty){
|
2419 |
var template = this.getTemplate(cache[location]); |
2420 |
this.rendered = template.nodelist;
|
2421 |
} |
2422 |
return this.rendered.render(context, buffer, this); |
2423 |
}else{
|
2424 |
if(this.text instanceof dd._TextNode){ |
2425 |
if(dirty){
|
2426 |
this.rendered = this.text; |
2427 |
this.rendered.set(dd.text._resolveTemplateArg(location, true)); |
2428 |
} |
2429 |
return this.rendered.render(context, buffer); |
2430 |
}else{
|
2431 |
if(!cache[location]){
|
2432 |
var nodelist = [];
|
2433 |
var div = document.createElement("div"); |
2434 |
div.innerHTML = dd.text._resolveTemplateArg(location, true);
|
2435 |
var children = div.childNodes;
|
2436 |
while(children.length){
|
2437 |
var removed = div.removeChild(children[0]); |
2438 |
nodelist.push(removed); |
2439 |
} |
2440 |
cache[location] = nodelist; |
2441 |
} |
2442 |
if(dirty){
|
2443 |
this.nodelist = [];
|
2444 |
var exists = true; |
2445 |
for(var i = 0, child; child = cache[location][i]; i++){ |
2446 |
this.nodelist.push(child.cloneNode(true)); |
2447 |
} |
2448 |
} |
2449 |
for(var i = 0, node; node = this.nodelist[i]; i++){ |
2450 |
buffer = buffer.concat(node); |
2451 |
} |
2452 |
} |
2453 |
} |
2454 |
return buffer;
|
2455 |
}, |
2456 |
unrender: function(context, buffer){ |
2457 |
if(this.rendered){ |
2458 |
buffer = this.rendered.unrender(context, buffer);
|
2459 |
} |
2460 |
if(this.nodelist){ |
2461 |
for(var i = 0, node; node = this.nodelist[i]; i++){ |
2462 |
buffer = buffer.remove(node); |
2463 |
} |
2464 |
} |
2465 |
return buffer;
|
2466 |
}, |
2467 |
clone: function(buffer){ |
2468 |
return new this.constructor(this._path, this.constant, this.getTemplate, this.text.clone(buffer), this.parsed); |
2469 |
} |
2470 |
}); |
2471 |
|
2472 |
dojo.mixin(ddtl, { |
2473 |
block: function(parser, token){ |
2474 |
var parts = token.contents.split();
|
2475 |
var name = parts[1]; |
2476 |
|
2477 |
parser._blocks = parser._blocks || {}; |
2478 |
parser._blocks[name] = parser._blocks[name] || []; |
2479 |
parser._blocks[name].push(name); |
2480 |
|
2481 |
var nodelist = parser.parse(["endblock", "endblock " + name]).rtrim(); |
2482 |
parser.next_token(); |
2483 |
return new dojox.dtl.tag.loader.BlockNode(name, nodelist); |
2484 |
}, |
2485 |
extends_: function(parser, token){ |
2486 |
var parts = token.contents.split();
|
2487 |
var shared = false; |
2488 |
var parent = null; |
2489 |
var key = null; |
2490 |
if(parts[1].charAt(0) == '"' || parts[1].charAt(0) == "'"){ |
2491 |
parent = parts[1].substring(1, parts[1].length - 1); |
2492 |
}else{
|
2493 |
key = parts[1];
|
2494 |
} |
2495 |
if(parent && parent.indexOf("shared:") == 0){ |
2496 |
shared = true;
|
2497 |
parent = parent.substring(7, parent.length);
|
2498 |
} |
2499 |
var nodelist = parser.parse();
|
2500 |
return new dojox.dtl.tag.loader.ExtendsNode(parser.getTemplate, nodelist, shared, parent, key); |
2501 |
}, |
2502 |
include: function(parser, token){ |
2503 |
var parts = token.contents.split();
|
2504 |
if(parts.length != 2){ |
2505 |
throw new Error(parts[0] + " tag takes one argument: the name of the template to be included"); |
2506 |
} |
2507 |
var path = parts[1]; |
2508 |
var constant = false; |
2509 |
if((path.charAt(0) == '"' || path.slice(-1) == "'") && path.charAt(0) == path.slice(-1)){ |
2510 |
path = path.slice(1, -1); |
2511 |
constant = true;
|
2512 |
} |
2513 |
return new ddtl.IncludeNode(path, constant, parser.getTemplate, parser.create_text_node()); |
2514 |
}, |
2515 |
ssi: function(parser, token){ |
2516 |
// We're going to treat things a little differently here.
|
2517 |
// First of all, this tag is *not* portable, so I'm not
|
2518 |
// concerned about it being a "drop in" replacement.
|
2519 |
|
2520 |
// Instead, we'll just replicate the include tag, but with that
|
2521 |
// optional "parsed" parameter.
|
2522 |
var parts = token.contents.split();
|
2523 |
var parsed = false; |
2524 |
if(parts.length == 3){ |
2525 |
parsed = (parts.pop() == "parsed");
|
2526 |
if(!parsed){
|
2527 |
throw new Error("Second (optional) argument to ssi tag must be 'parsed'"); |
2528 |
} |
2529 |
} |
2530 |
var node = ddtl.include(parser, new dd.Token(token.token_type, parts.join(" "))); |
2531 |
node.parsed = parsed; |
2532 |
return node;
|
2533 |
} |
2534 |
}); |
2535 |
})(); |
2536 |
|
2537 |
} |
2538 |
|
2539 |
if(!dojo._hasResource["dojox.dtl.tag.misc"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
2540 |
dojo._hasResource["dojox.dtl.tag.misc"] = true; |
2541 |
dojo.provide("dojox.dtl.tag.misc");
|
2542 |
|
2543 |
|
2544 |
(function(){
|
2545 |
var dd = dojox.dtl;
|
2546 |
var ddtm = dd.tag.misc;
|
2547 |
|
2548 |
ddtm.DebugNode = dojo.extend(function(text){
|
2549 |
this.text = text;
|
2550 |
}, |
2551 |
{ |
2552 |
render: function(context, buffer){ |
2553 |
var keys = context.getKeys();
|
2554 |
var debug = [];
|
2555 |
var only = {};
|
2556 |
for(var i = 0, key; key = keys[i]; i++){ |
2557 |
only[key] = context[key]; |
2558 |
debug += "[" + key + ": " + typeof context[key] + "]\n"; |
2559 |
} |
2560 |
console.debug(only); |
2561 |
return this.text.set(debug).render(context, buffer, this); |
2562 |
}, |
2563 |
unrender: function(context, buffer){ |
2564 |
return buffer;
|
2565 |
}, |
2566 |
clone: function(buffer){ |
2567 |
return new this.constructor(this.text.clone(buffer)); |
2568 |
}, |
2569 |
toString: function(){ return "ddtm.DebugNode"; } |
2570 |
}); |
2571 |
|
2572 |
ddtm.FilterNode = dojo.extend(function(varnode, nodelist){
|
2573 |
this._varnode = varnode;
|
2574 |
this._nodelist = nodelist;
|
2575 |
}, |
2576 |
{ |
2577 |
render: function(context, buffer){ |
2578 |
// Doing this in HTML requires a different buffer with a fake root node
|
2579 |
var output = this._nodelist.render(context, new dojox.string.Builder()); |
2580 |
context = context.update({ "var": output.toString() });
|
2581 |
var filtered = this._varnode.render(context, buffer); |
2582 |
context = context.pop(); |
2583 |
return buffer;
|
2584 |
}, |
2585 |
unrender: function(context, buffer){ |
2586 |
return buffer;
|
2587 |
}, |
2588 |
clone: function(buffer){ |
2589 |
return new this.constructor(this._expression, this._nodelist.clone(buffer)); |
2590 |
} |
2591 |
}); |
2592 |
|
2593 |
ddtm.FirstOfNode = dojo.extend(function(vars, text){
|
2594 |
this._vars = vars;
|
2595 |
this.vars = dojo.map(vars, function(item){ |
2596 |
return new dojox.dtl._Filter(item); |
2597 |
}); |
2598 |
this.contents = text;
|
2599 |
}, |
2600 |
{ |
2601 |
render: function(context, buffer){ |
2602 |
for(var i = 0, item; item = this.vars[i]; i++){ |
2603 |
var resolved = item.resolve(context);
|
2604 |
if(typeof resolved != "undefined"){ |
2605 |
if(resolved === null){ |
2606 |
resolved = "null";
|
2607 |
} |
2608 |
this.contents.set(resolved);
|
2609 |
return this.contents.render(context, buffer); |
2610 |
} |
2611 |
} |
2612 |
return this.contents.unrender(context, buffer); |
2613 |
}, |
2614 |
unrender: function(context, buffer){ |
2615 |
return this.contents.unrender(context, buffer); |
2616 |
}, |
2617 |
clone: function(buffer){ |
2618 |
return new this.constructor(this._vars, this.contents.clone(buffer)); |
2619 |
} |
2620 |
}); |
2621 |
|
2622 |
ddtm.SpacelessNode = dojo.extend(function(nodelist, text){
|
2623 |
this.nodelist = nodelist;
|
2624 |
this.contents = text;
|
2625 |
}, |
2626 |
{ |
2627 |
render: function(context, buffer){ |
2628 |
if(buffer.getParent){
|
2629 |
// Unfortunately, we have to branch here
|
2630 |
var watch = [
|
2631 |
dojo.connect(buffer, "onAddNodeComplete", this, "_watch"), |
2632 |
dojo.connect(buffer, "onSetParent", this, "_watchParent") |
2633 |
]; |
2634 |
buffer = this.nodelist.render(context, buffer);
|
2635 |
dojo.disconnect(watch[0]);
|
2636 |
dojo.disconnect(watch[1]);
|
2637 |
}else{
|
2638 |
var value = this.nodelist.dummyRender(context); |
2639 |
this.contents.set(value.replace(/>\s+</g, '><')); |
2640 |
buffer = this.contents.render(context, buffer);
|
2641 |
} |
2642 |
return buffer;
|
2643 |
}, |
2644 |
unrender: function(context, buffer){ |
2645 |
return this.nodelist.unrender(context, buffer); |
2646 |
}, |
2647 |
clone: function(buffer){ |
2648 |
return new this.constructor(this.nodelist.clone(buffer), this.contents.clone(buffer)); |
2649 |
}, |
2650 |
_isEmpty: function(node){ |
2651 |
return (node.nodeType == 3 && !node.data.match(/[^\s\n]/)); |
2652 |
}, |
2653 |
_watch: function(node){ |
2654 |
if(this._isEmpty(node)){ |
2655 |
var remove = false; |
2656 |
if(node.parentNode.firstChild == node){
|
2657 |
node.parentNode.removeChild(node); |
2658 |
} |
2659 |
}else{
|
2660 |
var children = node.parentNode.childNodes;
|
2661 |
if(node.nodeType == 1 && children.length > 2){ |
2662 |
for(var i = 2, child; child = children[i]; i++){ |
2663 |
if(children[i - 2].nodeType == 1 && this._isEmpty(children[i - 1])){ |
2664 |
node.parentNode.removeChild(children[i - 1]);
|
2665 |
return;
|
2666 |
} |
2667 |
} |
2668 |
} |
2669 |
} |
2670 |
}, |
2671 |
_watchParent: function(node){ |
2672 |
var children = node.childNodes;
|
2673 |
if(children.length){
|
2674 |
while(node.childNodes.length){
|
2675 |
var last = node.childNodes[node.childNodes.length - 1]; |
2676 |
if(!this._isEmpty(last)){ |
2677 |
return;
|
2678 |
} |
2679 |
node.removeChild(last); |
2680 |
} |
2681 |
} |
2682 |
} |
2683 |
}); |
2684 |
|
2685 |
ddtm.TemplateTagNode = dojo.extend(function(tag, text){
|
2686 |
this.tag = tag;
|
2687 |
this.contents = text;
|
2688 |
}, |
2689 |
{ |
2690 |
mapping: {
|
2691 |
openblock: "{%", |
2692 |
closeblock: "%}", |
2693 |
openvariable: "{{", |
2694 |
closevariable: "}}", |
2695 |
openbrace: "{", |
2696 |
closebrace: "}", |
2697 |
opencomment: "{#", |
2698 |
closecomment: "#}" |
2699 |
}, |
2700 |
render: function(context, buffer){ |
2701 |
this.contents.set(this.mapping[this.tag]); |
2702 |
return this.contents.render(context, buffer); |
2703 |
}, |
2704 |
unrender: function(context, buffer){ |
2705 |
return this.contents.unrender(context, buffer); |
2706 |
}, |
2707 |
clone: function(buffer){ |
2708 |
return new this.constructor(this.tag, this.contents.clone(buffer)); |
2709 |
} |
2710 |
}); |
2711 |
|
2712 |
ddtm.WidthRatioNode = dojo.extend(function(current, max, width, text){
|
2713 |
this.current = new dd._Filter(current); |
2714 |
this.max = new dd._Filter(max); |
2715 |
this.width = width;
|
2716 |
this.contents = text;
|
2717 |
}, |
2718 |
{ |
2719 |
render: function(context, buffer){ |
2720 |
var current = +this.current.resolve(context); |
2721 |
var max = +this.max.resolve(context); |
2722 |
if(typeof current != "number" || typeof max != "number" || !max){ |
2723 |
this.contents.set(""); |
2724 |
}else{
|
2725 |
this.contents.set("" + Math.round((current / max) * this.width)); |
2726 |
} |
2727 |
return this.contents.render(context, buffer); |
2728 |
}, |
2729 |
unrender: function(context, buffer){ |
2730 |
return this.contents.unrender(context, buffer); |
2731 |
}, |
2732 |
clone: function(buffer){ |
2733 |
return new this.constructor(this.current.getExpression(), this.max.getExpression(), this.width, this.contents.clone(buffer)); |
2734 |
} |
2735 |
}); |
2736 |
|
2737 |
ddtm.WithNode = dojo.extend(function(target, alias, nodelist){
|
2738 |
this.target = new dd._Filter(target); |
2739 |
this.alias = alias;
|
2740 |
this.nodelist = nodelist;
|
2741 |
}, |
2742 |
{ |
2743 |
render: function(context, buffer){ |
2744 |
var target = this.target.resolve(context); |
2745 |
context = context.push(); |
2746 |
context[this.alias] = target;
|
2747 |
buffer = this.nodelist.render(context, buffer);
|
2748 |
context = context.pop(); |
2749 |
return buffer;
|
2750 |
}, |
2751 |
unrender: function(context, buffer){ |
2752 |
return buffer;
|
2753 |
}, |
2754 |
clone: function(buffer){ |
2755 |
return new this.constructor(this.target.getExpression(), this.alias, this.nodelist.clone(buffer)); |
2756 |
} |
2757 |
}); |
2758 |
|
2759 |
dojo.mixin(ddtm, { |
2760 |
comment: function(parser, token){ |
2761 |
// summary: Ignore everything between {% comment %} and {% endcomment %}
|
2762 |
parser.skip_past("endcomment");
|
2763 |
return dd._noOpNode;
|
2764 |
}, |
2765 |
debug: function(parser, token){ |
2766 |
// summary: Output the current context, maybe add more stuff later.
|
2767 |
return new ddtm.DebugNode(parser.create_text_node()); |
2768 |
}, |
2769 |
filter: function(parser, token){ |
2770 |
// summary: Filter the contents of the blog through variable filters.
|
2771 |
var rest = token.contents.split(null, 1)[1]; |
2772 |
var varnode = parser.create_variable_node("var|" + rest); |
2773 |
var nodelist = parser.parse(["endfilter"]); |
2774 |
parser.next_token(); |
2775 |
return new ddtm.FilterNode(varnode, nodelist); |
2776 |
}, |
2777 |
firstof: function(parser, token){ |
2778 |
var parts = token.split_contents().slice(1); |
2779 |
if(!parts.length){
|
2780 |
throw new Error("'firstof' statement requires at least one argument"); |
2781 |
} |
2782 |
return new ddtm.FirstOfNode(parts, parser.create_text_node()); |
2783 |
}, |
2784 |
spaceless: function(parser, token){ |
2785 |
var nodelist = parser.parse(["endspaceless"]); |
2786 |
parser.delete_first_token(); |
2787 |
return new ddtm.SpacelessNode(nodelist, parser.create_text_node()); |
2788 |
}, |
2789 |
templatetag: function(parser, token){ |
2790 |
var parts = token.contents.split();
|
2791 |
if(parts.length != 2){ |
2792 |
throw new Error("'templatetag' statement takes one argument"); |
2793 |
} |
2794 |
var tag = parts[1]; |
2795 |
var mapping = ddtm.TemplateTagNode.prototype.mapping;
|
2796 |
if(!mapping[tag]){
|
2797 |
var keys = [];
|
2798 |
for(var key in mapping){ |
2799 |
keys.push(key); |
2800 |
} |
2801 |
throw new Error("Invalid templatetag argument: '" + tag + "'. Must be one of: " + keys.join(", ")); |
2802 |
} |
2803 |
return new ddtm.TemplateTagNode(tag, parser.create_text_node()); |
2804 |
}, |
2805 |
widthratio: function(parser, token){ |
2806 |
var parts = token.contents.split();
|
2807 |
if(parts.length != 4){ |
2808 |
throw new Error("widthratio takes three arguments"); |
2809 |
} |
2810 |
var width = +parts[3]; |
2811 |
if(typeof width != "number"){ |
2812 |
throw new Error("widthratio final argument must be an integer"); |
2813 |
} |
2814 |
return new ddtm.WidthRatioNode(parts[1], parts[2], width, parser.create_text_node()); |
2815 |
}, |
2816 |
with_: function(parser, token){ |
2817 |
var parts = token.split_contents();
|
2818 |
if(parts.length != 4 || parts[2] != "as"){ |
2819 |
throw new Error("do_width expected format as 'with value as name'"); |
2820 |
} |
2821 |
var nodelist = parser.parse(["endwith"]); |
2822 |
parser.next_token(); |
2823 |
return new ddtm.WithNode(parts[1], parts[3], nodelist); |
2824 |
} |
2825 |
}); |
2826 |
})(); |
2827 |
|
2828 |
} |
2829 |
|
2830 |
if(!dojo._hasResource["dojox.dtl.ext-dojo.NodeList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
2831 |
dojo._hasResource["dojox.dtl.ext-dojo.NodeList"] = true; |
2832 |
dojo.provide("dojox.dtl.ext-dojo.NodeList");
|
2833 |
|
2834 |
|
2835 |
dojo.extend(dojo.NodeList, { |
2836 |
dtl: function(template, context){ |
2837 |
// template: dojox.dtl.__StringArgs|String
|
2838 |
// The template string or location
|
2839 |
// context: dojox.dtl.__ObjectArgs|Object
|
2840 |
// The context object or location
|
2841 |
var d = dojox.dtl;
|
2842 |
|
2843 |
var self = this; |
2844 |
var render = function(template, context){ |
2845 |
var content = template.render(new d._Context(context)); |
2846 |
self.forEach(function(node){
|
2847 |
node.innerHTML = content; |
2848 |
}); |
2849 |
} |
2850 |
|
2851 |
d.text._resolveTemplateArg(template).addCallback(function(templateString){
|
2852 |
template = new d.Template(templateString);
|
2853 |
d.text._resolveContextArg(context).addCallback(function(context){
|
2854 |
render(template, context); |
2855 |
}); |
2856 |
}); |
2857 |
|
2858 |
return this; |
2859 |
} |
2860 |
}); |
2861 |
|
2862 |
} |
2863 |
|