pikaday-gem 1.1.0.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MDg2MTQ5M2FkNWE5ZjUwM2ZlYzk1OTdkMDQzZWY2MWMyMTRmZGU3YQ==
5
+ data.tar.gz: !binary |-
6
+ YzA2ZDI0NzY4YzEzZjg5NGFkNDhjMzgyZjhmZWU1MmQ4ZjgxMDBmNw==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ ZjMzOTVmZWJmNTRhMTVhOThkN2ZhNWFmMDM3MzBlMGVkY2IxNmI1YjNkNzMx
10
+ NDIyNmNkNTEzNzY4MjgwNDlmYTZkNWNhYWFlNzhmMTJjYTQ4NjNmNTU2MDU2
11
+ NDIwNTcwZDI4OTVkYjBkZDdiZTQ2MDBlYTIyYzI2YzE0MjIxNGE=
12
+ data.tar.gz: !binary |-
13
+ MmRmNzBlOGYxMDI4ZTEyYjRlNTQwMDQ5MWE3YmY1NTkxNDU2NDU3MzFlMjU5
14
+ NmZmYWFjNDMwNmMzYjcyOTdmMTgyNzY1ZWFmM2JhYTM2OTk0YjY4MjVlYTIy
15
+ OTY0Y2RlZTg4NTNiOTNjOTlkYjQ3ZGM2YjU5NWMwODQyYzBlMWI=
@@ -1,3 +1,3 @@
1
1
  module PikadayGem
2
- VERSION = "1.1.0.0"
2
+ VERSION = "1.2.0"
3
3
  end
@@ -0,0 +1,920 @@
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
+
158
+ /**
159
+ * defaults and localisation
160
+ */
161
+ defaults = {
162
+
163
+ // bind the picker to a form field
164
+ field: null,
165
+
166
+ // automatically show/hide the picker on `field` focus (default `true` if `field` is set)
167
+ bound: undefined,
168
+
169
+ // position of the datepicker, relative to the field (default to bottom & left)
170
+ // ('bottom' & 'left' keywords are not used, 'top' & 'right' are modifier on the bottom/left position)
171
+ position: 'bottom left',
172
+
173
+ // the default output format for `.toString()` and `field` value
174
+ format: 'YYYY-MM-DD',
175
+
176
+ // the initial date to view when first opened
177
+ defaultDate: null,
178
+
179
+ // make the `defaultDate` the initial selected value
180
+ setDefaultDate: false,
181
+
182
+ // first day of week (0: Sunday, 1: Monday etc)
183
+ firstDay: 0,
184
+
185
+ // the minimum/earliest date that can be selected
186
+ minDate: null,
187
+ // the maximum/latest date that can be selected
188
+ maxDate: null,
189
+
190
+ // number of years either side, or array of upper/lower range
191
+ yearRange: 10,
192
+
193
+ // used internally (don't config outside)
194
+ minYear: 0,
195
+ maxYear: 9999,
196
+ minMonth: undefined,
197
+ maxMonth: undefined,
198
+
199
+ isRTL: false,
200
+
201
+ // Additional text to append to the year in the calendar title
202
+ yearSuffix: '',
203
+
204
+ // Render the month after year in the calendar title
205
+ showMonthAfterYear: false,
206
+
207
+ // how many months are visible (not implemented yet)
208
+ numberOfMonths: 1,
209
+
210
+ // internationalization
211
+ i18n: {
212
+ previousMonth : 'Previous Month',
213
+ nextMonth : 'Next Month',
214
+ months : ['January','February','March','April','May','June','July','August','September','October','November','December'],
215
+ weekdays : ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
216
+ weekdaysShort : ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
217
+ },
218
+
219
+ // callback function
220
+ onSelect: null,
221
+ onOpen: null,
222
+ onClose: null,
223
+ onDraw: null
224
+ },
225
+
226
+
227
+ /**
228
+ * templating functions to abstract HTML rendering
229
+ */
230
+ renderDayName = function(opts, day, abbr)
231
+ {
232
+ day += opts.firstDay;
233
+ while (day >= 7) {
234
+ day -= 7;
235
+ }
236
+ return abbr ? opts.i18n.weekdaysShort[day] : opts.i18n.weekdays[day];
237
+ },
238
+
239
+ renderDay = function(i, isSelected, isToday, isDisabled, isEmpty)
240
+ {
241
+ if (isEmpty) {
242
+ return '<td class="is-empty"></td>';
243
+ }
244
+ var arr = [];
245
+ if (isDisabled) {
246
+ arr.push('is-disabled');
247
+ }
248
+ if (isToday) {
249
+ arr.push('is-today');
250
+ }
251
+ if (isSelected) {
252
+ arr.push('is-selected');
253
+ }
254
+ return '<td data-day="' + i + '" class="' + arr.join(' ') + '"><button class="pika-button" type="button">' + i + '</button>' + '</td>';
255
+ },
256
+
257
+ renderRow = function(days, isRTL)
258
+ {
259
+ return '<tr>' + (isRTL ? days.reverse() : days).join('') + '</tr>';
260
+ },
261
+
262
+ renderBody = function(rows)
263
+ {
264
+ return '<tbody>' + rows.join('') + '</tbody>';
265
+ },
266
+
267
+ renderHead = function(opts)
268
+ {
269
+ var i, arr = [];
270
+ for (i = 0; i < 7; i++) {
271
+ arr.push('<th scope="col"><abbr title="' + renderDayName(opts, i) + '">' + renderDayName(opts, i, true) + '</abbr></th>');
272
+ }
273
+ return '<thead>' + (opts.isRTL ? arr.reverse() : arr).join('') + '</thead>';
274
+ },
275
+
276
+ renderTitle = function(instance)
277
+ {
278
+ var i, j, arr,
279
+ opts = instance._o,
280
+ month = instance._m,
281
+ year = instance._y,
282
+ isMinYear = year === opts.minYear,
283
+ isMaxYear = year === opts.maxYear,
284
+ html = '<div class="pika-title">',
285
+ monthHtml,
286
+ yearHtml,
287
+ prev = true,
288
+ next = true;
289
+
290
+ for (arr = [], i = 0; i < 12; i++) {
291
+ arr.push('<option value="' + i + '"' +
292
+ (i === month ? ' selected': '') +
293
+ ((isMinYear && i < opts.minMonth) || (isMaxYear && i > opts.maxMonth) ? 'disabled' : '') + '>' +
294
+ opts.i18n.months[i] + '</option>');
295
+ }
296
+ monthHtml = '<div class="pika-label">' + opts.i18n.months[month] + '<select class="pika-select pika-select-month">' + arr.join('') + '</select></div>';
297
+
298
+ if (isArray(opts.yearRange)) {
299
+ i = opts.yearRange[0];
300
+ j = opts.yearRange[1] + 1;
301
+ } else {
302
+ i = year - opts.yearRange;
303
+ j = 1 + year + opts.yearRange;
304
+ }
305
+
306
+ for (arr = []; i < j && i <= opts.maxYear; i++) {
307
+ if (i >= opts.minYear) {
308
+ arr.push('<option value="' + i + '"' + (i === year ? ' selected': '') + '>' + (i) + '</option>');
309
+ }
310
+ }
311
+ yearHtml = '<div class="pika-label">' + year + opts.yearSuffix + '<select class="pika-select pika-select-year">' + arr.join('') + '</select></div>';
312
+
313
+ if (opts.showMonthAfterYear) {
314
+ html += yearHtml + monthHtml;
315
+ } else {
316
+ html += monthHtml + yearHtml;
317
+ }
318
+
319
+ if (isMinYear && (month === 0 || opts.minMonth >= month)) {
320
+ prev = false;
321
+ }
322
+
323
+ if (isMaxYear && (month === 11 || opts.maxMonth <= month)) {
324
+ next = false;
325
+ }
326
+
327
+ html += '<button class="pika-prev' + (prev ? '' : ' is-disabled') + '" type="button">' + opts.i18n.previousMonth + '</button>';
328
+ html += '<button class="pika-next' + (next ? '' : ' is-disabled') + '" type="button">' + opts.i18n.nextMonth + '</button>';
329
+
330
+ return html += '</div>';
331
+ },
332
+
333
+ renderTable = function(opts, data)
334
+ {
335
+ return '<table cellpadding="0" cellspacing="0" class="pika-table">' + renderHead(opts) + renderBody(data) + '</table>';
336
+ },
337
+
338
+
339
+ /**
340
+ * Pikaday constructor
341
+ */
342
+ Pikaday = function(options)
343
+ {
344
+ var self = this,
345
+ opts = self.config(options);
346
+
347
+ self._onMouseDown = function(e)
348
+ {
349
+ if (!self._v) {
350
+ return;
351
+ }
352
+ e = e || window.event;
353
+ var target = e.target || e.srcElement;
354
+ if (!target) {
355
+ return;
356
+ }
357
+
358
+ if (!hasClass(target, 'is-disabled')) {
359
+ if (hasClass(target, 'pika-button') && !hasClass(target, 'is-empty')) {
360
+ self.setDate(new Date(self._y, self._m, parseInt(target.innerHTML, 10)));
361
+ if (opts.bound) {
362
+ sto(function() {
363
+ self.hide();
364
+ }, 100);
365
+ }
366
+ return;
367
+ }
368
+ else if (hasClass(target, 'pika-prev')) {
369
+ self.prevMonth();
370
+ }
371
+ else if (hasClass(target, 'pika-next')) {
372
+ self.nextMonth();
373
+ }
374
+ }
375
+ if (!hasClass(target, 'pika-select')) {
376
+ if (e.preventDefault) {
377
+ e.preventDefault();
378
+ } else {
379
+ e.returnValue = false;
380
+ return false;
381
+ }
382
+ } else {
383
+ self._c = true;
384
+ }
385
+ };
386
+
387
+ self._onChange = function(e)
388
+ {
389
+ e = e || window.event;
390
+ var target = e.target || e.srcElement;
391
+ if (!target) {
392
+ return;
393
+ }
394
+ if (hasClass(target, 'pika-select-month')) {
395
+ self.gotoMonth(target.value);
396
+ }
397
+ else if (hasClass(target, 'pika-select-year')) {
398
+ self.gotoYear(target.value);
399
+ }
400
+ };
401
+
402
+ self._onInputChange = function(e)
403
+ {
404
+ var date;
405
+
406
+ if (e.firedBy === self) {
407
+ return;
408
+ }
409
+ if (hasMoment) {
410
+ date = moment(opts.field.value, opts.format);
411
+ date = (date && date.isValid()) ? date.toDate() : null;
412
+ }
413
+ else {
414
+ date = new Date(Date.parse(opts.field.value));
415
+ }
416
+ self.setDate(isDate(date) ? date : null);
417
+ if (!self._v) {
418
+ self.show();
419
+ }
420
+ };
421
+
422
+ self._onInputFocus = function()
423
+ {
424
+ self.show();
425
+ };
426
+
427
+ self._onInputClick = function()
428
+ {
429
+ self.show();
430
+ };
431
+
432
+ self._onInputBlur = function()
433
+ {
434
+ if (!self._c) {
435
+ self._b = sto(function() {
436
+ self.hide();
437
+ }, 50);
438
+ }
439
+ self._c = false;
440
+ };
441
+
442
+ self._onClick = function(e)
443
+ {
444
+ e = e || window.event;
445
+ var target = e.target || e.srcElement,
446
+ pEl = target;
447
+ if (!target) {
448
+ return;
449
+ }
450
+ if (!hasEventListeners && hasClass(target, 'pika-select')) {
451
+ if (!target.onchange) {
452
+ target.setAttribute('onchange', 'return;');
453
+ addEvent(target, 'change', self._onChange);
454
+ }
455
+ }
456
+ do {
457
+ if (hasClass(pEl, 'pika-single')) {
458
+ return;
459
+ }
460
+ }
461
+ while ((pEl = pEl.parentNode));
462
+ if (self._v && target !== opts.trigger) {
463
+ self.hide();
464
+ }
465
+ };
466
+
467
+ self.el = document.createElement('div');
468
+ self.el.className = 'pika-single' + (opts.isRTL ? ' is-rtl' : '');
469
+
470
+ addEvent(self.el, 'mousedown', self._onMouseDown, true);
471
+ addEvent(self.el, 'change', self._onChange);
472
+
473
+ if (opts.field) {
474
+ if (opts.bound) {
475
+ document.body.appendChild(self.el);
476
+ } else {
477
+ opts.field.parentNode.insertBefore(self.el, opts.field.nextSibling);
478
+ }
479
+ addEvent(opts.field, 'change', self._onInputChange);
480
+
481
+ if (!opts.defaultDate) {
482
+ if (hasMoment && opts.field.value) {
483
+ opts.defaultDate = moment(opts.field.value, opts.format).toDate();
484
+ } else {
485
+ opts.defaultDate = new Date(Date.parse(opts.field.value));
486
+ }
487
+ opts.setDefaultDate = true;
488
+ }
489
+ }
490
+
491
+ var defDate = opts.defaultDate;
492
+
493
+ if (isDate(defDate)) {
494
+ if (opts.setDefaultDate) {
495
+ self.setDate(defDate, true);
496
+ } else {
497
+ self.gotoDate(defDate);
498
+ }
499
+ } else {
500
+ self.gotoDate(new Date());
501
+ }
502
+
503
+ if (opts.bound) {
504
+ this.hide();
505
+ self.el.className += ' is-bound';
506
+ addEvent(opts.trigger, 'click', self._onInputClick);
507
+ addEvent(opts.trigger, 'focus', self._onInputFocus);
508
+ addEvent(opts.trigger, 'blur', self._onInputBlur);
509
+ } else {
510
+ this.show();
511
+ }
512
+
513
+ };
514
+
515
+
516
+ /**
517
+ * public Pikaday API
518
+ */
519
+ Pikaday.prototype = {
520
+
521
+
522
+ /**
523
+ * configure functionality
524
+ */
525
+ config: function(options)
526
+ {
527
+ if (!this._o) {
528
+ this._o = extend({}, defaults, true);
529
+ }
530
+
531
+ var opts = extend(this._o, options, true);
532
+
533
+ opts.isRTL = !!opts.isRTL;
534
+
535
+ opts.field = (opts.field && opts.field.nodeName) ? opts.field : null;
536
+
537
+ opts.bound = !!(opts.bound !== undefined ? opts.field && opts.bound : opts.field);
538
+
539
+ opts.trigger = (opts.trigger && opts.trigger.nodeName) ? opts.trigger : opts.field;
540
+
541
+ var nom = parseInt(opts.numberOfMonths, 10) || 1;
542
+ opts.numberOfMonths = nom > 4 ? 4 : nom;
543
+
544
+ if (!isDate(opts.minDate)) {
545
+ opts.minDate = false;
546
+ }
547
+ if (!isDate(opts.maxDate)) {
548
+ opts.maxDate = false;
549
+ }
550
+ if ((opts.minDate && opts.maxDate) && opts.maxDate < opts.minDate) {
551
+ opts.maxDate = opts.minDate = false;
552
+ }
553
+ if (opts.minDate) {
554
+ setToStartOfDay(opts.minDate);
555
+ opts.minYear = opts.minDate.getFullYear();
556
+ opts.minMonth = opts.minDate.getMonth();
557
+ }
558
+ if (opts.maxDate) {
559
+ setToStartOfDay(opts.maxDate);
560
+ opts.maxYear = opts.maxDate.getFullYear();
561
+ opts.maxMonth = opts.maxDate.getMonth();
562
+ }
563
+
564
+ if (isArray(opts.yearRange)) {
565
+ var fallback = new Date().getFullYear() - 10;
566
+ opts.yearRange[0] = parseInt(opts.yearRange[0], 10) || fallback;
567
+ opts.yearRange[1] = parseInt(opts.yearRange[1], 10) || fallback;
568
+ } else {
569
+ opts.yearRange = Math.abs(parseInt(opts.yearRange, 10)) || defaults.yearRange;
570
+ if (opts.yearRange > 100) {
571
+ opts.yearRange = 100;
572
+ }
573
+ }
574
+
575
+ return opts;
576
+ },
577
+
578
+ /**
579
+ * return a formatted string of the current selection (using Moment.js if available)
580
+ */
581
+ toString: function(format)
582
+ {
583
+ return !isDate(this._d) ? '' : hasMoment ? moment(this._d).format(format || this._o.format) : this._d.toDateString();
584
+ },
585
+
586
+ /**
587
+ * return a Moment.js object of the current selection (if available)
588
+ */
589
+ getMoment: function()
590
+ {
591
+ return hasMoment ? moment(this._d) : null;
592
+ },
593
+
594
+ /**
595
+ * set the current selection from a Moment.js object (if available)
596
+ */
597
+ setMoment: function(date, preventOnSelect)
598
+ {
599
+ if (hasMoment && moment.isMoment(date)) {
600
+ this.setDate(date.toDate(), preventOnSelect);
601
+ }
602
+ },
603
+
604
+ /**
605
+ * return a Date object of the current selection
606
+ */
607
+ getDate: function()
608
+ {
609
+ return isDate(this._d) ? new Date(this._d.getTime()) : null;
610
+ },
611
+
612
+ /**
613
+ * set the current selection
614
+ */
615
+ setDate: function(date, preventOnSelect)
616
+ {
617
+ if (!date) {
618
+ this._d = null;
619
+ return this.draw();
620
+ }
621
+ if (typeof date === 'string') {
622
+ date = new Date(Date.parse(date));
623
+ }
624
+ if (!isDate(date)) {
625
+ return;
626
+ }
627
+
628
+ var min = this._o.minDate,
629
+ max = this._o.maxDate;
630
+
631
+ if (isDate(min) && date < min) {
632
+ date = min;
633
+ } else if (isDate(max) && date > max) {
634
+ date = max;
635
+ }
636
+
637
+ this._d = new Date(date.getTime());
638
+ setToStartOfDay(this._d);
639
+ this.gotoDate(this._d);
640
+
641
+ if (this._o.field) {
642
+ this._o.field.value = this.toString();
643
+ fireEvent(this._o.field, 'change', { firedBy: this });
644
+ }
645
+ if (!preventOnSelect && typeof this._o.onSelect === 'function') {
646
+ this._o.onSelect.call(this, this.getDate());
647
+ }
648
+ },
649
+
650
+ /**
651
+ * change view to a specific date
652
+ */
653
+ gotoDate: function(date)
654
+ {
655
+ if (!isDate(date)) {
656
+ return;
657
+ }
658
+ this._y = date.getFullYear();
659
+ this._m = date.getMonth();
660
+ this.draw();
661
+ },
662
+
663
+ gotoToday: function()
664
+ {
665
+ this.gotoDate(new Date());
666
+ },
667
+
668
+ /**
669
+ * change view to a specific month (zero-index, e.g. 0: January)
670
+ */
671
+ gotoMonth: function(month)
672
+ {
673
+ if (!isNaN( (month = parseInt(month, 10)) )) {
674
+ this._m = month < 0 ? 0 : month > 11 ? 11 : month;
675
+ this.draw();
676
+ }
677
+ },
678
+
679
+ nextMonth: function()
680
+ {
681
+ if (++this._m > 11) {
682
+ this._m = 0;
683
+ this._y++;
684
+ }
685
+ this.draw();
686
+ },
687
+
688
+ prevMonth: function()
689
+ {
690
+ if (--this._m < 0) {
691
+ this._m = 11;
692
+ this._y--;
693
+ }
694
+ this.draw();
695
+ },
696
+
697
+ /**
698
+ * change view to a specific full year (e.g. "2012")
699
+ */
700
+ gotoYear: function(year)
701
+ {
702
+ if (!isNaN(year)) {
703
+ this._y = parseInt(year, 10);
704
+ this.draw();
705
+ }
706
+ },
707
+
708
+ /**
709
+ * change the minDate
710
+ */
711
+ setMinDate: function(value)
712
+ {
713
+ this._o.minDate = value;
714
+ },
715
+
716
+ /**
717
+ * change the maxDate
718
+ */
719
+ setMaxDate: function(value)
720
+ {
721
+ this._o.maxDate = value;
722
+ },
723
+
724
+ /**
725
+ * refresh the HTML
726
+ */
727
+ draw: function(force)
728
+ {
729
+ if (!this._v && !force) {
730
+ return;
731
+ }
732
+ var opts = this._o,
733
+ minYear = opts.minYear,
734
+ maxYear = opts.maxYear,
735
+ minMonth = opts.minMonth,
736
+ maxMonth = opts.maxMonth;
737
+
738
+ if (this._y <= minYear) {
739
+ this._y = minYear;
740
+ if (!isNaN(minMonth) && this._m < minMonth) {
741
+ this._m = minMonth;
742
+ }
743
+ }
744
+ if (this._y >= maxYear) {
745
+ this._y = maxYear;
746
+ if (!isNaN(maxMonth) && this._m > maxMonth) {
747
+ this._m = maxMonth;
748
+ }
749
+ }
750
+
751
+ this.el.innerHTML = renderTitle(this) + this.render(this._y, this._m);
752
+
753
+ if (opts.bound) {
754
+ this.adjustPosition();
755
+ if(opts.field.type !== 'hidden') {
756
+ sto(function() {
757
+ opts.trigger.focus();
758
+ }, 1);
759
+ }
760
+ }
761
+
762
+ if (typeof this._o.onDraw === 'function') {
763
+ var self = this;
764
+ sto(function() {
765
+ self._o.onDraw.call(self);
766
+ }, 0);
767
+ }
768
+ },
769
+
770
+ adjustPosition: function()
771
+ {
772
+ var field = this._o.trigger, pEl = field,
773
+ width = this.el.offsetWidth, height = this.el.offsetHeight,
774
+ viewportWidth = window.innerWidth || document.documentElement.clientWidth,
775
+ viewportHeight = window.innerHeight || document.documentElement.clientHeight,
776
+ scrollTop = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop,
777
+ left, top, clientRect;
778
+
779
+ if (typeof field.getBoundingClientRect === 'function') {
780
+ clientRect = field.getBoundingClientRect();
781
+ left = clientRect.left + window.pageXOffset;
782
+ top = clientRect.bottom + window.pageYOffset;
783
+ } else {
784
+ left = pEl.offsetLeft;
785
+ top = pEl.offsetTop + pEl.offsetHeight;
786
+ while((pEl = pEl.offsetParent)) {
787
+ left += pEl.offsetLeft;
788
+ top += pEl.offsetTop;
789
+ }
790
+ }
791
+
792
+ // default position is bottom & left
793
+ if (left + width > viewportWidth ||
794
+ (
795
+ this._o.position.indexOf('right') > -1 &&
796
+ left - width + field.offsetWidth > 0
797
+ )
798
+ ) {
799
+ left = left - width + field.offsetWidth;
800
+ }
801
+ if (top + height > viewportHeight + scrollTop ||
802
+ (
803
+ this._o.position.indexOf('top') > -1 &&
804
+ top - height - field.offsetHeight > 0
805
+ )
806
+ ) {
807
+ top = top - height - field.offsetHeight;
808
+ }
809
+ this.el.style.cssText = [
810
+ 'position: absolute',
811
+ 'left: ' + left + 'px',
812
+ 'top: ' + top + 'px'
813
+ ].join(';');
814
+ },
815
+
816
+ /**
817
+ * render HTML for a particular month
818
+ */
819
+ render: function(year, month)
820
+ {
821
+ var opts = this._o,
822
+ now = new Date(),
823
+ days = getDaysInMonth(year, month),
824
+ before = new Date(year, month, 1).getDay(),
825
+ data = [],
826
+ row = [];
827
+ setToStartOfDay(now);
828
+ if (opts.firstDay > 0) {
829
+ before -= opts.firstDay;
830
+ if (before < 0) {
831
+ before += 7;
832
+ }
833
+ }
834
+ var cells = days + before,
835
+ after = cells;
836
+ while(after > 7) {
837
+ after -= 7;
838
+ }
839
+ cells += 7 - after;
840
+ for (var i = 0, r = 0; i < cells; i++)
841
+ {
842
+ var day = new Date(year, month, 1 + (i - before)),
843
+ isDisabled = (opts.minDate && day < opts.minDate) || (opts.maxDate && day > opts.maxDate),
844
+ isSelected = isDate(this._d) ? compareDates(day, this._d) : false,
845
+ isToday = compareDates(day, now),
846
+ isEmpty = i < before || i >= (days + before);
847
+
848
+ row.push(renderDay(1 + (i - before), isSelected, isToday, isDisabled, isEmpty));
849
+
850
+ if (++r === 7) {
851
+ data.push(renderRow(row, opts.isRTL));
852
+ row = [];
853
+ r = 0;
854
+ }
855
+ }
856
+ return renderTable(opts, data);
857
+ },
858
+
859
+ isVisible: function()
860
+ {
861
+ return this._v;
862
+ },
863
+
864
+ show: function()
865
+ {
866
+ if (!this._v) {
867
+ if (this._o.bound) {
868
+ addEvent(document, 'click', this._onClick);
869
+ }
870
+ removeClass(this.el, 'is-hidden');
871
+ this._v = true;
872
+ this.draw();
873
+ if (typeof this._o.onOpen === 'function') {
874
+ this._o.onOpen.call(this);
875
+ }
876
+ }
877
+ },
878
+
879
+ hide: function()
880
+ {
881
+ var v = this._v;
882
+ if (v !== false) {
883
+ if (this._o.bound) {
884
+ removeEvent(document, 'click', this._onClick);
885
+ }
886
+ this.el.style.cssText = '';
887
+ addClass(this.el, 'is-hidden');
888
+ this._v = false;
889
+ if (v !== undefined && typeof this._o.onClose === 'function') {
890
+ this._o.onClose.call(this);
891
+ }
892
+ }
893
+ },
894
+
895
+ /**
896
+ * GAME OVER
897
+ */
898
+ destroy: function()
899
+ {
900
+ this.hide();
901
+ removeEvent(this.el, 'mousedown', this._onMouseDown, true);
902
+ removeEvent(this.el, 'change', this._onChange);
903
+ if (this._o.field) {
904
+ removeEvent(this._o.field, 'change', this._onInputChange);
905
+ if (this._o.bound) {
906
+ removeEvent(this._o.trigger, 'click', this._onInputClick);
907
+ removeEvent(this._o.trigger, 'focus', this._onInputFocus);
908
+ removeEvent(this._o.trigger, 'blur', this._onInputBlur);
909
+ }
910
+ }
911
+ if (this.el.parentNode) {
912
+ this.el.parentNode.removeChild(this.el);
913
+ }
914
+ }
915
+
916
+ };
917
+
918
+ return Pikaday;
919
+
920
+ }));