PageSourceSearch

https://www.raschau-markersbach.de/typo3conf/ext/kjo_wbs_searchand…/bootstrap-datepicker.js?1665058668

js raschau-markersbach.de collected 2026-10-02 18:42:25 UTC 57,308 bytes, 2,036 lines download raw bytes

vendor: 32,669 bytes, lines 1-1137
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
30	function UTCDate(){
31		return new Date(Date.UTC.apply(Date, arguments));
32	}
33	function UTCToday(){
34		var today = new Date();
35		return UTCDate(today.getFullYear(), today.getMonth(), today.getDate());
36	}
37	function isUTCEquals(date1, date2) {
38		return (
39			date1.getUTCFullYear() === date2.getUTCFullYear() &&
40			date1.getUTCMonth() === date2.getUTCMonth() &&
41			date1.getUTCDate() === date2.getUTCDate()
42		);
43	}
44	function alias(method){
45		return function(){
46			return this[method].apply(this, arguments);
47		};
48	}
49	function isValidDate(d) {
50		return d && !isNaN(d.getTime());
51	}
52
53	var DateArray = (function(){
54		var extras = {
55			get: function(i){
56				return this.slice(i)[0];
57			},
58			contains: function(d){
59				// Array.indexOf is not cross-browser;
60				// $.inArray doesn't work with Dates
61				var val = d && d.valueOf();
62				for (var i=0, l=this.length; i < l; i++)
63          // Use date arithmetic to allow dates with different times to match
64          if (0 <= this[i].valueOf() - val && this[i].valueOf() - val < 1000*60*60*24)
65						return i;
66				return -1;
67			},
68			remove: function(i){
69				this.splice(i,1);
70			},
71			replace: function(new_array){
72				if (!new_array)
73					return;
74				if (!$.isArray(new_array))
75					new_array = [new_array];
76				this.clear();
77				this.push.apply(this, new_array);
78			},
79			clear: function(){
80				this.length = 0;
81			},
82			copy: function(){
83				var a = new DateArray();
84				a.replace(this);
85				return a;
86			}
87		};
88
89		return function(){
90			var a = [];
91			a.push.apply(a, arguments);
92			$.extend(a, extras);
93			return a;
94		};
95	})();
96
97
98	// Picker object
99
100	var Datepicker = function(element, options){
101		$.data(element, 'datepicker', this);
102		this._process_options(options);
103
104		this.dates = new DateArray();
105		this.viewDate = this.o.defaultViewDate;
106		this.focusDate = null;
107
108		this.element = $(element);
109		this.isInput = this.element.is('input');
110		this.inputField = this.isInput ? this.element : this.element.find('input');
111		this.component = this.element.hasClass('date') ? this.element.find('.add-on, .input-group-addon, .btn') : false;
112		if (this.component && this.component.length === 0)
113			this.component = false;
114		this.isInline = !this.component && this.element.is('div');
115
116		this.picker = $(DPGlobal.template);
117
118		// Checking templates and inserting
119		if (this._check_template(this.o.templates.leftArrow)) {
120			this.picker.find('.prev').html(this.o.templates.leftArrow);
121		}
122
123		if (this._check_template(this.o.templates.rightArrow)) {
124			this.picker.find('.next').html(this.o.templates.rightArrow);
125		}
126
127		this._buildEvents();
128		this._attachEvents();
129
130		if (this.isInline){
131			this.picker.addClass('datepicker-inline').appendTo(this.element);
132		}
133		else {
134			this.picker.addClass('datepicker-dropdown dropdown-menu');
135		}
136
137		if (this.o.rtl){
138			this.picker.addClass('datepicker-rtl');
139		}
140
141		if (this.o.calendarWeeks) {
142			this.picker.find('.datepicker-days .datepicker-switch, thead .datepicker-title, tfoot .today, tfoot .clear')
143				.attr('colspan', function(i, val){
144					return Number(val) + 1;
145				});
146		}
147
148		this._allow_update = false;
149
150		this.setStartDate(this._o.startDate);
151		this.setEndDate(this._o.endDate);
152		this.setDaysOfWeekDisabled(this.o.daysOfWeekDisabled);
153		this.setDaysOfWeekHighlighted(this.o.daysOfWeekHighlighted);
154		this.setDatesDisabled(this.o.datesDisabled);
155
156		this.setViewMode(this.o.startView);
157		this.fillDow();
158		this.fillMonths();
159
160		this._allow_update = true;
161
162		this.update();
163
164		if (this.isInline){
165			this.show();
166		}
167	};
168
169	Datepicker.prototype = {
170		constructor: Datepicker,
171
172		_resolveViewName: function(view){
173			$.each(DPGlobal.viewModes, function(i, viewMode){
174				if (view === i || $.inArray(view, viewMode.names) !== -1){
175					view = i;
176					return false;
177				}
178			});
179
180			return view;
181		},
182
183		_resolveDaysOfWeek: function(daysOfWeek){
184			if (!$.isArray(daysOfWeek))
185				daysOfWeek = daysOfWeek.split(/[,\s]*/);
186			return $.map(daysOfWeek, Number);
187		},
188
189		_check_template: function(tmp){
190			try {
191				// If empty
192				if (tmp === undefined || tmp === "") {
193					return false;
194				}
195				// If no html, everything ok
196				if ((tmp.match(/[<>]/g) || []).length <= 0) {
197					return true;
198				}
199				// Checking if html is fine
200				var jDom = $(tmp);
201				return jDom.length > 0;
202			}
203			catch (ex) {
204				return false;
205			}
206		},
207
208		_process_options: function(opts){
209			// Store raw options for reference
210			this._o = $.extend({}, this._o, opts);
211			// Processed options
212			var o = this.o = $.extend({}, this._o);
213
214			// Check if "de-DE" style date is available, if not language should
215			// fallback to 2 letter code eg "de"
216			var lang = o.language;
217			if (!dates[lang]){
218				lang = lang.split('-')[0];
219				if (!dates[lang])
220					lang = defaults.language;
221			}
222			o.language = lang;
223
224			// Retrieve view index from any aliases
225			o.startView = this._resolveViewName(o.startView);
226			o.minViewMode = this._resolveViewName(o.minViewMode);
227			o.maxViewMode = this._resolveViewName(o.maxViewMode);
228
229			// Check view is between min and max
230			o.startView = Math.max(this.o.minViewMode, Math.min(this.o.maxViewMode, o.startView));
231
232			// true, false, or Number > 0
233			if (o.multidate !== true){
234				o.multidate = Number(o.multidate) || false;
235				if (o.multidate !== false)
236					o.multidate = Math.max(0, o.multidate);
237			}
238			o.multidateSeparator = String(o.multidateSeparator);
239
240			o.weekStart %= 7;
241			o.weekEnd = (o.weekStart + 6) % 7;
242
243			var format = DPGlobal.parseFormat(o.format);
244			if (o.startDate !== -Infinity){
245				if (!!o.startDate){
246					if (o.startDate instanceof Date)
247						o.startDate = this._local_to_utc(this._zero_time(o.startDate));
248					else
249						o.startDate = DPGlobal.parseDate(o.startDate, format, o.language, o.assumeNearbyYear);
250				}
251				else {
252					o.startDate = -Infinity;
253				}
254			}
255			if (o.endDate !== Infinity){
256				if (!!o.endDate){
257					if (o.endDate instanceof Date)
258						o.endDate = this._local_to_utc(this._zero_time(o.endDate));
259					else
260						o.endDate = DPGlobal.parseDate(o.endDate, format, o.language, o.assumeNearbyYear);
261				}
262				else {
263					o.endDate = Infinity;
264				}
265			}
266
267			o.daysOfWeekDisabled = this._resolveDaysOfWeek(o.daysOfWeekDisabled||[]);
268			o.daysOfWeekHighlighted = this._resolveDaysOfWeek(o.daysOfWeekHighlighted||[]);
269
270			o.datesDisabled = o.datesDisabled||[];
271			if (!$.isArray(o.datesDisabled)) {
272				o.datesDisabled = o.datesDisabled.split(',');
273			}
274			o.datesDisabled = $.map(o.datesDisabled, function(d){
275				return DPGlobal.parseDate(d, format, o.language, o.assumeNearbyYear);
276			});
277
278			var plc = String(o.orientation).toLowerCase().split(/\s+/g),
279				_plc = o.orientation.toLowerCase();
280			plc = $.grep(plc, function(word){
281				return /^auto|left|right|top|bottom$/.test(word);
282			});
283			o.orientation = {x: 'auto', y: 'auto'};
284			if (!_plc || _plc === 'auto')
285				; // no action
286			else if (plc.length === 1){
287				switch (plc[0]){
288					case 'top':
289					case 'bottom':
290						o.orientation.y = plc[0];
291						break;
292					case 'left':
293					case 'right':
294						o.orientation.x = plc[0];
295						break;
296				}
297			}
298			else {
299				_plc = $.grep(plc, function(word){
300					return /^left|right$/.test(word);
301				});
302				o.orientation.x = _plc[0] || 'auto';
303
304				_plc = $.grep(plc, function(word){
305					return /^top|bottom$/.test(word);
306				});
307				o.orientation.y = _plc[0] || 'auto';
308			}
309			if (o.defaultViewDate) {
310				var year = o.defaultViewDate.year || new Date().getFullYear();
311				var month = o.defaultViewDate.month || 0;
312				var day = o.defaultViewDate.day || 1;
313				o.defaultViewDate = UTCDate(year, month, day);
314			} else {
315				o.defaultViewDate = UTCToday();
316			}
317		},
318		_events: [],
319		_secondaryEvents: [],
320		_applyEvents: function(evs){
321			for (var i=0, el, ch, ev; i < evs.length; i++){
322				el = evs[i][0];
323				if (evs[i].length === 2){
324					ch = undefined;
325					ev = evs[i][1];
326				} else if (evs[i].length === 3){
327					ch = evs[i][1];
328					ev = evs[i][2];
329				}
330				el.on(ev, ch);
331			}
332		},
333		_unapplyEvents: function(evs){
334			for (var i=0, el, ev, ch; i < evs.length; i++){
335				el = evs[i][0];
336				if (evs[i].length === 2){
337					ch = undefined;
338					ev = evs[i][1];
339				} else if (evs[i].length === 3){
340					ch = evs[i][1];
341					ev = evs[i][2];
342				}
343				el.off(ev, ch);
344			}
345		},
346		_buildEvents: function(){
347            var events = {
348                keyup: $.proxy(function(e){
349                    if ($.inArray(e.keyCode, [27, 37, 39, 38, 40, 32, 13, 9]) === -1)
350                        this.update();
351                }, this),
352                keydown: $.proxy(this.keydown, this),
353                paste: $.proxy(this.paste, this)
354            };
355
356            if (this.o.showOnFocus === true) {
357                events.focus = $.proxy(this.show, this);
358            }
359
360            if (this.isInput) { // single input
361                this._events = [
362                    [this.element, events]
363                ];
364            }
365            // component: input + button
366            else if (this.component && this.inputField.length) {
367                this._events = [
368                    // For components that are not readonly, allow keyboard nav
369                    [this.inputField, events],
370                    [this.component, {
371                        click: $.proxy(this.show, this)
372                    }]
373                ];
374            }
375			else {
376				this._events = [
377					[this.element, {
378						click: $.proxy(this.show, this),
379						keydown: $.proxy(this.keydown, this)
380					}]
381				];
382			}
383			this._events.push(
384				// Component: listen for blur on element descendants
385				[this.element, '*', {
386					blur: $.proxy(function(e){
387						this._focused_from = e.target;
388					}, this)
389				}],
390				// Input: listen for blur on element
391				[this.element, {
392					blur: $.proxy(function(e){
393						this._focused_from = e.target;
394					}, this)
395				}]
396			);
397
398			if (this.o.immediateUpdates) {
399				// Trigger input updates immediately on changed year/month
400				this._events.push([this.element, {
401					'changeYear changeMonth': $.proxy(function(e){
402						this.update(e.date);
403					}, this)
404				}]);
405			}
406
407			this._secondaryEvents = [
408				[this.picker, {
409					click: $.proxy(this.click, this)
410				}],
411				[this.picker, '.prev, .next', {
412					click: $.proxy(this.navArrowsClick, this)
413				}],
414				[$(window), {
415					resize: $.proxy(this.place, this)
416				}],
417				[$(document), {
418					'mousedown touchstart': $.proxy(function(e){
419						// Clicked outside the datepicker, hide it
420						if (!(
421							this.element.is(e.target) ||
422							this.element.find(e.target).length ||
423							this.picker.is(e.target) ||
424							this.picker.find(e.target).length ||
425							this.isInline
426						)){
427							this.hide();
428						}
429					}, this)
430				}]
431			];
432		},
433		_attachEvents: function(){
434			this._detachEvents();
435			this._applyEvents(this._events);
436		},
437		_detachEvents: function(){
438			this._unapplyEvents(this._events);
439		},
440		_attachSecondaryEvents: function(){
441			this._detachSecondaryEvents();
442			this._applyEvents(this._secondaryEvents);
443		},
444		_detachSecondaryEvents: function(){
445			this._unapplyEvents(this._secondaryEvents);
446		},
447		_trigger: function(event, altdate){
448			var date = altdate || this.dates.get(-1),
449				local_date = this._utc_to_local(date);
450
451			this.element.trigger({
452				type: event,
453				date: local_date,
454				viewMode: this.viewMode,
455				dates: $.map(this.dates, this._utc_to_local),
456				format: $.proxy(function(ix, format){
457					if (arguments.length === 0){
458						ix = this.dates.length - 1;
459						format = this.o.format;
460					} else if (typeof ix === 'string'){
461						format = ix;
462						ix = this.dates.length - 1;
463					}
464					format = format || this.o.format;
465					var date = this.dates.get(ix);
466					return DPGlobal.formatDate(date, format, this.o.language);
467				}, this)
468			});
469		},
470
471		show: function(){
472			if (this.inputField.prop('disabled') || (this.inputField.prop('readonly') && this.o.enableOnReadonly === false))
473				return;
474			if (!this.isInline)
475				this.picker.appendTo(this.o.container);
476			this.place();
477			this.picker.show();
478			this._attachSecondaryEvents();
479			this._trigger('show');
480			if ((window.navigator.msMaxTouchPoints || 'ontouchstart' in document) && this.o.disableTouchKeyboard) {
481				$(this.element).blur();
482			}
483			return this;
484		},
485
486		hide: function(){
487			if (this.isInline || !this.picker.is(':visible'))
488				return this;
489			this.focusDate = null;
490			this.picker.hide().detach();
491			this._detachSecondaryEvents();
492			this.setViewMode(this.o.startView);
493
494			if (this.o.forceParse && this.inputField.val())
495				this.setValue();
496			this._trigger('hide');
497			return this;
498		},
499
500		destroy: function(){
501			this.hide();
502			this._detachEvents();
503			this._detachSecondaryEvents();
504			this.picker.remove();
505			delete this.element.data().datepicker;
506			if (!this.isInput){
507				delete this.element.data().date;
508			}
509			return this;
510		},
511
512		paste: function(e){
513			var dateString;
514			if (e.originalEvent.clipboardData && e.originalEvent.clipboardData.types
515				&& $.inArray('text/plain', e.originalEvent.clipboardData.types) !== -1) {
516				dateString = e.originalEvent.clipboardData.getData('text/plain');
517			} else if (window.clipboardData) {
518				dateString = window.clipboardData.getData('Text');
519			} else {
520				return;
521			}
522			this.setDate(dateString);
523			this.update();
524			e.preventDefault();
525		},
526
527		_utc_to_local: function(utc){
528			if (!utc) {
529				return utc;
530			}
531
532			var local = new Date(utc.getTime() + (utc.getTimezoneOffset() * 60000));
533
534			if (local.getTimezoneOffset() !== utc.getTimezoneOffset()) {
535				local = new Date(utc.getTime() + (local.getTimezoneOffset() * 60000));
536			}
537
538			return local;
539		},
540		_local_to_utc: function(local){
541			return local && new Date(local.getTime() - (local.getTimezoneOffset()*60000));
542		},
543		_zero_time: function(local){
544			return local && new Date(local.getFullYear(), local.getMonth(), local.getDate());
545		},
546		_zero_utc_time: function(utc){
547			return utc && UTCDate(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate());
548		},
549
550		getDates: function(){
551			return $.map(this.dates, this._utc_to_local);
552		},
553
554		getUTCDates: function(){
555			return $.map(this.dates, function(d){
556				return new Date(d);
557			});
558		},
559
560		getDate: function(){
561			return this._utc_to_local(this.getUTCDate());
562		},
563
564		getUTCDate: function(){
565			var selected_date = this.dates.get(-1);
566			if (selected_date !== undefined) {
567				return new Date(selected_date);
568			} else {
569				return null;
570			}
571		},
572
573		clearDates: function(){
574			this.inputField.val('');
575			this.update();
576			this._trigger('changeDate');
577
578			if (this.o.autoclose) {
579				this.hide();
580			}
581		},
582
583		setDates: function(){
584			var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
585			this.update.apply(this, args);
586			this._trigger('changeDate');
587			this.setValue();
588			return this;
589		},
590
591		setUTCDates: function(){
592			var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
593			this.setDates.apply(this, $.map(args, this._utc_to_local));
594			return this;
595		},
596
597		setDate: alias('setDates'),
598		setUTCDate: alias('setUTCDates'),
599		remove: alias('destroy'),
600
601		setValue: function(){
602			var formatted = this.getFormattedDate();
603			this.inputField.val(formatted);
604			return this;
605		},
606
607		getFormattedDate: function(format){
608			if (format === undefined)
609				format = this.o.format;
610
611			var lang = this.o.language;
612			return $.map(this.dates, function(d){
613				return DPGlobal.formatDate(d, format, lang);
614			}).join(this.o.multidateSeparator);
615		},
616
617		getStartDate: function(){
618			return this.o.startDate;
619		},
620
621		setStartDate: function(startDate){
622			this._process_options({startDate: startDate});
623			this.update();
624			this.updateNavArrows();
625			return this;
626		},
627
628		getEndDate: function(){
629			return this.o.endDate;
630		},
631
632		setEndDate: function(endDate){
633			this._process_options({endDate: endDate});
634			this.update();
635			this.updateNavArrows();
636			return this;
637		},
638
639		setDaysOfWeekDisabled: function(daysOfWeekDisabled){
640			this._process_options({daysOfWeekDisabled: daysOfWeekDisabled});
641			this.update();
642			return this;
643		},
644
645		setDaysOfWeekHighlighted: function(daysOfWeekHighlighted){
646			this._process_options({daysOfWeekHighlighted: daysOfWeekHighlighted});
647			this.update();
648			return this;
649		},
650
651		setDatesDisabled: function(datesDisabled){
652			this._process_options({datesDisabled: datesDisabled});
653			this.update();
654			return this;
655		},
656
657		place: function(){
658			if (this.isInline)
659				return this;
660			var calendarWidth = this.picker.outerWidth(),
661				calendarHeight = this.picker.outerHeight(),
662				visualPadding = 10,
663				container = $(this.o.container),
664				windowWidth = container.width(),
665				scrollTop = this.o.container === 'body' ? $(document).scrollTop() : container.scrollTop(),
666				appendOffset = container.offset();
667
668			var parentsZindex = [];
669			this.element.parents().each(function(){
670				var itemZIndex = $(this).css('z-index');
671				if (itemZIndex !== 'auto' && itemZIndex !== 0) parentsZindex.push(parseInt(itemZIndex));
672			});
673			var zIndex = Math.max.apply(Math, parentsZindex) + this.o.zIndexOffset;
674			var offset = this.component ? this.component.parent().offset() : this.element.offset();
675			var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(false);
676			var width = this.component ? this.component.outerWidth(true) : this.element.outerWidth(false);
677			var left = offset.left - appendOffset.left,
678				top = offset.top - appendOffset.top;
679
680			if (this.o.container !== 'body') {
681				top += scrollTop;
682			}
683
684			this.picker.removeClass(
685				'datepicker-orient-top datepicker-orient-bottom '+
686				'datepicker-orient-right datepicker-orient-left'
687			);
688
689			if (this.o.orientation.x !== 'auto'){
690				this.picker.addClass('datepicker-orient-' + this.o.orientation.x);
691				if (this.o.orientation.x === 'right')
692					left -= calendarWidth - width;
693			}
694			// auto x orientation is best-placement: if it crosses a window
695			// edge, fudge it sideways
696			else {
697				if (offset.left < 0) {
698					// component is outside the window on the left side. Move it into visible range
699					this.picker.addClass('datepicker-orient-left');
700					left -= offset.left - visualPadding;
701				} else if (left + calendarWidth > windowWidth) {
702					// the calendar passes the widow right edge. Align it to component right side
703					this.picker.addClass('datepicker-orient-right');
704					left += width - calendarWidth;
705				} else {
706					if (this.o.rtl) {
707						// Default to right
708						this.picker.addClass('datepicker-orient-right');
709					} else {
710						// Default to left
711						this.picker.addClass('datepicker-orient-left');
712					}
713				}
714			}
715
716			// auto y orientation is best-situation: top or bottom, no fudging,
717			// decision based on which shows more of the calendar
718			var yorient = this.o.orientation.y,
719				top_overflow;
720			if (yorient === 'auto'){
721				top_overflow = -scrollTop + top - calendarHeight;
722				yorient = top_overflow < 0 ? 'bottom' : 'top';
723			}
724
725			this.picker.addClass('datepicker-orient-' + yorient);
726			if (yorient === 'top')
727				top -= calendarHeight + parseInt(this.picker.css('padding-top'));
728			else
729				top += height;
730
731			if (this.o.rtl) {
732				var right = windowWidth - (left + width);
733				this.picker.css({
734					top: top,
735					right: right,
736					zIndex: zIndex
737				});
738			} else {
739				this.picker.css({
740					top: top,
741					left: left,
742					zIndex: zIndex
743				});
744			}
745			return this;
746		},
747
748		_allow_update: true,
749		update: function(){
750			if (!this._allow_update)
751				return this;
752
753			var oldDates = this.dates.copy(),
754				dates = [],
755				fromArgs = false;
756			if (arguments.length){
757				$.each(arguments, $.proxy(function(i, date){
758					if (date instanceof Date)
759						date = this._local_to_utc(date);
760					dates.push(date);
761				}, this));
762				fromArgs = true;
763			} else {
764				dates = this.isInput
765						? this.element.val()
766						: this.element.data('date') || this.inputField.val();
767				if (dates && this.o.multidate)
768					dates = dates.split(this.o.multidateSeparator);
769				else
770					dates = [dates];
771				delete this.element.data().date;
772			}
773
774			dates = $.map(dates, $.proxy(function(date){
775				return DPGlobal.parseDate(date, this.o.format, this.o.language, this.o.assumeNearbyYear);
776			}, this));
777			dates = $.grep(dates, $.proxy(function(date){
778				return (
779					!this.dateWithinRange(date) ||
780					!date
781				);
782			}, this), true);
783			this.dates.replace(dates);
784
785			if (this.o.updateViewDate) {
786				if (this.dates.length)
787					this.viewDate = new Date(this.dates.get(-1));
788				else if (this.viewDate < this.o.startDate)
789					this.viewDate = new Date(this.o.startDate);
790				else if (this.viewDate > this.o.endDate)
791					this.viewDate = new Date(this.o.endDate);
792				else
793					this.viewDate = this.o.defaultViewDate;
794			}
795
796			if (fromArgs){
797				// setting date by clicking
798				this.setValue();
799				this.element.change();
800			}
801			else if (this.dates.length){
802				// setting date by typing
803				if (String(oldDates) !== String(this.dates) && fromArgs) {
804					this._trigger('changeDate');
805					this.element.change();
806				}
807			}
808			if (!this.dates.length && oldDates.length) {
809				this._trigger('clearDate');
810				this.element.change();
811			}
812
813			this.fill();
814			return this;
815		},
816
817		fillDow: function(){
818			var dowCnt = this.o.weekStart,
819				html = '<tr>';
820			if (this.o.calendarWeeks){
821				html += '<th class="cw">&#160;</th>';
822			}
823			while (dowCnt < this.o.weekStart + 7){
824				html += '<th class="dow';
825        if ($.inArray(dowCnt, this.o.daysOfWeekDisabled) !== -1)
826          html += ' disabled';
827        html += '">'+dates[this.o.language].daysMin[(dowCnt++)%7]+'</th>';
828			}
829			html += '</tr>';
830			this.picker.find('.datepicker-days thead').append(html);
831		},
832
833		fillMonths: function(){
834      var localDate = this._utc_to_local(this.viewDate);
835			var html = '',
836			i = 0;
837			while (i < 12){
838        var focused = localDate && localDate.getMonth() === i ? ' focused' : '';
839				html += '<span class="month' + focused + '">' + dates[this.o.language].monthsShort[i++]+'</span>';
840			}
841			this.picker.find('.datepicker-months td').html(html);
842		},
843
844		setRange: function(range){
845			if (!range || !range.length)
846				delete this.range;
847			else
848				this.range = $.map(range, function(d){
849					return d.valueOf();
850				});
851			this.fill();
852		},
853
854		getClassNames: function(date){
855			var cls = [],
856				year = this.viewDate.getUTCFullYear(),
857				month = this.viewDate.getUTCMonth(),
858				today = UTCToday();
859			if (date.getUTCFullYear() < year || (date.getUTCFullYear() === year && date.getUTCMonth() < month)){
860				cls.push('old');
861			} else if (date.getUTCFullYear() > year || (date.getUTCFullYear() === year && date.getUTCMonth() > month)){
862				cls.push('new');
863			}
864			if (this.focusDate && date.valueOf() === this.focusDate.valueOf())
865				cls.push('focused');
866			// Compare internal UTC date with UTC today, not local today
867			if (this.o.todayHighlight && isUTCEquals(date, today)) {
868				cls.push('today');
869			}
870			if (this.dates.contains(date) !== -1)
871				cls.push('active');
872			if (!this.dateWithinRange(date)){
873				cls.push('disabled');
874			}
875			if (this.dateIsDisabled(date)){
876				cls.push('disabled', 'disabled-date');
877			}
878			if ($.inArray(date.getUTCDay(), this.o.daysOfWeekHighlighted) !== -1){
879				cls.push('highlighted');
880			}
881
882			if (this.range){
883				if (date > this.range[0] && date < this.range[this.range.length-1]){
884					cls.push('range');
885				}
886				if ($.inArray(date.valueOf(), this.range) !== -1){
887					cls.push('selected');
888				}
889				if (date.valueOf() === this.range[0]){
890          cls.push('range-start');
891        }
892        if (date.valueOf() === this.range[this.range.length-1]){
893          cls.push('range-end');
894        }
895			}
896			return cls;
897		},
898
899		_fill_yearsView: function(selector, cssClass, factor, step, currentYear, startYear, endYear, callback){
900			var html, view, year, steps, startStep, endStep, thisYear, i, classes, tooltip, before;
901
902			html      = '';
903			view      = this.picker.find(selector);
904			year      = parseInt(currentYear / factor, 10) * factor;
905			startStep = parseInt(startYear / step, 10) * step;
906			endStep   = parseInt(endYear / step, 10) * step;
907			steps     = $.map(this.dates, function(d){
908				return parseInt(d.getUTCFullYear() / step, 10) * step;
909			});
910
911			view.find('.datepicker-switch').text(year + '-' + (year + step * 9));
912
913			thisYear = year - step;
914			for (i = -1; i < 11; i += 1) {
915				classes = [cssClass];
916				tooltip = null;
917
918				if (i === -1) {
919					classes.push('old');
920				} else if (i === 10) {
921					classes.push('new');
922				}
923				if ($.inArray(thisYear, steps) !== -1) {
924					classes.push('active');
925				}
926				if (thisYear < startStep || thisYear > endStep) {
927					classes.push('disabled');
928				}
929        if (thisYear === this.viewDate.getFullYear()) {
930				  classes.push('focused');
931        }
932
933				if (callback !== $.noop) {
934					before = callback(new Date(thisYear, 0, 1));
935					if (before === undefined) {
936						before = {};
937					} else if (typeof before === 'boolean') {
938						before = {enabled: before};
939					} else if (typeof before === 'string') {
940						before = {classes: before};
941					}
942					if (before.enabled === false) {
943						classes.push('disabled');
944					}
945					if (before.classes) {
946						classes = classes.concat(before.classes.split(/\s+/));
947					}
948					if (before.tooltip) {
949						tooltip = before.tooltip;
950					}
951				}
952
953				html += '<span class="' + classes.join(' ') + '"' + (tooltip ? ' title="' + tooltip + '"' : '') + '>' + thisYear + '</span>';
954				thisYear += step;
955			}
956			view.find('td').html(html);
957		},
958
959		fill: function(){
960			var d = new Date(this.viewDate),
961				year = d.getUTCFullYear(),
962				month = d.getUTCMonth(),
963				startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,
964				startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,
965				endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,
966				endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,
967				todaytxt = dates[this.o.language].today || dates['en'].today || '',
968				cleartxt = dates[this.o.language].clear || dates['en'].clear || '',
969				titleFormat = dates[this.o.language].titleFormat || dates['en'].titleFormat,
970				tooltip,
971				before;
972			if (isNaN(year) || isNaN(month))
973				return;
974			this.picker.find('.datepicker-days .datepicker-switch')
975						.text(DPGlobal.formatDate(d, titleFormat, this.o.language));
976			this.picker.find('tfoot .today')
977						.text(todaytxt)
978						.toggle(this.o.todayBtn !== false);
979			this.picker.find('tfoot .clear')
980						.text(cleartxt)
981						.toggle(this.o.clearBtn !== false);
982			this.picker.find('thead .datepicker-title')
983						.text(this.o.title)
984						.toggle(this.o.title !== '');
985			this.updateNavArrows();
986			this.fillMonths();
987			var prevMonth = UTCDate(year, month, 0),
988				day = prevMonth.getUTCDate();
989			prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7)%7);
990			var nextMonth = new Date(prevMonth);
991			if (prevMonth.getUTCFullYear() < 100){
992        nextMonth.setUTCFullYear(prevMonth.getUTCFullYear());
993      }
994			nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
995			nextMonth = nextMonth.valueOf();
996			var html = [];
997			var weekDay, clsName;
998			while (prevMonth.valueOf() < nextMonth){
999				weekDay = prevMonth.getUTCDay();
1000				if (weekDay === this.o.weekStart){
1001					html.push('<tr>');
1002					if (this.o.calendarWeeks){
1003						// ISO 8601: First week contains first thursday.
1004						// ISO also states week starts on Monday, but we can be more abstract here.
1005						var
1006							// Start of current week: based on weekstart/current date
1007							ws = new Date(+prevMonth + (this.o.weekStart - weekDay - 7) % 7 * 864e5),
1008							// Thursday of this week
1009							th = new Date(Number(ws) + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
1010							// First Thursday of year, year from thursday
1011							yth = new Date(Number(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay()) % 7 * 864e5),
1012							// Calendar week: ms between thursdays, div ms per day, div 7 days
1013							calWeek = (th - yth) / 864e5 / 7 + 1;
1014						html.push('<td class="cw">'+ calWeek +'</td>');
1015					}
1016				}
1017				clsName = this.getClassNames(prevMonth);
1018				clsName.push('day');
1019
1020				if (this.o.beforeShowDay !== $.noop){
1021					before = this.o.beforeShowDay(this._utc_to_local(prevMonth));
1022					if (before === undefined)
1023						before = {};
1024					else if (typeof before === 'boolean')
1025						before = {enabled: before};
1026					else if (typeof before === 'string')
1027						before = {classes: before};
1028					if (before.enabled === false)
1029						clsName.push('disabled');
1030					if (before.classes)
1031						clsName = clsName.concat(before.classes.split(/\s+/));
1032					if (before.tooltip)
1033						tooltip = before.tooltip;
1034				}
1035
1036				//Check if uniqueSort exists (supported by jquery >=1.12 and >=2.2)
1037				//Fallback to unique function for older jquery versions
1038				if ($.isFunction($.uniqueSort)) {
1039					clsName = $.uniqueSort(clsName);
1040				} else {
1041					clsName = $.unique(clsName);
1042				}
1043
1044				html.push('<td class="'+clsName.join(' ')+'"' + (tooltip ? ' title="'+tooltip+'"' : '') + (this.o.dateCells ? ' data-date="'+(prevMonth.getTime().toString())+'"' : '') + '>'+prevMonth.getUTCDate() + '</td>');
1045				tooltip = null;
1046				if (weekDay === this.o.weekEnd){
1047					html.push('</tr>');
1048				}
1049				prevMonth.setUTCDate(prevMonth.getUTCDate() + 1);
1050			}
1051			this.picker.find('.datepicker-days tbody').html(html.join(''));
1052
1053			var monthsTitle = dates[this.o.language].monthsTitle || dates['en'].monthsTitle || 'Months';
1054			var months = this.picker.find('.datepicker-months')
1055						.find('.datepicker-switch')
1056							.text(this.o.maxViewMode < 2 ? monthsTitle : year)
1057							.end()
1058						.find('tbody span').removeClass('active');
1059
1060			$.each(this.dates, function(i, d){
1061				if (d.getUTCFullYear() === year)
1062					months.eq(d.getUTCMonth()).addClass('active');
1063			});
1064
1065			if (year < startYear || year > endYear){
1066				months.addClass('disabled');
1067			}
1068			if (year === startYear){
1069				months.slice(0, startMonth).addClass('disabled');
1070			}
1071			if (year === endYear){
1072				months.slice(endMonth+1).addClass('disabled');
1073			}
1074
1075			if (this.o.beforeShowMonth !== $.noop){
1076				var that = this;
1077				$.each(months, function(i, month){
1078          var moDate = new Date(year, i, 1);
1079          var before = that.o.beforeShowMonth(moDate);
1080					if (before === undefined)
1081						before = {};
1082					else if (typeof before === 'boolean')
1083						before = {enabled: before};
1084					else if (typeof before === 'string')
1085						before = {classes: before};
1086					if (before.enabled === false && !$(month).hasClass('disabled'))
1087					    $(month).addClass('disabled');
1088					if (before.classes)
1089					    $(month).addClass(before.classes);
1090					if (before.tooltip)
1091					    $(month).prop('title', before.tooltip);
1092				});
1093			}
1094
1095			// Generating decade/years picker
1096			this._fill_yearsView(
1097				'.datepicker-years',
1098				'year',
1099				10,
1100				1,
1101				year,
1102				startYear,
1103				endYear,
1104				this.o.beforeShowYear
1105			);
1106
1107			// Generating century/decades picker
1108			this._fill_yearsView(
1109				'.datepicker-decades',
1110				'decade',
1111				100,
1112				10,
1113				year,
1114				startYear,
1115				endYear,
1116				this.o.beforeShowDecade
1117			);
1118
1119			// Generating millennium/centuries picker
1120			this._fill_yearsView(
1121				'.datepicker-centuries',
1122				'century',
1123				1000,
1124				100,
1125				year,
1126				startYear,
1127				endYear,
1128				this.o.beforeShowCentury
1129			);
1130		},
1131
1132		updateNavArrows: function(){
1133			if (!this._allow_update)
1134				return;
1135
1136			var d = new Date(this.viewDate),
1137				year = d.getUTCFullYear(),
1138				month = d.getUTCMonth(),
1139				prevState,
1140				nextState;
1141			switch (this.viewMode){
1142				case 0:
1143					prevState = (
1144						this.o.startDate !== -Infinity &&
1145						year <= this.o.startDate.getUTCFullYear() &&
1146						month <= this.o.startDate.getUTCMonth()
1147					);
1148
1149					nextState = (
1150						this.o.endDate !== Infinity &&
1151						year >= this.o.endDate.getUTCFullYear() &&
1152						month >= this.o.endDate.getUTCMonth()
1153					);
1154					break;
1155				case 1:
1156				case 2:
1157				case 3:
1158				case 4:
1159					prevState = (
1160						this.o.startDate !== -Infinity &&
1161						year <= this.o.startDate.getUTCFullYear()
1162					);
1163
1164					nextState = (
1165						this.o.endDate !== Infinity &&
1166						year >= this.o.endDate.getUTCFullYear()
1167					);
1168					break;
1169			}
1170
1171			this.picker.find('.prev').toggleClass('disabled', prevState);
1172			this.picker.find('.next').toggleClass('disabled', nextState);
1173		},
1174
1175		click: function(e){
1176			e.preventDefault();
1177			e.stopPropagation();
1178
1179			var target, dir, day, year, month;
1180			target = $(e.target);
1181
1182			// Clicked on the switch
1183			if (target.hasClass('datepicker-switch') && this.viewMode !== this.o.maxViewMode){
1184				this.setViewMode(this.viewMode + 1);
1185			}
1186
1187			// Clicked on today button
1188			if (target.hasClass('today') && !target.hasClass('day')){
1189				this.setViewMode(0);
1190				this._setDate(UTCToday(), this.o.todayBtn === 'linked' ? null : 'view');
1191			}
1192
1193			// Clicked on clear button
1194			if (target.hasClass('clear')){
1195				this.clearDates();
1196			}
1197
1198			if (!target.hasClass('disabled')){
1199				// Clicked on a day
1200				if (target.hasClass('day')){
1201					day = Number(target.text());
1202					year = this.viewDate.getUTCFullYear();
1203					month = this.viewDate.getUTCMonth();
1204
1205					if (target.hasClass('old') || target.hasClass('new')){
1206						dir = target.hasClass('old') ? -1 : 1;
1207						month = (month + dir + 12) % 12;
1208						if ((dir === -1 && month === 11) || (dir === 1 && month === 0)) {
1209							year += dir;
1210							if (this.o.updateViewDate) {
1211								this._trigger('changeYear', this.viewDate);
1212							}
1213						}
1214						if (this.o.updateViewDate) {
1215							this._trigger('changeMonth', this.viewDate);
1216						}
1217					}
1218					this._setDate(UTCDate(year, month, day));
1219				}
1220
1221				// Clicked on a month, year, decade, century
1222				if (target.hasClass('month')
1223						|| target.hasClass('year')
1224						|| target.hasClass('decade')
1225						|| target.hasClass('century')) {
1226					this.viewDate.setUTCDate(1);
1227
1228					day = 1;
1229					if (this.viewMode === 1){
1230						month = target.parent().find('span').index(target);
1231						year = this.viewDate.getUTCFullYear();
1232						this.viewDate.setUTCMonth(month);
1233					} else {
1234						month = 0;
1235						year = Number(target.text());
1236						this.viewDate.setUTCFullYear(year);
1237					}
1238
1239					this._trigger(DPGlobal.viewModes[this.viewMode - 1].e, this.viewDate);
1240
1241					if (this.viewMode === this.o.minViewMode){
1242						this._setDate(UTCDate(year, month, day));
1243					} else {
1244						this.setViewMode(this.viewMode - 1);
1245						this.fill();
1246					}
1247				}
1248			}
1249
1250			if (this.picker.is(':visible') && this._focused_from){
1251				this._focused_from.focus();
1252			}
1253			delete this._focused_from;
1254		},
1255
1256		// Clicked on prev or next
1257		navArrowsClick: function(e){
1258			var target = $(e.target);
1259			var dir = 
vendor: 7,941 bytes, lines 1259-1548
1259target.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		
vendor: 13,045 bytes, lines 1548-2015
1548dateUpdated: 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')
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		dateCells:false,
1719		title: '',
1720		templates: {
1721			leftArrow: '&#x00AB;',
1722			rightArrow: '&#x00BB;'
1723		}
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 UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
1824			}
1825
1826			parts = date && date.match(this.nonpunctuation) || [];
1827			date = new Date();
1828
1829			function applyNearbyYear(year, threshold){
1830				if (threshold === true)
1831					threshold = 10;
1832
1833				// if year is 2 digits or less, than the user most likely is trying to get a recent century
1834				if (year < 100){
1835					year += 2000;
1836					// if the new year is more than threshold years in advance, use last century
1837					if (year > ((new Date()).getFullYear()+threshold)){
1838						year -= 100;
1839					}
1840				}
1841
1842				return year;
1843			}
1844
1845			var parsed = {},
1846				setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'],
1847				setters_map = {
1848					yyyy: function(d,v){
1849						return d.setUTCFullYear(assumeNearby ? applyNearbyYear(v, assumeNearby) : v);
1850					},
1851					m: function(d,v){
1852						if (isNaN(d))
1853							return d;
1854						v -= 1;
1855						while (v < 0) v += 12;
1856						v %= 12;
1857						d.setUTCMonth(v);
1858						while (d.getUTCMonth() !== v)
1859							d.setUTCDate(d.getUTCDate()-1);
1860						return d;
1861					},
1862					d: function(d,v){
1863						return d.setUTCDate(v);
1864					}
1865				},
1866				val, filtered;
1867			setters_map['yy'] = setters_map['yyyy'];
1868			setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
1869			setters_map['dd'] = setters_map['d'];
1870			date = UTCToday();
1871			var fparts = format.parts.slice();
1872			// Remove noop parts
1873			if (parts.length !== fparts.length){
1874				fparts = $(fparts).filter(function(i,p){
1875					return $.inArray(p, setters_order) !== -1;
1876				}).toArray();
1877			}
1878			// Process remainder
1879			function match_part(){
1880				var m = this.slice(0, parts[i].length),
1881					p = parts[i].slice(0, m.length);
1882				return m.toLowerCase() === p.toLowerCase();
1883			}
1884			if (parts.length === fparts.length){
1885				var cnt;
1886				for (i=0, cnt = fparts.length; i < cnt; i++){
1887					val = parseInt(parts[i], 10);
1888					part = fparts[i];
1889					if (isNaN(val)){
1890						switch (part){
1891							case 'MM':
1892								filtered = $(dates[language].months).filter(match_part);
1893								val = $.inArray(filtered[0], dates[language].months) + 1;
1894								break;
1895							case 'M':
1896								filtered = $(dates[language].monthsShort).filter(match_part);
1897								val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
1898								break;
1899						}
1900					}
1901					parsed[part] = val;
1902				}
1903				var _date, s;
1904				for (i=0; i < setters_order.length; i++){
1905					s = setters_order[i];
1906					if (s in parsed && !isNaN(parsed[s])){
1907						_date = new Date(date);
1908						setters_map[s](_date, parsed[s]);
1909						if (!isNaN(_date))
1910							date = _date;
1911					}
1912				}
1913			}
1914			return date;
1915		},
1916		formatDate: function(date, format, language){
1917			if (!date)
1918				return '';
1919			if (typeof format === 'string')
1920				format = DPGlobal.parseFormat(format);
1921			if (format.toDisplay)
1922                return format.toDisplay(date, format, language);
1923            var val = {
1924				d: date.getUTCDate(),
1925				D: dates[language].daysShort[date.getUTCDay()],
1926				DD: dates[language].days[date.getUTCDay()],
1927				m: date.getUTCMonth() + 1,
1928				M: dates[language].monthsShort[date.getUTCMonth()],
1929				MM: dates[language].months[date.getUTCMonth()],
1930				yy: date.getUTCFullYear().toString().substring(2),
1931				yyyy: date.getUTCFullYear()
1932			};
1933			val.dd = (val.d < 10 ? '0' : '') + val.d;
1934			val.mm = (val.m < 10 ? '0' : '') + val.m;
1935			date = [];
1936			var seps = $.extend([], format.separators);
1937			for (var i=0, cnt = format.parts.length; i <= cnt; i++){
1938				if (seps.length)
1939					date.push(seps.shift());
1940				date.push(val[format.parts[i]]);
1941			}
1942			return date.join('');
1943		},
1944		headTemplate: '<thead>'+
1945			              '<tr>'+
1946			                '<th colspan="7" class="datepicker-title"></th>'+
1947			              '</tr>'+
1948							'<tr>'+
1949								'<th class="prev">&laquo;</th>'+
1950								'<th colspan="5" class="datepicker-switch"></th>'+
1951								'<th class="next">&raquo;</th>'+
1952							'</tr>'+
1953						'</thead>',
1954		contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>',
1955		footTemplate: '<tfoot>'+
1956							'<tr>'+
1957								'<th colspan="7" class="today"></th>'+
1958							'</tr>'+
1959							'<tr>'+
1960								'<th colspan="7" class="clear"></th>'+
1961							'</tr>'+
1962						'</tfoot>'
1963	};
1964	DPGlobal.template = '<div class="datepicker">'+
1965							'<div class="datepicker-days">'+
1966								'<table class="table-condensed">'+
1967									DPGlobal.headTemplate+
1968									'<tbody></tbody>'+
1969									DPGlobal.footTemplate+
1970								'</table>'+
1971							'</div>'+
1972							'<div class="datepicker-months">'+
1973								'<table class="table-condensed">'+
1974									DPGlobal.headTemplate+
1975									DPGlobal.contTemplate+
1976									DPGlobal.footTemplate+
1977								'</table>'+
1978							'</div>'+
1979							'<div class="datepicker-years">'+
1980								'<table class="table-condensed">'+
1981									DPGlobal.headTemplate+
1982									DPGlobal.contTemplate+
1983									DPGlobal.footTemplate+
1984								'</table>'+
1985							'</div>'+
1986							'<div class="datepicker-decades">'+
1987								'<table class="table-condensed">'+
1988									DPGlobal.headTemplate+
1989									DPGlobal.contTemplate+
1990									DPGlobal.footTemplate+
1991								'</table>'+
1992							'</div>'+
1993							'<div class="datepicker-centuries">'+
1994								'<table class="table-condensed">'+
1995									DPGlobal.headTemplate+
1996									DPGlobal.contTemplate+
1997									DPGlobal.footTemplate+
1998								'</table>'+
1999							'</div>'+
2000						'</div>';
2001
2002	$.fn.datepicker.DPGlobal = DPGlobal;
2003
2004
2005	/* DATEPICKER NO CONFLICT
2006	* =================== */
2007
2008	$.fn.datepicker.noConflict = function(){
2009		$.fn.datepicker = old;
2010		return this;
2011	};
2012
2013	/* DATEPICKER VERSION
2014	 * =================== */
2015	$.fn.datepicker.version = '1.7.0-dev';
vendor: 463 bytes, lines 2015-2036
2015
2016
2017	/* DATEPICKER DATA-API
2018	* ================== */
2019
2020	$(document).on(
2021		'focus.datepicker.data-api click.datepicker.data-api',
2022		'[data-provide="datepicker"]',
2023		function(e){
2024			var $this = $(this);
2025			if ($this.data('datepicker'))
2026				return;
2027			e.preventDefault();
2028			// component click requires us to explicitly show it
2029			datepickerPlugin.call($this, 'show');
2030		}
2031	);
2032	$(function(){
2033		datepickerPlugin.call($('[data-provide="datepicker-inline"]'));
2034	});
2035
2036}));

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.