refinerycms-bookings 2.0.3

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