PageSourceSearch

https://app.ringostat.com/interface/js/plugins/datapicker/bootstrap-datepicker.js?version=20210920

js ringostat.com collected 2026-09-24 08:41:26 UTC 46,821 bytes, 1,671 lines download raw bytes

1/* =========================================================
2 * bootstrap-datepicker.js
3 * Repo: https://github.com/eternicode/bootstrap-datepicker/
4 * Demo: http://eternicode.github.io/bootstrap-datepicker/
5 * Docs: http://bootstrap-datepicker.readthedocs.org/
6 * Forked from http://www.eyecon.ro/bootstrap-datepicker
7 * =========================================================
8 * Started by Stefan Petre; improvements by Andrew Rowls + contributors
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 * ========================================================= */
22
23(function($, undefined){
24
25	var $window = $(window);
26
27	function UTCDate(){
28		return new Date(Date.UTC.apply(Date, arguments));
29	}
30	function UTCToday(){
31		var today = new Date();
32		return UTCDate(today.getFullYear(), today.getMonth(), today.getDate());
33	}
34	function alias(method){
35		return function(){
36			return this[method].apply(this, arguments);
37		};
38	}
39
40	var DateArray = (function(){
41		var extras = {
42			get: function(i){
43				return this.slice(i)[0];
44			},
45			contains: function(d){
46				// Array.indexOf is not cross-browser;
47				// $.inArray doesn't work with Dates
48				var val = d && d.valueOf();
49				for (var i=0, l=this.length; i < l; i++)
50					if (this[i].valueOf() === val)
51						return i;
52				return -1;
53			},
54			remove: function(i){
55				this.splice(i,1);
56			},
57			replace: function(new_array){
58				if (!new_array)
59					return;
60				if (!$.isArray(new_array))
61					new_array = [new_array];
62				this.clear();
63				this.push.apply(this, new_array);
64			},
65			clear: function(){
66				this.splice(0);
67			},
68			copy: function(){
69				var a = new DateArray();
70				a.replace(this);
71				return a;
72			}
73		};
74
75		return function(){
76			var a = [];
77			a.push.apply(a, arguments);
78			$.extend(a, extras);
79			return a;
80		};
81	})();
82
83
84	// Picker object
85
86	var Datepicker = function(element, options){
87		this.dates = new DateArray();
88		this.viewDate = UTCToday();
89		this.focusDate = null;
90
91		this._process_options(options);
92
93		this.element = $(element);
94		this.isInline = false;
95		this.isInput = this.element.is('input');
96		this.component = this.element.is('.date') ? this.element.find('.add-on, .input-group-addon, .btn') : false;
97		this.hasInput = this.component && this.element.find('input').length;
98		if (this.component && this.component.length === 0)
99			this.component = false;
100
101		this.picker = $(DPGlobal.template);
102		this._buildEvents();
103		this._attachEvents();
104
105		if (this.isInline){
106			this.picker.addClass('datepicker-inline').appendTo(this.element);
107		}
108		else {
109			this.picker.addClass('datepicker-dropdown dropdown-menu');
110		}
111
112		if (this.o.rtl){
113			this.picker.addClass('datepicker-rtl');
114		}
115
116		this.viewMode = this.o.startView;
117
118		if (this.o.calendarWeeks)
119			this.picker.find('tfoot th.today')
120						.attr('colspan', function(i, val){
121							return parseInt(val) + 1;
122						});
123
124		this._allow_update = false;
125
126		this.setStartDate(this._o.startDate);
127		this.setEndDate(this._o.endDate);
128		this.setDaysOfWeekDisabled(this.o.daysOfWeekDisabled);
129
130		this.fillDow();
131		this.fillMonths();
132
133		this._allow_update = true;
134
135		this.update();
136		this.showMode();
137
138		if (this.isInline){
139			this.show();
140		}
141	};
142
143	Datepicker.prototype = {
144		constructor: Datepicker,
145
146		_process_options: function(opts){
147			// Store raw options for reference
148			this._o = $.extend({}, this._o, opts);
149			// Processed options
150			var o = this.o = $.extend({}, this._o);
151
152			// Check if "de-DE" style date is available, if not language should
153			// fallback to 2 letter code eg "de"
154			var lang = o.language;
155			if (!dates[lang]){
156				lang = lang.split('-')[0];
157				if (!dates[lang])
158					lang = defaults.language;
159			}
160			o.language = lang;
161
162			switch (o.startView){
163				case 2:
164				case 'decade':
165					o.startView = 2;
166					break;
167				case 1:
168				case 'year':
169					o.startView = 1;
170					break;
171				default:
172					o.startView = 0;
173			}
174
175			switch (o.minViewMode){
176				case 1:
177				case 'months':
178					o.minViewMode = 1;
179					break;
180				case 2:
181				case 'years':
182					o.minViewMode = 2;
183					break;
184				default:
185					o.minViewMode = 0;
186			}
187
188			o.startView = Math.max(o.startView, o.minViewMode);
189
190			// true, false, or Number > 0
191			if (o.multidate !== true){
192				o.multidate = Number(o.multidate) || false;
193				if (o.multidate !== false)
194					o.multidate = Math.max(0, o.multidate);
195				else
196					o.multidate = 1;
197			}
198			o.multidateSeparator = String(o.multidateSeparator);
199
200			o.weekStart %= 7;
201			o.weekEnd = ((o.weekStart + 6) % 7);
202
203			var format = DPGlobal.parseFormat(o.format);
204			if (o.startDate !== -Infinity){
205				if (!!o.startDate){
206					if (o.startDate instanceof Date)
207						o.startDate = this._local_to_utc(this._zero_time(o.startDate));
208					else
209						o.startDate = DPGlobal.parseDate(o.startDate, format, o.language);
210				}
211				else {
212					o.startDate = -Infinity;
213				}
214			}
215			if (o.endDate !== Infinity){
216				if (!!o.endDate){
217					if (o.endDate instanceof Date)
218						o.endDate = this._local_to_utc(this._zero_time(o.endDate));
219					else
220						o.endDate = DPGlobal.parseDate(o.endDate, format, o.language);
221				}
222				else {
223					o.endDate = Infinity;
224				}
225			}
226
227			o.daysOfWeekDisabled = o.daysOfWeekDisabled||[];
228			if (!$.isArray(o.daysOfWeekDisabled))
229				o.daysOfWeekDisabled = o.daysOfWeekDisabled.split(/[,\s]*/);
230			o.daysOfWeekDisabled = $.map(o.daysOfWeekDisabled, function(d){
231				return parseInt(d, 10);
232			});
233
234			var plc = String(o.orientation).toLowerCase().split(/\s+/g),
235				_plc = o.orientation.toLowerCase();
236			plc = $.grep(plc, function(word){
237				return (/^auto|left|right|top|bottom$/).test(word);
238			});
239			o.orientation = {x: 'auto', y: 'auto'};
240			if (!_plc || _plc === 'auto')
241				; // no action
242			else if (plc.length === 1){
243				switch (plc[0]){
244					case 'top':
245					case 'bottom':
246						o.orientation.y = plc[0];
247						break;
248					case 'left':
249					case 'right':
250						o.orientation.x = plc[0];
251						break;
252				}
253			}
254			else {
255				_plc = $.grep(plc, function(word){
256					return (/^left|right$/).test(word);
257				});
258				o.orientation.x = _plc[0] || 'auto';
259
260				_plc = $.grep(plc, function(word){
261					return (/^top|bottom$/).test(word);
262				});
263				o.orientation.y = _plc[0] || 'auto';
264			}
265		},
266		_events: [],
267		_secondaryEvents: [],
268		_applyEvents: function(evs){
269			for (var i=0, el, ch, ev; i < evs.length; i++){
270				el = evs[i][0];
271				if (evs[i].length === 2){
272					ch = undefined;
273					ev = evs[i][1];
274				}
275				else if (evs[i].length === 3){
276					ch = evs[i][1];
277					ev = evs[i][2];
278				}
279				el.on(ev, ch);
280			}
281		},
282		_unapplyEvents: function(evs){
283			for (var i=0, el, ev, ch; i < evs.length; i++){
284				el = evs[i][0];
285				if (evs[i].length === 2){
286					ch = undefined;
287					ev = evs[i][1];
288				}
289				else if (evs[i].length === 3){
290					ch = evs[i][1];
291					ev = evs[i][2];
292				}
293				el.off(ev, ch);
294			}
295		},
296		_buildEvents: function(){
297			if (this.isInput){ // single input
298				this._events = [
299					[this.element, {
300						focus: $.proxy(this.show, this),
301						keyup: $.proxy(function(e){
302							if ($.inArray(e.keyCode, [27,37,39,38,40,32,13,9]) === -1)
303								this.update();
304						}, this),
305						keydown: $.proxy(this.keydown, this)
306					}]
307				];
308			}
309			else if (this.component && this.hasInput){ // component: input + button
310				this._events = [
311					// For components that are not readonly, allow keyboard nav
312					[this.element.find('input'), {
313						focus: $.proxy(this.show, this),
314						keyup: $.proxy(function(e){
315							if ($.inArray(e.keyCode, [27,37,39,38,40,32,13,9]) === -1)
316								this.update();
317						}, this),
318						keydown: $.proxy(this.keydown, this)
319					}],
320					[this.component, {
321						click: $.proxy(this.show, this)
322					}]
323				];
324			}
325			else if (this.element.is('div')){  // inline datepicker
326				this.isInline = true;
327			}
328			else {
329				this._events = [
330					[this.element, {
331						click: $.proxy(this.show, this)
332					}]
333				];
334			}
335			this._events.push(
336				// Component: listen for blur on element descendants
337				[this.element, '*', {
338					blur: $.proxy(function(e){
339						this._focused_from = e.target;
340					}, this)
341				}],
342				// Input: listen for blur on element
343				[this.element, {
344					blur: $.proxy(function(e){
345						this._focused_from = e.target;
346					}, this)
347				}]
348			);
349
350			this._secondaryEvents = [
351				[this.picker, {
352					click: $.proxy(this.click, this)
353				}],
354				[$(window), {
355					resize: $.proxy(this.place, this)
356				}],
357				[$(document), {
358					'mousedown touchstart': $.proxy(function(e){
359						// Clicked outside the datepicker, hide it
360						if (!(
361							this.element.is(e.target) ||
362							this.element.find(e.target).length ||
363							this.picker.is(e.target) ||
364							this.picker.find(e.target).length
365						)){
366							this.hide();
367						}
368					}, this)
369				}]
370			];
371		},
372		_attachEvents: function(){
373			this._detachEvents();
374			this._applyEvents(this._events);
375		},
376		_detachEvents: function(){
377			this._unapplyEvents(this._events);
378		},
379		_attachSecondaryEvents: function(){
380			this._detachSecondaryEvents();
381			this._applyEvents(this._secondaryEvents);
382		},
383		_detachSecondaryEvents: function(){
384			this._unapplyEvents(this._secondaryEvents);
385		},
386		_trigger: function(event, altdate){
387			var date = altdate || this.dates.get(-1),
388				local_date = this._utc_to_local(date);
389
390			this.element.trigger({
391				type: event,
392				date: local_date,
393				dates: $.map(this.dates, this._utc_to_local),
394				format: $.proxy(function(ix, format){
395					if (arguments.length === 0){
396						ix = this.dates.length - 1;
397						format = this.o.format;
398					}
399					else if (typeof ix === 'string'){
400						format = ix;
401						ix = this.dates.length - 1;
402					}
403					format = format || this.o.format;
404					var date = this.dates.get(ix);
405					return DPGlobal.formatDate(date, format, this.o.language);
406				}, this)
407			});
408		},
409
410		show: function(){
411			if (!this.isInline)
412				this.picker.appendTo('body');
413			this.picker.show();
414			this.place();
415			this._attachSecondaryEvents();
416			this._trigger('show');
417		},
418
419		hide: function(){
420			if (this.isInline)
421				return;
422			if (!this.picker.is(':visible'))
423				return;
424			this.focusDate = null;
425			this.picker.hide().detach();
426			this._detachSecondaryEvents();
427			this.viewMode = this.o.startView;
428			this.showMode();
429
430			if (
431				this.o.forceParse &&
432				(
433					this.isInput && this.element.val() ||
434					this.hasInput && this.element.find('input').val()
435				)
436			)
437				this.setValue();
438			this._trigger('hide');
439		},
440
441		remove: function(){
442			this.hide();
443			this._detachEvents();
444			this._detachSecondaryEvents();
445			this.picker.remove();
446			delete this.element.data().datepicker;
447			if (!this.isInput){
448				delete this.element.data().date;
449			}
450		},
451
452		_utc_to_local: function(utc){
453			return utc && new Date(utc.getTime() + (utc.getTimezoneOffset()*60000));
454		},
455		_local_to_utc: function(local){
456			return local && new Date(local.getTime() - (local.getTimezoneOffset()*60000));
457		},
458		_zero_time: function(local){
459			return local && new Date(local.getFullYear(), local.getMonth(), local.getDate());
460		},
461		_zero_utc_time: function(utc){
462			return utc && new Date(Date.UTC(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate()));
463		},
464
465		getDates: function(){
466			return $.map(this.dates, this._utc_to_local);
467		},
468
469		getUTCDates: function(){
470			return $.map(this.dates, function(d){
471				return new Date(d);
472			});
473		},
474
475		getDate: function(){
476			return this._utc_to_local(this.getUTCDate());
477		},
478
479		getUTCDate: function(){
480			return new Date(this.dates.get(-1));
481		},
482
483		setDates: function(){
484			var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
485			this.update.apply(this, args);
486			this._trigger('changeDate');
487			this.setValue();
488		},
489
490		setUTCDates: function(){
491			var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
492			this.update.apply(this, $.map(args, this._utc_to_local));
493			this._trigger('changeDate');
494			this.setValue();
495		},
496
497		setDate: alias('setDates'),
498		setUTCDate: alias('setUTCDates'),
499
500		setValue: function(){
501			var formatted = this.getFormattedDate();
502			if (!this.isInput){
503				if (this.component){
504					this.element.find('input').val(formatted).change();
505				}
506			}
507			else {
508				this.element.val(formatted).change();
509			}
510		},
511
512		getFormattedDate: function(format){
513			if (format === undefined)
514				format = this.o.format;
515
516			var lang = this.o.language;
517			return $.map(this.dates, function(d){
518				return DPGlobal.formatDate(d, format, lang);
519			}).join(this.o.multidateSeparator);
520		},
521
522		setStartDate: function(startDate){
523			this._process_options({startDate: startDate});
524			this.update();
525			this.updateNavArrows();
526		},
527
528		setEndDate: function(endDate){
529			this._process_options({endDate: endDate});
530			this.update();
531			this.updateNavArrows();
532		},
533
534		setDaysOfWeekDisabled: function(daysOfWeekDisabled){
535			this._process_options({daysOfWeekDisabled: daysOfWeekDisabled});
536			this.update();
537			this.updateNavArrows();
538		},
539
540		place: function(){
541			if (this.isInline)
542				return;
543			var calendarWidth = this.picker.outerWidth(),
544				calendarHeight = this.picker.outerHeight(),
545				visualPadding = 10,
546				windowWidth = $window.width(),
547				windowHeight = $window.height(),
548				scrollTop = $window.scrollTop();
549
550			var zIndex = parseInt(this.element.parents().filter(function(){
551					return $(this).css('z-index') !== 'auto';
552				}).first().css('z-index'))+10;
553			var offset = this.component ? this.component.parent().offset() : this.element.offset();
554			var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(false);
555			var width = this.component ? this.component.outerWidth(true) : this.element.outerWidth(false);
556			var left = offset.left,
557				top = offset.top;
558
559			this.picker.removeClass(
560				'datepicker-orient-top datepicker-orient-bottom '+
561				'datepicker-orient-right datepicker-orient-left'
562			);
563
564			if (this.o.orientation.x !== 'auto'){
565				this.picker.addClass('datepicker-orient-' + this.o.orientation.x);
566				if (this.o.orientation.x === 'right')
567					left -= calendarWidth - width;
568			}
569			// auto x orientation is best-placement: if it crosses a window
570			// edge, fudge it sideways
571			else {
572				// Default to left
573				this.picker.addClass('datepicker-orient-left');
574				if (offset.left < 0)
575					left -= offset.left - visualPadding;
576				else if (offset.left + calendarWidth > windowWidth)
577					left = windowWidth - calendarWidth - visualPadding;
578			}
579
580			// auto y orientation is best-situation: top or bottom, no fudging,
581			// decision based on which shows more of the calendar
582			var yorient = this.o.orientation.y,
583				top_overflow, bottom_overflow;
584			if (yorient === 'auto'){
585				top_overflow = -scrollTop + offset.top - calendarHeight;
586				bottom_overflow = scrollTop + windowHeight - (offset.top + height + calendarHeight);
587				if (Math.max(top_overflow, bottom_overflow) === bottom_overflow)
588					yorient = 'top';
589				else
590					yorient = 'bottom';
591			}
592			this.picker.addClass('datepicker-orient-' + yorient);
593			if (yorient === 'top')
594				top += height;
595			else
596				top -= calendarHeight + parseInt(this.picker.css('padding-top'));
597
598			this.picker.css({
599				top: top,
600				left: left,
601				zIndex: zIndex
602			});
603		},
604
605		_allow_update: true,
606		update: function(){
607			if (!this._allow_update)
608				return;
609
610			var oldDates = this.dates.copy(),
611				dates = [],
612				fromArgs = false;
613			if (arguments.length){
614				$.each(arguments, $.proxy(function(i, date){
615					if (date instanceof Date)
616						date = this._local_to_utc(date);
617					dates.push(date);
618				}, this));
619				fromArgs = true;
620			}
621			else {
622				dates = this.isInput
623						? this.element.val()
624						: this.element.data('date') || this.element.find('input').val();
625				if (dates && this.o.multidate)
626					dates = dates.split(this.o.multidateSeparator);
627				else
628					dates = [dates];
629				delete this.element.data().date;
630			}
631
632			dates = $.map(dates, $.proxy(function(date){
633				return DPGlobal.parseDate(date, this.o.format, this.o.language);
634			}, this));
635			dates = $.grep(dates, $.proxy(function(date){
636				return (
637					date < this.o.startDate ||
638					date > this.o.endDate ||
639					!date
640				);
641			}, this), true);
642			this.dates.replace(dates);
643
644			if (this.dates.length)
645				this.viewDate = new Date(this.dates.get(-1));
646			else if (this.viewDate < this.o.startDate)
647				this.viewDate = new Date(this.o.startDate);
648			else if (this.viewDate > this.o.endDate)
649				this.viewDate = new Date(this.o.endDate);
650
651			if (fromArgs){
652				// setting date by clicking
653				this.setValue();
654			}
655			else if (dates.length){
656				// setting date by typing
657				if (String(oldDates) !== String(this.dates))
658					this._trigger('changeDate');
659			}
660			if (!this.dates.length && oldDates.length)
661				this._trigger('clearDate');
662
663			this.fill();
664		},
665
666		fillDow: function(){
667			var dowCnt = this.o.weekStart,
668				html = '<tr>';
669			if (this.o.calendarWeeks){
670				var cell = '<th class="cw">&nbsp;</th>';
671				html += cell;
672				this.picker.find('.datepicker-days thead tr:first-child').prepend(cell);
673			}
674			while (dowCnt < this.o.weekStart + 7){
675				html += '<th class="dow">'+dates[this.o.language].daysMin[(dowCnt++)%7]+'</th>';
676			}
677			html += '</tr>';
678			this.picker.find('.datepicker-days thead').append(html);
679		},
680
681		fillMonths: function(){
682			var html = '',
683			i = 0;
684			while (i < 12){
685				html += '<span class="month">'+dates[this.o.language].monthsShort[i++]+'</span>';
686			}
687			this.picker.find('.datepicker-months td').html(html);
688		},
689
690		setRange: function(range){
691			if (!range || !range.length)
692				delete this.range;
693			else
694				this.range = $.map(range, function(d){
695					return d.valueOf();
696				});
697			this.fill();
698		},
699
700		getClassNames: function(date){
701			var cls = [],
702				year = this.viewDate.getUTCFullYear(),
703				month = this.viewDate.getUTCMonth(),
704				today = new Date();
705			if (date.getUTCFullYear() < year || (date.getUTCFullYear() === year && date.getUTCMonth() < month)){
706				cls.push('old');
707			}
708			else if (date.getUTCFullYear() > year || (date.getUTCFullYear() === year && date.getUTCMonth() > month)){
709				cls.push('new');
710			}
711			if (this.focusDate && date.valueOf() === this.focusDate.valueOf())
712				cls.push('focused');
713			// Compare internal UTC date with local today, not UTC today
714			if (this.o.todayHighlight &&
715				date.getUTCFullYear() === today.getFullYear() &&
716				date.getUTCMonth() === today.getMonth() &&
717				date.getUTCDate() === today.getDate()){
718				cls.push('today');
719			}
720			if (this.dates.contains(date) !== -1)
721				cls.push('active');
722			if (date.valueOf() < this.o.startDate || date.valueOf() > this.o.endDate ||
723				$.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1){
724				cls.push('disabled');
725			}
726			if (this.range){
727				if (date > this.range[0] && date < this.range[this.range.length-1]){
728					cls.push('range');
729				}
730				if ($.inArray(date.valueOf(), this.range) !== -1){
731					cls.push('selected');
732				}
733			}
734			return cls;
735		},
736
737		fill: function(){
738			var d = new Date(this.viewDate),
739				year = d.getUTCFullYear(),
740				month = d.getUTCMonth(),
741				startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,
742				startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,
743				endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,
744				endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,
745				todaytxt = dates[this.o.language].today || dates['en'].today || '',
746				cleartxt = dates[this.o.language].clear || dates['en'].clear || '',
747				tooltip;
748			this.picker.find('.datepicker-days thead th.datepicker-switch')
749						.text(dates[this.o.language].months[month]+' '+year);
750			this.picker.find('tfoot th.today')
751						.text(todaytxt)
752						.toggle(this.o.todayBtn !== false);
753			this.picker.find('tfoot th.clear')
754						.text(cleartxt)
755						.toggle(this.o.clearBtn !== false);
756			this.updateNavArrows();
757			this.fillMonths();
758			var prevMonth = UTCDate(year, month-1, 28),
759				day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
760			prevMonth.setUTCDate(day);
761			prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7)%7);
762			var nextMonth = new Date(prevMonth);
763			nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
764			nextMonth = nextMonth.valueOf();
765			var html = [];
766			var clsName;
767			while (prevMonth.valueOf() < nextMonth){
768				if (prevMonth.getUTCDay() === this.o.weekStart){
769					html.push('<tr>');
770					if (this.o.calendarWeeks){
771						// ISO 8601: First week contains first thursday.
772						// ISO also states week starts on Monday, but we can be more abstract here.
773						var
774							// Start of current week: based on weekstart/current date
775							ws = new Date(+prevMonth + (this.o.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
776							// Thursday of this week
777							th = new Date(Number(ws) + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
778							// First Thursday of year, year from thursday
779							yth = new Date(Number(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
780							// Calendar week: ms between thursdays, div ms per day, div 7 days
781							calWeek =  (th - yth) / 864e5 / 7 + 1;
782						html.push('<td class="cw">'+ calWeek +'</td>');
783
784					}
785				}
786				clsName = this.getClassNames(prevMonth);
787				clsName.push('day');
788
789				if (this.o.beforeShowDay !== $.noop){
790					var before = this.o.beforeShowDay(this._utc_to_local(prevMonth));
791					if (before === undefined)
792						before = {};
793					else if (typeof(before) === 'boolean')
794						before = {enabled: before};
795					else if (typeof(before) === 'string')
796						before = {classes: before};
797					if (before.enabled === false)
798						clsName.push('disabled');
799					if (before.classes)
800						clsName = clsName.concat(before.classes.split(/\s+/));
801					if (before.tooltip)
802						tooltip = before.tooltip;
803				}
804
805				clsName = $.unique(clsName);
806				html.push('<td class="'+clsName.join(' ')+'"' + (tooltip ? ' title="'+tooltip+'"' : '') + '>'+prevMonth.getUTCDate() + '</td>');
807				if (prevMonth.getUTCDay() === this.o.weekEnd){
808					html.push('</tr>');
809				}
810				prevMonth.setUTCDate(prevMonth.getUTCDate()+1);
811			}
812			this.picker.find('.datepicker-days tbody').empty().append(html.join(''));
813
814			var months = this.picker.find('.datepicker-months')
815						.find('th:eq(1)')
816							.text(year)
817							.end()
818						.find('span').removeClass('active');
819
820			$.each(this.dates, function(i, d){
821				if (d.getUTCFullYear() === year)
822					months.eq(d.getUTCMonth()).addClass('active');
823			});
824
825			if (year < startYear || year > endYear){
826				months.addClass('disabled');
827			}
828			if (year === startYear){
829				months.slice(0, startMonth).addClass('disabled');
830			}
831			if (year === endYear){
832				months.slice(endMonth+1).addClass('disabled');
833			}
834
835			html = '';
836			year = parseInt(year/10, 10) * 10;
837			var yearCont = this.picker.find('.datepicker-years')
838								.find('th:eq(1)')
839									.text(year + '-' + (year + 9))
840									.end()
841								.find('td');
842			year -= 1;
843			var years = $.map(this.dates, function(d){
844					return d.getUTCFullYear();
845				}),
846				classes;
847			for (var i = -1; i < 11; i++){
848				classes = ['year'];
849				if (i === -1)
850					classes.push('old');
851				else if (i === 10)
852					classes.push('new');
853				if ($.inArray(year, years) !== -1)
854					classes.push('active');
855				if (year < startYear || year > endYear)
856					classes.push('disabled');
857				html += '<span class="' + classes.join(' ') + '">'+year+'</span>';
858				year += 1;
859			}
860			yearCont.html(html);
861		},
862
863		updateNavArrows: function(){
864			if (!this._allow_update)
865				return;
866
867			var d = new Date(this.viewDate),
868				year = d.getUTCFullYear(),
869				month = d.getUTCMonth();
870			switch (this.viewMode){
871				case 0:
872					if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear() && month <= this.o.startDate.getUTCMonth()){
873						this.picker.find('.prev').css({visibility: 'hidden'});
874					}
875					else {
876						this.picker.find('.prev').css({visibility: 'visible'});
877					}
878					if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear() && month >= this.o.endDate.getUTCMonth()){
879						this.picker.find('.next').css({visibility: 'hidden'});
880					}
881					else {
882						this.picker.find('.next').css({visibility: 'visible'});
883					}
884					break;
885				case 1:
886				case 2:
887					if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear()){
888						this.picker.find('.prev').css({visibility: 'hidden'});
889					}
890					else {
891						this.picker.find('.prev').css({visibility: 'visible'});
892					}
893					if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear()){
894						this.picker.find('.next').css({visibility: 'hidden'});
895					}
896					else {
897						this.picker.find('.next').css({visibility: 'visible'});
898					}
899					break;
900			}
901		},
902
903		click: function(e){
904			e.preventDefault();
905			var target = $(e.target).closest('span, td, th'),
906				year, month, day;
907			if (target.length === 1){
908				switch (target[0].nodeName.toLowerCase()){
909					case 'th':
910						switch (target[0].className){
911							case 'datepicker-switch':
912								this.showMode(1);
913								break;
914							case 'prev':
915							case 'next':
916								var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1);
917								switch (this.viewMode){
918									case 0:
919										this.viewDate = this.moveMonth(this.viewDate, dir);
920										this._trigger('changeMonth', this.viewDate);
921										break;
922									case 1:
923									case 2:
924										this.viewDate = this.moveYear(this.viewDate, dir);
925										if (this.viewMode === 1)
926											this._trigger('changeYear', this.viewDate);
927										break;
928								}
929								this.fill();
930								break;
931							case 'today':
932								var date = new Date();
933								date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
934
935								this.showMode(-2);
936								var which = this.o.todayBtn === 'linked' ? null : 'view';
937								this._setDate(date, which);
938								break;
939							case 'clear':
940								var element;
941								if (this.isInput)
942									element = this.element;
943								else if (this.component)
944									element = this.element.find('input');
945								if (element)
946									element.val("").change();
947								this.update();
948								this._trigger('changeDate');
949								if (this.o.autoclose)
950									this.hide();
951								break;
952						}
953						break;
954					case 'span':
955						if (!target.is('.disabled')){
956							this.viewDate.setUTCDate(1);
957							if (target.is('.month')){
958								day = 1;
959								month = target.parent().find('span').index(target);
960								year = this.viewDate.getUTCFullYear();
961								this.viewDate.setUTCMonth(month);
962								this._trigger('changeMonth', this.viewDate);
963								if (this.o.minViewMode === 1){
964									this._setDate(UTCDate(year, month, day));
965								}
966							}
967							else {
968								day = 1;
969								month = 0;
970								year = parseInt(target.text(), 10)||0;
971								this.viewDate.setUTCFullYear(year);
972								this._trigger('changeYear', this.viewDate);
973								if (this.o.minViewMode === 2){
974									this._setDate(UTCDate(year, month, day));
975								}
976							}
977							this.showMode(-1);
978							this.fill();
979						}
980						break;
981					case 'td':
982						if (target.is('.day') && !target.is('.disabled')){
983							day = parseInt(target.text(), 10)||1;
984							year = this.viewDate.getUTCFullYear();
985							month = this.viewDate.getUTCMonth();
986							if (target.is('.old')){
987								if (month === 0){
988									month = 11;
989									year -= 1;
990								}
991								else {
992									month -= 1;
993								}
994							}
995							else if (target.is('.new')){
996								if (month === 11){
997									month = 0;
998									year += 1;
999								}
1000								else {
1001									month += 1;
1002								}
1003							}
1004							this._setDate(UTCDate(year, month, day));
1005						}
1006						break;
1007				}
1008			}
1009			if (this.picker.is(':visible') && this._focused_from){
1010				$(this._focused_from).focus();
1011			}
1012			delete this._focused_from;
1013		},
1014
1015		_toggle_multidate: function(date){
1016			var ix = this.dates.contains(date);
1017			if (!date){
1018				this.dates.clear();
1019			}
1020			else if (ix !== -1){
1021				this.dates.remove(ix);
1022			}
1023			else {
1024				this.dates.push(date);
1025			}
1026			if (typeof this.o.multidate === 'number')
1027				while (this.dates.length > this.o.multidate)
1028					this.dates.remove(0);
1029		},
1030
1031		_setDate: function(date, which){
1032			if (!which || which === 'date')
1033				this._toggle_multidate(date && new Date(date));
1034			if (!which || which  === 'view')
1035				this.viewDate = date && new Date(date);
1036
1037			this.fill();
1038			this.setValue();
1039			this._trigger('changeDate');
1040			var element;
1041			if (this.isInput){
1042				element = this.element;
1043			}
1044			else if (this.component){
1045				element = this.element.find('input');
1046			}
1047			if (element){
1048				element.change();
1049			}
1050			if (this.o.autoclose && (!which || which === 'date')){
1051				this.hide();
1052			}
1053		},
1054
1055		moveMonth: function(date, dir){
1056			if (!date)
1057				return undefined;
1058			if (!dir)
1059				return date;
1060			var new_date = new Date(date.valueOf()),
1061				day = new_date.getUTCDate(),
1062				month = new_date.getUTCMonth(),
1063				mag = Math.abs(dir),
1064				new_month, test;
1065			dir = dir > 0 ? 1 : -1;
1066			if (mag === 1){
1067				test = dir === -1
1068					// If going back one month, make sure month is not current month
1069					// (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
1070					? function(){
1071						return new_date.getUTCMonth() === month;
1072					}
1073					// If going forward one month, make sure month is as expected
1074					// (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
1075					: function(){
1076						return new_date.getUTCMonth() !== new_month;
1077					};
1078				new_month = month + dir;
1079				new_date.setUTCMonth(new_month);
1080				// Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
1081				if (new_month < 0 || new_month > 11)
1082					new_month = (new_month + 12) % 12;
1083			}
1084			else {
1085				// For magnitudes >1, move one month at a time...
1086				for (var i=0; i < mag; i++)
1087					// ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
1088					new_date = this.moveMonth(new_date, dir);
1089				// ...then reset the day, keeping it in the new month
1090				new_month = new_date.getUTCMonth();
1091				new_date.setUTCDate(day);
1092				test = function(){
1093					return new_month !== new_date.getUTCMonth();
1094				};
1095			}
1096			// Common date-resetting loop -- if date is beyond end of month, make it
1097			// end of month
1098			while (test()){
1099				new_date.setUTCDate(--day);
1100				new_date.setUTCMonth(new_month);
1101			}
1102			return new_date;
1103		},
1104
1105		moveYear: function(date, dir){
1106			return this.moveMonth(date, dir*12);
1107		},
1108
1109		dateWithinRange: function(date){
1110			return date >= this.o.startDate && date <= this.o.endDate;
1111		},
1112
1113		keydown: function(e){
1114			if (this.picker.is(':not(:visible)')){
1115				if (e.keyCode === 27) // allow escape to hide and re-show picker
1116					this.show();
1117				return;
1118			}
1119			var dateChanged = false,
1120				dir, newDate, newViewDate,
1121				focusDate = this.focusDate || this.viewDate;
1122			switch (e.keyCode){
1123				case 27: // escape
1124					if (this.focusDate){
1125						this.focusDate = null;
1126						this.viewDate = this.dates.get(-1) || this.viewDate;
1127						this.fill();
1128					}
1129					else
1130						this.hide();
1131					e.preventDefault();
1132					break;
1133				case 37: // left
1134				case 39: // right
1135					if (!this.o.keyboardNavigation)
1136						break;
1137					dir = e.keyCode === 37 ? -1 : 1;
1138					if (e.ctrlKey){
1139						newDate = this.moveYear(this.dates.get(-1) || UTCToday(), dir);
1140						newViewDate = this.moveYear(focusDate, dir);
1141						this._trigger('changeYear', this.viewDate);
1142					}
1143					else if (e.shiftKey){
1144						newDate = this.moveMonth(this.dates.get(-1) || UTCToday(), dir);
1145						newViewDate = this.moveMonth(focusDate, dir);
1146						this._trigger('changeMonth', this.viewDate);
1147					}
1148					else {
1149						newDate = new Date(this.dates.get(-1) || UTCToday());
1150						newDate.setUTCDate(newDate.getUTCDate() + dir);
1151						newViewDate = new Date(focusDate);
1152						newViewDate.setUTCDate(focusDate.getUTCDate() + dir);
1153					}
1154					if (this.dateWithinRange(newDate)){
1155						this.focusDate = this.viewDate = newViewDate;
1156						this.setValue();
1157						this.fill();
1158						e.preventDefault();
1159					}
1160					break;
1161				case 38: // up
1162				case 40: // down
1163					if (!this.o.keyboardNavigation)
1164						break;
1165					dir = e.keyCode === 38 ? -1 : 1;
1166					if (e.ctrlKey){
1167						newDate = this.moveYear(this.dates.get(-1) || UTCToday(), dir);
1168						newViewDate = this.moveYear(focusDate, dir);
1169						this._trigger('changeYear', this.viewDate);
1170					}
1171					else if (e.shiftKey){
1172						newDate = this.moveMonth(this.dates.get(-1) || UTCToday(), dir);
1173						newViewDate = this.moveMonth(focusDate, dir);
1174						this._trigger('changeMonth', this.viewDate);
1175					}
1176					else {
1177						newDate = new Date(this.dates.get(-1) || UTCToday());
1178						newDate.setUTCDate(newDate.getUTCDate() + dir * 7);
1179						newViewDate = new Date(focusDate);
1180						newViewDate.setUTCDate(focusDate.getUTCDate() + dir * 7);
1181					}
1182					if (this.dateWithinRange(newDate)){
1183						this.focusDate = this.viewDate = newViewDate;
1184						this.setValue();
1185						this.fill();
1186						e.preventDefault();
1187					}
1188					break;
1189				case 32: // spacebar
1190					// Spacebar is used in manually typing dates in some formats.
1191					// As such, its behavior should not be hijacked.
1192					break;
1193				case 13: // enter
1194					focusDate = this.focusDate || this.dates.get(-1) || this.viewDate;
1195					this._toggle_multidate(focusDate);
1196					dateChanged = true;
1197					this.focusDate = null;
1198					this.viewDate = this.dates.get(-1) || this.viewDate;
1199					this.setValue();
1200					this.fill();
1201					if (this.picker.is(':visible')){
1202						e.preventDefault();
1203						if (this.o.autoclose)
1204							this.hide();
1205					}
1206					break;
1207				case 9: // tab
1208					this.focusDate = null;
1209					this.viewDate = this.dates.get(-1) || this.viewDate;
1210					this.fill();
1211					this.hide();
1212					break;
1213			}
1214			if (dateChanged){
1215				if (this.dates.length)
1216					this._trigger('changeDate');
1217				else
1218					this._trigger('clearDate');
1219				var element;
1220				if (this.isInput){
1221					element = this.element;
1222				}
1223				else if (this.component){
1224					element = this.element.find('input');
1225				}
1226				if (element){
1227					element.change();
1228				}
1229			}
1230		},
1231
1232		showMode: function(dir){
1233			if (dir){
1234				this.viewMode = Math.max(this.o.minViewMode, Math.min(2, this.viewMode + dir));
1235			}
1236			this.picker
1237				.find('>div')
1238				.hide()
1239				.filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName)
1240					.css('display', 'block');
1241			this.updateNavArrows();
1242		}
1243	};
1244
1245	var DateRangePicker = function(element, options){
1246		this.element = $(element);
1247		this.inputs = $.map(options.inputs, function(i){
1248			return i.jquery ? i[0] : i;
1249		});
1250		delete options.inputs;
1251
1252		$(this.inputs)
1253			.datepicker(options)
1254			.bind('changeDate', $.proxy(this.dateUpdated, this));
1255
1256		this.pickers = $.map(this.inputs, function(i){
1257			return $(i).data('datepicker');
1258		});
1259		this.updateDates();
1260	};
1261	DateRangePicker.prototype = {
1262		updateDates: function(){
1263			this.dates = $.map(this.pickers, function(i){
1264				return i.getUTCDate();
1265			});
1266			this.updateRanges();
1267		},
1268		updateRanges: function(){
1269			var range = $.map(this.dates, function(d){
1270				return d.valueOf();
1271			});
1272			$.each(this.pickers, function(i, p){
1273				p.setRange(range);
1274			});
1275		},
1276		dateUpdated: function(e){
1277			// `this.updating` is a workaround for preventing infinite recursion
1278			// between `changeDate` triggering and `setUTCDate` calling.  Until
1279			// there is a better mechanism.
1280			if (this.updating)
1281				return;
1282			this.updating = true;
1283
1284			var dp = $(e.target).data('datepicker'),
1285				new_date = dp.getUTCDate(),
1286				i = $.inArray(e.target, this.inputs),
1287				l = this.inputs.length;
1288			if (i === -1)
1289				return;
1290
1291			$.each(this.pickers, function(i, p){
1292				if (!p.getUTCDate())
1293					p.setUTCDate(new_date);
1294			});
1295
1296			if (new_date < this.dates[i]){
1297				// Date being moved earlier/left
1298				while (i >= 0 && new_date < this.dates[i]){
1299					this.pickers[i--].setUTCDate(new_date);
1300				}
1301			}
1302			else if (new_date > this.dates[i]){
1303				// Date being moved later/right
1304				while (i < l && new_date > this.dates[i]){
1305					this.pickers[i++].setUTCDate(new_date);
1306				}
1307			}
1308			this.updateDates();
1309
1310			delete this.updating;
1311		},
1312		remove: function(){
1313			$.map(this.pickers, function(p){ p.remove(); });
1314			delete this.element.data().datepicker;
1315		}
1316	};
1317
1318	function opts_from_el(el, prefix){
1319		// Derive options from element data-attrs
1320		var data = $(el).data(),
1321			out = {}, inkey,
1322			replace = new RegExp('^' + prefix.toLowerCase() + '([A-Z])');
1323		prefix = new RegExp('^' + prefix.toLowerCase());
1324		function re_lower(_,a){
1325			return a.toLowerCase();
1326		}
1327		for (var key in data)
1328			if (prefix.test(key)){
1329				inkey = key.replace(replace, re_lower);
1330				out[inkey] = data[key];
1331			}
1332		return out;
1333	}
1334
1335	function opts_from_locale(lang){
1336		// Derive options from locale plugins
1337		var out = {};
1338		// Check if "de-DE" style date is available, if not language should
1339		// fallback to 2 letter code eg "de"
1340		if (!dates[lang]){
1341			lang = lang.split('-')[0];
1342			if (!dates[lang])
1343				return;
1344		}
1345		var d = dates[lang];
1346		$.each(locale_opts, function(i,k){
1347			if (k in d)
1348				out[k] = d[k];
1349		});
1350		return out;
1351	}
1352
1353	var old = $.fn.datepicker;
1354	$.fn.datepicker = function(option){
1355		var args = Array.apply(null, arguments);
1356		args.shift();
1357		var internal_return;
1358		this.each(function(){
1359			var $this = $(this),
1360				data = $this.data('datepicker'),
1361				options = typeof option === 'object' && option;
1362			if (!data){
1363				var elopts = opts_from_el(this, 'date'),
1364					// Preliminary otions
1365					xopts = $.extend({}, defaults, elopts, options),
1366					locopts = opts_from_locale(xopts.language),
1367					// Options priority: js args, data-attrs, locales, defaults
1368					opts = $.extend({}, defaults, locopts, elopts, options);
1369				if ($this.is('.input-daterange') || opts.inputs){
1370					var ropts = {
1371						inputs: opts.inputs || $this.find('input').toArray()
1372					};
1373					$this.data('datepicker', (data = new DateRangePicker(this, $.extend(opts, ropts))));
1374				}
1375				else {
1376					$this.data('datepicker', (data = new Datepicker(this, opts)));
1377				}
1378			}
1379			if (typeof option === 'string' && typeof data[option] === 'function'){
1380				internal_return = data[option].apply(data, args);
1381				if (internal_return !== undefined)
1382					return false;
1383			}
1384		});
1385		if (internal_return !== undefined)
1386			return internal_return;
1387		else
1388			return this;
1389	};
1390
1391	var defaults = $.fn.datepicker.defaults = {
1392		autoclose: false,
1393		beforeShowDay: $.noop,
1394		calendarWeeks: false,
1395		clearBtn: false,
1396		daysOfWeekDisabled: [],
1397		endDate: Infinity,
1398		forceParse: true,
1399		format: 'mm/dd/yyyy',
1400		keyboardNavigation: true,
1401		language: 'en',
1402		minViewMode: 0,
1403		multidate: false,
1404		multidateSeparator: ',',
1405		orientation: "auto",
1406		rtl: false,
1407		startDate: -Infinity,
1408		startView: 0,
1409		todayBtn: false,
1410		todayHighlight: false,
1411		weekStart: 0
1412	};
1413	var locale_opts = $.fn.datepicker.locale_opts = [
1414		'format',
1415		'rtl',
1416		'weekStart'
1417	];
1418	$.fn.datepicker.Constructor = Datepicker;
1419	var dates = $.fn.datepicker.dates = {
1420		en: {
1421			days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
1422			daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
1423			daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
1424			months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "
1424November", "December"],
1425			monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
1426			today: "Today",
1427			clear: "Clear"
1428		}
1429	};
1430
1431	var DPGlobal = {
1432		modes: [
1433			{
1434				clsName: 'days',
1435				navFnc: 'Month',
1436				navStep: 1
1437			},
1438			{
1439				clsName: 'months',
1440				navFnc: 'FullYear',
1441				navStep: 1
1442			},
1443			{
1444				clsName: 'years',
1445				navFnc: 'FullYear',
1446				navStep: 10
1447		}],
1448		isLeapYear: function(year){
1449			return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0));
1450		},
1451		getDaysInMonth: function(year, month){
1452			return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
1453		},
1454		validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g,
1455		nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g,
1456		parseFormat: function(format){
1457			// IE treats \0 as a string end in inputs (truncating the value),
1458			// so it's a bad format delimiter, anyway
1459			var separators = format.replace(this.validParts, '\0').split('\0'),
1460				parts = format.match(this.validParts);
1461			if (!separators || !separators.length || !parts || parts.length === 0){
1462				throw new Error("Invalid date format.");
1463			}
1464			return {separators: separators, parts: parts};
1465		},
1466		parseDate: function(date, format, language){
1467			if (!date)
1468				return undefined;
1469			if (date instanceof Date)
1470				return date;
1471			if (typeof format === 'string')
1472				format = DPGlobal.parseFormat(format);
1473			var part_re = /([\-+]\d+)([dmwy])/,
1474				parts = date.match(/([\-+]\d+)([dmwy])/g),
1475				part, dir, i;
1476			if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)){
1477				date = new Date();
1478				for (i=0; i < parts.length; i++){
1479					part = part_re.exec(parts[i]);
1480					dir = parseInt(part[1]);
1481					switch (part[2]){
1482						case 'd':
1483							date.setUTCDate(date.getUTCDate() + dir);
1484							break;
1485						case 'm':
1486							date = Datepicker.prototype.moveMonth.call(Datepicker.prototype, date, dir);
1487							break;
1488						case 'w':
1489							date.setUTCDate(date.getUTCDate() + dir * 7);
1490							break;
1491						case 'y':
1492							date = Datepicker.prototype.moveYear.call(Datepicker.prototype, date, dir);
1493							break;
1494					}
1495				}
1496				return UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), 0, 0, 0);
1497			}
1498			parts = date && date.match(this.nonpunctuation) || [];
1499			date = new Date();
1500			var parsed = {},
1501				setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'],
1502				setters_map = {
1503					yyyy: function(d,v){
1504						return d.setUTCFullYear(v);
1505					},
1506					yy: function(d,v){
1507						return d.setUTCFullYear(2000+v);
1508					},
1509					m: function(d,v){
1510						if (isNaN(d))
1511							return d;
1512						v -= 1;
1513						while (v < 0) v += 12;
1514						v %= 12;
1515						d.setUTCMonth(v);
1516						while (d.getUTCMonth() !== v)
1517							d.setUTCDate(d.getUTCDate()-1);
1518						return d;
1519					},
1520					d: function(d,v){
1521						return d.setUTCDate(v);
1522					}
1523				},
1524				val, filtered;
1525			setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
1526			setters_map['dd'] = setters_map['d'];
1527			date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
1528			var fparts = format.parts.slice();
1529			// Remove noop parts
1530			if (parts.length !== fparts.length){
1531				fparts = $(fparts).filter(function(i,p){
1532					return $.inArray(p, setters_order) !== -1;
1533				}).toArray();
1534			}
1535			// Process remainder
1536			function match_part(){
1537				var m = this.slice(0, parts[i].length),
1538					p = parts[i].slice(0, m.length);
1539				return m === p;
1540			}
1541			if (parts.length === fparts.length){
1542				var cnt;
1543				for (i=0, cnt = fparts.length; i < cnt; i++){
1544					val = parseInt(parts[i], 10);
1545					part = fparts[i];
1546					if (isNaN(val)){
1547						switch (part){
1548							case 'MM':
1549								filtered = $(dates[language].months).filter(match_part);
1550								val = $.inArray(filtered[0], dates[language].months) + 1;
1551								break;
1552							case 'M':
1553								filtered = $(dates[language].monthsShort).filter(match_part);
1554								val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
1555								break;
1556						}
1557					}
1558					parsed[part] = val;
1559				}
1560				var _date, s;
1561				for (i=0; i < setters_order.length; i++){
1562					s = setters_order[i];
1563					if (s in parsed && !isNaN(parsed[s])){
1564						_date = new Date(date);
1565						setters_map[s](_date, parsed[s]);
1566						if (!isNaN(_date))
1567							date = _date;
1568					}
1569				}
1570			}
1571			return date;
1572		},
1573		formatDate: function(date, format, language){
1574			if (!date)
1575				return '';
1576			if (typeof format === 'string')
1577				format = DPGlobal.parseFormat(format);
1578			var val = {
1579				d: date.getUTCDate(),
1580				D: dates[language].daysShort[date.getUTCDay()],
1581				DD: dates[language].days[date.getUTCDay()],
1582				m: date.getUTCMonth() + 1,
1583				M: dates[language].monthsShort[date.getUTCMonth()],
1584				MM: dates[language].months[date.getUTCMonth()],
1585				yy: date.getUTCFullYear().toString().substring(2),
1586				yyyy: date.getUTCFullYear()
1587			};
1588			val.dd = (val.d < 10 ? '0' : '') + val.d;
1589			val.mm = (val.m < 10 ? '0' : '') + val.m;
1590			date = [];
1591			var seps = $.extend([], format.separators);
1592			for (var i=0, cnt = format.parts.length; i <= cnt; i++){
1593				if (seps.length)
1594					date.push(seps.shift());
1595				date.push(val[format.parts[i]]);
1596			}
1597			return date.join('');
1598		},
1599		headTemplate: '<thead>'+
1600							'<tr>'+
1601								'<th class="prev">&laquo;</th>'+
1602								'<th colspan="5" class="datepicker-switch"></th>'+
1603								'<th class="next">&raquo;</th>'+
1604							'</tr>'+
1605						'</thead>',
1606		contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>',
1607		footTemplate: '<tfoot>'+
1608							'<tr>'+
1609								'<th colspan="7" class="today"></th>'+
1610							'</tr>'+
1611							'<tr>'+
1612								'<th colspan="7" class="clear"></th>'+
1613							'</tr>'+
1614						'</tfoot>'
1615	};
1616	DPGlobal.template = '<div class="datepicker">'+
1617							'<div class="datepicker-days">'+
1618								'<table class=" table-condensed">'+
1619									DPGlobal.headTemplate+
1620									'<tbody></tbody>'+
1621									DPGlobal.footTemplate+
1622								'</table>'+
1623							'</div>'+
1624							'<div class="datepicker-months">'+
1625								'<table class="table-condensed">'+
1626									DPGlobal.headTemplate+
1627									DPGlobal.contTemplate+
1628									DPGlobal.footTemplate+
1629								'</table>'+
1630							'</div>'+
1631							'<div class="datepicker-years">'+
1632								'<table class="table-condensed">'+
1633									DPGlobal.headTemplate+
1634									DPGlobal.contTemplate+
1635									DPGlobal.footTemplate+
1636								'</table>'+
1637							'</div>'+
1638						'</div>';
1639
1640	$.fn.datepicker.DPGlobal = DPGlobal;
1641
1642
1643	/* DATEPICKER NO CONFLICT
1644	* =================== */
1645
1646	$.fn.datepicker.noConflict = function(){
1647		$.fn.datepicker = old;
1648		return this;
1649	};
1650
1651
1652	/* DATEPICKER DATA-API
1653	* ================== */
1654
1655	$(document).on(
1656		'focus.datepicker.data-api click.datepicker.data-api',
1657		'[data-provide="datepicker"]',
1658		function(e){
1659			var $this = $(this);
1660			if ($this.data('datepicker'))
1661				return;
1662			e.preventDefault();
1663			// component click requires us to explicitly show it
1664			$this.datepicker('show');
1665		}
1666	);
1667	$(function(){
1668		$('[data-provide="datepicker-inline"]').datepicker();
1669	});
1670
1671}(window.jQuery));

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.