upmin 0.0.34

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) 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 +38 -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/pikaday.js +997 -0
  9. data/app/assets/stylesheets/upmin/application.css +16 -0
  10. data/app/assets/stylesheets/upmin/base.css.scss +24 -0
  11. data/app/assets/stylesheets/upmin/button_mixins.scss +37 -0
  12. data/app/assets/stylesheets/upmin/colors.scss +20 -0
  13. data/app/assets/stylesheets/upmin/instances.css.scss +91 -0
  14. data/app/assets/stylesheets/upmin/jquery-clockpicker.css +370 -0
  15. data/app/assets/stylesheets/upmin/models.css.scss +207 -0
  16. data/app/assets/stylesheets/upmin/pikaday.css +196 -0
  17. data/app/controllers/upmin/application_controller.rb +4 -0
  18. data/app/controllers/upmin/models_controller.rb +94 -0
  19. data/app/helpers/upmin/application_helper.rb +17 -0
  20. data/app/helpers/upmin/instances_helper.rb +13 -0
  21. data/app/helpers/upmin/models_helper.rb +4 -0
  22. data/app/views/layouts/upmin/_navbar.html.haml +15 -0
  23. data/app/views/layouts/upmin/application.html.haml +24 -0
  24. data/app/views/upmin/models/_search_result.html.haml +25 -0
  25. data/app/views/upmin/models/dashboard.html.haml +9 -0
  26. data/app/views/upmin/models/search.html.haml +20 -0
  27. data/app/views/upmin/models/show.html.haml +21 -0
  28. data/app/views/upmin/search_boxes/_unknown.html.haml +31 -0
  29. data/app/views/upmin/search_fields/_string.html.haml +3 -0
  30. data/app/views/upmin/types/_datetime.html.haml +95 -0
  31. data/app/views/upmin/types/_integer.html.haml +6 -0
  32. data/app/views/upmin/types/_string.html.haml +7 -0
  33. data/app/views/upmin/types/_unknown.html.haml +2 -0
  34. data/app/views/upmin/types/_unknown_collection.html.haml +18 -0
  35. data/app/views/upmin/types/_unknown_model.html.haml +57 -0
  36. data/app/views/upmin/types/_unknown_model_badge.html.haml +3 -0
  37. data/app/views/upmin/types/_unknown_model_nested.html.haml +24 -0
  38. data/app/views/upmin/types/_unknown_model_search_result.html.haml +31 -0
  39. data/config/routes.rb +19 -0
  40. data/lib/tasks/accordive_rails_tasks.rake +4 -0
  41. data/lib/tasks/upmin_tasks.rake +4 -0
  42. data/lib/upmin.rb +44 -0
  43. data/lib/upmin/engine.rb +7 -0
  44. data/lib/upmin/graph/collection_node.rb +72 -0
  45. data/lib/upmin/graph/data_node.rb +69 -0
  46. data/lib/upmin/graph/model_node.rb +151 -0
  47. data/lib/upmin/graph/node.rb +98 -0
  48. data/lib/upmin/model.rb +131 -0
  49. data/lib/upmin/railtie.rb +19 -0
  50. data/lib/upmin/railties/active_record.rb +156 -0
  51. data/lib/upmin/railties/render.rb +56 -0
  52. data/lib/upmin/railties/render_helpers.rb +57 -0
  53. data/lib/upmin/version.rb +3 -0
  54. data/test/controllers/upmin/model_controller_test.rb +11 -0
  55. data/test/dummy/README.rdoc +28 -0
  56. data/test/dummy/Rakefile +6 -0
  57. data/test/dummy/app/assets/javascripts/application.js +13 -0
  58. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  59. data/test/dummy/app/controllers/application_controller.rb +5 -0
  60. data/test/dummy/app/helpers/application_helper.rb +2 -0
  61. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  62. data/test/dummy/bin/bundle +3 -0
  63. data/test/dummy/bin/rails +4 -0
  64. data/test/dummy/bin/rake +4 -0
  65. data/test/dummy/config.ru +4 -0
  66. data/test/dummy/config/application.rb +23 -0
  67. data/test/dummy/config/boot.rb +5 -0
  68. data/test/dummy/config/database.yml +25 -0
  69. data/test/dummy/config/environment.rb +5 -0
  70. data/test/dummy/config/environments/development.rb +37 -0
  71. data/test/dummy/config/environments/production.rb +83 -0
  72. data/test/dummy/config/environments/test.rb +39 -0
  73. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  74. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  75. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  76. data/test/dummy/config/initializers/inflections.rb +16 -0
  77. data/test/dummy/config/initializers/mime_types.rb +4 -0
  78. data/test/dummy/config/initializers/session_store.rb +3 -0
  79. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  80. data/test/dummy/config/locales/en.yml +23 -0
  81. data/test/dummy/config/routes.rb +4 -0
  82. data/test/dummy/config/secrets.yml +22 -0
  83. data/test/dummy/public/404.html +67 -0
  84. data/test/dummy/public/422.html +67 -0
  85. data/test/dummy/public/500.html +66 -0
  86. data/test/dummy/public/favicon.ico +0 -0
  87. data/test/helpers/upmin/model_helper_test.rb +6 -0
  88. data/test/integration/navigation_test.rb +10 -0
  89. data/test/test_helper.rb +15 -0
  90. data/test/upmin_test.rb +7 -0
  91. metadata +253 -0
@@ -0,0 +1,23 @@
1
+ var Models = {
2
+ init: function() {
3
+ return console.log("Init Models JS...");
4
+ },
5
+
6
+
7
+ Search: {
8
+ init: function() {
9
+ console.log("Init Models.Search JS...");
10
+ }, // end of Search.init()
11
+
12
+ } // end of Search
13
+
14
+
15
+
16
+
17
+ };
18
+
19
+ if (window.Upmin == null) {
20
+ window.Upmin = {};
21
+ }
22
+
23
+ window.Upmin.Models = Models;
@@ -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
+ }));