datepicker.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853
  1. /**
  2. *
  3. * Date picker
  4. * Author: Stefan Petre www.eyecon.ro
  5. * Download: http://www.jb51.net
  6. */
  7. (function ($) {
  8. var DatePicker = function () {
  9. var ids = {},
  10. tpl = {
  11. wrapper: '<div class="datepicker"><div class="datepickerBorderT"></div><div class="datepickerBorderB"></div><div class="datepickerBorderL"></div><div class="datepickerBorderR"></div><div class="datepickerBorderTL"></div><div class="datepickerBorderTR"></div><div class="datepickerBorderBL"></div><div class="datepickerBorderBR"></div><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. 0
  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. (function(){
  821. var cache = {};
  822. this.tmpl = function tmpl(str, data){
  823. // Figure out if we're getting a template, or if we need to
  824. // load the template - and be sure to cache the result.
  825. var fn = !/\W/.test(str) ?
  826. cache[str] = cache[str] ||
  827. tmpl(document.getElementById(str).innerHTML) :
  828. // Generate a reusable function that will serve as a template
  829. // generator (and which will be cached).
  830. new Function("obj",
  831. "var p=[],print=function(){p.push.apply(p,arguments);};" +
  832. // Introduce the data as local variables using with(){}
  833. "with(obj){p.push('" +
  834. // Convert the template into pure JavaScript
  835. str
  836. .replace(/[\r\t\n]/g, " ")
  837. .split("<%").join("\t")
  838. .replace(/((^|%>)[^\t]*)'/g, "$1\r")
  839. .replace(/\t=(.*?)%>/g, "',$1,'")
  840. .split("\t").join("');")
  841. .split("%>").join("p.push('")
  842. .split("\r").join("\\'")
  843. + "');}return p.join('');");
  844. // Provide some basic currying to the user
  845. return data ? fn( data ) : fn;
  846. };
  847. })();