upmin-admin 0.0.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +34 -0
  3. data/app/assets/images/upmin/logo_large.png +0 -0
  4. data/app/assets/images/upmin/logo_small.png +0 -0
  5. data/app/assets/javascripts/upmin/application.js +40 -0
  6. data/app/assets/javascripts/upmin/jquery-clockpicker.js +729 -0
  7. data/app/assets/javascripts/upmin/models.js +23 -0
  8. data/app/assets/javascripts/upmin/moment.js +2856 -0
  9. data/app/assets/javascripts/upmin/pikaday.js +997 -0
  10. data/app/assets/stylesheets/upmin/application.css +16 -0
  11. data/app/assets/stylesheets/upmin/attributes.css.scss +57 -0
  12. data/app/assets/stylesheets/upmin/base.css.scss +53 -0
  13. data/app/assets/stylesheets/upmin/button_mixins.scss +37 -0
  14. data/app/assets/stylesheets/upmin/colors.scss +20 -0
  15. data/app/assets/stylesheets/upmin/instances.css.scss +77 -0
  16. data/app/assets/stylesheets/upmin/jquery-clockpicker.css +370 -0
  17. data/app/assets/stylesheets/upmin/models.css.scss +207 -0
  18. data/app/assets/stylesheets/upmin/pikaday.css +196 -0
  19. data/app/controllers/upmin/application_controller.rb +4 -0
  20. data/app/controllers/upmin/models_controller.rb +90 -0
  21. data/app/helpers/upmin/application_helper.rb +28 -0
  22. data/app/helpers/upmin/instances_helper.rb +13 -0
  23. data/app/helpers/upmin/models_helper.rb +4 -0
  24. data/app/views/layouts/upmin/_navbar.html.haml +15 -0
  25. data/app/views/layouts/upmin/application.html.haml +27 -0
  26. data/app/views/upmin/models/dashboard.html.haml +9 -0
  27. data/app/views/upmin/models/search.html.haml +9 -0
  28. data/app/views/upmin/models/show.html.haml +21 -0
  29. data/app/views/upmin/partials/actions/_action.html.haml +13 -0
  30. data/app/views/upmin/partials/associations/_associations.html.haml +14 -0
  31. data/app/views/upmin/partials/attributes/_datetime.html.haml +95 -0
  32. data/app/views/upmin/partials/attributes/_integer.html.haml +7 -0
  33. data/app/views/upmin/partials/attributes/_progress_bar.html.haml +11 -0
  34. data/app/views/upmin/partials/attributes/_string.html.haml +7 -0
  35. data/app/views/upmin/partials/attributes/_unknown.html.haml +3 -0
  36. data/app/views/upmin/partials/models/_model.html.haml +67 -0
  37. data/app/views/upmin/partials/search_boxes/_ransack_search_box.html.haml +37 -0
  38. data/app/views/upmin/partials/search_results/_result.html.haml +8 -0
  39. data/app/views/upmin/partials/search_results/_results.html.haml +2 -0
  40. data/config/routes.rb +20 -0
  41. data/lib/tasks/accordive_rails_tasks.rake +4 -0
  42. data/lib/tasks/upmin_tasks.rake +4 -0
  43. data/lib/upmin.rb +18 -0
  44. data/lib/upmin/engine.rb +7 -0
  45. data/lib/upmin/klass.rb +165 -0
  46. data/lib/upmin/model.rb +133 -0
  47. data/lib/upmin/railtie.rb +19 -0
  48. data/lib/upmin/railties/active_record.rb +62 -0
  49. data/lib/upmin/railties/render.rb +120 -0
  50. data/lib/upmin/railties/render_helpers.rb +144 -0
  51. data/lib/upmin/version.rb +3 -0
  52. data/test/controllers/upmin/model_controller_test.rb +11 -0
  53. data/test/dummy/README.rdoc +28 -0
  54. data/test/dummy/Rakefile +6 -0
  55. data/test/dummy/app/assets/javascripts/application.js +13 -0
  56. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  57. data/test/dummy/app/controllers/application_controller.rb +5 -0
  58. data/test/dummy/app/helpers/application_helper.rb +2 -0
  59. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  60. data/test/dummy/bin/bundle +3 -0
  61. data/test/dummy/bin/rails +4 -0
  62. data/test/dummy/bin/rake +4 -0
  63. data/test/dummy/config.ru +4 -0
  64. data/test/dummy/config/application.rb +23 -0
  65. data/test/dummy/config/boot.rb +5 -0
  66. data/test/dummy/config/database.yml +25 -0
  67. data/test/dummy/config/environment.rb +5 -0
  68. data/test/dummy/config/environments/development.rb +37 -0
  69. data/test/dummy/config/environments/production.rb +83 -0
  70. data/test/dummy/config/environments/test.rb +39 -0
  71. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  72. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  73. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  74. data/test/dummy/config/initializers/inflections.rb +16 -0
  75. data/test/dummy/config/initializers/mime_types.rb +4 -0
  76. data/test/dummy/config/initializers/session_store.rb +3 -0
  77. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  78. data/test/dummy/config/locales/en.yml +23 -0
  79. data/test/dummy/config/routes.rb +4 -0
  80. data/test/dummy/config/secrets.yml +22 -0
  81. data/test/dummy/public/404.html +67 -0
  82. data/test/dummy/public/422.html +67 -0
  83. data/test/dummy/public/500.html +66 -0
  84. data/test/dummy/public/favicon.ico +0 -0
  85. data/test/helpers/upmin/model_helper_test.rb +6 -0
  86. data/test/integration/navigation_test.rb +10 -0
  87. data/test/test_helper.rb +15 -0
  88. data/test/upmin_test.rb +7 -0
  89. metadata +237 -0
@@ -0,0 +1,997 @@
1
+ /*!
2
+ * Pikaday
3
+ *
4
+ * Copyright © 2014 David Bushell | BSD & MIT license | https://github.com/dbushell/Pikaday
5
+ */
6
+
7
+ (function (root, factory)
8
+ {
9
+ 'use strict';
10
+
11
+ var moment;
12
+ if (typeof exports === 'object') {
13
+ // CommonJS module
14
+ // Load moment.js as an optional dependency
15
+ try { moment = require('moment'); } catch (e) {}
16
+ module.exports = factory(moment);
17
+ } else if (typeof define === 'function' && define.amd) {
18
+ // AMD. Register as an anonymous module.
19
+ define(function (req)
20
+ {
21
+ // Load moment.js as an optional dependency
22
+ var id = 'moment';
23
+ moment = req.defined && req.defined(id) ? req(id) : undefined;
24
+ return factory(moment);
25
+ });
26
+ } else {
27
+ root.Pikaday = factory(root.moment);
28
+ }
29
+ }(this, function (moment)
30
+ {
31
+ 'use strict';
32
+
33
+ /**
34
+ * feature detection and helper functions
35
+ */
36
+ var hasMoment = typeof moment === 'function',
37
+
38
+ hasEventListeners = !!window.addEventListener,
39
+
40
+ document = window.document,
41
+
42
+ sto = window.setTimeout,
43
+
44
+ addEvent = function(el, e, callback, capture)
45
+ {
46
+ if (hasEventListeners) {
47
+ el.addEventListener(e, callback, !!capture);
48
+ } else {
49
+ el.attachEvent('on' + e, callback);
50
+ }
51
+ },
52
+
53
+ removeEvent = function(el, e, callback, capture)
54
+ {
55
+ if (hasEventListeners) {
56
+ el.removeEventListener(e, callback, !!capture);
57
+ } else {
58
+ el.detachEvent('on' + e, callback);
59
+ }
60
+ },
61
+
62
+ fireEvent = function(el, eventName, data)
63
+ {
64
+ var ev;
65
+
66
+ if (document.createEvent) {
67
+ ev = document.createEvent('HTMLEvents');
68
+ ev.initEvent(eventName, true, false);
69
+ ev = extend(ev, data);
70
+ el.dispatchEvent(ev);
71
+ } else if (document.createEventObject) {
72
+ ev = document.createEventObject();
73
+ ev = extend(ev, data);
74
+ el.fireEvent('on' + eventName, ev);
75
+ }
76
+ },
77
+
78
+ trim = function(str)
79
+ {
80
+ return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g,'');
81
+ },
82
+
83
+ hasClass = function(el, cn)
84
+ {
85
+ return (' ' + el.className + ' ').indexOf(' ' + cn + ' ') !== -1;
86
+ },
87
+
88
+ addClass = function(el, cn)
89
+ {
90
+ if (!hasClass(el, cn)) {
91
+ el.className = (el.className === '') ? cn : el.className + ' ' + cn;
92
+ }
93
+ },
94
+
95
+ removeClass = function(el, cn)
96
+ {
97
+ el.className = trim((' ' + el.className + ' ').replace(' ' + cn + ' ', ' '));
98
+ },
99
+
100
+ isArray = function(obj)
101
+ {
102
+ return (/Array/).test(Object.prototype.toString.call(obj));
103
+ },
104
+
105
+ isDate = function(obj)
106
+ {
107
+ return (/Date/).test(Object.prototype.toString.call(obj)) && !isNaN(obj.getTime());
108
+ },
109
+
110
+ isLeapYear = function(year)
111
+ {
112
+ // solution by Matti Virkkunen: http://stackoverflow.com/a/4881951
113
+ return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
114
+ },
115
+
116
+ getDaysInMonth = function(year, month)
117
+ {
118
+ return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
119
+ },
120
+
121
+ setToStartOfDay = function(date)
122
+ {
123
+ if (isDate(date)) date.setHours(0,0,0,0);
124
+ },
125
+
126
+ compareDates = function(a,b)
127
+ {
128
+ // weak date comparison (use setToStartOfDay(date) to ensure correct result)
129
+ return a.getTime() === b.getTime();
130
+ },
131
+
132
+ extend = function(to, from, overwrite)
133
+ {
134
+ var prop, hasProp;
135
+ for (prop in from) {
136
+ hasProp = to[prop] !== undefined;
137
+ if (hasProp && typeof from[prop] === 'object' && from[prop].nodeName === undefined) {
138
+ if (isDate(from[prop])) {
139
+ if (overwrite) {
140
+ to[prop] = new Date(from[prop].getTime());
141
+ }
142
+ }
143
+ else if (isArray(from[prop])) {
144
+ if (overwrite) {
145
+ to[prop] = from[prop].slice(0);
146
+ }
147
+ } else {
148
+ to[prop] = extend({}, from[prop], overwrite);
149
+ }
150
+ } else if (overwrite || !hasProp) {
151
+ to[prop] = from[prop];
152
+ }
153
+ }
154
+ return to;
155
+ },
156
+
157
+ adjustCalendar = function(calendar) {
158
+ if (calendar.month < 0) {
159
+ calendar.year -= Math.ceil(Math.abs(calendar.month)/12);
160
+ calendar.month += 12;
161
+ }
162
+ if (calendar.month > 11) {
163
+ calendar.year += Math.floor(Math.abs(calendar.month)/12);
164
+ calendar.month -= 12;
165
+ }
166
+ return calendar;
167
+ },
168
+
169
+ /**
170
+ * defaults and localisation
171
+ */
172
+ defaults = {
173
+
174
+ // bind the picker to a form field
175
+ field: null,
176
+
177
+ // automatically show/hide the picker on `field` focus (default `true` if `field` is set)
178
+ bound: undefined,
179
+
180
+ // position of the datepicker, relative to the field (default to bottom & left)
181
+ // ('bottom' & 'left' keywords are not used, 'top' & 'right' are modifier on the bottom/left position)
182
+ position: 'bottom left',
183
+
184
+ // the default output format for `.toString()` and `field` value
185
+ format: 'YYYY-MM-DD',
186
+
187
+ // the initial date to view when first opened
188
+ defaultDate: null,
189
+
190
+ // make the `defaultDate` the initial selected value
191
+ setDefaultDate: false,
192
+
193
+ // first day of week (0: Sunday, 1: Monday etc)
194
+ firstDay: 0,
195
+
196
+ // the minimum/earliest date that can be selected
197
+ minDate: null,
198
+ // the maximum/latest date that can be selected
199
+ maxDate: null,
200
+
201
+ // number of years either side, or array of upper/lower range
202
+ yearRange: 10,
203
+
204
+ // show week numbers at head of row
205
+ showWeekNumber: false,
206
+
207
+ // used internally (don't config outside)
208
+ minYear: 0,
209
+ maxYear: 9999,
210
+ minMonth: undefined,
211
+ maxMonth: undefined,
212
+
213
+ isRTL: false,
214
+
215
+ // Additional text to append to the year in the calendar title
216
+ yearSuffix: '',
217
+
218
+ // Render the month after year in the calendar title
219
+ showMonthAfterYear: false,
220
+
221
+ // how many months are visible
222
+ numberOfMonths: 1,
223
+
224
+ // when numberOfMonths is used, this will help you to choose where the main calendar will be (default `left`, can be set to `right`)
225
+ // only used for the first display or when a selected date is not visible
226
+ mainCalendar: 'left',
227
+
228
+ // Specify a DOM element to render the calendar in
229
+ container: undefined,
230
+
231
+ // internationalization
232
+ i18n: {
233
+ previousMonth : 'Previous Month',
234
+ nextMonth : 'Next Month',
235
+ months : ['January','February','March','April','May','June','July','August','September','October','November','December'],
236
+ weekdays : ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
237
+ weekdaysShort : ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
238
+ },
239
+
240
+ // callback function
241
+ onSelect: null,
242
+ onOpen: null,
243
+ onClose: null,
244
+ onDraw: null
245
+ },
246
+
247
+
248
+ /**
249
+ * templating functions to abstract HTML rendering
250
+ */
251
+ renderDayName = function(opts, day, abbr)
252
+ {
253
+ day += opts.firstDay;
254
+ while (day >= 7) {
255
+ day -= 7;
256
+ }
257
+ return abbr ? opts.i18n.weekdaysShort[day] : opts.i18n.weekdays[day];
258
+ },
259
+
260
+ renderDay = function(d, m, y, isSelected, isToday, isDisabled, isEmpty)
261
+ {
262
+ if (isEmpty) {
263
+ return '<td class="is-empty"></td>';
264
+ }
265
+ var arr = [];
266
+ if (isDisabled) {
267
+ arr.push('is-disabled');
268
+ }
269
+ if (isToday) {
270
+ arr.push('is-today');
271
+ }
272
+ if (isSelected) {
273
+ arr.push('is-selected');
274
+ }
275
+ return '<td data-day="' + d + '" class="' + arr.join(' ') + '">' +
276
+ '<button class="pika-button pika-day" type="button" ' +
277
+ 'data-pika-year="' + y + '" data-pika-month="' + m + '" data-pika-day="' + d + '">' +
278
+ d +
279
+ '</button>' +
280
+ '</td>';
281
+ },
282
+
283
+ renderWeek = function (d, m, y) {
284
+ // Lifted from http://javascript.about.com/library/blweekyear.htm, lightly modified.
285
+ var onejan = new Date(y, 0, 1),
286
+ weekNum = Math.ceil((((new Date(y, m, d) - onejan) / 86400000) + onejan.getDay()+1)/7);
287
+ return '<td class="pika-week">' + weekNum + '</td>';
288
+ },
289
+
290
+ renderRow = function(days, isRTL)
291
+ {
292
+ return '<tr>' + (isRTL ? days.reverse() : days).join('') + '</tr>';
293
+ },
294
+
295
+ renderBody = function(rows)
296
+ {
297
+ return '<tbody>' + rows.join('') + '</tbody>';
298
+ },
299
+
300
+ renderHead = function(opts)
301
+ {
302
+ var i, arr = [];
303
+ if (opts.showWeekNumber) {
304
+ arr.push('<th></th>');
305
+ }
306
+ for (i = 0; i < 7; i++) {
307
+ arr.push('<th scope="col"><abbr title="' + renderDayName(opts, i) + '">' + renderDayName(opts, i, true) + '</abbr></th>');
308
+ }
309
+ return '<thead>' + (opts.isRTL ? arr.reverse() : arr).join('') + '</thead>';
310
+ },
311
+
312
+ renderTitle = function(instance, c, year, month, refYear)
313
+ {
314
+ var i, j, arr,
315
+ opts = instance._o,
316
+ isMinYear = year === opts.minYear,
317
+ isMaxYear = year === opts.maxYear,
318
+ html = '<div class="pika-title">',
319
+ monthHtml,
320
+ yearHtml,
321
+ prev = true,
322
+ next = true;
323
+
324
+ for (arr = [], i = 0; i < 12; i++) {
325
+ arr.push('<option value="' + (year === refYear ? i - c : 12 + i - c) + '"' +
326
+ (i === month ? ' selected': '') +
327
+ ((isMinYear && i < opts.minMonth) || (isMaxYear && i > opts.maxMonth) ? 'disabled' : '') + '>' +
328
+ opts.i18n.months[i] + '</option>');
329
+ }
330
+ monthHtml = '<div class="pika-label">' + opts.i18n.months[month] + '<select class="pika-select pika-select-month">' + arr.join('') + '</select></div>';
331
+
332
+ if (isArray(opts.yearRange)) {
333
+ i = opts.yearRange[0];
334
+ j = opts.yearRange[1] + 1;
335
+ } else {
336
+ i = year - opts.yearRange;
337
+ j = 1 + year + opts.yearRange;
338
+ }
339
+
340
+ for (arr = []; i < j && i <= opts.maxYear; i++) {
341
+ if (i >= opts.minYear) {
342
+ arr.push('<option value="' + i + '"' + (i === year ? ' selected': '') + '>' + (i) + '</option>');
343
+ }
344
+ }
345
+ yearHtml = '<div class="pika-label">' + year + opts.yearSuffix + '<select class="pika-select pika-select-year">' + arr.join('') + '</select></div>';
346
+
347
+ if (opts.showMonthAfterYear) {
348
+ html += yearHtml + monthHtml;
349
+ } else {
350
+ html += monthHtml + yearHtml;
351
+ }
352
+
353
+ if (isMinYear && (month === 0 || opts.minMonth >= month)) {
354
+ prev = false;
355
+ }
356
+
357
+ if (isMaxYear && (month === 11 || opts.maxMonth <= month)) {
358
+ next = false;
359
+ }
360
+
361
+ if (c === 0) {
362
+ html += '<button class="pika-prev' + (prev ? '' : ' is-disabled') + '" type="button">' + opts.i18n.previousMonth + '</button>';
363
+ }
364
+ if (c === (instance._o.numberOfMonths - 1) ) {
365
+ html += '<button class="pika-next' + (next ? '' : ' is-disabled') + '" type="button">' + opts.i18n.nextMonth + '</button>';
366
+ }
367
+
368
+ return html += '</div>';
369
+ },
370
+
371
+ renderTable = function(opts, data)
372
+ {
373
+ return '<table cellpadding="0" cellspacing="0" class="pika-table">' + renderHead(opts) + renderBody(data) + '</table>';
374
+ },
375
+
376
+
377
+ /**
378
+ * Pikaday constructor
379
+ */
380
+ Pikaday = function(options)
381
+ {
382
+ var self = this,
383
+ opts = self.config(options);
384
+
385
+ self._onMouseDown = function(e)
386
+ {
387
+ if (!self._v) {
388
+ return;
389
+ }
390
+ e = e || window.event;
391
+ var target = e.target || e.srcElement;
392
+ if (!target) {
393
+ return;
394
+ }
395
+
396
+ if (!hasClass(target, 'is-disabled')) {
397
+ if (hasClass(target, 'pika-button') && !hasClass(target, 'is-empty')) {
398
+ self.setDate(new Date(target.getAttribute('data-pika-year'), target.getAttribute('data-pika-month'), target.getAttribute('data-pika-day')));
399
+ if (opts.bound) {
400
+ sto(function() {
401
+ self.hide();
402
+ if (opts.field) {
403
+ opts.field.blur();
404
+ }
405
+ }, 100);
406
+ }
407
+ return;
408
+ }
409
+ else if (hasClass(target, 'pika-prev')) {
410
+ self.prevMonth();
411
+ }
412
+ else if (hasClass(target, 'pika-next')) {
413
+ self.nextMonth();
414
+ }
415
+ }
416
+ if (!hasClass(target, 'pika-select')) {
417
+ if (e.preventDefault) {
418
+ e.preventDefault();
419
+ } else {
420
+ e.returnValue = false;
421
+ return false;
422
+ }
423
+ } else {
424
+ self._c = true;
425
+ }
426
+ };
427
+
428
+ self._onChange = function(e)
429
+ {
430
+ e = e || window.event;
431
+ var target = e.target || e.srcElement;
432
+ if (!target) {
433
+ return;
434
+ }
435
+ if (hasClass(target, 'pika-select-month')) {
436
+ self.gotoMonth(target.value);
437
+ }
438
+ else if (hasClass(target, 'pika-select-year')) {
439
+ self.gotoYear(target.value);
440
+ }
441
+ };
442
+
443
+ self._onInputChange = function(e)
444
+ {
445
+ var date;
446
+
447
+ if (e.firedBy === self) {
448
+ return;
449
+ }
450
+ if (hasMoment) {
451
+ date = moment(opts.field.value, opts.format);
452
+ date = (date && date.isValid()) ? date.toDate() : null;
453
+ }
454
+ else {
455
+ date = new Date(Date.parse(opts.field.value));
456
+ }
457
+ self.setDate(isDate(date) ? date : null);
458
+ if (!self._v) {
459
+ self.show();
460
+ }
461
+ };
462
+
463
+ self._onInputFocus = function()
464
+ {
465
+ self.show();
466
+ };
467
+
468
+ self._onInputClick = function()
469
+ {
470
+ self.show();
471
+ };
472
+
473
+ self._onInputBlur = function()
474
+ {
475
+ if (!self._c) {
476
+ self._b = sto(function() {
477
+ self.hide();
478
+ }, 50);
479
+ }
480
+ self._c = false;
481
+ };
482
+
483
+ self._onClick = function(e)
484
+ {
485
+ e = e || window.event;
486
+ var target = e.target || e.srcElement,
487
+ pEl = target;
488
+ if (!target) {
489
+ return;
490
+ }
491
+ if (!hasEventListeners && hasClass(target, 'pika-select')) {
492
+ if (!target.onchange) {
493
+ target.setAttribute('onchange', 'return;');
494
+ addEvent(target, 'change', self._onChange);
495
+ }
496
+ }
497
+ do {
498
+ if (hasClass(pEl, 'pika-single')) {
499
+ return;
500
+ }
501
+ }
502
+ while ((pEl = pEl.parentNode));
503
+ if (self._v && target !== opts.trigger) {
504
+ self.hide();
505
+ }
506
+ };
507
+
508
+ self.el = document.createElement('div');
509
+ self.el.className = 'pika-single' + (opts.isRTL ? ' is-rtl' : '');
510
+
511
+ addEvent(self.el, 'mousedown', self._onMouseDown, true);
512
+ addEvent(self.el, 'change', self._onChange);
513
+
514
+ if (opts.field) {
515
+ if (opts.container) {
516
+ opts.container.appendChild(self.el);
517
+ } else if (opts.bound) {
518
+ document.body.appendChild(self.el);
519
+ } else {
520
+ opts.field.parentNode.insertBefore(self.el, opts.field.nextSibling);
521
+ }
522
+ addEvent(opts.field, 'change', self._onInputChange);
523
+
524
+ if (!opts.defaultDate) {
525
+ if (hasMoment && opts.field.value) {
526
+ opts.defaultDate = moment(opts.field.value, opts.format).toDate();
527
+ } else {
528
+ opts.defaultDate = new Date(Date.parse(opts.field.value));
529
+ }
530
+ opts.setDefaultDate = true;
531
+ }
532
+ }
533
+
534
+ var defDate = opts.defaultDate;
535
+
536
+ if (isDate(defDate)) {
537
+ if (opts.setDefaultDate) {
538
+ self.setDate(defDate, true);
539
+ } else {
540
+ self.gotoDate(defDate);
541
+ }
542
+ } else {
543
+ self.gotoDate(new Date());
544
+ }
545
+
546
+ if (opts.bound) {
547
+ this.hide();
548
+ self.el.className += ' is-bound';
549
+ addEvent(opts.trigger, 'click', self._onInputClick);
550
+ addEvent(opts.trigger, 'focus', self._onInputFocus);
551
+ addEvent(opts.trigger, 'blur', self._onInputBlur);
552
+ } else {
553
+ this.show();
554
+ }
555
+ };
556
+
557
+
558
+ /**
559
+ * public Pikaday API
560
+ */
561
+ Pikaday.prototype = {
562
+
563
+
564
+ /**
565
+ * configure functionality
566
+ */
567
+ config: function(options)
568
+ {
569
+ if (!this._o) {
570
+ this._o = extend({}, defaults, true);
571
+ }
572
+
573
+ var opts = extend(this._o, options, true);
574
+
575
+ opts.isRTL = !!opts.isRTL;
576
+
577
+ opts.field = (opts.field && opts.field.nodeName) ? opts.field : null;
578
+
579
+ opts.bound = !!(opts.bound !== undefined ? opts.field && opts.bound : opts.field);
580
+
581
+ opts.trigger = (opts.trigger && opts.trigger.nodeName) ? opts.trigger : opts.field;
582
+
583
+ var nom = parseInt(opts.numberOfMonths, 10) || 1;
584
+ opts.numberOfMonths = nom > 4 ? 4 : nom;
585
+
586
+ if (!isDate(opts.minDate)) {
587
+ opts.minDate = false;
588
+ }
589
+ if (!isDate(opts.maxDate)) {
590
+ opts.maxDate = false;
591
+ }
592
+ if ((opts.minDate && opts.maxDate) && opts.maxDate < opts.minDate) {
593
+ opts.maxDate = opts.minDate = false;
594
+ }
595
+ if (opts.minDate) {
596
+ setToStartOfDay(opts.minDate);
597
+ opts.minYear = opts.minDate.getFullYear();
598
+ opts.minMonth = opts.minDate.getMonth();
599
+ }
600
+ if (opts.maxDate) {
601
+ setToStartOfDay(opts.maxDate);
602
+ opts.maxYear = opts.maxDate.getFullYear();
603
+ opts.maxMonth = opts.maxDate.getMonth();
604
+ }
605
+
606
+ if (isArray(opts.yearRange)) {
607
+ var fallback = new Date().getFullYear() - 10;
608
+ opts.yearRange[0] = parseInt(opts.yearRange[0], 10) || fallback;
609
+ opts.yearRange[1] = parseInt(opts.yearRange[1], 10) || fallback;
610
+ } else {
611
+ opts.yearRange = Math.abs(parseInt(opts.yearRange, 10)) || defaults.yearRange;
612
+ if (opts.yearRange > 100) {
613
+ opts.yearRange = 100;
614
+ }
615
+ }
616
+
617
+ return opts;
618
+ },
619
+
620
+ /**
621
+ * return a formatted string of the current selection (using Moment.js if available)
622
+ */
623
+ toString: function(format)
624
+ {
625
+ return !isDate(this._d) ? '' : hasMoment ? moment(this._d).format(format || this._o.format) : this._d.toDateString();
626
+ },
627
+
628
+ /**
629
+ * return a Moment.js object of the current selection (if available)
630
+ */
631
+ getMoment: function()
632
+ {
633
+ return hasMoment ? moment(this._d) : null;
634
+ },
635
+
636
+ /**
637
+ * set the current selection from a Moment.js object (if available)
638
+ */
639
+ setMoment: function(date, preventOnSelect)
640
+ {
641
+ if (hasMoment && moment.isMoment(date)) {
642
+ this.setDate(date.toDate(), preventOnSelect);
643
+ }
644
+ },
645
+
646
+ /**
647
+ * return a Date object of the current selection
648
+ */
649
+ getDate: function()
650
+ {
651
+ return isDate(this._d) ? new Date(this._d.getTime()) : null;
652
+ },
653
+
654
+ /**
655
+ * set the current selection
656
+ */
657
+ setDate: function(date, preventOnSelect)
658
+ {
659
+ if (!date) {
660
+ this._d = null;
661
+ return this.draw();
662
+ }
663
+ if (typeof date === 'string') {
664
+ date = new Date(Date.parse(date));
665
+ }
666
+ if (!isDate(date)) {
667
+ return;
668
+ }
669
+
670
+ var min = this._o.minDate,
671
+ max = this._o.maxDate;
672
+
673
+ if (isDate(min) && date < min) {
674
+ date = min;
675
+ } else if (isDate(max) && date > max) {
676
+ date = max;
677
+ }
678
+
679
+ this._d = new Date(date.getTime());
680
+ setToStartOfDay(this._d);
681
+ this.gotoDate(this._d);
682
+
683
+ if (this._o.field) {
684
+ this._o.field.value = this.toString();
685
+ fireEvent(this._o.field, 'change', { firedBy: this });
686
+ }
687
+ if (!preventOnSelect && typeof this._o.onSelect === 'function') {
688
+ this._o.onSelect.call(this, this.getDate());
689
+ }
690
+ },
691
+
692
+ /**
693
+ * change view to a specific date
694
+ */
695
+ gotoDate: function(date)
696
+ {
697
+ var newCalendar = true;
698
+
699
+ if (!isDate(date)) {
700
+ return;
701
+ }
702
+
703
+ if (this.calendars) {
704
+ var firstVisibleDate = new Date(this.calendars[0].year, this.calendars[0].month, 1),
705
+ lastVisibleDate = new Date(this.calendars[this.calendars.length-1].year, this.calendars[this.calendars.length-1].month, 1),
706
+ visibleDate = date.getTime();
707
+ // get the end of the month
708
+ lastVisibleDate.setMonth(lastVisibleDate.getMonth()+1);
709
+ lastVisibleDate.setDate(lastVisibleDate.getDate()-1);
710
+ newCalendar = (visibleDate < firstVisibleDate.getTime() || lastVisibleDate.getTime() < visibleDate);
711
+ }
712
+
713
+ if (newCalendar) {
714
+ this.calendars = [{
715
+ month: date.getMonth(),
716
+ year: date.getFullYear()
717
+ }];
718
+ if (this._o.mainCalendar === 'right') {
719
+ this.calendars[0].month += 1 - this._o.numberOfMonths;
720
+ }
721
+ }
722
+
723
+ this.adjustCalendars();
724
+ },
725
+
726
+ adjustCalendars: function() {
727
+ this.calendars[0] = adjustCalendar(this.calendars[0]);
728
+ for (var c = 1; c < this._o.numberOfMonths; c++) {
729
+ this.calendars[c] = adjustCalendar({
730
+ month: this.calendars[0].month + c,
731
+ year: this.calendars[0].year
732
+ });
733
+ }
734
+ this.draw();
735
+ },
736
+
737
+ gotoToday: function()
738
+ {
739
+ this.gotoDate(new Date());
740
+ },
741
+
742
+ /**
743
+ * change view to a specific month (zero-index, e.g. 0: January)
744
+ */
745
+ gotoMonth: function(month)
746
+ {
747
+ if (!isNaN(month)) {
748
+ this.calendars[0].month = parseInt(month, 10);
749
+ this.adjustCalendars();
750
+ }
751
+ },
752
+
753
+ nextMonth: function()
754
+ {
755
+ this.calendars[0].month++;
756
+ this.adjustCalendars();
757
+ },
758
+
759
+ prevMonth: function()
760
+ {
761
+ this.calendars[0].month--;
762
+ this.adjustCalendars();
763
+ },
764
+
765
+ /**
766
+ * change view to a specific full year (e.g. "2012")
767
+ */
768
+ gotoYear: function(year)
769
+ {
770
+ if (!isNaN(year)) {
771
+ this.calendars[0].year = parseInt(year, 10);
772
+ this.adjustCalendars();
773
+ }
774
+ },
775
+
776
+ /**
777
+ * change the minDate
778
+ */
779
+ setMinDate: function(value)
780
+ {
781
+ this._o.minDate = value;
782
+ },
783
+
784
+ /**
785
+ * change the maxDate
786
+ */
787
+ setMaxDate: function(value)
788
+ {
789
+ this._o.maxDate = value;
790
+ },
791
+
792
+ /**
793
+ * refresh the HTML
794
+ */
795
+ draw: function(force)
796
+ {
797
+ if (!this._v && !force) {
798
+ return;
799
+ }
800
+ var opts = this._o,
801
+ minYear = opts.minYear,
802
+ maxYear = opts.maxYear,
803
+ minMonth = opts.minMonth,
804
+ maxMonth = opts.maxMonth,
805
+ html = '';
806
+
807
+ if (this._y <= minYear) {
808
+ this._y = minYear;
809
+ if (!isNaN(minMonth) && this._m < minMonth) {
810
+ this._m = minMonth;
811
+ }
812
+ }
813
+ if (this._y >= maxYear) {
814
+ this._y = maxYear;
815
+ if (!isNaN(maxMonth) && this._m > maxMonth) {
816
+ this._m = maxMonth;
817
+ }
818
+ }
819
+
820
+ for (var c = 0; c < opts.numberOfMonths; c++) {
821
+ html += '<div class="pika-lendar">' + renderTitle(this, c, this.calendars[c].year, this.calendars[c].month, this.calendars[0].year) + this.render(this.calendars[c].year, this.calendars[c].month) + '</div>';
822
+ }
823
+
824
+ this.el.innerHTML = html;
825
+
826
+ if (opts.bound) {
827
+ if(opts.field.type !== 'hidden') {
828
+ sto(function() {
829
+ opts.trigger.focus();
830
+ }, 1);
831
+ }
832
+ }
833
+
834
+ if (typeof this._o.onDraw === 'function') {
835
+ var self = this;
836
+ sto(function() {
837
+ self._o.onDraw.call(self);
838
+ }, 0);
839
+ }
840
+ },
841
+
842
+ adjustPosition: function()
843
+ {
844
+ if (this._o.container) return;
845
+ var field = this._o.trigger, pEl = field,
846
+ width = this.el.offsetWidth, height = this.el.offsetHeight,
847
+ viewportWidth = window.innerWidth || document.documentElement.clientWidth,
848
+ viewportHeight = window.innerHeight || document.documentElement.clientHeight,
849
+ scrollTop = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop,
850
+ left, top, clientRect;
851
+
852
+ if (typeof field.getBoundingClientRect === 'function') {
853
+ clientRect = field.getBoundingClientRect();
854
+ left = clientRect.left + window.pageXOffset;
855
+ top = clientRect.bottom + window.pageYOffset;
856
+ } else {
857
+ left = pEl.offsetLeft;
858
+ top = pEl.offsetTop + pEl.offsetHeight;
859
+ while((pEl = pEl.offsetParent)) {
860
+ left += pEl.offsetLeft;
861
+ top += pEl.offsetTop;
862
+ }
863
+ }
864
+
865
+ // default position is bottom & left
866
+ if (left + width > viewportWidth ||
867
+ (
868
+ this._o.position.indexOf('right') > -1 &&
869
+ left - width + field.offsetWidth > 0
870
+ )
871
+ ) {
872
+ left = left - width + field.offsetWidth;
873
+ }
874
+ if (top + height > viewportHeight + scrollTop ||
875
+ (
876
+ this._o.position.indexOf('top') > -1 &&
877
+ top - height - field.offsetHeight > 0
878
+ )
879
+ ) {
880
+ top = top - height - field.offsetHeight;
881
+ }
882
+ this.el.style.cssText = [
883
+ 'position: absolute',
884
+ 'left: ' + left + 'px',
885
+ 'top: ' + top + 'px'
886
+ ].join(';');
887
+ },
888
+
889
+ /**
890
+ * render HTML for a particular month
891
+ */
892
+ render: function(year, month)
893
+ {
894
+ var opts = this._o,
895
+ now = new Date(),
896
+ days = getDaysInMonth(year, month),
897
+ before = new Date(year, month, 1).getDay(),
898
+ data = [],
899
+ row = [];
900
+ setToStartOfDay(now);
901
+ if (opts.firstDay > 0) {
902
+ before -= opts.firstDay;
903
+ if (before < 0) {
904
+ before += 7;
905
+ }
906
+ }
907
+ var cells = days + before,
908
+ after = cells;
909
+ while(after > 7) {
910
+ after -= 7;
911
+ }
912
+ cells += 7 - after;
913
+ for (var i = 0, r = 0; i < cells; i++)
914
+ {
915
+ var day = new Date(year, month, 1 + (i - before)),
916
+ isDisabled = (opts.minDate && day < opts.minDate) || (opts.maxDate && day > opts.maxDate),
917
+ isSelected = isDate(this._d) ? compareDates(day, this._d) : false,
918
+ isToday = compareDates(day, now),
919
+ isEmpty = i < before || i >= (days + before);
920
+
921
+ row.push(renderDay(1 + (i - before), month, year, isSelected, isToday, isDisabled, isEmpty));
922
+
923
+ if (++r === 7) {
924
+ if (opts.showWeekNumber) {
925
+ row.unshift(renderWeek(i - before, month, year));
926
+ }
927
+ data.push(renderRow(row, opts.isRTL));
928
+ row = [];
929
+ r = 0;
930
+ }
931
+ }
932
+ return renderTable(opts, data);
933
+ },
934
+
935
+ isVisible: function()
936
+ {
937
+ return this._v;
938
+ },
939
+
940
+ show: function()
941
+ {
942
+ if (!this._v) {
943
+ removeClass(this.el, 'is-hidden');
944
+ this._v = true;
945
+ this.draw();
946
+ if (this._o.bound) {
947
+ addEvent(document, 'click', this._onClick);
948
+ this.adjustPosition();
949
+ }
950
+ if (typeof this._o.onOpen === 'function') {
951
+ this._o.onOpen.call(this);
952
+ }
953
+ }
954
+ },
955
+
956
+ hide: function()
957
+ {
958
+ var v = this._v;
959
+ if (v !== false) {
960
+ if (this._o.bound) {
961
+ removeEvent(document, 'click', this._onClick);
962
+ }
963
+ this.el.style.cssText = '';
964
+ addClass(this.el, 'is-hidden');
965
+ this._v = false;
966
+ if (v !== undefined && typeof this._o.onClose === 'function') {
967
+ this._o.onClose.call(this);
968
+ }
969
+ }
970
+ },
971
+
972
+ /**
973
+ * GAME OVER
974
+ */
975
+ destroy: function()
976
+ {
977
+ this.hide();
978
+ removeEvent(this.el, 'mousedown', this._onMouseDown, true);
979
+ removeEvent(this.el, 'change', this._onChange);
980
+ if (this._o.field) {
981
+ removeEvent(this._o.field, 'change', this._onInputChange);
982
+ if (this._o.bound) {
983
+ removeEvent(this._o.trigger, 'click', this._onInputClick);
984
+ removeEvent(this._o.trigger, 'focus', this._onInputFocus);
985
+ removeEvent(this._o.trigger, 'blur', this._onInputBlur);
986
+ }
987
+ }
988
+ if (this.el.parentNode) {
989
+ this.el.parentNode.removeChild(this.el);
990
+ }
991
+ }
992
+
993
+ };
994
+
995
+ return Pikaday;
996
+
997
+ }));