Subversion Repositories Applications.papyrus

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2150 mathias 1
/**
2
 *
3
 * Date picker
4
 * Author: Stefan Petre www.eyecon.ro
5
 *
6
 */
7
(function ($) {
8
	var DatePicker = function () {
9
		var	ids = {},
10
			tpl = {
11
				wrapper: '<div class="datepicker"><div class="datepickerBorderT" /><div class="datepickerBorderB" /><div class="datepickerBorderL" /><div class="datepickerBorderR" /><div class="datepickerBorderTL" /><div class="datepickerBorderTR" /><div class="datepickerBorderBL" /><div class="datepickerBorderBR" /><div class="datepickerContainer"><table cellspacing="0" cellpadding="0"><tbody><tr></tr></tbody></table></div></div>',
12
				head: [
13
					'<td>',
14
					'<table cellspacing="0" cellpadding="0">',
15
						'<thead>',
16
							'<tr>',
17
								'<th class="datepickerGoPrev"><a href="#"><span><%=prev%></span></a></th>',
18
								'<th colspan="6" class="datepickerMonth"><a href="#"><span></span></a></th>',
19
								'<th class="datepickerGoNext"><a href="#"><span><%=next%></span></a></th>',
20
							'</tr>',
21
							'<tr class="datepickerDoW">',
22
								'<th><span><%=week%></span></th>',
23
								'<th><span><%=day1%></span></th>',
24
								'<th><span><%=day2%></span></th>',
25
								'<th><span><%=day3%></span></th>',
26
								'<th><span><%=day4%></span></th>',
27
								'<th><span><%=day5%></span></th>',
28
								'<th><span><%=day6%></span></th>',
29
								'<th><span><%=day7%></span></th>',
30
							'</tr>',
31
						'</thead>',
32
					'</table></td>'
33
				],
34
				space : '<td class="datepickerSpace"><div></div></td>',
35
				days: [
36
					'<tbody class="datepickerDays">',
37
						'<tr>',
38
							'<th class="datepickerWeek"><a href="#"><span><%=weeks[0].week%></span></a></th>',
39
							'<td class="<%=weeks[0].days[0].classname%>"><a href="#"><span><%=weeks[0].days[0].text%></span></a></td>',
40
							'<td class="<%=weeks[0].days[1].classname%>"><a href="#"><span><%=weeks[0].days[1].text%></span></a></td>',
41
							'<td class="<%=weeks[0].days[2].classname%>"><a href="#"><span><%=weeks[0].days[2].text%></span></a></td>',
42
							'<td class="<%=weeks[0].days[3].classname%>"><a href="#"><span><%=weeks[0].days[3].text%></span></a></td>',
43
							'<td class="<%=weeks[0].days[4].classname%>"><a href="#"><span><%=weeks[0].days[4].text%></span></a></td>',
44
							'<td class="<%=weeks[0].days[5].classname%>"><a href="#"><span><%=weeks[0].days[5].text%></span></a></td>',
45
							'<td class="<%=weeks[0].days[6].classname%>"><a href="#"><span><%=weeks[0].days[6].text%></span></a></td>',
46
						'</tr>',
47
						'<tr>',
48
							'<th class="datepickerWeek"><a href="#"><span><%=weeks[1].week%></span></a></th>',
49
							'<td class="<%=weeks[1].days[0].classname%>"><a href="#"><span><%=weeks[1].days[0].text%></span></a></td>',
50
							'<td class="<%=weeks[1].days[1].classname%>"><a href="#"><span><%=weeks[1].days[1].text%></span></a></td>',
51
							'<td class="<%=weeks[1].days[2].classname%>"><a href="#"><span><%=weeks[1].days[2].text%></span></a></td>',
52
							'<td class="<%=weeks[1].days[3].classname%>"><a href="#"><span><%=weeks[1].days[3].text%></span></a></td>',
53
							'<td class="<%=weeks[1].days[4].classname%>"><a href="#"><span><%=weeks[1].days[4].text%></span></a></td>',
54
							'<td class="<%=weeks[1].days[5].classname%>"><a href="#"><span><%=weeks[1].days[5].text%></span></a></td>',
55
							'<td class="<%=weeks[1].days[6].classname%>"><a href="#"><span><%=weeks[1].days[6].text%></span></a></td>',
56
						'</tr>',
57
						'<tr>',
58
							'<th class="datepickerWeek"><a href="#"><span><%=weeks[2].week%></span></a></th>',
59
							'<td class="<%=weeks[2].days[0].classname%>"><a href="#"><span><%=weeks[2].days[0].text%></span></a></td>',
60
							'<td class="<%=weeks[2].days[1].classname%>"><a href="#"><span><%=weeks[2].days[1].text%></span></a></td>',
61
							'<td class="<%=weeks[2].days[2].classname%>"><a href="#"><span><%=weeks[2].days[2].text%></span></a></td>',
62
							'<td class="<%=weeks[2].days[3].classname%>"><a href="#"><span><%=weeks[2].days[3].text%></span></a></td>',
63
							'<td class="<%=weeks[2].days[4].classname%>"><a href="#"><span><%=weeks[2].days[4].text%></span></a></td>',
64
							'<td class="<%=weeks[2].days[5].classname%>"><a href="#"><span><%=weeks[2].days[5].text%></span></a></td>',
65
							'<td class="<%=weeks[2].days[6].classname%>"><a href="#"><span><%=weeks[2].days[6].text%></span></a></td>',
66
						'</tr>',
67
						'<tr>',
68
							'<th class="datepickerWeek"><a href="#"><span><%=weeks[3].week%></span></a></th>',
69
							'<td class="<%=weeks[3].days[0].classname%>"><a href="#"><span><%=weeks[3].days[0].text%></span></a></td>',
70
							'<td class="<%=weeks[3].days[1].classname%>"><a href="#"><span><%=weeks[3].days[1].text%></span></a></td>',
71
							'<td class="<%=weeks[3].days[2].classname%>"><a href="#"><span><%=weeks[3].days[2].text%></span></a></td>',
72
							'<td class="<%=weeks[3].days[3].classname%>"><a href="#"><span><%=weeks[3].days[3].text%></span></a></td>',
73
							'<td class="<%=weeks[3].days[4].classname%>"><a href="#"><span><%=weeks[3].days[4].text%></span></a></td>',
74
							'<td class="<%=weeks[3].days[5].classname%>"><a href="#"><span><%=weeks[3].days[5].text%></span></a></td>',
75
							'<td class="<%=weeks[3].days[6].classname%>"><a href="#"><span><%=weeks[3].days[6].text%></span></a></td>',
76
						'</tr>',
77
						'<tr>',
78
							'<th class="datepickerWeek"><a href="#"><span><%=weeks[4].week%></span></a></th>',
79
							'<td class="<%=weeks[4].days[0].classname%>"><a href="#"><span><%=weeks[4].days[0].text%></span></a></td>',
80
							'<td class="<%=weeks[4].days[1].classname%>"><a href="#"><span><%=weeks[4].days[1].text%></span></a></td>',
81
							'<td class="<%=weeks[4].days[2].classname%>"><a href="#"><span><%=weeks[4].days[2].text%></span></a></td>',
82
							'<td class="<%=weeks[4].days[3].classname%>"><a href="#"><span><%=weeks[4].days[3].text%></span></a></td>',
83
							'<td class="<%=weeks[4].days[4].classname%>"><a href="#"><span><%=weeks[4].days[4].text%></span></a></td>',
84
							'<td class="<%=weeks[4].days[5].classname%>"><a href="#"><span><%=weeks[4].days[5].text%></span></a></td>',
85
							'<td class="<%=weeks[4].days[6].classname%>"><a href="#"><span><%=weeks[4].days[6].text%></span></a></td>',
86
						'</tr>',
87
						'<tr>',
88
							'<th class="datepickerWeek"><a href="#"><span><%=weeks[5].week%></span></a></th>',
89
							'<td class="<%=weeks[5].days[0].classname%>"><a href="#"><span><%=weeks[5].days[0].text%></span></a></td>',
90
							'<td class="<%=weeks[5].days[1].classname%>"><a href="#"><span><%=weeks[5].days[1].text%></span></a></td>',
91
							'<td class="<%=weeks[5].days[2].classname%>"><a href="#"><span><%=weeks[5].days[2].text%></span></a></td>',
92
							'<td class="<%=weeks[5].days[3].classname%>"><a href="#"><span><%=weeks[5].days[3].text%></span></a></td>',
93
							'<td class="<%=weeks[5].days[4].classname%>"><a href="#"><span><%=weeks[5].days[4].text%></span></a></td>',
94
							'<td class="<%=weeks[5].days[5].classname%>"><a href="#"><span><%=weeks[5].days[5].text%></span></a></td>',
95
							'<td class="<%=weeks[5].days[6].classname%>"><a href="#"><span><%=weeks[5].days[6].text%></span></a></td>',
96
						'</tr>',
97
					'</tbody>'
98
				],
99
				months: [
100
					'<tbody class="<%=className%>">',
101
						'<tr>',
102
							'<td colspan="2"><a href="#"><span><%=data[0]%></span></a></td>',
103
							'<td colspan="2"><a href="#"><span><%=data[1]%></span></a></td>',
104
							'<td colspan="2"><a href="#"><span><%=data[2]%></span></a></td>',
105
							'<td colspan="2"><a href="#"><span><%=data[3]%></span></a></td>',
106
						'</tr>',
107
						'<tr>',
108
							'<td colspan="2"><a href="#"><span><%=data[4]%></span></a></td>',
109
							'<td colspan="2"><a href="#"><span><%=data[5]%></span></a></td>',
110
							'<td colspan="2"><a href="#"><span><%=data[6]%></span></a></td>',
111
							'<td colspan="2"><a href="#"><span><%=data[7]%></span></a></td>',
112
						'</tr>',
113
						'<tr>',
114
							'<td colspan="2"><a href="#"><span><%=data[8]%></span></a></td>',
115
							'<td colspan="2"><a href="#"><span><%=data[9]%></span></a></td>',
116
							'<td colspan="2"><a href="#"><span><%=data[10]%></span></a></td>',
117
							'<td colspan="2"><a href="#"><span><%=data[11]%></span></a></td>',
118
						'</tr>',
119
					'</tbody>'
120
				]
121
			},
122
			defaults = {
123
				flat: false,
124
				starts: 1,
125
				prev: '&#9664;',
126
				next: '&#9654;',
127
				lastSel: false,
128
				mode: 'single',
129
				calendars: 1,
130
				format: 'Y-m-d',
131
				position: 'bottom',
132
				eventName: 'click',
133
				onRender: function(){return {};},
134
				onChange: function(){return true;},
135
				onShow: function(){return true;},
136
				onBeforeShow: function(){return true;},
137
				onHide: function(){return true;},
138
				locale: {
139
					days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
140
					daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
141
					daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
142
					months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
143
					monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
144
					weekMin: 'wk'
145
				}
146
			},
147
			fill = function(el) {
148
				var options = $(el).data('datepicker');
149
				var cal = $(el);
150
				var currentCal = Math.floor(options.calendars/2), date, data, dow, month, cnt = 0, week, days, indic, indic2, html, tblCal;
151
				cal.find('td>table tbody').remove();
152
				for (var i = 0; i < options.calendars; i++) {
153
					date = new Date(options.current);
154
					date.addMonths(-currentCal + i);
155
					tblCal = cal.find('table').eq(i+1);
156
					switch (tblCal[0].className) {
157
						case 'datepickerViewDays':
158
							dow = formatDate(date, 'B, Y');
159
							break;
160
						case 'datepickerViewMonths':
161
							dow = date.getFullYear();
162
							break;
163
						case 'datepickerViewYears':
164
							dow = (date.getFullYear()-6) + ' - ' + (date.getFullYear()+5);
165
							break;
166
					}
167
					tblCal.find('thead tr:first th:eq(1) span').text(dow);
168
					dow = date.getFullYear()-6;
169
					data = {
170
						data: [],
171
						className: 'datepickerYears'
172
					}
173
					for ( var j = 0; j < 12; j++) {
174
						data.data.push(dow + j);
175
					}
176
					html = tmpl(tpl.months.join(''), data);
177
					date.setDate(1);
178
					data = {weeks:[], test: 10};
179
					month = date.getMonth();
180
					var dow = (date.getDay() - options.starts) % 7;
181
					date.addDays(-(dow + (dow < 0 ? 7 : 0)));
182
					week = -1;
183
					cnt = 0;
184
					while (cnt < 42) {
185
						indic = parseInt(cnt/7,10);
186
						indic2 = cnt%7;
187
						if (!data.weeks[indic]) {
188
							week = date.getWeekNumber();
189
							data.weeks[indic] = {
190
								week: week,
191
								days: []
192
							};
193
						}
194
						data.weeks[indic].days[indic2] = {
195
							text: date.getDate(),
196
							classname: []
197
						};
198
						if (month != date.getMonth()) {
199
							data.weeks[indic].days[indic2].classname.push('datepickerNotInMonth');
200
						}
201
						if (date.getDay() == 0) {
202
							data.weeks[indic].days[indic2].classname.push('datepickerSunday');
203
						}
204
						if (date.getDay() == 6) {
205
							data.weeks[indic].days[indic2].classname.push('datepickerSaturday');
206
						}
207
						var fromUser = options.onRender(date);
208
						var val = date.valueOf();
209
						if (fromUser.selected || options.date == val || $.inArray(val, options.date) > -1 || (options.mode == 'range' && val >= options.date[0] && val <= options.date[1])) {
210
							data.weeks[indic].days[indic2].classname.push('datepickerSelected');
211
						}
212
						if (fromUser.disabled) {
213
							data.weeks[indic].days[indic2].classname.push('datepickerDisabled');
214
						}
215
						if (fromUser.className) {
216
							data.weeks[indic].days[indic2].classname.push(fromUser.className);
217
						}
218
						data.weeks[indic].days[indic2].classname = data.weeks[indic].days[indic2].classname.join(' ');
219
						cnt++;
220
						date.addDays(1);
221
					}
222
					html = tmpl(tpl.days.join(''), data) + html;
223
					data = {
224
						data: options.locale.monthsShort,
225
						className: 'datepickerMonths'
226
					};
227
					html = tmpl(tpl.months.join(''), data) + html;
228
					tblCal.append(html);
229
				}
230
			},
231
			parseDate = function (date, format) {
232
				if (date.constructor == Date) {
233
					return new Date(date);
234
				}
235
				var parts = date.split(/\W+/);
236
				var against = format.split(/\W+/), d, m, y, h, min, now = new Date();
237
				for (var i = 0; i < parts.length; i++) {
238
					switch (against[i]) {
239
						case 'd':
240
						case 'e':
241
							d = parseInt(parts[i],10);
242
							break;
243
						case 'm':
244
							m = parseInt(parts[i], 10) - 1;
245
							break;
246
						case 'Y':
247
						case 'y':
248
							y = parseInt(parts[i], 10);
249
							y += y > 100 ? 0 : (y < 29 ? 2000 : 1900);
250
							break;
251
						case 'H':
252
						case 'I':
253
						case 'k':
254
						case 'l':
255
							h = parseInt(parts[i], 10);
256
							break;
257
						case 'P':
258
						case 'p':
259
							if (/pm/i.test(parts[i]) && h < 12) {
260
								h += 12;
261
							} else if (/am/i.test(parts[i]) && h >= 12) {
262
								h -= 12;
263
							}
264
							break;
265
						case 'M':
266
							min = parseInt(parts[i], 10);
267
							break;
268
					}
269
				}
270
				return new Date(
271
					y||now.getFullYear(),
272
					m||now.getMonth(),
273
					d||now.getDate(),
274
					h||now.getHours(),
275
					min||now.getMinutes(),
276
 
277
				);
278
			},
279
			formatDate = function(date, format) {
280
				var m = date.getMonth();
281
				var d = date.getDate();
282
				var y = date.getFullYear();
283
				var wn = date.getWeekNumber();
284
				var w = date.getDay();
285
				var s = {};
286
				var hr = date.getHours();
287
				var pm = (hr >= 12);
288
				var ir = (pm) ? (hr - 12) : hr;
289
				var dy = date.getDayOfYear();
290
				if (ir == 0) {
291
					ir = 12;
292
				}
293
				var min = date.getMinutes();
294
				var sec = date.getSeconds();
295
				var parts = format.split(''), part;
296
				for ( var i = 0; i < parts.length; i++ ) {
297
					part = parts[i];
298
					switch (parts[i]) {
299
						case 'a':
300
							part = date.getDayName();
301
							break;
302
						case 'A':
303
							part = date.getDayName(true);
304
							break;
305
						case 'b':
306
							part = date.getMonthName();
307
							break;
308
						case 'B':
309
							part = date.getMonthName(true);
310
							break;
311
						case 'C':
312
							part = 1 + Math.floor(y / 100);
313
							break;
314
						case 'd':
315
							part = (d < 10) ? ("0" + d) : d;
316
							break;
317
						case 'e':
318
							part = d;
319
							break;
320
						case 'H':
321
							part = (hr < 10) ? ("0" + hr) : hr;
322
							break;
323
						case 'I':
324
							part = (ir < 10) ? ("0" + ir) : ir;
325
							break;
326
						case 'j':
327
							part = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy;
328
							break;
329
						case 'k':
330
							part = hr;
331
							break;
332
						case 'l':
333
							part = ir;
334
							break;
335
						case 'm':
336
							part = (m < 9) ? ("0" + (1+m)) : (1+m);
337
							break;
338
						case 'M':
339
							part = (min < 10) ? ("0" + min) : min;
340
							break;
341
						case 'p':
342
						case 'P':
343
							part = pm ? "PM" : "AM";
344
							break;
345
						case 's':
346
							part = Math.floor(date.getTime() / 1000);
347
							break;
348
						case 'S':
349
							part = (sec < 10) ? ("0" + sec) : sec;
350
							break;
351
						case 'u':
352
							part = w + 1;
353
							break;
354
						case 'w':
355
							part = w;
356
							break;
357
						case 'y':
358
							part = ('' + y).substr(2, 2);
359
							break;
360
						case 'Y':
361
							part = y;
362
							break;
363
					}
364
					parts[i] = part;
365
				}
366
				return parts.join('');
367
			},
368
			extendDate = function(options) {
369
				if (Date.prototype.tempDate) {
370
					return;
371
				}
372
				Date.prototype.tempDate = null;
373
				Date.prototype.months = options.months;
374
				Date.prototype.monthsShort = options.monthsShort;
375
				Date.prototype.days = options.days;
376
				Date.prototype.daysShort = options.daysShort;
377
				Date.prototype.getMonthName = function(fullName) {
378
					return this[fullName ? 'months' : 'monthsShort'][this.getMonth()];
379
				};
380
				Date.prototype.getDayName = function(fullName) {
381
					return this[fullName ? 'days' : 'daysShort'][this.getDay()];
382
				};
383
				Date.prototype.addDays = function (n) {
384
					this.setDate(this.getDate() + n);
385
					this.tempDate = this.getDate();
386
				};
387
				Date.prototype.addMonths = function (n) {
388
					if (this.tempDate == null) {
389
						this.tempDate = this.getDate();
390
					}
391
					this.setDate(1);
392
					this.setMonth(this.getMonth() + n);
393
					this.setDate(Math.min(this.tempDate, this.getMaxDays()));
394
				};
395
				Date.prototype.addYears = function (n) {
396
					if (this.tempDate == null) {
397
						this.tempDate = this.getDate();
398
					}
399
					this.setDate(1);
400
					this.setFullYear(this.getFullYear() + n);
401
					this.setDate(Math.min(this.tempDate, this.getMaxDays()));
402
				};
403
				Date.prototype.getMaxDays = function() {
404
					var tmpDate = new Date(Date.parse(this)),
405
						d = 28, m;
406
					m = tmpDate.getMonth();
407
					d = 28;
408
					while (tmpDate.getMonth() == m) {
409
						d ++;
410
						tmpDate.setDate(d);
411
					}
412
					return d - 1;
413
				};
414
				Date.prototype.getFirstDay = function() {
415
					var tmpDate = new Date(Date.parse(this));
416
					tmpDate.setDate(1);
417
					return tmpDate.getDay();
418
				};
419
				Date.prototype.getWeekNumber = function() {
420
					var tempDate = new Date(this);
421
					tempDate.setDate(tempDate.getDate() - (tempDate.getDay() + 6) % 7 + 3);
422
					var dms = tempDate.valueOf();
423
					tempDate.setMonth(0);
424
					tempDate.setDate(4);
425
					return Math.round((dms - tempDate.valueOf()) / (604800000)) + 1;
426
				};
427
				Date.prototype.getDayOfYear = function() {
428
					var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
429
					var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0);
430
					var time = now - then;
431
					return Math.floor(time / 24*60*60*1000);
432
				};
433
			},
434
			layout = function (el) {
435
				var options = $(el).data('datepicker');
436
				var cal = $('#' + options.id);
437
				if (!options.extraHeight) {
438
					var divs = $(el).find('div');
439
					options.extraHeight = divs.get(0).offsetHeight + divs.get(1).offsetHeight;
440
					options.extraWidth = divs.get(2).offsetWidth + divs.get(3).offsetWidth;
441
				}
442
				var tbl = cal.find('table:first').get(0);
443
				var width = tbl.offsetWidth;
444
				var height = tbl.offsetHeight;
445
				cal.css({
446
					width: width + options.extraWidth + 'px',
447
					height: height + options.extraHeight + 'px'
448
				}).find('div.datepickerContainer').css({
449
					width: width + 'px',
450
					height: height + 'px'
451
				});
452
			},
453
			click = function(ev) {
454
				if ($(ev.target).is('span')) {
455
					ev.target = ev.target.parentNode;
456
				}
457
				var el = $(ev.target);
458
				if (el.is('a')) {
459
					ev.target.blur();
460
					if (el.hasClass('datepickerDisabled')) {
461
						return false;
462
					}
463
					var options = $(this).data('datepicker');
464
					var parentEl = el.parent();
465
					var tblEl = parentEl.parent().parent().parent();
466
					var tblIndex = $('table', this).index(tblEl.get(0)) - 1;
467
					var tmp = new Date(options.current);
468
					var changed = false;
469
					var fillIt = false;
470
					if (parentEl.is('th')) {
471
						if (parentEl.hasClass('datepickerWeek') && options.mode == 'range' && !parentEl.next().hasClass('datepickerDisabled')) {
472
							var val = parseInt(parentEl.next().text(), 10);
473
							tmp.addMonths(tblIndex - Math.floor(options.calendars/2));
474
							if (parentEl.next().hasClass('datepickerNotInMonth')) {
475
								tmp.addMonths(val > 15 ? -1 : 1);
476
							}
477
							tmp.setDate(val);
478
							options.date[0] = (tmp.setHours(0,0,0,0)).valueOf();
479
							tmp.setHours(23,59,59,0);
480
							tmp.addDays(6);
481
							options.date[1] = tmp.valueOf();
482
							fillIt = true;
483
							changed = true;
484
							options.lastSel = false;
485
						} else if (parentEl.hasClass('datepickerMonth')) {
486
							tmp.addMonths(tblIndex - Math.floor(options.calendars/2));
487
							switch (tblEl.get(0).className) {
488
								case 'datepickerViewDays':
489
									tblEl.get(0).className = 'datepickerViewMonths';
490
									el.find('span').text(tmp.getFullYear());
491
									break;
492
								case 'datepickerViewMonths':
493
									tblEl.get(0).className = 'datepickerViewYears';
494
									el.find('span').text((tmp.getFullYear()-6) + ' - ' + (tmp.getFullYear()+5));
495
									break;
496
								case 'datepickerViewYears':
497
									tblEl.get(0).className = 'datepickerViewDays';
498
									el.find('span').text(formatDate(tmp, 'B, Y'));
499
									break;
500
							}
501
						} else if (parentEl.parent().parent().is('thead')) {
502
							switch (tblEl.get(0).className) {
503
								case 'datepickerViewDays':
504
									options.current.addMonths(parentEl.hasClass('datepickerGoPrev') ? -1 : 1);
505
									break;
506
								case 'datepickerViewMonths':
507
									options.current.addYears(parentEl.hasClass('datepickerGoPrev') ? -1 : 1);
508
									break;
509
								case 'datepickerViewYears':
510
									options.current.addYears(parentEl.hasClass('datepickerGoPrev') ? -12 : 12);
511
									break;
512
							}
513
							fillIt = true;
514
						}
515
					} else if (parentEl.is('td') && !parentEl.hasClass('datepickerDisabled')) {
516
						switch (tblEl.get(0).className) {
517
							case 'datepickerViewMonths':
518
								options.current.setMonth(tblEl.find('tbody.datepickerMonths td').index(parentEl));
519
								options.current.setFullYear(parseInt(tblEl.find('thead th.datepickerMonth span').text(), 10));
520
								options.current.addMonths(Math.floor(options.calendars/2) - tblIndex);
521
								tblEl.get(0).className = 'datepickerViewDays';
522
								break;
523
							case 'datepickerViewYears':
524
								options.current.setFullYear(parseInt(el.text(), 10));
525
								tblEl.get(0).className = 'datepickerViewMonths';
526
								break;
527
							default:
528
								var val = parseInt(el.text(), 10);
529
								tmp.addMonths(tblIndex - Math.floor(options.calendars/2));
530
								if (parentEl.hasClass('datepickerNotInMonth')) {
531
									tmp.addMonths(val > 15 ? -1 : 1);
532
								}
533
								tmp.setDate(val);
534
								switch (options.mode) {
535
									case 'multiple':
536
										val = (tmp.setHours(0,0,0,0)).valueOf();
537
										if ($.inArray(val, options.date) > -1) {
538
											$.each(options.date, function(nr, dat){
539
												if (dat == val) {
540
													delete options.date[nr];
541
													return false;
542
												}
543
											});
544
										} else {
545
											options.date.push(val);
546
										}
547
										break;
548
									case 'range':
549
										if (!options.lastSel) {
550
											options.date[0] = (tmp.setHours(0,0,0,0)).valueOf();
551
										}
552
										val = (tmp.setHours(23,59,59,0)).valueOf();
553
										if (val < options.date[0]) {
554
											options.date[1] = options.date[0] + 86399000;
555
											options.date[0] = val - 86399000;
556
										} else {
557
											options.date[1] = val;
558
										}
559
										options.lastSel = !options.lastSel;
560
										break;
561
									default:
562
										options.date = tmp.valueOf();
563
										break;
564
								}
565
								break;
566
						}
567
						fillIt = true;
568
						changed = true;
569
					}
570
					if (fillIt) {
571
						fill(this);
572
					}
573
					if (changed) {
574
						options.onChange.apply(this, prepareDate(options));
575
					}
576
				}
577
				return false;
578
			},
579
			prepareDate = function (options) {
580
				var tmp;
581
				if (options.mode == 'single') {
582
					tmp = new Date(options.date);
583
					return [formatDate(tmp, options.format), tmp];
584
				} else {
585
					tmp = [[],[]];
586
					$.each(options.date, function(nr, val){
587
						var date = new Date(val);
588
						tmp[0].push(formatDate(date, options.format));
589
						tmp[1].push(date);
590
					});
591
					return tmp;
592
				}
593
			},
594
			getViewport = function () {
595
				var m = document.compatMode == 'CSS1Compat';
596
				return {
597
					l : window.pageXOffset || (m ? document.documentElement.scrollLeft : document.body.scrollLeft),
598
					t : window.pageYOffset || (m ? document.documentElement.scrollTop : document.body.scrollTop),
599
					w : window.innerWidth || (m ? document.documentElement.clientWidth : document.body.clientWidth),
600
					h : window.innerHeight || (m ? document.documentElement.clientHeight : document.body.clientHeight)
601
				};
602
			},
603
			isChildOf = function(parentEl, el, container) {
604
				if (parentEl == el) {
605
					return true;
606
				}
607
				if (parentEl.contains) {
608
					return parentEl.contains(el);
609
				}
610
				if ( parentEl.compareDocumentPosition ) {
611
					return !!(parentEl.compareDocumentPosition(el) & 16);
612
				}
613
				var prEl = el.parentNode;
614
				while(prEl && prEl != container) {
615
					if (prEl == parentEl)
616
						return true;
617
					prEl = prEl.parentNode;
618
				}
619
				return false;
620
			},
621
			show = function (ev) {
622
				var cal = $('#' + $(this).data('datepickerId'));
623
				if (!cal.is(':visible')) {
624
					var calEl = cal.get(0);
625
					var options = cal.data('datepicker');
626
					options.onBeforeShow.apply(this, [cal.get(0)]);
627
					var pos = $(this).offset();
628
					var viewPort = getViewport();
629
					var top = pos.top;
630
					var left = pos.left;
631
					var oldDisplay = $.curCSS(calEl, 'display');
632
					cal.css({
633
						visibility: 'hidden',
634
						display: 'block'
635
					});
636
					layout(calEl);
637
					switch (options.position){
638
						case 'top':
639
							top -= calEl.offsetHeight;
640
							break;
641
						case 'left':
642
							left -= calEl.offsetWidth;
643
							break;
644
						case 'right':
645
							left += this.offsetWidth;
646
							break;
647
						case 'bottom':
648
							top += this.offsetHeight;
649
							break;
650
					}
651
					if (top + calEl.offsetHeight > viewPort.t + viewPort.h) {
652
						top = pos.top  - calEl.offsetHeight;
653
					}
654
					if (top < viewPort.t) {
655
						top = pos.top + this.offsetHeight + calEl.offsetHeight;
656
					}
657
					if (left + calEl.offsetWidth > viewPort.l + viewPort.w) {
658
						left = pos.left - calEl.offsetWidth;
659
					}
660
					if (left < viewPort.l) {
661
						left = pos.left + this.offsetWidth
662
					}
663
					cal.css({
664
						visibility: 'visible',
665
						display: 'block',
666
						top: top + 'px',
667
						left: left + 'px'
668
					});
669
					if (options.onShow.apply(this, [cal.get(0)]) != false) {
670
						cal.show();
671
					}
672
					$(document).bind('mousedown', {cal: cal, trigger: this}, hide);
673
				}
674
				return false;
675
			},
676
			hide = function (ev) {
677
				if (ev.target != ev.data.trigger && !isChildOf(ev.data.cal.get(0), ev.target, ev.data.cal.get(0))) {
678
					if (ev.data.cal.data('datepicker').onHide.apply(this, [ev.data.cal.get(0)]) != false) {
679
						ev.data.cal.hide();
680
					}
681
					$(document).unbind('mousedown', hide);
682
				}
683
			};
684
		return {
685
			init: function(options){
686
				options = $.extend({}, defaults, options||{});
687
				extendDate(options.locale);
688
				options.calendars = Math.max(1, parseInt(options.calendars,10)||1);
689
				options.mode = /single|multiple|range/.test(options.mode) ? options.mode : 'single';
690
				return this.each(function(){
691
					if (!$(this).data('datepicker')) {
692
						if (options.date.constructor == String) {
693
							options.date = parseDate(options.date, options.format);
694
							options.date.setHours(0,0,0,0);
695
						}
696
						if (options.mode != 'single') {
697
							if (options.date.constructor != Array) {
698
								options.date = [options.date.valueOf()];
699
								if (options.mode == 'range') {
700
									options.date.push(((new Date(options.date[0])).setHours(23,59,59,0)).valueOf());
701
								}
702
							} else {
703
								for (var i = 0; i < options.date.length; i++) {
704
									options.date[i] = (parseDate(options.date[i], options.format).setHours(0,0,0,0)).valueOf();
705
								}
706
								if (options.mode == 'range') {
707
									options.date[1] = ((new Date(options.date[1])).setHours(23,59,59,0)).valueOf();
708
								}
709
							}
710
						} else {
711
							options.date = options.date.valueOf();
712
						}
713
						if (!options.current) {
714
							options.current = new Date();
715
						} else {
716
							options.current = parseDate(options.current, options.format);
717
						}
718
						options.current.setDate(1);
719
						options.current.setHours(0,0,0,0);
720
						var id = 'datepicker_' + parseInt(Math.random() * 1000), cnt;
721
						options.id = id;
722
						$(this).data('datepickerId', options.id);
723
						var cal = $(tpl.wrapper).attr('id', id).bind('click', click).data('datepicker', options);
724
						if (options.className) {
725
							cal.addClass(options.className);
726
						}
727
						for (var i = 0; i < options.calendars; i++) {
728
							cnt = options.starts;
729
							cal.find('tr:first').append(
730
								i > 0 ?  tpl.space: '',
731
								tmpl(tpl.head.join(''), {
732
									week: options.locale.weekMin,
733
									prev: options.prev,
734
									next: options.next,
735
									day1: options.locale.daysMin[(cnt++)%7],
736
									day2: options.locale.daysMin[(cnt++)%7],
737
									day3: options.locale.daysMin[(cnt++)%7],
738
									day4: options.locale.daysMin[(cnt++)%7],
739
									day5: options.locale.daysMin[(cnt++)%7],
740
									day6: options.locale.daysMin[(cnt++)%7],
741
									day7: options.locale.daysMin[(cnt++)%7]
742
								})
743
							);
744
						}
745
						cal.find('tr:first table').addClass('datepickerViewDays');
746
						fill(cal.get(0));
747
						if (options.flat) {
748
							cal.appendTo(this).show().css('position', 'relative');
749
							layout(cal.get(0));
750
						} else {
751
							cal.appendTo(document.body);
752
							$(this).bind(options.eventName, show);
753
						}
754
					}
755
				});
756
			},
757
			showPicker: function() {
758
				return this.each( function () {
759
					if ($(this).data('datepickerId')) {
760
						show.apply(this);
761
					}
762
				});
763
			},
764
			hidePicker: function() {
765
				return this.each( function () {
766
					if ($(this).data('datepickerId')) {
767
						$('#' + $(this).data('datepickerId')).hide();
768
					}
769
				});
770
			},
771
			setDate: function(date, shiftTo){
772
				return this.each(function(){
773
					if ($(this).data('datepickerId')) {
774
						var cal = $('#' + $(this).data('datepickerId'));
775
						var options = cal.data('datepicker');
776
						options.date = date;
777
						if (options.date.constructor == String) {
778
							options.date = parseDate(options.date, options.format);
779
							options.date.setHours(0,0,0,0);
780
						}
781
						if (options.mode != 'single') {
782
							if (options.date.constructor != Array) {
783
								options.date = [options.date.valueOf()];
784
								if (options.mode == 'range') {
785
									options.date.push(((new Date(options.date[0])).setHours(23,59,59,0)).valueOf());
786
								}
787
							} else {
788
								for (var i = 0; i < options.date.length; i++) {
789
									options.date[i] = (parseDate(options.date[i], options.format).setHours(0,0,0,0)).valueOf();
790
								}
791
								if (options.mode == 'range') {
792
									options.date[1] = ((new Date(options.date[1])).setHours(23,59,59,0)).valueOf();
793
								}
794
							}
795
						} else {
796
							options.date = options.date.valueOf();
797
						}
798
						if (shiftTo) {
799
							options.current = new Date (options.mode != 'single' ? options.date[0] : options.date);
800
						}
801
						fill(cal.get(0));
802
					}
803
				});
804
			},
805
			getDate: function(formated) {
806
				if (this.size() > 0) {
807
					return prepareDate($('#' + $(this).data('datepickerId')).data('datepicker'))[formated ? 0 : 1];
808
				}
809
			}
810
		};
811
	}();
812
	$.fn.extend({
813
		DatePicker: DatePicker.init,
814
		DatePickerHide: DatePicker.hide,
815
		DatePickerShow: DatePicker.show,
816
		DatePickerSetDate: DatePicker.setDate,
817
		DatePickerGetDate: DatePicker.getDate
818
	});
819
})(jQuery);
820
 
821
(function(){
822
  var cache = {};
823
 
824
  this.tmpl = function tmpl(str, data){
825
    // Figure out if we're getting a template, or if we need to
826
    // load the template - and be sure to cache the result.
827
    var fn = !/\W/.test(str) ?
828
      cache[str] = cache[str] ||
829
        tmpl(document.getElementById(str).innerHTML) :
830
 
831
      // Generate a reusable function that will serve as a template
832
      // generator (and which will be cached).
833
      new Function("obj",
834
        "var p=[],print=function(){p.push.apply(p,arguments);};" +
835
 
836
        // Introduce the data as local variables using with(){}
837
        "with(obj){p.push('" +
838
 
839
        // Convert the template into pure JavaScript
840
        str
841
          .replace(/[\r\t\n]/g, " ")
842
          .split("<%").join("\t")
843
          .replace(/((^|%>)[^\t]*)'/g, "$1\r")
844
          .replace(/\t=(.*?)%>/g, "',$1,'")
845
          .split("\t").join("');")
846
          .split("%>").join("p.push('")
847
          .split("\r").join("\\'")
848
      + "');}return p.join('');");
849
 
850
    // Provide some basic currying to the user
851
    return data ? fn( data ) : fn;
852
  };
853
})();