3 Jappix - An open social platform
\r
4 These are the datepicker JS script
\r
6 -------------------------------------------------
\r
8 Licenses: MIT, GPL, AGPL
\r
9 Authors: Stefan Petre, Vanaryon
\r
10 Last revision: 19/12/10
\r
15 var DatePicker = function () {
\r
18 years: 'datepickerViewYears',
\r
19 moths: 'datepickerViewMonths',
\r
20 days: 'datepickerViewDays'
\r
23 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>',
\r
26 '<table cellspacing="0" cellpadding="0">',
\r
29 '<th class="datepickerGoPrev"><a href="#"><span><%=prev%></span></a></th>',
\r
30 '<th colspan="6" class="datepickerMonth"><a href="#"><span></span></a></th>',
\r
31 '<th class="datepickerGoNext"><a href="#"><span><%=next%></span></a></th>',
\r
33 '<tr class="datepickerDoW">',
\r
34 '<th><span><%=week%></span></th>',
\r
35 '<th><span><%=day1%></span></th>',
\r
36 '<th><span><%=day2%></span></th>',
\r
37 '<th><span><%=day3%></span></th>',
\r
38 '<th><span><%=day4%></span></th>',
\r
39 '<th><span><%=day5%></span></th>',
\r
40 '<th><span><%=day6%></span></th>',
\r
41 '<th><span><%=day7%></span></th>',
\r
46 space : '<td class="datepickerSpace"><div></div></td>',
\r
48 '<tbody class="datepickerDays">',
\r
50 '<th class="datepickerWeek"><a href="#"><span><%=weeks[0].week%></span></a></th>',
\r
51 '<td class="<%=weeks[0].days[0].classname%>"><a href="#"><span><%=weeks[0].days[0].text%></span></a></td>',
\r
52 '<td class="<%=weeks[0].days[1].classname%>"><a href="#"><span><%=weeks[0].days[1].text%></span></a></td>',
\r
53 '<td class="<%=weeks[0].days[2].classname%>"><a href="#"><span><%=weeks[0].days[2].text%></span></a></td>',
\r
54 '<td class="<%=weeks[0].days[3].classname%>"><a href="#"><span><%=weeks[0].days[3].text%></span></a></td>',
\r
55 '<td class="<%=weeks[0].days[4].classname%>"><a href="#"><span><%=weeks[0].days[4].text%></span></a></td>',
\r
56 '<td class="<%=weeks[0].days[5].classname%>"><a href="#"><span><%=weeks[0].days[5].text%></span></a></td>',
\r
57 '<td class="<%=weeks[0].days[6].classname%>"><a href="#"><span><%=weeks[0].days[6].text%></span></a></td>',
\r
60 '<th class="datepickerWeek"><a href="#"><span><%=weeks[1].week%></span></a></th>',
\r
61 '<td class="<%=weeks[1].days[0].classname%>"><a href="#"><span><%=weeks[1].days[0].text%></span></a></td>',
\r
62 '<td class="<%=weeks[1].days[1].classname%>"><a href="#"><span><%=weeks[1].days[1].text%></span></a></td>',
\r
63 '<td class="<%=weeks[1].days[2].classname%>"><a href="#"><span><%=weeks[1].days[2].text%></span></a></td>',
\r
64 '<td class="<%=weeks[1].days[3].classname%>"><a href="#"><span><%=weeks[1].days[3].text%></span></a></td>',
\r
65 '<td class="<%=weeks[1].days[4].classname%>"><a href="#"><span><%=weeks[1].days[4].text%></span></a></td>',
\r
66 '<td class="<%=weeks[1].days[5].classname%>"><a href="#"><span><%=weeks[1].days[5].text%></span></a></td>',
\r
67 '<td class="<%=weeks[1].days[6].classname%>"><a href="#"><span><%=weeks[1].days[6].text%></span></a></td>',
\r
70 '<th class="datepickerWeek"><a href="#"><span><%=weeks[2].week%></span></a></th>',
\r
71 '<td class="<%=weeks[2].days[0].classname%>"><a href="#"><span><%=weeks[2].days[0].text%></span></a></td>',
\r
72 '<td class="<%=weeks[2].days[1].classname%>"><a href="#"><span><%=weeks[2].days[1].text%></span></a></td>',
\r
73 '<td class="<%=weeks[2].days[2].classname%>"><a href="#"><span><%=weeks[2].days[2].text%></span></a></td>',
\r
74 '<td class="<%=weeks[2].days[3].classname%>"><a href="#"><span><%=weeks[2].days[3].text%></span></a></td>',
\r
75 '<td class="<%=weeks[2].days[4].classname%>"><a href="#"><span><%=weeks[2].days[4].text%></span></a></td>',
\r
76 '<td class="<%=weeks[2].days[5].classname%>"><a href="#"><span><%=weeks[2].days[5].text%></span></a></td>',
\r
77 '<td class="<%=weeks[2].days[6].classname%>"><a href="#"><span><%=weeks[2].days[6].text%></span></a></td>',
\r
80 '<th class="datepickerWeek"><a href="#"><span><%=weeks[3].week%></span></a></th>',
\r
81 '<td class="<%=weeks[3].days[0].classname%>"><a href="#"><span><%=weeks[3].days[0].text%></span></a></td>',
\r
82 '<td class="<%=weeks[3].days[1].classname%>"><a href="#"><span><%=weeks[3].days[1].text%></span></a></td>',
\r
83 '<td class="<%=weeks[3].days[2].classname%>"><a href="#"><span><%=weeks[3].days[2].text%></span></a></td>',
\r
84 '<td class="<%=weeks[3].days[3].classname%>"><a href="#"><span><%=weeks[3].days[3].text%></span></a></td>',
\r
85 '<td class="<%=weeks[3].days[4].classname%>"><a href="#"><span><%=weeks[3].days[4].text%></span></a></td>',
\r
86 '<td class="<%=weeks[3].days[5].classname%>"><a href="#"><span><%=weeks[3].days[5].text%></span></a></td>',
\r
87 '<td class="<%=weeks[3].days[6].classname%>"><a href="#"><span><%=weeks[3].days[6].text%></span></a></td>',
\r
90 '<th class="datepickerWeek"><a href="#"><span><%=weeks[4].week%></span></a></th>',
\r
91 '<td class="<%=weeks[4].days[0].classname%>"><a href="#"><span><%=weeks[4].days[0].text%></span></a></td>',
\r
92 '<td class="<%=weeks[4].days[1].classname%>"><a href="#"><span><%=weeks[4].days[1].text%></span></a></td>',
\r
93 '<td class="<%=weeks[4].days[2].classname%>"><a href="#"><span><%=weeks[4].days[2].text%></span></a></td>',
\r
94 '<td class="<%=weeks[4].days[3].classname%>"><a href="#"><span><%=weeks[4].days[3].text%></span></a></td>',
\r
95 '<td class="<%=weeks[4].days[4].classname%>"><a href="#"><span><%=weeks[4].days[4].text%></span></a></td>',
\r
96 '<td class="<%=weeks[4].days[5].classname%>"><a href="#"><span><%=weeks[4].days[5].text%></span></a></td>',
\r
97 '<td class="<%=weeks[4].days[6].classname%>"><a href="#"><span><%=weeks[4].days[6].text%></span></a></td>',
\r
100 '<th class="datepickerWeek"><a href="#"><span><%=weeks[5].week%></span></a></th>',
\r
101 '<td class="<%=weeks[5].days[0].classname%>"><a href="#"><span><%=weeks[5].days[0].text%></span></a></td>',
\r
102 '<td class="<%=weeks[5].days[1].classname%>"><a href="#"><span><%=weeks[5].days[1].text%></span></a></td>',
\r
103 '<td class="<%=weeks[5].days[2].classname%>"><a href="#"><span><%=weeks[5].days[2].text%></span></a></td>',
\r
104 '<td class="<%=weeks[5].days[3].classname%>"><a href="#"><span><%=weeks[5].days[3].text%></span></a></td>',
\r
105 '<td class="<%=weeks[5].days[4].classname%>"><a href="#"><span><%=weeks[5].days[4].text%></span></a></td>',
\r
106 '<td class="<%=weeks[5].days[5].classname%>"><a href="#"><span><%=weeks[5].days[5].text%></span></a></td>',
\r
107 '<td class="<%=weeks[5].days[6].classname%>"><a href="#"><span><%=weeks[5].days[6].text%></span></a></td>',
\r
112 '<tbody class="<%=className%>">',
\r
114 '<td colspan="2"><a href="#"><span><%=data[0]%></span></a></td>',
\r
115 '<td colspan="2"><a href="#"><span><%=data[1]%></span></a></td>',
\r
116 '<td colspan="2"><a href="#"><span><%=data[2]%></span></a></td>',
\r
117 '<td colspan="2"><a href="#"><span><%=data[3]%></span></a></td>',
\r
120 '<td colspan="2"><a href="#"><span><%=data[4]%></span></a></td>',
\r
121 '<td colspan="2"><a href="#"><span><%=data[5]%></span></a></td>',
\r
122 '<td colspan="2"><a href="#"><span><%=data[6]%></span></a></td>',
\r
123 '<td colspan="2"><a href="#"><span><%=data[7]%></span></a></td>',
\r
126 '<td colspan="2"><a href="#"><span><%=data[8]%></span></a></td>',
\r
127 '<td colspan="2"><a href="#"><span><%=data[9]%></span></a></td>',
\r
128 '<td colspan="2"><a href="#"><span><%=data[10]%></span></a></td>',
\r
129 '<td colspan="2"><a href="#"><span><%=data[11]%></span></a></td>',
\r
144 position: 'bottom',
\r
145 eventName: 'click',
\r
146 onRender: function(){return {};},
\r
147 onChange: function(){return true;},
\r
148 onShow: function(){return true;},
\r
149 onBeforeShow: function(){return true;},
\r
150 onHide: function(){return true;},
\r
152 days: [_e("Sunday"), _e("Monday"), _e("Tuesday"), _e("Wednesday"), _e("Thursday"), _e("Friday"), _e("Saturday"), _e("Sunday")],
\r
153 daysShort: [cut(_e("Sunday"), 3), cut(_e("Monday"), 3), cut(_e("Tuesday"), 3), cut(_e("Wednesday"), 3), cut(_e("Thursday"), 3), cut(_e("Friday"), 3), cut(_e("Saturday"), 3), cut(_e("Sunday"), 3)],
\r
154 daysMin: [cut(_e("Sunday"), 2), cut(_e("Monday"), 2), cut(_e("Tuesday"), 2), cut(_e("Wednesday"), 2), cut(_e("Thursday"), 2), cut(_e("Friday"), 2), cut(_e("Saturday"), 2), cut(_e("Sunday"), 2)],
\r
155 months: [_e("January"), _e("February"), _e("March"), _e("April"), _e("May"), _e("June"), _e("July"), _e("August"), _e("September"), _e("October"), _e("November"), _e("December")],
\r
156 monthsShort: [cut(_e("January"), 3), cut(_e("February"), 3), cut(_e("March"), 3), cut(_e("April"), 3), cut(_e("May"), 3), cut(_e("June"), 3), cut(_e("July"), 3), cut(_e("August"), 3), cut(_e("September"), 3), cut(_e("October"), 3), cut(_e("November"), 3), cut(_e("December"), 3)],
\r
160 fill = function(el) {
\r
161 var options = $(el).data('datepicker');
\r
163 var currentCal = Math.floor(options.calendars/2), date, data, dow, month, cnt = 0, week, days, indic, indic2, html, tblCal;
\r
164 cal.find('td>table tbody').remove();
\r
165 for (var i = 0; i < options.calendars; i++) {
\r
166 date = new Date(options.current);
\r
167 date.addMonths(-currentCal + i);
\r
168 tblCal = cal.find('table').eq(i+1);
\r
169 switch (tblCal[0].className) {
\r
170 case 'datepickerViewDays':
\r
171 dow = formatDate(date, 'B, Y');
\r
173 case 'datepickerViewMonths':
\r
174 dow = date.getFullYear();
\r
176 case 'datepickerViewYears':
\r
177 dow = (date.getFullYear()-6) + ' - ' + (date.getFullYear()+5);
\r
180 tblCal.find('thead tr:first th:eq(1) span').text(dow);
\r
181 dow = date.getFullYear()-6;
\r
184 className: 'datepickerYears'
\r
186 for ( var j = 0; j < 12; j++) {
\r
187 data.data.push(dow + j);
\r
189 html = tmpl(tpl.months.join(''), data);
\r
191 data = {weeks:[], test: 10};
\r
192 month = date.getMonth();
\r
193 var dow = (date.getDay() - options.starts) % 7;
\r
194 date.addDays(-(dow + (dow < 0 ? 7 : 0)));
\r
198 indic = parseInt(cnt/7,10);
\r
200 if (!data.weeks[indic]) {
\r
201 week = date.getWeekNumber();
\r
202 data.weeks[indic] = {
\r
207 data.weeks[indic].days[indic2] = {
\r
208 text: date.getDate(),
\r
211 if (month != date.getMonth()) {
\r
212 data.weeks[indic].days[indic2].classname.push('datepickerNotInMonth');
\r
214 if (date.getDay() == 0) {
\r
215 data.weeks[indic].days[indic2].classname.push('datepickerSunday');
\r
217 if (date.getDay() == 6) {
\r
218 data.weeks[indic].days[indic2].classname.push('datepickerSaturday');
\r
220 var fromUser = options.onRender(date);
\r
221 var val = date.valueOf();
\r
222 if (fromUser.selected || options.date == val || $.inArray(val, options.date) > -1 || (options.mode == 'range' && val >= options.date[0] && val <= options.date[1])) {
\r
223 data.weeks[indic].days[indic2].classname.push('datepickerSelected');
\r
225 if (fromUser.disabled) {
\r
226 data.weeks[indic].days[indic2].classname.push('datepickerDisabled');
\r
228 if (fromUser.className) {
\r
229 data.weeks[indic].days[indic2].classname.push(fromUser.className);
\r
231 data.weeks[indic].days[indic2].classname = data.weeks[indic].days[indic2].classname.join(' ');
\r
235 html = tmpl(tpl.days.join(''), data) + html;
\r
237 data: options.locale.monthsShort,
\r
238 className: 'datepickerMonths'
\r
240 html = tmpl(tpl.months.join(''), data) + html;
\r
241 tblCal.append(html);
\r
244 parseDate = function (date, format) {
\r
245 if (date.constructor == Date) {
\r
246 return new Date(date);
\r
248 var parts = date.split(/\W+/);
\r
249 var against = format.split(/\W+/), d, m, y, h, min, now = new Date();
\r
250 for (var i = 0; i < parts.length; i++) {
\r
251 switch (against[i]) {
\r
254 d = parseInt(parts[i],10);
\r
257 m = parseInt(parts[i], 10)-1;
\r
261 y = parseInt(parts[i], 10);
\r
262 y += y > 100 ? 0 : (y < 29 ? 2000 : 1900);
\r
268 h = parseInt(parts[i], 10);
\r
272 if (/pm/i.test(parts[i]) && h < 12) {
\r
274 } else if (/am/i.test(parts[i]) && h >= 12) {
\r
279 min = parseInt(parts[i], 10);
\r
284 y === undefined ? now.getFullYear() : y,
\r
285 m === undefined ? now.getMonth() : m,
\r
286 d === undefined ? now.getDate() : d,
\r
287 h === undefined ? now.getHours() : h,
\r
288 min === undefined ? now.getMinutes() : min,
\r
292 formatDate = function(date, format) {
\r
293 var m = date.getMonth();
\r
294 var d = date.getDate();
\r
295 var y = date.getFullYear();
\r
296 var wn = date.getWeekNumber();
\r
297 var w = date.getDay();
\r
299 var hr = date.getHours();
\r
300 var pm = (hr >= 12);
\r
301 var ir = (pm) ? (hr - 12) : hr;
\r
302 var dy = date.getDayOfYear();
\r
306 var min = date.getMinutes();
\r
307 var sec = date.getSeconds();
\r
308 var parts = format.split(''), part;
\r
309 for ( var i = 0; i < parts.length; i++ ) {
\r
311 switch (parts[i]) {
\r
313 part = date.getDayName();
\r
316 part = date.getDayName(true);
\r
319 part = date.getMonthName();
\r
322 part = date.getMonthName(true);
\r
325 part = 1 + Math.floor(y / 100);
\r
328 part = (d < 10) ? ("0" + d) : d;
\r
334 part = (hr < 10) ? ("0" + hr) : hr;
\r
337 part = (ir < 10) ? ("0" + ir) : ir;
\r
340 part = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy;
\r
349 part = (m < 9) ? ("0" + (1+m)) : (1+m);
\r
352 part = (min < 10) ? ("0" + min) : min;
\r
356 part = pm ? "PM" : "AM";
\r
359 part = Math.floor(date.getTime() / 1000);
\r
362 part = (sec < 10) ? ("0" + sec) : sec;
\r
371 part = ('' + y).substr(2, 2);
\r
379 return parts.join('');
\r
381 extendDate = function(options) {
\r
382 if (Date.prototype.tempDate) {
\r
385 Date.prototype.tempDate = null;
\r
386 Date.prototype.months = options.months;
\r
387 Date.prototype.monthsShort = options.monthsShort;
\r
388 Date.prototype.days = options.days;
\r
389 Date.prototype.daysShort = options.daysShort;
\r
390 Date.prototype.getMonthName = function(fullName) {
\r
391 return this[fullName ? 'months' : 'monthsShort'][this.getMonth()];
\r
393 Date.prototype.getDayName = function(fullName) {
\r
394 return this[fullName ? 'days' : 'daysShort'][this.getDay()];
\r
396 Date.prototype.addDays = function (n) {
\r
397 this.setDate(this.getDate() + n);
\r
398 this.tempDate = this.getDate();
\r
400 Date.prototype.addMonths = function (n) {
\r
401 if (this.tempDate == null) {
\r
402 this.tempDate = this.getDate();
\r
405 this.setMonth(this.getMonth() + n);
\r
406 this.setDate(Math.min(this.tempDate, this.getMaxDays()));
\r
408 Date.prototype.addYears = function (n) {
\r
409 if (this.tempDate == null) {
\r
410 this.tempDate = this.getDate();
\r
413 this.setFullYear(this.getFullYear() + n);
\r
414 this.setDate(Math.min(this.tempDate, this.getMaxDays()));
\r
416 Date.prototype.getMaxDays = function() {
\r
417 var tmpDate = new Date(Date.parse(this)),
\r
419 m = tmpDate.getMonth();
\r
421 while (tmpDate.getMonth() == m) {
\r
423 tmpDate.setDate(d);
\r
427 Date.prototype.getFirstDay = function() {
\r
428 var tmpDate = new Date(Date.parse(this));
\r
429 tmpDate.setDate(1);
\r
430 return tmpDate.getDay();
\r
432 Date.prototype.getWeekNumber = function() {
\r
433 var tempDate = new Date(this);
\r
434 tempDate.setDate(tempDate.getDate() - (tempDate.getDay() + 6) % 7 + 3);
\r
435 var dms = tempDate.valueOf();
\r
436 tempDate.setMonth(0);
\r
437 tempDate.setDate(4);
\r
438 return Math.round((dms - tempDate.valueOf()) / (604800000)) + 1;
\r
440 Date.prototype.getDayOfYear = function() {
\r
441 var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
\r
442 var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0);
\r
443 var time = now - then;
\r
444 return Math.floor(time / 24*60*60*1000);
\r
447 layout = function (el) {
\r
448 var options = $(el).data('datepicker');
\r
449 var cal = $('#' + options.id);
\r
450 if (!options.extraHeight) {
\r
451 var divs = $(el).find('div');
\r
452 options.extraHeight = divs.get(0).offsetHeight + divs.get(1).offsetHeight;
\r
453 options.extraWidth = divs.get(2).offsetWidth + divs.get(3).offsetWidth;
\r
455 var tbl = cal.find('table:first').get(0);
\r
456 var width = tbl.offsetWidth;
\r
457 var height = tbl.offsetHeight;
\r
459 width: width + options.extraWidth + 'px',
\r
460 height: height + options.extraHeight + 'px'
\r
461 }).find('div.datepickerContainer').css({
\r
462 width: width + 'px',
\r
463 height: height + 'px'
\r
466 click = function(ev) {
\r
467 if ($(ev.target).is('span')) {
\r
468 ev.target = ev.target.parentNode;
\r
470 var el = $(ev.target);
\r
473 if (el.hasClass('datepickerDisabled')) {
\r
476 var options = $(this).data('datepicker');
\r
477 var parentEl = el.parent();
\r
478 var tblEl = parentEl.parent().parent().parent();
\r
479 var tblIndex = $('table', this).index(tblEl.get(0)) - 1;
\r
480 var tmp = new Date(options.current);
\r
481 var changed = false;
\r
482 var fillIt = false;
\r
483 if (parentEl.is('th')) {
\r
484 if (parentEl.hasClass('datepickerWeek') && options.mode == 'range' && !parentEl.next().hasClass('datepickerDisabled')) {
\r
485 var val = parseInt(parentEl.next().text(), 10);
\r
486 tmp.addMonths(tblIndex - Math.floor(options.calendars/2));
\r
487 if (parentEl.next().hasClass('datepickerNotInMonth')) {
\r
488 tmp.addMonths(val > 15 ? -1 : 1);
\r
491 options.date[0] = (tmp.setHours(0,0,0,0)).valueOf();
\r
492 tmp.setHours(23,59,59,0);
\r
494 options.date[1] = tmp.valueOf();
\r
497 options.lastSel = false;
\r
498 } else if (parentEl.hasClass('datepickerMonth')) {
\r
499 tmp.addMonths(tblIndex - Math.floor(options.calendars/2));
\r
500 switch (tblEl.get(0).className) {
\r
501 case 'datepickerViewDays':
\r
502 tblEl.get(0).className = 'datepickerViewMonths';
\r
503 el.find('span').text(tmp.getFullYear());
\r
505 case 'datepickerViewMonths':
\r
506 tblEl.get(0).className = 'datepickerViewYears';
\r
507 el.find('span').text((tmp.getFullYear()-6) + ' - ' + (tmp.getFullYear()+5));
\r
509 case 'datepickerViewYears':
\r
510 tblEl.get(0).className = 'datepickerViewDays';
\r
511 el.find('span').text(formatDate(tmp, 'B, Y'));
\r
514 } else if (parentEl.parent().parent().is('thead')) {
\r
515 switch (tblEl.get(0).className) {
\r
516 case 'datepickerViewDays':
\r
517 options.current.addMonths(parentEl.hasClass('datepickerGoPrev') ? -1 : 1);
\r
519 case 'datepickerViewMonths':
\r
520 options.current.addYears(parentEl.hasClass('datepickerGoPrev') ? -1 : 1);
\r
522 case 'datepickerViewYears':
\r
523 options.current.addYears(parentEl.hasClass('datepickerGoPrev') ? -12 : 12);
\r
528 } else if (parentEl.is('td') && !parentEl.hasClass('datepickerDisabled')) {
\r
529 switch (tblEl.get(0).className) {
\r
530 case 'datepickerViewMonths':
\r
531 options.current.setMonth(tblEl.find('tbody.datepickerMonths td').index(parentEl));
\r
532 options.current.setFullYear(parseInt(tblEl.find('thead th.datepickerMonth span').text(), 10));
\r
533 options.current.addMonths(Math.floor(options.calendars/2) - tblIndex);
\r
534 tblEl.get(0).className = 'datepickerViewDays';
\r
536 case 'datepickerViewYears':
\r
537 options.current.setFullYear(parseInt(el.text(), 10));
\r
538 tblEl.get(0).className = 'datepickerViewMonths';
\r
541 var val = parseInt(el.text(), 10);
\r
542 tmp.addMonths(tblIndex - Math.floor(options.calendars/2));
\r
543 if (parentEl.hasClass('datepickerNotInMonth')) {
\r
544 tmp.addMonths(val > 15 ? -1 : 1);
\r
547 switch (options.mode) {
\r
549 val = (tmp.setHours(0,0,0,0)).valueOf();
\r
550 if ($.inArray(val, options.date) > -1) {
\r
551 $.each(options.date, function(nr, dat){
\r
553 options.date.splice(nr,1);
\r
558 options.date.push(val);
\r
562 if (!options.lastSel) {
\r
563 options.date[0] = (tmp.setHours(0,0,0,0)).valueOf();
\r
565 val = (tmp.setHours(23,59,59,0)).valueOf();
\r
566 if (val < options.date[0]) {
\r
567 options.date[1] = options.date[0] + 86399000;
\r
568 options.date[0] = val - 86399000;
\r
570 options.date[1] = val;
\r
572 options.lastSel = !options.lastSel;
\r
575 options.date = tmp.valueOf();
\r
587 options.onChange.apply(this, prepareDate(options));
\r
592 prepareDate = function (options) {
\r
594 if (options.mode == 'single') {
\r
595 tmp = new Date(options.date);
\r
596 return [formatDate(tmp, options.format), tmp, options.el];
\r
598 tmp = [[],[], options.el];
\r
599 $.each(options.date, function(nr, val){
\r
600 var date = new Date(val);
\r
601 tmp[0].push(formatDate(date, options.format));
\r
607 getViewport = function () {
\r
608 var m = document.compatMode == 'CSS1Compat';
\r
610 l : window.pageXOffset || (m ? document.documentElement.scrollLeft : document.body.scrollLeft),
\r
611 t : window.pageYOffset || (m ? document.documentElement.scrollTop : document.body.scrollTop),
\r
612 w : window.innerWidth || (m ? document.documentElement.clientWidth : document.body.clientWidth),
\r
613 h : window.innerHeight || (m ? document.documentElement.clientHeight : document.body.clientHeight)
\r
616 isChildOf = function(parentEl, el, container) {
\r
617 if (parentEl == el) {
\r
620 if (parentEl.contains) {
\r
621 return parentEl.contains(el);
\r
623 if ( parentEl.compareDocumentPosition ) {
\r
624 return !!(parentEl.compareDocumentPosition(el) & 16);
\r
626 var prEl = el.parentNode;
\r
627 while(prEl && prEl != container) {
\r
628 if (prEl == parentEl)
\r
630 prEl = prEl.parentNode;
\r
634 show = function (ev) {
\r
635 var cal = $('#' + $(this).data('datepickerId'));
\r
636 if (!cal.is(':visible')) {
\r
637 var calEl = cal.get(0);
\r
639 var options = cal.data('datepicker');
\r
640 options.onBeforeShow.apply(this, [cal.get(0)]);
\r
641 var pos = $(this).offset();
\r
642 var viewPort = getViewport();
\r
644 var left = pos.left;
\r
645 var oldDisplay = $.curCSS(calEl, 'display');
\r
647 visibility: 'hidden',
\r
651 switch (options.position){
\r
653 top -= calEl.offsetHeight;
\r
656 left -= calEl.offsetWidth;
\r
659 left += this.offsetWidth;
\r
662 top += this.offsetHeight;
\r
665 if (top + calEl.offsetHeight > viewPort.t + viewPort.h) {
\r
666 top = pos.top - calEl.offsetHeight;
\r
668 if (top < viewPort.t) {
\r
669 top = pos.top + this.offsetHeight + calEl.offsetHeight;
\r
671 if (left + calEl.offsetWidth > viewPort.l + viewPort.w) {
\r
672 left = pos.left - calEl.offsetWidth;
\r
674 if (left < viewPort.l) {
\r
675 left = pos.left + this.offsetWidth
\r
678 visibility: 'visible',
\r
683 if (options.onShow.apply(this, [cal.get(0)]) != false) {
\r
686 $(document).bind('mousedown', {cal: cal, trigger: this}, hide);
\r
690 hide = function (ev) {
\r
691 if (ev.target != ev.data.trigger && !isChildOf(ev.data.cal.get(0), ev.target, ev.data.cal.get(0))) {
\r
692 if (ev.data.cal.data('datepicker').onHide.apply(this, [ev.data.cal.get(0)]) != false) {
\r
693 ev.data.cal.hide();
\r
695 $(document).unbind('mousedown', hide);
\r
699 init: function(options){
\r
700 options = $.extend({}, defaults, options||{});
\r
701 extendDate(options.locale);
\r
702 options.calendars = Math.max(1, parseInt(options.calendars,10)||1);
\r
703 options.mode = /single|multiple|range/.test(options.mode) ? options.mode : 'single';
\r
704 return this.each(function(){
\r
705 if (!$(this).data('datepicker')) {
\r
707 if (options.date.constructor == String) {
\r
708 options.date = parseDate(options.date, options.format);
\r
709 options.date.setHours(0,0,0,0);
\r
711 if (options.mode != 'single') {
\r
712 if (options.date.constructor != Array) {
\r
713 options.date = [options.date.valueOf()];
\r
714 if (options.mode == 'range') {
\r
715 options.date.push(((new Date(options.date[0])).setHours(23,59,59,0)).valueOf());
\r
718 for (var i = 0; i < options.date.length; i++) {
\r
719 options.date[i] = (parseDate(options.date[i], options.format).setHours(0,0,0,0)).valueOf();
\r
721 if (options.mode == 'range') {
\r
722 options.date[1] = ((new Date(options.date[1])).setHours(23,59,59,0)).valueOf();
\r
726 options.date = options.date.valueOf();
\r
728 if (!options.current) {
\r
729 options.current = new Date();
\r
731 options.current = parseDate(options.current, options.format);
\r
733 options.current.setDate(1);
\r
734 options.current.setHours(0,0,0,0);
\r
735 var id = 'datepicker_' + parseInt(Math.random() * 1000), cnt;
\r
737 $(this).data('datepickerId', options.id);
\r
738 var cal = $(tpl.wrapper).attr('id', id).bind('click', click).data('datepicker', options);
\r
739 if (options.className) {
\r
740 cal.addClass(options.className);
\r
743 for (var i = 0; i < options.calendars; i++) {
\r
744 cnt = options.starts;
\r
748 html += tmpl(tpl.head.join(''), {
\r
749 week: options.locale.weekMin,
\r
750 prev: options.prev,
\r
751 next: options.next,
\r
752 day1: options.locale.daysMin[(cnt++)%7],
\r
753 day2: options.locale.daysMin[(cnt++)%7],
\r
754 day3: options.locale.daysMin[(cnt++)%7],
\r
755 day4: options.locale.daysMin[(cnt++)%7],
\r
756 day5: options.locale.daysMin[(cnt++)%7],
\r
757 day6: options.locale.daysMin[(cnt++)%7],
\r
758 day7: options.locale.daysMin[(cnt++)%7]
\r
762 .find('tr:first').append(html)
\r
763 .find('table').addClass(views[options.view]);
\r
765 if (options.flat) {
\r
766 cal.appendTo(this).show().css('position', 'relative');
\r
767 layout(cal.get(0));
\r
769 cal.appendTo(document.body);
\r
770 $(this).bind(options.eventName, show);
\r
775 showPicker: function() {
\r
776 return this.each( function () {
\r
777 if ($(this).data('datepickerId')) {
\r
782 hidePicker: function() {
\r
783 return this.each( function () {
\r
784 if ($(this).data('datepickerId')) {
\r
785 $('#' + $(this).data('datepickerId')).hide();
\r
789 setDate: function(date, shiftTo){
\r
790 return this.each(function(){
\r
791 if ($(this).data('datepickerId')) {
\r
792 var cal = $('#' + $(this).data('datepickerId'));
\r
793 var options = cal.data('datepicker');
\r
794 options.date = date;
\r
795 if (options.date.constructor == String) {
\r
796 options.date = parseDate(options.date, options.format);
\r
797 options.date.setHours(0,0,0,0);
\r
799 if (options.mode != 'single') {
\r
800 if (options.date.constructor != Array) {
\r
801 options.date = [options.date.valueOf()];
\r
802 if (options.mode == 'range') {
\r
803 options.date.push(((new Date(options.date[0])).setHours(23,59,59,0)).valueOf());
\r
806 for (var i = 0; i < options.date.length; i++) {
\r
807 options.date[i] = (parseDate(options.date[i], options.format).setHours(0,0,0,0)).valueOf();
\r
809 if (options.mode == 'range') {
\r
810 options.date[1] = ((new Date(options.date[1])).setHours(23,59,59,0)).valueOf();
\r
814 options.date = options.date.valueOf();
\r
817 options.current = new Date (options.mode != 'single' ? options.date[0] : options.date);
\r
823 getDate: function(formated) {
\r
824 if (this.size() > 0) {
\r
825 return prepareDate($('#' + $(this).data('datepickerId')).data('datepicker'))[formated ? 0 : 1];
\r
829 return this.each(function(){
\r
830 if ($(this).data('datepickerId')) {
\r
831 var cal = $('#' + $(this).data('datepickerId'));
\r
832 var options = cal.data('datepicker');
\r
833 if (options.mode != 'single') {
\r
840 fixLayout: function(){
\r
841 return this.each(function(){
\r
842 if ($(this).data('datepickerId')) {
\r
843 var cal = $('#' + $(this).data('datepickerId'));
\r
844 var options = cal.data('datepicker');
\r
845 if (options.flat) {
\r
846 layout(cal.get(0));
\r
854 DatePicker: DatePicker.init,
\r
855 DatePickerHide: DatePicker.hidePicker,
\r
856 DatePickerShow: DatePicker.showPicker,
\r
857 DatePickerSetDate: DatePicker.setDate,
\r
858 DatePickerGetDate: DatePicker.getDate,
\r
859 DatePickerClear: DatePicker.clear,
\r
860 DatePickerLayout: DatePicker.fixLayout
\r
867 this.tmpl = function tmpl(str, data){
\r
868 // Figure out if we're getting a template, or if we need to
\r
869 // load the template - and be sure to cache the result.
\r
870 var fn = !/\W/.test(str) ?
\r
871 cache[str] = cache[str] ||
\r
872 tmpl(document.getElementById(str).innerHTML) :
\r
874 // Generate a reusable function that will serve as a template
\r
875 // generator (and which will be cached).
\r
876 new Function("obj",
\r
877 "var p=[],print=function(){p.push.apply(p,arguments);};" +
\r
879 // Introduce the data as local variables using with(){}
\r
880 "with(obj){p.push('" +
\r
882 // Convert the template into pure JavaScript
\r
884 .replace(/[\r\t\n]/g, " ")
\r
885 .split("<%").join("\t")
\r
886 .replace(/((^|%>)[^\t]*)'/g, "$1\r")
\r
887 .replace(/\t=(.*?)%>/g, "',$1,'")
\r
888 .split("\t").join("');")
\r
889 .split("%>").join("p.push('")
\r
890 .split("\r").join("\\'")
\r
891 + "');}return p.join('');");
\r
893 // Provide some basic currying to the user
\r
894 return data ? fn( data ) : fn;
\r