PageSourceSearch

https://my.sequoiasoft.com/akuiteo.clients/js/lib/bootstrap/bootstrap-datepicker.js?build=null

js sequoiasoft.com collected 2026-10-08 20:29:13 UTC 41,528 bytes, 1,395 lines download raw bytes

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