PageSourceSearch

https://tickets.rom.on.ca/javascript/bootstrap/bootstrap-datepicker-master/js/bootstrap-datepicker.js

js rom.on.ca collected 2026-10-01 08:49:52 UTC 58,854 bytes, 2,058 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.