PageSourceSearch

https://seoup.su/bitrix/templates/seoup/assets/plugins/bootstrap-datepicker/js/bootstrap-datepicker.js

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