rails-bootstrap-datepicker 1.0.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2f4e4a3351a31c2f295ca425d6a718ea99ac3558
4
+ data.tar.gz: da557670346904ec03481a1105afb883017994fa
5
+ SHA512:
6
+ metadata.gz: 1f68293c5af72e98efb306cb7becc8e46b8c846213dda28f00a7faa703da8a2924080ab1ea85016fc62c6109f299a27144328ee54acac71bfc78d5a103a3f88b
7
+ data.tar.gz: 1efbf6ec2e020c5edd5c5b1437fbd7a988c3c2002edef174424e17bdb6467b96640f663fbb3c608a416f0f90fe8a5a80baaea404a8c5dd95e875f1fa66e9c895
@@ -0,0 +1,3 @@
1
+ module RailsBootstrapDatepicker
2
+ class Engine < ::Rails::Engine; end
3
+ end
@@ -0,0 +1,2043 @@
1
+ /* =========================================================
2
+ * bootstrap-datepicker.js
3
+ * Repo: https://github.com/uxsolutions/bootstrap-datepicker/
4
+ * Demo: https://eternicode.github.io/bootstrap-datepicker/
5
+ * Docs: https://bootstrap-datepicker.readthedocs.org/
6
+ * =========================================================
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ * ========================================================= */
19
+
20
+ (function(factory){
21
+ if (typeof define === "function" && define.amd) {
22
+ define(["jquery"], factory);
23
+ } else if (typeof exports === 'object') {
24
+ factory(require('jquery'));
25
+ } else {
26
+ factory(jQuery);
27
+ }
28
+ }(function($, undefined){
29
+ function UTCDate(){
30
+ return new Date(Date.UTC.apply(Date, arguments));
31
+ }
32
+ function UTCToday(){
33
+ var today = new Date();
34
+ return UTCDate(today.getFullYear(), today.getMonth(), today.getDate());
35
+ }
36
+ function isUTCEquals(date1, date2) {
37
+ return (
38
+ date1.getUTCFullYear() === date2.getUTCFullYear() &&
39
+ date1.getUTCMonth() === date2.getUTCMonth() &&
40
+ date1.getUTCDate() === date2.getUTCDate()
41
+ );
42
+ }
43
+ function alias(method, deprecationMsg){
44
+ return function(){
45
+ if (deprecationMsg !== undefined) {
46
+ $.fn.datepicker.deprecated(deprecationMsg);
47
+ }
48
+
49
+ return this[method].apply(this, arguments);
50
+ };
51
+ }
52
+ function isValidDate(d) {
53
+ return d && !isNaN(d.getTime());
54
+ }
55
+
56
+ var DateArray = (function(){
57
+ var extras = {
58
+ get: function(i){
59
+ return this.slice(i)[0];
60
+ },
61
+ contains: function(d){
62
+ // Array.indexOf is not cross-browser;
63
+ // $.inArray doesn't work with Dates
64
+ var val = d && d.valueOf();
65
+ for (var i=0, l=this.length; i < l; i++)
66
+ // Use date arithmetic to allow dates with different times to match
67
+ if (0 <= this[i].valueOf() - val && this[i].valueOf() - val < 1000*60*60*24)
68
+ return i;
69
+ return -1;
70
+ },
71
+ remove: function(i){
72
+ this.splice(i,1);
73
+ },
74
+ replace: function(new_array){
75
+ if (!new_array)
76
+ return;
77
+ if (!$.isArray(new_array))
78
+ new_array = [new_array];
79
+ this.clear();
80
+ this.push.apply(this, new_array);
81
+ },
82
+ clear: function(){
83
+ this.length = 0;
84
+ },
85
+ copy: function(){
86
+ var a = new DateArray();
87
+ a.replace(this);
88
+ return a;
89
+ }
90
+ };
91
+
92
+ return function(){
93
+ var a = [];
94
+ a.push.apply(a, arguments);
95
+ $.extend(a, extras);
96
+ return a;
97
+ };
98
+ })();
99
+
100
+
101
+ // Picker object
102
+
103
+ var Datepicker = function(element, options){
104
+ $.data(element, 'datepicker', this);
105
+ this._process_options(options);
106
+
107
+ this.dates = new DateArray();
108
+ this.viewDate = this.o.defaultViewDate;
109
+ this.focusDate = null;
110
+
111
+ this.element = $(element);
112
+ this.isInput = this.element.is('input');
113
+ this.inputField = this.isInput ? this.element : this.element.find('input');
114
+ this.component = this.element.hasClass('date') ? this.element.find('.add-on, .input-group-addon, .btn') : false;
115
+ if (this.component && this.component.length === 0)
116
+ this.component = false;
117
+ this.isInline = !this.component && this.element.is('div');
118
+
119
+ this.picker = $(DPGlobal.template);
120
+
121
+ // Checking templates and inserting
122
+ if (this._check_template(this.o.templates.leftArrow)) {
123
+ this.picker.find('.prev').html(this.o.templates.leftArrow);
124
+ }
125
+
126
+ if (this._check_template(this.o.templates.rightArrow)) {
127
+ this.picker.find('.next').html(this.o.templates.rightArrow);
128
+ }
129
+
130
+ this._buildEvents();
131
+ this._attachEvents();
132
+
133
+ if (this.isInline){
134
+ this.picker.addClass('datepicker-inline').appendTo(this.element);
135
+ }
136
+ else {
137
+ this.picker.addClass('datepicker-dropdown dropdown-menu');
138
+ }
139
+
140
+ if (this.o.rtl){
141
+ this.picker.addClass('datepicker-rtl');
142
+ }
143
+
144
+ if (this.o.calendarWeeks) {
145
+ this.picker.find('.datepicker-days .datepicker-switch, thead .datepicker-title, tfoot .today, tfoot .clear')
146
+ .attr('colspan', function(i, val){
147
+ return Number(val) + 1;
148
+ });
149
+ }
150
+
151
+ this._process_options({
152
+ startDate: this._o.startDate,
153
+ endDate: this._o.endDate,
154
+ daysOfWeekDisabled: this.o.daysOfWeekDisabled,
155
+ daysOfWeekHighlighted: this.o.daysOfWeekHighlighted,
156
+ datesDisabled: this.o.datesDisabled
157
+ });
158
+
159
+ this._allow_update = false;
160
+ this.setViewMode(this.o.startView);
161
+ this._allow_update = true;
162
+
163
+ this.fillDow();
164
+ this.fillMonths();
165
+
166
+ this.update();
167
+
168
+ if (this.isInline){
169
+ this.show();
170
+ }
171
+ };
172
+
173
+ Datepicker.prototype = {
174
+ constructor: Datepicker,
175
+
176
+ _resolveViewName: function(view){
177
+ $.each(DPGlobal.viewModes, function(i, viewMode){
178
+ if (view === i || $.inArray(view, viewMode.names) !== -1){
179
+ view = i;
180
+ return false;
181
+ }
182
+ });
183
+
184
+ return view;
185
+ },
186
+
187
+ _resolveDaysOfWeek: function(daysOfWeek){
188
+ if (!$.isArray(daysOfWeek))
189
+ daysOfWeek = daysOfWeek.split(/[,\s]*/);
190
+ return $.map(daysOfWeek, Number);
191
+ },
192
+
193
+ _check_template: function(tmp){
194
+ try {
195
+ // If empty
196
+ if (tmp === undefined || tmp === "") {
197
+ return false;
198
+ }
199
+ // If no html, everything ok
200
+ if ((tmp.match(/[<>]/g) || []).length <= 0) {
201
+ return true;
202
+ }
203
+ // Checking if html is fine
204
+ var jDom = $(tmp);
205
+ return jDom.length > 0;
206
+ }
207
+ catch (ex) {
208
+ return false;
209
+ }
210
+ },
211
+
212
+ _process_options: function(opts){
213
+ // Store raw options for reference
214
+ this._o = $.extend({}, this._o, opts);
215
+ // Processed options
216
+ var o = this.o = $.extend({}, this._o);
217
+
218
+ // Check if "de-DE" style date is available, if not language should
219
+ // fallback to 2 letter code eg "de"
220
+ var lang = o.language;
221
+ if (!dates[lang]){
222
+ lang = lang.split('-')[0];
223
+ if (!dates[lang])
224
+ lang = defaults.language;
225
+ }
226
+ o.language = lang;
227
+
228
+ // Retrieve view index from any aliases
229
+ o.startView = this._resolveViewName(o.startView);
230
+ o.minViewMode = this._resolveViewName(o.minViewMode);
231
+ o.maxViewMode = this._resolveViewName(o.maxViewMode);
232
+
233
+ // Check view is between min and max
234
+ o.startView = Math.max(this.o.minViewMode, Math.min(this.o.maxViewMode, o.startView));
235
+
236
+ // true, false, or Number > 0
237
+ if (o.multidate !== true){
238
+ o.multidate = Number(o.multidate) || false;
239
+ if (o.multidate !== false)
240
+ o.multidate = Math.max(0, o.multidate);
241
+ }
242
+ o.multidateSeparator = String(o.multidateSeparator);
243
+
244
+ o.weekStart %= 7;
245
+ o.weekEnd = (o.weekStart + 6) % 7;
246
+
247
+ var format = DPGlobal.parseFormat(o.format);
248
+ if (o.startDate !== -Infinity){
249
+ if (!!o.startDate){
250
+ if (o.startDate instanceof Date)
251
+ o.startDate = this._local_to_utc(this._zero_time(o.startDate));
252
+ else
253
+ o.startDate = DPGlobal.parseDate(o.startDate, format, o.language, o.assumeNearbyYear);
254
+ }
255
+ else {
256
+ o.startDate = -Infinity;
257
+ }
258
+ }
259
+ if (o.endDate !== Infinity){
260
+ if (!!o.endDate){
261
+ if (o.endDate instanceof Date)
262
+ o.endDate = this._local_to_utc(this._zero_time(o.endDate));
263
+ else
264
+ o.endDate = DPGlobal.parseDate(o.endDate, format, o.language, o.assumeNearbyYear);
265
+ }
266
+ else {
267
+ o.endDate = Infinity;
268
+ }
269
+ }
270
+
271
+ o.daysOfWeekDisabled = this._resolveDaysOfWeek(o.daysOfWeekDisabled||[]);
272
+ o.daysOfWeekHighlighted = this._resolveDaysOfWeek(o.daysOfWeekHighlighted||[]);
273
+
274
+ o.datesDisabled = o.datesDisabled||[];
275
+ if (!$.isArray(o.datesDisabled)) {
276
+ o.datesDisabled = o.datesDisabled.split(',');
277
+ }
278
+ o.datesDisabled = $.map(o.datesDisabled, function(d){
279
+ return DPGlobal.parseDate(d, format, o.language, o.assumeNearbyYear);
280
+ });
281
+
282
+ var plc = String(o.orientation).toLowerCase().split(/\s+/g),
283
+ _plc = o.orientation.toLowerCase();
284
+ plc = $.grep(plc, function(word){
285
+ return /^auto|left|right|top|bottom$/.test(word);
286
+ });
287
+ o.orientation = {x: 'auto', y: 'auto'};
288
+ if (!_plc || _plc === 'auto')
289
+ ; // no action
290
+ else if (plc.length === 1){
291
+ switch (plc[0]){
292
+ case 'top':
293
+ case 'bottom':
294
+ o.orientation.y = plc[0];
295
+ break;
296
+ case 'left':
297
+ case 'right':
298
+ o.orientation.x = plc[0];
299
+ break;
300
+ }
301
+ }
302
+ else {
303
+ _plc = $.grep(plc, function(word){
304
+ return /^left|right$/.test(word);
305
+ });
306
+ o.orientation.x = _plc[0] || 'auto';
307
+
308
+ _plc = $.grep(plc, function(word){
309
+ return /^top|bottom$/.test(word);
310
+ });
311
+ o.orientation.y = _plc[0] || 'auto';
312
+ }
313
+ if (o.defaultViewDate instanceof Date || typeof o.defaultViewDate === 'string') {
314
+ o.defaultViewDate = DPGlobal.parseDate(o.defaultViewDate, format, o.language, o.assumeNearbyYear);
315
+ } else if (o.defaultViewDate) {
316
+ var year = o.defaultViewDate.year || new Date().getFullYear();
317
+ var month = o.defaultViewDate.month || 0;
318
+ var day = o.defaultViewDate.day || 1;
319
+ o.defaultViewDate = UTCDate(year, month, day);
320
+ } else {
321
+ o.defaultViewDate = UTCToday();
322
+ }
323
+ },
324
+ _events: [],
325
+ _secondaryEvents: [],
326
+ _applyEvents: function(evs){
327
+ for (var i=0, el, ch, ev; i < evs.length; i++){
328
+ el = evs[i][0];
329
+ if (evs[i].length === 2){
330
+ ch = undefined;
331
+ ev = evs[i][1];
332
+ } else if (evs[i].length === 3){
333
+ ch = evs[i][1];
334
+ ev = evs[i][2];
335
+ }
336
+ el.on(ev, ch);
337
+ }
338
+ },
339
+ _unapplyEvents: function(evs){
340
+ for (var i=0, el, ev, ch; i < evs.length; i++){
341
+ el = evs[i][0];
342
+ if (evs[i].length === 2){
343
+ ch = undefined;
344
+ ev = evs[i][1];
345
+ } else if (evs[i].length === 3){
346
+ ch = evs[i][1];
347
+ ev = evs[i][2];
348
+ }
349
+ el.off(ev, ch);
350
+ }
351
+ },
352
+ _buildEvents: function(){
353
+ var events = {
354
+ keyup: $.proxy(function(e){
355
+ if ($.inArray(e.keyCode, [27, 37, 39, 38, 40, 32, 13, 9]) === -1)
356
+ this.update();
357
+ }, this),
358
+ keydown: $.proxy(this.keydown, this),
359
+ paste: $.proxy(this.paste, this)
360
+ };
361
+
362
+ if (this.o.showOnFocus === true) {
363
+ events.focus = $.proxy(this.show, this);
364
+ }
365
+
366
+ if (this.isInput) { // single input
367
+ this._events = [
368
+ [this.element, events]
369
+ ];
370
+ }
371
+ // component: input + button
372
+ else if (this.component && this.inputField.length) {
373
+ this._events = [
374
+ // For components that are not readonly, allow keyboard nav
375
+ [this.inputField, events],
376
+ [this.component, {
377
+ click: $.proxy(this.show, this)
378
+ }]
379
+ ];
380
+ }
381
+ else {
382
+ this._events = [
383
+ [this.element, {
384
+ click: $.proxy(this.show, this),
385
+ keydown: $.proxy(this.keydown, this)
386
+ }]
387
+ ];
388
+ }
389
+ this._events.push(
390
+ // Component: listen for blur on element descendants
391
+ [this.element, '*', {
392
+ blur: $.proxy(function(e){
393
+ this._focused_from = e.target;
394
+ }, this)
395
+ }],
396
+ // Input: listen for blur on element
397
+ [this.element, {
398
+ blur: $.proxy(function(e){
399
+ this._focused_from = e.target;
400
+ }, this)
401
+ }]
402
+ );
403
+
404
+ if (this.o.immediateUpdates) {
405
+ // Trigger input updates immediately on changed year/month
406
+ this._events.push([this.element, {
407
+ 'changeYear changeMonth': $.proxy(function(e){
408
+ this.update(e.date);
409
+ }, this)
410
+ }]);
411
+ }
412
+
413
+ this._secondaryEvents = [
414
+ [this.picker, {
415
+ click: $.proxy(this.click, this)
416
+ }],
417
+ [this.picker, '.prev, .next', {
418
+ click: $.proxy(this.navArrowsClick, this)
419
+ }],
420
+ [this.picker, '.day:not(.disabled)', {
421
+ click: $.proxy(this.dayCellClick, this)
422
+ }],
423
+ [$(window), {
424
+ resize: $.proxy(this.place, this)
425
+ }],
426
+ [$(document), {
427
+ 'mousedown touchstart': $.proxy(function(e){
428
+ // Clicked outside the datepicker, hide it
429
+ if (!(
430
+ this.element.is(e.target) ||
431
+ this.element.find(e.target).length ||
432
+ this.picker.is(e.target) ||
433
+ this.picker.find(e.target).length ||
434
+ this.isInline
435
+ )){
436
+ this.hide();
437
+ }
438
+ }, this)
439
+ }]
440
+ ];
441
+ },
442
+ _attachEvents: function(){
443
+ this._detachEvents();
444
+ this._applyEvents(this._events);
445
+ },
446
+ _detachEvents: function(){
447
+ this._unapplyEvents(this._events);
448
+ },
449
+ _attachSecondaryEvents: function(){
450
+ this._detachSecondaryEvents();
451
+ this._applyEvents(this._secondaryEvents);
452
+ },
453
+ _detachSecondaryEvents: function(){
454
+ this._unapplyEvents(this._secondaryEvents);
455
+ },
456
+ _trigger: function(event, altdate){
457
+ var date = altdate || this.dates.get(-1),
458
+ local_date = this._utc_to_local(date);
459
+
460
+ this.element.trigger({
461
+ type: event,
462
+ date: local_date,
463
+ viewMode: this.viewMode,
464
+ dates: $.map(this.dates, this._utc_to_local),
465
+ format: $.proxy(function(ix, format){
466
+ if (arguments.length === 0){
467
+ ix = this.dates.length - 1;
468
+ format = this.o.format;
469
+ } else if (typeof ix === 'string'){
470
+ format = ix;
471
+ ix = this.dates.length - 1;
472
+ }
473
+ format = format || this.o.format;
474
+ var date = this.dates.get(ix);
475
+ return DPGlobal.formatDate(date, format, this.o.language);
476
+ }, this)
477
+ });
478
+ },
479
+
480
+ show: function(){
481
+ if (this.inputField.prop('disabled') || (this.inputField.prop('readonly') && this.o.enableOnReadonly === false))
482
+ return;
483
+ if (!this.isInline)
484
+ this.picker.appendTo(this.o.container);
485
+ this.place();
486
+ this.picker.show();
487
+ this._attachSecondaryEvents();
488
+ this._trigger('show');
489
+ if ((window.navigator.msMaxTouchPoints || 'ontouchstart' in document) && this.o.disableTouchKeyboard) {
490
+ $(this.element).blur();
491
+ }
492
+ return this;
493
+ },
494
+
495
+ hide: function(){
496
+ if (this.isInline || !this.picker.is(':visible'))
497
+ return this;
498
+ this.focusDate = null;
499
+ this.picker.hide().detach();
500
+ this._detachSecondaryEvents();
501
+ this.setViewMode(this.o.startView);
502
+
503
+ if (this.o.forceParse && this.inputField.val())
504
+ this.setValue();
505
+ this._trigger('hide');
506
+ return this;
507
+ },
508
+
509
+ destroy: function(){
510
+ this.hide();
511
+ this._detachEvents();
512
+ this._detachSecondaryEvents();
513
+ this.picker.remove();
514
+ delete this.element.data().datepicker;
515
+ if (!this.isInput){
516
+ delete this.element.data().date;
517
+ }
518
+ return this;
519
+ },
520
+
521
+ paste: function(e){
522
+ var dateString;
523
+ if (e.originalEvent.clipboardData && e.originalEvent.clipboardData.types
524
+ && $.inArray('text/plain', e.originalEvent.clipboardData.types) !== -1) {
525
+ dateString = e.originalEvent.clipboardData.getData('text/plain');
526
+ } else if (window.clipboardData) {
527
+ dateString = window.clipboardData.getData('Text');
528
+ } else {
529
+ return;
530
+ }
531
+ this.setDate(dateString);
532
+ this.update();
533
+ e.preventDefault();
534
+ },
535
+
536
+ _utc_to_local: function(utc){
537
+ if (!utc) {
538
+ return utc;
539
+ }
540
+
541
+ var local = new Date(utc.getTime() + (utc.getTimezoneOffset() * 60000));
542
+
543
+ if (local.getTimezoneOffset() !== utc.getTimezoneOffset()) {
544
+ local = new Date(utc.getTime() + (local.getTimezoneOffset() * 60000));
545
+ }
546
+
547
+ return local;
548
+ },
549
+ _local_to_utc: function(local){
550
+ return local && new Date(local.getTime() - (local.getTimezoneOffset()*60000));
551
+ },
552
+ _zero_time: function(local){
553
+ return local && new Date(local.getFullYear(), local.getMonth(), local.getDate());
554
+ },
555
+ _zero_utc_time: function(utc){
556
+ return utc && UTCDate(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate());
557
+ },
558
+
559
+ getDates: function(){
560
+ return $.map(this.dates, this._utc_to_local);
561
+ },
562
+
563
+ getUTCDates: function(){
564
+ return $.map(this.dates, function(d){
565
+ return new Date(d);
566
+ });
567
+ },
568
+
569
+ getDate: function(){
570
+ return this._utc_to_local(this.getUTCDate());
571
+ },
572
+
573
+ getUTCDate: function(){
574
+ var selected_date = this.dates.get(-1);
575
+ if (selected_date !== undefined) {
576
+ return new Date(selected_date);
577
+ } else {
578
+ return null;
579
+ }
580
+ },
581
+
582
+ clearDates: function(){
583
+ this.inputField.val('');
584
+ this.update();
585
+ this._trigger('changeDate');
586
+
587
+ if (this.o.autoclose) {
588
+ this.hide();
589
+ }
590
+ },
591
+
592
+ setDates: function(){
593
+ var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
594
+ this.update.apply(this, args);
595
+ this._trigger('changeDate');
596
+ this.setValue();
597
+ return this;
598
+ },
599
+
600
+ setUTCDates: function(){
601
+ var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
602
+ this.setDates.apply(this, $.map(args, this._utc_to_local));
603
+ return this;
604
+ },
605
+
606
+ setDate: alias('setDates'),
607
+ setUTCDate: alias('setUTCDates'),
608
+ remove: alias('destroy', 'Method `remove` is deprecated and will be removed in version 2.0. Use `destroy` instead'),
609
+
610
+ setValue: function(){
611
+ var formatted = this.getFormattedDate();
612
+ this.inputField.val(formatted);
613
+ return this;
614
+ },
615
+
616
+ getFormattedDate: function(format){
617
+ if (format === undefined)
618
+ format = this.o.format;
619
+
620
+ var lang = this.o.language;
621
+ return $.map(this.dates, function(d){
622
+ return DPGlobal.formatDate(d, format, lang);
623
+ }).join(this.o.multidateSeparator);
624
+ },
625
+
626
+ getStartDate: function(){
627
+ return this.o.startDate;
628
+ },
629
+
630
+ setStartDate: function(startDate){
631
+ this._process_options({startDate: startDate});
632
+ this.update();
633
+ this.updateNavArrows();
634
+ return this;
635
+ },
636
+
637
+ getEndDate: function(){
638
+ return this.o.endDate;
639
+ },
640
+
641
+ setEndDate: function(endDate){
642
+ this._process_options({endDate: endDate});
643
+ this.update();
644
+ this.updateNavArrows();
645
+ return this;
646
+ },
647
+
648
+ setDaysOfWeekDisabled: function(daysOfWeekDisabled){
649
+ this._process_options({daysOfWeekDisabled: daysOfWeekDisabled});
650
+ this.update();
651
+ return this;
652
+ },
653
+
654
+ setDaysOfWeekHighlighted: function(daysOfWeekHighlighted){
655
+ this._process_options({daysOfWeekHighlighted: daysOfWeekHighlighted});
656
+ this.update();
657
+ return this;
658
+ },
659
+
660
+ setDatesDisabled: function(datesDisabled){
661
+ this._process_options({datesDisabled: datesDisabled});
662
+ this.update();
663
+ return this;
664
+ },
665
+
666
+ place: function(){
667
+ if (this.isInline)
668
+ return this;
669
+ var calendarWidth = this.picker.outerWidth(),
670
+ calendarHeight = this.picker.outerHeight(),
671
+ visualPadding = 10,
672
+ container = $(this.o.container),
673
+ windowWidth = container.width(),
674
+ scrollTop = this.o.container === 'body' ? $(document).scrollTop() : container.scrollTop(),
675
+ appendOffset = container.offset();
676
+
677
+ var parentsZindex = [0];
678
+ this.element.parents().each(function(){
679
+ var itemZIndex = $(this).css('z-index');
680
+ if (itemZIndex !== 'auto' && Number(itemZIndex) !== 0) parentsZindex.push(Number(itemZIndex));
681
+ });
682
+ var zIndex = Math.max.apply(Math, parentsZindex) + this.o.zIndexOffset;
683
+ var offset = this.component ? this.component.parent().offset() : this.element.offset();
684
+ var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(false);
685
+ var width = this.component ? this.component.outerWidth(true) : this.element.outerWidth(false);
686
+ var left = offset.left - appendOffset.left;
687
+ var top = offset.top - appendOffset.top;
688
+
689
+ if (this.o.container !== 'body') {
690
+ top += scrollTop;
691
+ }
692
+
693
+ this.picker.removeClass(
694
+ 'datepicker-orient-top datepicker-orient-bottom '+
695
+ 'datepicker-orient-right datepicker-orient-left'
696
+ );
697
+
698
+ if (this.o.orientation.x !== 'auto'){
699
+ this.picker.addClass('datepicker-orient-' + this.o.orientation.x);
700
+ if (this.o.orientation.x === 'right')
701
+ left -= calendarWidth - width;
702
+ }
703
+ // auto x orientation is best-placement: if it crosses a window
704
+ // edge, fudge it sideways
705
+ else {
706
+ if (offset.left < 0) {
707
+ // component is outside the window on the left side. Move it into visible range
708
+ this.picker.addClass('datepicker-orient-left');
709
+ left -= offset.left - visualPadding;
710
+ } else if (left + calendarWidth > windowWidth) {
711
+ // the calendar passes the widow right edge. Align it to component right side
712
+ this.picker.addClass('datepicker-orient-right');
713
+ left += width - calendarWidth;
714
+ } else {
715
+ if (this.o.rtl) {
716
+ // Default to right
717
+ this.picker.addClass('datepicker-orient-right');
718
+ } else {
719
+ // Default to left
720
+ this.picker.addClass('datepicker-orient-left');
721
+ }
722
+ }
723
+ }
724
+
725
+ // auto y orientation is best-situation: top or bottom, no fudging,
726
+ // decision based on which shows more of the calendar
727
+ var yorient = this.o.orientation.y,
728
+ top_overflow;
729
+ if (yorient === 'auto'){
730
+ top_overflow = -scrollTop + top - calendarHeight;
731
+ yorient = top_overflow < 0 ? 'bottom' : 'top';
732
+ }
733
+
734
+ this.picker.addClass('datepicker-orient-' + yorient);
735
+ if (yorient === 'top')
736
+ top -= calendarHeight + parseInt(this.picker.css('padding-top'));
737
+ else
738
+ top += height;
739
+
740
+ if (this.o.rtl) {
741
+ var right = windowWidth - (left + width);
742
+ this.picker.css({
743
+ top: top,
744
+ right: right,
745
+ zIndex: zIndex
746
+ });
747
+ } else {
748
+ this.picker.css({
749
+ top: top,
750
+ left: left,
751
+ zIndex: zIndex
752
+ });
753
+ }
754
+ return this;
755
+ },
756
+
757
+ _allow_update: true,
758
+ update: function(){
759
+ if (!this._allow_update)
760
+ return this;
761
+
762
+ var oldDates = this.dates.copy(),
763
+ dates = [],
764
+ fromArgs = false;
765
+ if (arguments.length){
766
+ $.each(arguments, $.proxy(function(i, date){
767
+ if (date instanceof Date)
768
+ date = this._local_to_utc(date);
769
+ dates.push(date);
770
+ }, this));
771
+ fromArgs = true;
772
+ } else {
773
+ dates = this.isInput
774
+ ? this.element.val()
775
+ : this.element.data('date') || this.inputField.val();
776
+ if (dates && this.o.multidate)
777
+ dates = dates.split(this.o.multidateSeparator);
778
+ else
779
+ dates = [dates];
780
+ delete this.element.data().date;
781
+ }
782
+
783
+ dates = $.map(dates, $.proxy(function(date){
784
+ return DPGlobal.parseDate(date, this.o.format, this.o.language, this.o.assumeNearbyYear);
785
+ }, this));
786
+ dates = $.grep(dates, $.proxy(function(date){
787
+ return (
788
+ !this.dateWithinRange(date) ||
789
+ !date
790
+ );
791
+ }, this), true);
792
+ this.dates.replace(dates);
793
+
794
+ if (this.o.updateViewDate) {
795
+ if (this.dates.length)
796
+ this.viewDate = new Date(this.dates.get(-1));
797
+ else if (this.viewDate < this.o.startDate)
798
+ this.viewDate = new Date(this.o.startDate);
799
+ else if (this.viewDate > this.o.endDate)
800
+ this.viewDate = new Date(this.o.endDate);
801
+ else
802
+ this.viewDate = this.o.defaultViewDate;
803
+ }
804
+
805
+ if (fromArgs){
806
+ // setting date by clicking
807
+ this.setValue();
808
+ this.element.change();
809
+ }
810
+ else if (this.dates.length){
811
+ // setting date by typing
812
+ if (String(oldDates) !== String(this.dates) && fromArgs) {
813
+ this._trigger('changeDate');
814
+ this.element.change();
815
+ }
816
+ }
817
+ if (!this.dates.length && oldDates.length) {
818
+ this._trigger('clearDate');
819
+ this.element.change();
820
+ }
821
+
822
+ this.fill();
823
+ return this;
824
+ },
825
+
826
+ fillDow: function(){
827
+ if (this.o.showWeekDays) {
828
+ var dowCnt = this.o.weekStart,
829
+ html = '<tr>';
830
+ if (this.o.calendarWeeks){
831
+ html += '<th class="cw">&#160;</th>';
832
+ }
833
+ while (dowCnt < this.o.weekStart + 7){
834
+ html += '<th class="dow';
835
+ if ($.inArray(dowCnt, this.o.daysOfWeekDisabled) !== -1)
836
+ html += ' disabled';
837
+ html += '">'+dates[this.o.language].daysMin[(dowCnt++)%7]+'</th>';
838
+ }
839
+ html += '</tr>';
840
+ this.picker.find('.datepicker-days thead').append(html);
841
+ }
842
+ },
843
+
844
+ fillMonths: function(){
845
+ var localDate = this._utc_to_local(this.viewDate);
846
+ var html = '';
847
+ var focused;
848
+ for (var i = 0; i < 12; i++){
849
+ focused = localDate && localDate.getMonth() === i ? ' focused' : '';
850
+ html += '<span class="month' + focused + '">' + dates[this.o.language].monthsShort[i] + '</span>';
851
+ }
852
+ this.picker.find('.datepicker-months td').html(html);
853
+ },
854
+
855
+ setRange: function(range){
856
+ if (!range || !range.length)
857
+ delete this.range;
858
+ else
859
+ this.range = $.map(range, function(d){
860
+ return d.valueOf();
861
+ });
862
+ this.fill();
863
+ },
864
+
865
+ getClassNames: function(date){
866
+ var cls = [],
867
+ year = this.viewDate.getUTCFullYear(),
868
+ month = this.viewDate.getUTCMonth(),
869
+ today = UTCToday();
870
+ if (date.getUTCFullYear() < year || (date.getUTCFullYear() === year && date.getUTCMonth() < month)){
871
+ cls.push('old');
872
+ } else if (date.getUTCFullYear() > year || (date.getUTCFullYear() === year && date.getUTCMonth() > month)){
873
+ cls.push('new');
874
+ }
875
+ if (this.focusDate && date.valueOf() === this.focusDate.valueOf())
876
+ cls.push('focused');
877
+ // Compare internal UTC date with UTC today, not local today
878
+ if (this.o.todayHighlight && isUTCEquals(date, today)) {
879
+ cls.push('today');
880
+ }
881
+ if (this.dates.contains(date) !== -1)
882
+ cls.push('active');
883
+ if (!this.dateWithinRange(date)){
884
+ cls.push('disabled');
885
+ }
886
+ if (this.dateIsDisabled(date)){
887
+ cls.push('disabled', 'disabled-date');
888
+ }
889
+ if ($.inArray(date.getUTCDay(), this.o.daysOfWeekHighlighted) !== -1){
890
+ cls.push('highlighted');
891
+ }
892
+
893
+ if (this.range){
894
+ if (date > this.range[0] && date < this.range[this.range.length-1]){
895
+ cls.push('range');
896
+ }
897
+ if ($.inArray(date.valueOf(), this.range) !== -1){
898
+ cls.push('selected');
899
+ }
900
+ if (date.valueOf() === this.range[0]){
901
+ cls.push('range-start');
902
+ }
903
+ if (date.valueOf() === this.range[this.range.length-1]){
904
+ cls.push('range-end');
905
+ }
906
+ }
907
+ return cls;
908
+ },
909
+
910
+ _fill_yearsView: function(selector, cssClass, factor, year, startYear, endYear, beforeFn){
911
+ var html = '';
912
+ var step = factor / 10;
913
+ var view = this.picker.find(selector);
914
+ var startVal = Math.floor(year / factor) * factor;
915
+ var endVal = startVal + step * 9;
916
+ var focusedVal = Math.floor(this.viewDate.getFullYear() / step) * step;
917
+ var selected = $.map(this.dates, function(d){
918
+ return Math.floor(d.getUTCFullYear() / step) * step;
919
+ });
920
+
921
+ var classes, tooltip, before;
922
+ for (var currVal = startVal - step; currVal <= endVal + step; currVal += step) {
923
+ classes = [cssClass];
924
+ tooltip = null;
925
+
926
+ if (currVal === startVal - step) {
927
+ classes.push('old');
928
+ } else if (currVal === endVal + step) {
929
+ classes.push('new');
930
+ }
931
+ if ($.inArray(currVal, selected) !== -1) {
932
+ classes.push('active');
933
+ }
934
+ if (currVal < startYear || currVal > endYear) {
935
+ classes.push('disabled');
936
+ }
937
+ if (currVal === focusedVal) {
938
+ classes.push('focused');
939
+ }
940
+
941
+ if (beforeFn !== $.noop) {
942
+ before = beforeFn(new Date(currVal, 0, 1));
943
+ if (before === undefined) {
944
+ before = {};
945
+ } else if (typeof before === 'boolean') {
946
+ before = {enabled: before};
947
+ } else if (typeof before === 'string') {
948
+ before = {classes: before};
949
+ }
950
+ if (before.enabled === false) {
951
+ classes.push('disabled');
952
+ }
953
+ if (before.classes) {
954
+ classes = classes.concat(before.classes.split(/\s+/));
955
+ }
956
+ if (before.tooltip) {
957
+ tooltip = before.tooltip;
958
+ }
959
+ }
960
+
961
+ html += '<span class="' + classes.join(' ') + '"' + (tooltip ? ' title="' + tooltip + '"' : '') + '>' + currVal + '</span>';
962
+ }
963
+
964
+ view.find('.datepicker-switch').text(startVal + '-' + endVal);
965
+ view.find('td').html(html);
966
+ },
967
+
968
+ fill: function(){
969
+ var d = new Date(this.viewDate),
970
+ year = d.getUTCFullYear(),
971
+ month = d.getUTCMonth(),
972
+ startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,
973
+ startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,
974
+ endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,
975
+ endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,
976
+ todaytxt = dates[this.o.language].today || dates['en'].today || '',
977
+ cleartxt = dates[this.o.language].clear || dates['en'].clear || '',
978
+ titleFormat = dates[this.o.language].titleFormat || dates['en'].titleFormat,
979
+ tooltip,
980
+ before;
981
+ if (isNaN(year) || isNaN(month))
982
+ return;
983
+ this.picker.find('.datepicker-days .datepicker-switch')
984
+ .text(DPGlobal.formatDate(d, titleFormat, this.o.language));
985
+ this.picker.find('tfoot .today')
986
+ .text(todaytxt)
987
+ .css('display', this.o.todayBtn === true || this.o.todayBtn === 'linked' ? 'table-cell' : 'none');
988
+ this.picker.find('tfoot .clear')
989
+ .text(cleartxt)
990
+ .css('display', this.o.clearBtn === true ? 'table-cell' : 'none');
991
+ this.picker.find('thead .datepicker-title')
992
+ .text(this.o.title)
993
+ .css('display', typeof this.o.title === 'string' && this.o.title !== '' ? 'table-cell' : 'none');
994
+ this.updateNavArrows();
995
+ this.fillMonths();
996
+ var prevMonth = UTCDate(year, month, 0),
997
+ day = prevMonth.getUTCDate();
998
+ prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7)%7);
999
+ var nextMonth = new Date(prevMonth);
1000
+ if (prevMonth.getUTCFullYear() < 100){
1001
+ nextMonth.setUTCFullYear(prevMonth.getUTCFullYear());
1002
+ }
1003
+ nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
1004
+ nextMonth = nextMonth.valueOf();
1005
+ var html = [];
1006
+ var weekDay, clsName;
1007
+ while (prevMonth.valueOf() < nextMonth){
1008
+ weekDay = prevMonth.getUTCDay();
1009
+ if (weekDay === this.o.weekStart){
1010
+ html.push('<tr>');
1011
+ if (this.o.calendarWeeks){
1012
+ // ISO 8601: First week contains first thursday.
1013
+ // ISO also states week starts on Monday, but we can be more abstract here.
1014
+ var
1015
+ // Start of current week: based on weekstart/current date
1016
+ ws = new Date(+prevMonth + (this.o.weekStart - weekDay - 7) % 7 * 864e5),
1017
+ // Thursday of this week
1018
+ th = new Date(Number(ws) + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
1019
+ // First Thursday of year, year from thursday
1020
+ yth = new Date(Number(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay()) % 7 * 864e5),
1021
+ // Calendar week: ms between thursdays, div ms per day, div 7 days
1022
+ calWeek = (th - yth) / 864e5 / 7 + 1;
1023
+ html.push('<td class="cw">'+ calWeek +'</td>');
1024
+ }
1025
+ }
1026
+ clsName = this.getClassNames(prevMonth);
1027
+ clsName.push('day');
1028
+
1029
+ var content = prevMonth.getUTCDate();
1030
+
1031
+ if (this.o.beforeShowDay !== $.noop){
1032
+ before = this.o.beforeShowDay(this._utc_to_local(prevMonth));
1033
+ if (before === undefined)
1034
+ before = {};
1035
+ else if (typeof before === 'boolean')
1036
+ before = {enabled: before};
1037
+ else if (typeof before === 'string')
1038
+ before = {classes: before};
1039
+ if (before.enabled === false)
1040
+ clsName.push('disabled');
1041
+ if (before.classes)
1042
+ clsName = clsName.concat(before.classes.split(/\s+/));
1043
+ if (before.tooltip)
1044
+ tooltip = before.tooltip;
1045
+ if (before.content)
1046
+ content = before.content;
1047
+ }
1048
+
1049
+ //Check if uniqueSort exists (supported by jquery >=1.12 and >=2.2)
1050
+ //Fallback to unique function for older jquery versions
1051
+ if ($.isFunction($.uniqueSort)) {
1052
+ clsName = $.uniqueSort(clsName);
1053
+ } else {
1054
+ clsName = $.unique(clsName);
1055
+ }
1056
+
1057
+ html.push('<td class="'+clsName.join(' ')+'"' + (tooltip ? ' title="'+tooltip+'"' : '') + ' data-date="' + prevMonth.getTime().toString() + '">' + content + '</td>');
1058
+ tooltip = null;
1059
+ if (weekDay === this.o.weekEnd){
1060
+ html.push('</tr>');
1061
+ }
1062
+ prevMonth.setUTCDate(prevMonth.getUTCDate() + 1);
1063
+ }
1064
+ this.picker.find('.datepicker-days tbody').html(html.join(''));
1065
+
1066
+ var monthsTitle = dates[this.o.language].monthsTitle || dates['en'].monthsTitle || 'Months';
1067
+ var months = this.picker.find('.datepicker-months')
1068
+ .find('.datepicker-switch')
1069
+ .text(this.o.maxViewMode < 2 ? monthsTitle : year)
1070
+ .end()
1071
+ .find('tbody span').removeClass('active');
1072
+
1073
+ $.each(this.dates, function(i, d){
1074
+ if (d.getUTCFullYear() === year)
1075
+ months.eq(d.getUTCMonth()).addClass('active');
1076
+ });
1077
+
1078
+ if (year < startYear || year > endYear){
1079
+ months.addClass('disabled');
1080
+ }
1081
+ if (year === startYear){
1082
+ months.slice(0, startMonth).addClass('disabled');
1083
+ }
1084
+ if (year === endYear){
1085
+ months.slice(endMonth+1).addClass('disabled');
1086
+ }
1087
+
1088
+ if (this.o.beforeShowMonth !== $.noop){
1089
+ var that = this;
1090
+ $.each(months, function(i, month){
1091
+ var moDate = new Date(year, i, 1);
1092
+ var before = that.o.beforeShowMonth(moDate);
1093
+ if (before === undefined)
1094
+ before = {};
1095
+ else if (typeof before === 'boolean')
1096
+ before = {enabled: before};
1097
+ else if (typeof before === 'string')
1098
+ before = {classes: before};
1099
+ if (before.enabled === false && !$(month).hasClass('disabled'))
1100
+ $(month).addClass('disabled');
1101
+ if (before.classes)
1102
+ $(month).addClass(before.classes);
1103
+ if (before.tooltip)
1104
+ $(month).prop('title', before.tooltip);
1105
+ });
1106
+ }
1107
+
1108
+ // Generating decade/years picker
1109
+ this._fill_yearsView(
1110
+ '.datepicker-years',
1111
+ 'year',
1112
+ 10,
1113
+ year,
1114
+ startYear,
1115
+ endYear,
1116
+ this.o.beforeShowYear
1117
+ );
1118
+
1119
+ // Generating century/decades picker
1120
+ this._fill_yearsView(
1121
+ '.datepicker-decades',
1122
+ 'decade',
1123
+ 100,
1124
+ year,
1125
+ startYear,
1126
+ endYear,
1127
+ this.o.beforeShowDecade
1128
+ );
1129
+
1130
+ // Generating millennium/centuries picker
1131
+ this._fill_yearsView(
1132
+ '.datepicker-centuries',
1133
+ 'century',
1134
+ 1000,
1135
+ year,
1136
+ startYear,
1137
+ endYear,
1138
+ this.o.beforeShowCentury
1139
+ );
1140
+ },
1141
+
1142
+ updateNavArrows: function(){
1143
+ if (!this._allow_update)
1144
+ return;
1145
+
1146
+ var d = new Date(this.viewDate),
1147
+ year = d.getUTCFullYear(),
1148
+ month = d.getUTCMonth(),
1149
+ startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,
1150
+ startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,
1151
+ endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,
1152
+ endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,
1153
+ prevIsDisabled,
1154
+ nextIsDisabled,
1155
+ factor = 1;
1156
+ switch (this.viewMode){
1157
+ case 0:
1158
+ prevIsDisabled = year <= startYear && month <= startMonth;
1159
+ nextIsDisabled = year >= endYear && month >= endMonth;
1160
+ break;
1161
+ case 4:
1162
+ factor *= 10;
1163
+ /* falls through */
1164
+ case 3:
1165
+ factor *= 10;
1166
+ /* falls through */
1167
+ case 2:
1168
+ factor *= 10;
1169
+ /* falls through */
1170
+ case 1:
1171
+ prevIsDisabled = Math.floor(year / factor) * factor <= startYear;
1172
+ nextIsDisabled = Math.floor(year / factor) * factor + factor >= endYear;
1173
+ break;
1174
+ }
1175
+
1176
+ this.picker.find('.prev').toggleClass('disabled', prevIsDisabled);
1177
+ this.picker.find('.next').toggleClass('disabled', nextIsDisabled);
1178
+ },
1179
+
1180
+ click: function(e){
1181
+ e.preventDefault();
1182
+ e.stopPropagation();
1183
+
1184
+ var target, dir, day, year, month;
1185
+ target = $(e.target);
1186
+
1187
+ // Clicked on the switch
1188
+ if (target.hasClass('datepicker-switch') && this.viewMode !== this.o.maxViewMode){
1189
+ this.setViewMode(this.viewMode + 1);
1190
+ }
1191
+
1192
+ // Clicked on today button
1193
+ if (target.hasClass('today') && !target.hasClass('day')){
1194
+ this.setViewMode(0);
1195
+ this._setDate(UTCToday(), this.o.todayBtn === 'linked' ? null : 'view');
1196
+ }
1197
+
1198
+ // Clicked on clear button
1199
+ if (target.hasClass('clear')){
1200
+ this.clearDates();
1201
+ }
1202
+
1203
+ if (!target.hasClass('disabled')){
1204
+ // Clicked on a month, year, decade, century
1205
+ if (target.hasClass('month')
1206
+ || target.hasClass('year')
1207
+ || target.hasClass('decade')
1208
+ || target.hasClass('century')) {
1209
+ this.viewDate.setUTCDate(1);
1210
+
1211
+ day = 1;
1212
+ if (this.viewMode === 1){
1213
+ month = target.parent().find('span').index(target);
1214
+ year = this.viewDate.getUTCFullYear();
1215
+ this.viewDate.setUTCMonth(month);
1216
+ } else {
1217
+ month = 0;
1218
+ year = Number(target.text());
1219
+ this.viewDate.setUTCFullYear(year);
1220
+ }
1221
+
1222
+ this._trigger(DPGlobal.viewModes[this.viewMode - 1].e, this.viewDate);
1223
+
1224
+ if (this.viewMode === this.o.minViewMode){
1225
+ this._setDate(UTCDate(year, month, day));
1226
+ } else {
1227
+ this.setViewMode(this.viewMode - 1);
1228
+ this.fill();
1229
+ }
1230
+ }
1231
+ }
1232
+
1233
+ if (this.picker.is(':visible') && this._focused_from){
1234
+ this._focused_from.focus();
1235
+ }
1236
+ delete this._focused_from;
1237
+ },
1238
+
1239
+ dayCellClick: function(e){
1240
+ var $target = $(e.currentTarget);
1241
+ var timestamp = $target.data('date');
1242
+ var date = new Date(timestamp);
1243
+
1244
+ if (this.o.updateViewDate) {
1245
+ if (date.getUTCFullYear() !== this.viewDate.getUTCFullYear()) {
1246
+ this._trigger('changeYear', this.viewDate);
1247
+ }
1248
+
1249
+ if (date.getUTCMonth() !== this.viewDate.getUTCMonth()) {
1250
+ this._trigger('changeMonth', this.viewDate);
1251
+ }
1252
+ }
1253
+ this._setDate(date);
1254
+ },
1255
+
1256
+ // Clicked on prev or next
1257
+ navArrowsClick: function(e){
1258
+ var $target = $(e.currentTarget);
1259
+ var dir = $target.hasClass('prev') ? -1 : 1;
1260
+ if (this.viewMode !== 0){
1261
+ dir *= DPGlobal.viewModes[this.viewMode].navStep * 12;
1262
+ }
1263
+ this.viewDate = this.moveMonth(this.viewDate, dir);
1264
+ this._trigger(DPGlobal.viewModes[this.viewMode].e, this.viewDate);
1265
+ this.fill();
1266
+ },
1267
+
1268
+ _toggle_multidate: function(date){
1269
+ var ix = this.dates.contains(date);
1270
+ if (!date){
1271
+ this.dates.clear();
1272
+ }
1273
+
1274
+ if (ix !== -1){
1275
+ if (this.o.multidate === true || this.o.multidate > 1 || this.o.toggleActive){
1276
+ this.dates.remove(ix);
1277
+ }
1278
+ } else if (this.o.multidate === false) {
1279
+ this.dates.clear();
1280
+ this.dates.push(date);
1281
+ }
1282
+ else {
1283
+ this.dates.push(date);
1284
+ }
1285
+
1286
+ if (typeof this.o.multidate === 'number')
1287
+ while (this.dates.length > this.o.multidate)
1288
+ this.dates.remove(0);
1289
+ },
1290
+
1291
+ _setDate: function(date, which){
1292
+ if (!which || which === 'date')
1293
+ this._toggle_multidate(date && new Date(date));
1294
+ if ((!which && this.o.updateViewDate) || which === 'view')
1295
+ this.viewDate = date && new Date(date);
1296
+
1297
+ this.fill();
1298
+ this.setValue();
1299
+ if (!which || which !== 'view') {
1300
+ this._trigger('changeDate');
1301
+ }
1302
+ this.inputField.trigger('change');
1303
+ if (this.o.autoclose && (!which || which === 'date')){
1304
+ this.hide();
1305
+ }
1306
+ },
1307
+
1308
+ moveDay: function(date, dir){
1309
+ var newDate = new Date(date);
1310
+ newDate.setUTCDate(date.getUTCDate() + dir);
1311
+
1312
+ return newDate;
1313
+ },
1314
+
1315
+ moveWeek: function(date, dir){
1316
+ return this.moveDay(date, dir * 7);
1317
+ },
1318
+
1319
+ moveMonth: function(date, dir){
1320
+ if (!isValidDate(date))
1321
+ return this.o.defaultViewDate;
1322
+ if (!dir)
1323
+ return date;
1324
+ var new_date = new Date(date.valueOf()),
1325
+ day = new_date.getUTCDate(),
1326
+ month = new_date.getUTCMonth(),
1327
+ mag = Math.abs(dir),
1328
+ new_month, test;
1329
+ dir = dir > 0 ? 1 : -1;
1330
+ if (mag === 1){
1331
+ test = dir === -1
1332
+ // If going back one month, make sure month is not current month
1333
+ // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
1334
+ ? function(){
1335
+ return new_date.getUTCMonth() === month;
1336
+ }
1337
+ // If going forward one month, make sure month is as expected
1338
+ // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
1339
+ : function(){
1340
+ return new_date.getUTCMonth() !== new_month;
1341
+ };
1342
+ new_month = month + dir;
1343
+ new_date.setUTCMonth(new_month);
1344
+ // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
1345
+ new_month = (new_month + 12) % 12;
1346
+ }
1347
+ else {
1348
+ // For magnitudes >1, move one month at a time...
1349
+ for (var i=0; i < mag; i++)
1350
+ // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
1351
+ new_date = this.moveMonth(new_date, dir);
1352
+ // ...then reset the day, keeping it in the new month
1353
+ new_month = new_date.getUTCMonth();
1354
+ new_date.setUTCDate(day);
1355
+ test = function(){
1356
+ return new_month !== new_date.getUTCMonth();
1357
+ };
1358
+ }
1359
+ // Common date-resetting loop -- if date is beyond end of month, make it
1360
+ // end of month
1361
+ while (test()){
1362
+ new_date.setUTCDate(--day);
1363
+ new_date.setUTCMonth(new_month);
1364
+ }
1365
+ return new_date;
1366
+ },
1367
+
1368
+ moveYear: function(date, dir){
1369
+ return this.moveMonth(date, dir*12);
1370
+ },
1371
+
1372
+ moveAvailableDate: function(date, dir, fn){
1373
+ do {
1374
+ date = this[fn](date, dir);
1375
+
1376
+ if (!this.dateWithinRange(date))
1377
+ return false;
1378
+
1379
+ fn = 'moveDay';
1380
+ }
1381
+ while (this.dateIsDisabled(date));
1382
+
1383
+ return date;
1384
+ },
1385
+
1386
+ weekOfDateIsDisabled: function(date){
1387
+ return $.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1;
1388
+ },
1389
+
1390
+ dateIsDisabled: function(date){
1391
+ return (
1392
+ this.weekOfDateIsDisabled(date) ||
1393
+ $.grep(this.o.datesDisabled, function(d){
1394
+ return isUTCEquals(date, d);
1395
+ }).length > 0
1396
+ );
1397
+ },
1398
+
1399
+ dateWithinRange: function(date){
1400
+ return date >= this.o.startDate && date <= this.o.endDate;
1401
+ },
1402
+
1403
+ keydown: function(e){
1404
+ if (!this.picker.is(':visible')){
1405
+ if (e.keyCode === 40 || e.keyCode === 27) { // allow down to re-show picker
1406
+ this.show();
1407
+ e.stopPropagation();
1408
+ }
1409
+ return;
1410
+ }
1411
+ var dateChanged = false,
1412
+ dir, newViewDate,
1413
+ focusDate = this.focusDate || this.viewDate;
1414
+ switch (e.keyCode){
1415
+ case 27: // escape
1416
+ if (this.focusDate){
1417
+ this.focusDate = null;
1418
+ this.viewDate = this.dates.get(-1) || this.viewDate;
1419
+ this.fill();
1420
+ }
1421
+ else
1422
+ this.hide();
1423
+ e.preventDefault();
1424
+ e.stopPropagation();
1425
+ break;
1426
+ case 37: // left
1427
+ case 38: // up
1428
+ case 39: // right
1429
+ case 40: // down
1430
+ if (!this.o.keyboardNavigation || this.o.daysOfWeekDisabled.length === 7)
1431
+ break;
1432
+ dir = e.keyCode === 37 || e.keyCode === 38 ? -1 : 1;
1433
+ if (this.viewMode === 0) {
1434
+ if (e.ctrlKey){
1435
+ newViewDate = this.moveAvailableDate(focusDate, dir, 'moveYear');
1436
+
1437
+ if (newViewDate)
1438
+ this._trigger('changeYear', this.viewDate);
1439
+ } else if (e.shiftKey){
1440
+ newViewDate = this.moveAvailableDate(focusDate, dir, 'moveMonth');
1441
+
1442
+ if (newViewDate)
1443
+ this._trigger('changeMonth', this.viewDate);
1444
+ } else if (e.keyCode === 37 || e.keyCode === 39){
1445
+ newViewDate = this.moveAvailableDate(focusDate, dir, 'moveDay');
1446
+ } else if (!this.weekOfDateIsDisabled(focusDate)){
1447
+ newViewDate = this.moveAvailableDate(focusDate, dir, 'moveWeek');
1448
+ }
1449
+ } else if (this.viewMode === 1) {
1450
+ if (e.keyCode === 38 || e.keyCode === 40) {
1451
+ dir = dir * 4;
1452
+ }
1453
+ newViewDate = this.moveAvailableDate(focusDate, dir, 'moveMonth');
1454
+ } else if (this.viewMode === 2) {
1455
+ if (e.keyCode === 38 || e.keyCode === 40) {
1456
+ dir = dir * 4;
1457
+ }
1458
+ newViewDate = this.moveAvailableDate(focusDate, dir, 'moveYear');
1459
+ }
1460
+ if (newViewDate){
1461
+ this.focusDate = this.viewDate = newViewDate;
1462
+ this.setValue();
1463
+ this.fill();
1464
+ e.preventDefault();
1465
+ }
1466
+ break;
1467
+ case 13: // enter
1468
+ if (!this.o.forceParse)
1469
+ break;
1470
+ focusDate = this.focusDate || this.dates.get(-1) || this.viewDate;
1471
+ if (this.o.keyboardNavigation) {
1472
+ this._toggle_multidate(focusDate);
1473
+ dateChanged = true;
1474
+ }
1475
+ this.focusDate = null;
1476
+ this.viewDate = this.dates.get(-1) || this.viewDate;
1477
+ this.setValue();
1478
+ this.fill();
1479
+ if (this.picker.is(':visible')){
1480
+ e.preventDefault();
1481
+ e.stopPropagation();
1482
+ if (this.o.autoclose)
1483
+ this.hide();
1484
+ }
1485
+ break;
1486
+ case 9: // tab
1487
+ this.focusDate = null;
1488
+ this.viewDate = this.dates.get(-1) || this.viewDate;
1489
+ this.fill();
1490
+ this.hide();
1491
+ break;
1492
+ }
1493
+ if (dateChanged){
1494
+ if (this.dates.length)
1495
+ this._trigger('changeDate');
1496
+ else
1497
+ this._trigger('clearDate');
1498
+ this.inputField.trigger('change');
1499
+ }
1500
+ },
1501
+
1502
+ setViewMode: function(viewMode){
1503
+ this.viewMode = viewMode;
1504
+ this.picker
1505
+ .children('div')
1506
+ .hide()
1507
+ .filter('.datepicker-' + DPGlobal.viewModes[this.viewMode].clsName)
1508
+ .show();
1509
+ this.updateNavArrows();
1510
+ this._trigger('changeViewMode', new Date(this.viewDate));
1511
+ }
1512
+ };
1513
+
1514
+ var DateRangePicker = function(element, options){
1515
+ $.data(element, 'datepicker', this);
1516
+ this.element = $(element);
1517
+ this.inputs = $.map(options.inputs, function(i){
1518
+ return i.jquery ? i[0] : i;
1519
+ });
1520
+ delete options.inputs;
1521
+
1522
+ this.keepEmptyValues = options.keepEmptyValues;
1523
+ delete options.keepEmptyValues;
1524
+
1525
+ datepickerPlugin.call($(this.inputs), options)
1526
+ .on('changeDate', $.proxy(this.dateUpdated, this));
1527
+
1528
+ this.pickers = $.map(this.inputs, function(i){
1529
+ return $.data(i, 'datepicker');
1530
+ });
1531
+ this.updateDates();
1532
+ };
1533
+ DateRangePicker.prototype = {
1534
+ updateDates: function(){
1535
+ this.dates = $.map(this.pickers, function(i){
1536
+ return i.getUTCDate();
1537
+ });
1538
+ this.updateRanges();
1539
+ },
1540
+ updateRanges: function(){
1541
+ var range = $.map(this.dates, function(d){
1542
+ return d.valueOf();
1543
+ });
1544
+ $.each(this.pickers, function(i, p){
1545
+ p.setRange(range);
1546
+ });
1547
+ },
1548
+ dateUpdated: function(e){
1549
+ // `this.updating` is a workaround for preventing infinite recursion
1550
+ // between `changeDate` triggering and `setUTCDate` calling. Until
1551
+ // there is a better mechanism.
1552
+ if (this.updating)
1553
+ return;
1554
+ this.updating = true;
1555
+
1556
+ var dp = $.data(e.target, 'datepicker');
1557
+
1558
+ if (dp === undefined) {
1559
+ return;
1560
+ }
1561
+
1562
+ var new_date = dp.getUTCDate(),
1563
+ keep_empty_values = this.keepEmptyValues,
1564
+ i = $.inArray(e.target, this.inputs),
1565
+ j = i - 1,
1566
+ k = i + 1,
1567
+ l = this.inputs.length;
1568
+ if (i === -1)
1569
+ return;
1570
+
1571
+ $.each(this.pickers, function(i, p){
1572
+ if (!p.getUTCDate() && (p === dp || !keep_empty_values))
1573
+ p.setUTCDate(new_date);
1574
+ });
1575
+
1576
+ if (new_date < this.dates[j]){
1577
+ // Date being moved earlier/left
1578
+ while (j >= 0 && new_date < this.dates[j]){
1579
+ this.pickers[j--].setUTCDate(new_date);
1580
+ }
1581
+ } else if (new_date > this.dates[k]){
1582
+ // Date being moved later/right
1583
+ while (k < l && new_date > this.dates[k]){
1584
+ this.pickers[k++].setUTCDate(new_date);
1585
+ }
1586
+ }
1587
+ this.updateDates();
1588
+
1589
+ delete this.updating;
1590
+ },
1591
+ destroy: function(){
1592
+ $.map(this.pickers, function(p){ p.destroy(); });
1593
+ $(this.inputs).off('changeDate', this.dateUpdated);
1594
+ delete this.element.data().datepicker;
1595
+ },
1596
+ remove: alias('destroy', 'Method `remove` is deprecated and will be removed in version 2.0. Use `destroy` instead')
1597
+ };
1598
+
1599
+ function opts_from_el(el, prefix){
1600
+ // Derive options from element data-attrs
1601
+ var data = $(el).data(),
1602
+ out = {}, inkey,
1603
+ replace = new RegExp('^' + prefix.toLowerCase() + '([A-Z])');
1604
+ prefix = new RegExp('^' + prefix.toLowerCase());
1605
+ function re_lower(_,a){
1606
+ return a.toLowerCase();
1607
+ }
1608
+ for (var key in data)
1609
+ if (prefix.test(key)){
1610
+ inkey = key.replace(replace, re_lower);
1611
+ out[inkey] = data[key];
1612
+ }
1613
+ return out;
1614
+ }
1615
+
1616
+ function opts_from_locale(lang){
1617
+ // Derive options from locale plugins
1618
+ var out = {};
1619
+ // Check if "de-DE" style date is available, if not language should
1620
+ // fallback to 2 letter code eg "de"
1621
+ if (!dates[lang]){
1622
+ lang = lang.split('-')[0];
1623
+ if (!dates[lang])
1624
+ return;
1625
+ }
1626
+ var d = dates[lang];
1627
+ $.each(locale_opts, function(i,k){
1628
+ if (k in d)
1629
+ out[k] = d[k];
1630
+ });
1631
+ return out;
1632
+ }
1633
+
1634
+ var old = $.fn.datepicker;
1635
+ var datepickerPlugin = function(option){
1636
+ var args = Array.apply(null, arguments);
1637
+ args.shift();
1638
+ var internal_return;
1639
+ this.each(function(){
1640
+ var $this = $(this),
1641
+ data = $this.data('datepicker'),
1642
+ options = typeof option === 'object' && option;
1643
+ if (!data){
1644
+ var elopts = opts_from_el(this, 'date'),
1645
+ // Preliminary otions
1646
+ xopts = $.extend({}, defaults, elopts, options),
1647
+ locopts = opts_from_locale(xopts.language),
1648
+ // Options priority: js args, data-attrs, locales, defaults
1649
+ opts = $.extend({}, defaults, locopts, elopts, options);
1650
+ if ($this.hasClass('input-daterange') || opts.inputs){
1651
+ $.extend(opts, {
1652
+ inputs: opts.inputs || $this.find('input').toArray()
1653
+ });
1654
+ data = new DateRangePicker(this, opts);
1655
+ }
1656
+ else {
1657
+ data = new Datepicker(this, opts);
1658
+ }
1659
+ $this.data('datepicker', data);
1660
+ }
1661
+ if (typeof option === 'string' && typeof data[option] === 'function'){
1662
+ internal_return = data[option].apply(data, args);
1663
+ }
1664
+ });
1665
+
1666
+ if (
1667
+ internal_return === undefined ||
1668
+ internal_return instanceof Datepicker ||
1669
+ internal_return instanceof DateRangePicker
1670
+ )
1671
+ return this;
1672
+
1673
+ if (this.length > 1)
1674
+ throw new Error('Using only allowed for the collection of a single element (' + option + ' function)');
1675
+ else
1676
+ return internal_return;
1677
+ };
1678
+ $.fn.datepicker = datepickerPlugin;
1679
+
1680
+ var defaults = $.fn.datepicker.defaults = {
1681
+ assumeNearbyYear: false,
1682
+ autoclose: false,
1683
+ beforeShowDay: $.noop,
1684
+ beforeShowMonth: $.noop,
1685
+ beforeShowYear: $.noop,
1686
+ beforeShowDecade: $.noop,
1687
+ beforeShowCentury: $.noop,
1688
+ calendarWeeks: false,
1689
+ clearBtn: false,
1690
+ toggleActive: false,
1691
+ daysOfWeekDisabled: [],
1692
+ daysOfWeekHighlighted: [],
1693
+ datesDisabled: [],
1694
+ endDate: Infinity,
1695
+ forceParse: true,
1696
+ format: 'mm/dd/yyyy',
1697
+ keepEmptyValues: false,
1698
+ keyboardNavigation: true,
1699
+ language: 'en',
1700
+ minViewMode: 0,
1701
+ maxViewMode: 4,
1702
+ multidate: false,
1703
+ multidateSeparator: ',',
1704
+ orientation: "auto",
1705
+ rtl: false,
1706
+ startDate: -Infinity,
1707
+ startView: 0,
1708
+ todayBtn: false,
1709
+ todayHighlight: false,
1710
+ updateViewDate: true,
1711
+ weekStart: 0,
1712
+ disableTouchKeyboard: false,
1713
+ enableOnReadonly: true,
1714
+ showOnFocus: true,
1715
+ zIndexOffset: 10,
1716
+ container: 'body',
1717
+ immediateUpdates: false,
1718
+ title: '',
1719
+ templates: {
1720
+ leftArrow: '&#x00AB;',
1721
+ rightArrow: '&#x00BB;'
1722
+ },
1723
+ showWeekDays: true
1724
+ };
1725
+ var locale_opts = $.fn.datepicker.locale_opts = [
1726
+ 'format',
1727
+ 'rtl',
1728
+ 'weekStart'
1729
+ ];
1730
+ $.fn.datepicker.Constructor = Datepicker;
1731
+ var dates = $.fn.datepicker.dates = {
1732
+ en: {
1733
+ days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
1734
+ daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
1735
+ daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
1736
+ months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
1737
+ monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
1738
+ today: "Today",
1739
+ clear: "Clear",
1740
+ titleFormat: "MM yyyy"
1741
+ }
1742
+ };
1743
+
1744
+ var DPGlobal = {
1745
+ viewModes: [
1746
+ {
1747
+ names: ['days', 'month'],
1748
+ clsName: 'days',
1749
+ e: 'changeMonth'
1750
+ },
1751
+ {
1752
+ names: ['months', 'year'],
1753
+ clsName: 'months',
1754
+ e: 'changeYear',
1755
+ navStep: 1
1756
+ },
1757
+ {
1758
+ names: ['years', 'decade'],
1759
+ clsName: 'years',
1760
+ e: 'changeDecade',
1761
+ navStep: 10
1762
+ },
1763
+ {
1764
+ names: ['decades', 'century'],
1765
+ clsName: 'decades',
1766
+ e: 'changeCentury',
1767
+ navStep: 100
1768
+ },
1769
+ {
1770
+ names: ['centuries', 'millennium'],
1771
+ clsName: 'centuries',
1772
+ e: 'changeMillennium',
1773
+ navStep: 1000
1774
+ }
1775
+ ],
1776
+ validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g,
1777
+ nonpunctuation: /[^ -\/:-@\u5e74\u6708\u65e5\[-`{-~\t\n\r]+/g,
1778
+ parseFormat: function(format){
1779
+ if (typeof format.toValue === 'function' && typeof format.toDisplay === 'function')
1780
+ return format;
1781
+ // IE treats \0 as a string end in inputs (truncating the value),
1782
+ // so it's a bad format delimiter, anyway
1783
+ var separators = format.replace(this.validParts, '\0').split('\0'),
1784
+ parts = format.match(this.validParts);
1785
+ if (!separators || !separators.length || !parts || parts.length === 0){
1786
+ throw new Error("Invalid date format.");
1787
+ }
1788
+ return {separators: separators, parts: parts};
1789
+ },
1790
+ parseDate: function(date, format, language, assumeNearby){
1791
+ if (!date)
1792
+ return undefined;
1793
+ if (date instanceof Date)
1794
+ return date;
1795
+ if (typeof format === 'string')
1796
+ format = DPGlobal.parseFormat(format);
1797
+ if (format.toValue)
1798
+ return format.toValue(date, format, language);
1799
+ var fn_map = {
1800
+ d: 'moveDay',
1801
+ m: 'moveMonth',
1802
+ w: 'moveWeek',
1803
+ y: 'moveYear'
1804
+ },
1805
+ dateAliases = {
1806
+ yesterday: '-1d',
1807
+ today: '+0d',
1808
+ tomorrow: '+1d'
1809
+ },
1810
+ parts, part, dir, i, fn;
1811
+ if (date in dateAliases){
1812
+ date = dateAliases[date];
1813
+ }
1814
+ if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/i.test(date)){
1815
+ parts = date.match(/([\-+]\d+)([dmwy])/gi);
1816
+ date = new Date();
1817
+ for (i=0; i < parts.length; i++){
1818
+ part = parts[i].match(/([\-+]\d+)([dmwy])/i);
1819
+ dir = Number(part[1]);
1820
+ fn = fn_map[part[2].toLowerCase()];
1821
+ date = Datepicker.prototype[fn](date, dir);
1822
+ }
1823
+ return Datepicker.prototype._zero_utc_time(date);
1824
+ }
1825
+
1826
+ parts = date && date.match(this.nonpunctuation) || [];
1827
+
1828
+ function applyNearbyYear(year, threshold){
1829
+ if (threshold === true)
1830
+ threshold = 10;
1831
+
1832
+ // if year is 2 digits or less, than the user most likely is trying to get a recent century
1833
+ if (year < 100){
1834
+ year += 2000;
1835
+ // if the new year is more than threshold years in advance, use last century
1836
+ if (year > ((new Date()).getFullYear()+threshold)){
1837
+ year -= 100;
1838
+ }
1839
+ }
1840
+
1841
+ return year;
1842
+ }
1843
+
1844
+ var parsed = {},
1845
+ setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'],
1846
+ setters_map = {
1847
+ yyyy: function(d,v){
1848
+ return d.setUTCFullYear(assumeNearby ? applyNearbyYear(v, assumeNearby) : v);
1849
+ },
1850
+ m: function(d,v){
1851
+ if (isNaN(d))
1852
+ return d;
1853
+ v -= 1;
1854
+ while (v < 0) v += 12;
1855
+ v %= 12;
1856
+ d.setUTCMonth(v);
1857
+ while (d.getUTCMonth() !== v)
1858
+ d.setUTCDate(d.getUTCDate()-1);
1859
+ return d;
1860
+ },
1861
+ d: function(d,v){
1862
+ return d.setUTCDate(v);
1863
+ }
1864
+ },
1865
+ val, filtered;
1866
+ setters_map['yy'] = setters_map['yyyy'];
1867
+ setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
1868
+ setters_map['dd'] = setters_map['d'];
1869
+ date = UTCToday();
1870
+ var fparts = format.parts.slice();
1871
+ // Remove noop parts
1872
+ if (parts.length !== fparts.length){
1873
+ fparts = $(fparts).filter(function(i,p){
1874
+ return $.inArray(p, setters_order) !== -1;
1875
+ }).toArray();
1876
+ }
1877
+ // Process remainder
1878
+ function match_part(){
1879
+ var m = this.slice(0, parts[i].length),
1880
+ p = parts[i].slice(0, m.length);
1881
+ return m.toLowerCase() === p.toLowerCase();
1882
+ }
1883
+ if (parts.length === fparts.length){
1884
+ var cnt;
1885
+ for (i=0, cnt = fparts.length; i < cnt; i++){
1886
+ val = parseInt(parts[i], 10);
1887
+ part = fparts[i];
1888
+ if (isNaN(val)){
1889
+ switch (part){
1890
+ case 'MM':
1891
+ filtered = $(dates[language].months).filter(match_part);
1892
+ val = $.inArray(filtered[0], dates[language].months) + 1;
1893
+ break;
1894
+ case 'M':
1895
+ filtered = $(dates[language].monthsShort).filter(match_part);
1896
+ val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
1897
+ break;
1898
+ }
1899
+ }
1900
+ parsed[part] = val;
1901
+ }
1902
+ var _date, s;
1903
+ for (i=0; i < setters_order.length; i++){
1904
+ s = setters_order[i];
1905
+ if (s in parsed && !isNaN(parsed[s])){
1906
+ _date = new Date(date);
1907
+ setters_map[s](_date, parsed[s]);
1908
+ if (!isNaN(_date))
1909
+ date = _date;
1910
+ }
1911
+ }
1912
+ }
1913
+ return date;
1914
+ },
1915
+ formatDate: function(date, format, language){
1916
+ if (!date)
1917
+ return '';
1918
+ if (typeof format === 'string')
1919
+ format = DPGlobal.parseFormat(format);
1920
+ if (format.toDisplay)
1921
+ return format.toDisplay(date, format, language);
1922
+ var val = {
1923
+ d: date.getUTCDate(),
1924
+ D: dates[language].daysShort[date.getUTCDay()],
1925
+ DD: dates[language].days[date.getUTCDay()],
1926
+ m: date.getUTCMonth() + 1,
1927
+ M: dates[language].monthsShort[date.getUTCMonth()],
1928
+ MM: dates[language].months[date.getUTCMonth()],
1929
+ yy: date.getUTCFullYear().toString().substring(2),
1930
+ yyyy: date.getUTCFullYear()
1931
+ };
1932
+ val.dd = (val.d < 10 ? '0' : '') + val.d;
1933
+ val.mm = (val.m < 10 ? '0' : '') + val.m;
1934
+ date = [];
1935
+ var seps = $.extend([], format.separators);
1936
+ for (var i=0, cnt = format.parts.length; i <= cnt; i++){
1937
+ if (seps.length)
1938
+ date.push(seps.shift());
1939
+ date.push(val[format.parts[i]]);
1940
+ }
1941
+ return date.join('');
1942
+ },
1943
+ headTemplate: '<thead>'+
1944
+ '<tr>'+
1945
+ '<th colspan="7" class="datepicker-title"></th>'+
1946
+ '</tr>'+
1947
+ '<tr>'+
1948
+ '<th class="prev">'+defaults.templates.leftArrow+'</th>'+
1949
+ '<th colspan="5" class="datepicker-switch"></th>'+
1950
+ '<th class="next">'+defaults.templates.rightArrow+'</th>'+
1951
+ '</tr>'+
1952
+ '</thead>',
1953
+ contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>',
1954
+ footTemplate: '<tfoot>'+
1955
+ '<tr>'+
1956
+ '<th colspan="7" class="today"></th>'+
1957
+ '</tr>'+
1958
+ '<tr>'+
1959
+ '<th colspan="7" class="clear"></th>'+
1960
+ '</tr>'+
1961
+ '</tfoot>'
1962
+ };
1963
+ DPGlobal.template = '<div class="datepicker">'+
1964
+ '<div class="datepicker-days">'+
1965
+ '<table class="table-condensed">'+
1966
+ DPGlobal.headTemplate+
1967
+ '<tbody></tbody>'+
1968
+ DPGlobal.footTemplate+
1969
+ '</table>'+
1970
+ '</div>'+
1971
+ '<div class="datepicker-months">'+
1972
+ '<table class="table-condensed">'+
1973
+ DPGlobal.headTemplate+
1974
+ DPGlobal.contTemplate+
1975
+ DPGlobal.footTemplate+
1976
+ '</table>'+
1977
+ '</div>'+
1978
+ '<div class="datepicker-years">'+
1979
+ '<table class="table-condensed">'+
1980
+ DPGlobal.headTemplate+
1981
+ DPGlobal.contTemplate+
1982
+ DPGlobal.footTemplate+
1983
+ '</table>'+
1984
+ '</div>'+
1985
+ '<div class="datepicker-decades">'+
1986
+ '<table class="table-condensed">'+
1987
+ DPGlobal.headTemplate+
1988
+ DPGlobal.contTemplate+
1989
+ DPGlobal.footTemplate+
1990
+ '</table>'+
1991
+ '</div>'+
1992
+ '<div class="datepicker-centuries">'+
1993
+ '<table class="table-condensed">'+
1994
+ DPGlobal.headTemplate+
1995
+ DPGlobal.contTemplate+
1996
+ DPGlobal.footTemplate+
1997
+ '</table>'+
1998
+ '</div>'+
1999
+ '</div>';
2000
+
2001
+ $.fn.datepicker.DPGlobal = DPGlobal;
2002
+
2003
+
2004
+ /* DATEPICKER NO CONFLICT
2005
+ * =================== */
2006
+
2007
+ $.fn.datepicker.noConflict = function(){
2008
+ $.fn.datepicker = old;
2009
+ return this;
2010
+ };
2011
+
2012
+ /* DATEPICKER VERSION
2013
+ * =================== */
2014
+ $.fn.datepicker.version = '1.7.0';
2015
+
2016
+ $.fn.datepicker.deprecated = function(msg){
2017
+ var console = window.console;
2018
+ if (console && console.warn) {
2019
+ console.warn('DEPRECATED: ' + msg);
2020
+ }
2021
+ };
2022
+
2023
+
2024
+ /* DATEPICKER DATA-API
2025
+ * ================== */
2026
+
2027
+ $(document).on(
2028
+ 'focus.datepicker.data-api click.datepicker.data-api',
2029
+ '[data-provide="datepicker"]',
2030
+ function(e){
2031
+ var $this = $(this);
2032
+ if ($this.data('datepicker'))
2033
+ return;
2034
+ e.preventDefault();
2035
+ // component click requires us to explicitly show it
2036
+ datepickerPlugin.call($this, 'show');
2037
+ }
2038
+ );
2039
+ $(function(){
2040
+ datepickerPlugin.call($('[data-provide="datepicker-inline"]'));
2041
+ });
2042
+
2043
+ }));