PageSourceSearch

https://wildmahseer.com/wp-content/themes/sailing/assets/js/libs/daterangepicker.min.js?ver=4.2.9

js wildmahseer.com collected 2026-10-02 12:24:50 UTC 55,668 bytes, 1,630 lines download raw bytes

1
2/**
3 * @version: 2.1.25
4 * @author: Dan Grossman http://www.dangrossman.info/
5 * @copyright: Copyright (c) 2012-2017 Dan Grossman. All rights reserved.
6 * @license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php
7 * @website: https://www.daterangepicker.com/
8 */
9// Follow the UMD template https://github.com/umdjs/umd/blob/master/templates/returnExportsGlobal.js
10(function (root, factory) {
11	if (typeof define === 'function' && define.amd) {
12		// AMD. Make globaly available as well
13		define(['moment', 'jquery'], function (moment, jquery) {
14			return (root.daterangepicker = factory(moment, jquery));
15		});
16	} else if (typeof module === 'object' && module.exports) {
17		// Node / Browserify
18		//isomorphic issue
19		var jQuery = (typeof window != 'undefined') ? window.jQuery : undefined;
20		if (!jQuery) {
21			jQuery = require('jquery');
22			if (!jQuery.fn) jQuery.fn = {};
23		}
24		module.exports = factory(require('moment'), jQuery);
25	} else {
26		// Browser globals
27		root.daterangepicker = factory(root.moment, root.jQuery);
28	}
29}(this, function(moment, $) {
30	var DateRangePicker = function(element, options, cb) {
31
32		//default settings for options
33		this.parentEl = 'body';
34		this.element = $(element);
35		this.startDate = moment().startOf('day');
36		this.endDate = moment().endOf('day');
37		this.minDate = false;
38		this.maxDate = false;
39		this.dateLimit = false;
40		this.autoApply = false;
41		this.singleDatePicker = false;
42		this.showDropdowns = false;
43		this.showWeekNumbers = false;
44		this.showISOWeekNumbers = false;
45		this.showCustomRangeLabel = true;
46		this.timePicker = false;
47		this.timePicker24Hour = false;
vendor: 10,711 bytes, lines 48-371
48		this.timePickerIncrement = 1;
49		this.timePickerSeconds = false;
50		this.linkedCalendars = true;
51		this.autoUpdateInput = true;
52		this.alwaysShowCalendars = false;
53		this.ranges = {};
54
55		this.opens = 'right';
56		if (this.element.hasClass('pull-right'))
57			this.opens = 'left';
58
59		this.drops = 'down';
60		if (this.element.hasClass('dropup'))
61			this.drops = 'up';
62
63		this.buttonClasses = 'btn btn-sm';
64		this.applyClass = 'btn-success';
65		this.cancelClass = 'btn-default';
66
67		this.locale = {
68			direction: 'ltr',
69			format: moment.localeData().longDateFormat('L'),
70			separator: ' - ',
71			applyLabel: 'Apply',
72			cancelLabel: 'Cancel',
73			weekLabel: 'W',
74			customRangeLabel: 'Custom Range',
75			daysOfWeek: moment.weekdaysMin(),
76			monthNames: moment.monthsShort(),
77			firstDay: moment.localeData().firstDayOfWeek()
78		};
79
80		this.callback = function() { };
81
82		//some state information
83		this.isShowing = false;
84		this.leftCalendar = {};
85		this.rightCalendar = {};
86
87		//custom options from user
88		if (typeof options !== 'object' || options === null)
89			options = {};
90
91		//allow setting options with data attributes
92		//data-api options will be overwritten with custom javascript options
93		options = $.extend(this.element.data(), options);
94
95		//html template for the picker UI
96		if (typeof options.template !== 'string' && !(options.template instanceof $))
97			options.template = '<div class="daterangepicker dropdown-menu">' +
98				'<div class="label">Calendar' +
99				'</div>' +
100				'<div class="calendar left">' +
101				'<div class="daterangepicker_input">' +
102				'<input class="input-mini form-control" type="text" name="daterangepicker_start" value="" />' +
103				'<i class="fa fa-calendar glyphicon glyphicon-calendar"></i>' +
104				'<div class="calendar-time">' +
105				'<div></div>' +
106				'<i class="fa fa-clock-o glyphicon glyphicon-time"></i>' +
107				'</div>' +
108				'</div>' +
109				'<div class="calendar-table"></div>' +
110				'</div>' +
111				'<div class="calendar right">' +
112				'<div class="daterangepicker_input">' +
113				'<input class="input-mini form-control" type="text" name="daterangepicker_end" value="" />' +
114				'<i class="fa fa-calendar glyphicon glyphicon-calendar"></i>' +
115				'<div class="calendar-time">' +
116				'<div></div>' +
117				'<i class="fa fa-clock-o glyphicon glyphicon-time"></i>' +
118				'</div>' +
119				'</div>' +
120				'<div class="calendar-table"></div>' +
121				'</div>' +
122				'<div class="ranges">' +
123				'<div class="range_inputs">' +
124				'<button class="applyBtn" disabled="disabled" type="button"></button> ' +
125				'<button class="cancelBtn" type="button"></button>' +
126				'</div>' +
127				'</div>' +
128				'</div>';
129
130		this.parentEl = (options.parentEl && $(options.parentEl).length) ? $(options.parentEl) : $(this.parentEl);
131		this.container = $(options.template).appendTo(this.parentEl);
132
133		//
134		// handle all the possible options overriding defaults
135		//
136
137		if (typeof options.locale === 'object') {
138
139			if (typeof options.locale.direction === 'string')
140				this.locale.direction = options.locale.direction;
141
142			if (typeof options.locale.format === 'string')
143				this.locale.format = options.locale.format;
144
145			if (typeof options.locale.separator === 'string')
146				this.locale.separator = options.locale.separator;
147
148			if (typeof options.locale.daysOfWeek === 'object')
149				this.locale.daysOfWeek = options.locale.daysOfWeek.slice();
150
151			if (typeof options.locale.monthNames === 'object')
152				this.locale.monthNames = options.locale.monthNames.slice();
153
154			if (typeof options.locale.firstDay === 'number')
155				this.locale.firstDay = options.locale.firstDay;
156
157			if (typeof options.locale.applyLabel === 'string')
158				this.locale.applyLabel = options.locale.applyLabel;
159
160			if (typeof options.locale.cancelLabel === 'string')
161				this.locale.cancelLabel = options.locale.cancelLabel;
162
163			if (typeof options.locale.weekLabel === 'string')
164				this.locale.weekLabel = options.locale.weekLabel;
165
166			if (typeof options.locale.customRangeLabel === 'string'){
167				//Support unicode chars in the custom range name.
168				var elem = document.createElement('textarea');
169				elem.innerHTML = options.locale.customRangeLabel;
170				var rangeHtml = elem.value;
171				this.locale.customRangeLabel = rangeHtml;
172			}
173		}
174		this.container.addClass(this.locale.direction);
175
176		if (typeof options.startDate === 'string')
177			this.startDate = moment(options.startDate, this.locale.format);
178
179		if (typeof options.endDate === 'string')
180			this.endDate = moment(options.endDate, this.locale.format);
181
182		if (typeof options.minDate === 'string')
183			this.minDate = moment(options.minDate, this.locale.format);
184
185		if (typeof options.maxDate === 'string')
186			this.maxDate = moment(options.maxDate, this.locale.format);
187
188		if (typeof options.startDate === 'object')
189			this.startDate = moment(options.startDate);
190
191		if (typeof options.endDate === 'object')
192			this.endDate = moment(options.endDate);
193
194		if (typeof options.minDate === 'object')
195			this.minDate = moment(options.minDate);
196
197		if (typeof options.maxDate === 'object')
198			this.maxDate = moment(options.maxDate);
199
200		// sanity check for bad options
201		if (this.minDate && this.startDate.isBefore(this.minDate))
202			this.startDate = this.minDate.clone();
203
204		// sanity check for bad options
205		if (this.maxDate && this.endDate.isAfter(this.maxDate))
206			this.endDate = this.maxDate.clone();
207
208		if (typeof options.applyClass === 'string')
209			this.applyClass = options.applyClass;
210
211		if (typeof options.cancelClass === 'string')
212			this.cancelClass = options.cancelClass;
213
214		if (typeof options.dateLimit === 'object')
215			this.dateLimit = options.dateLimit;
216
217		if (typeof options.opens === 'string')
218			this.opens = options.opens;
219
220		if (typeof options.drops === 'string')
221			this.drops = options.drops;
222
223		if (typeof options.showWeekNumbers === 'boolean')
224			this.showWeekNumbers = options.showWeekNumbers;
225
226		if (typeof options.showISOWeekNumbers === 'boolean')
227			this.showISOWeekNumbers = options.showISOWeekNumbers;
228
229		if (typeof options.buttonClasses === 'string')
230			this.buttonClasses = options.buttonClasses;
231
232		if (typeof options.buttonClasses === 'object')
233			this.buttonClasses = options.buttonClasses.join(' ');
234
235		if (typeof options.showDropdowns === 'boolean')
236			this.showDropdowns = options.showDropdowns;
237
238		if (typeof options.showCustomRangeLabel === 'boolean')
239			this.showCustomRangeLabel = options.showCustomRangeLabel;
240
241		if (typeof options.singleDatePicker === 'boolean') {
242			this.singleDatePicker = options.singleDatePicker;
243			if (this.singleDatePicker)
244				this.endDate = this.startDate.clone();
245		}
246
247		if (typeof options.timePicker === 'boolean')
248			this.timePicker = options.timePicker;
249
250		if (typeof options.timePickerSeconds === 'boolean')
251			this.timePickerSeconds = options.timePickerSeconds;
252
253		if (typeof options.timePickerIncrement === 'number')
254			this.timePickerIncrement = options.timePickerIncrement;
255
256		if (typeof options.timePicker24Hour === 'boolean')
257			this.timePicker24Hour = options.timePicker24Hour;
258
259		if (typeof options.autoApply === 'boolean')
260			this.autoApply = options.autoApply;
261
262		if (typeof options.autoUpdateInput === 'boolean')
263			this.autoUpdateInput = options.autoUpdateInput;
264
265		if (typeof options.linkedCalendars === 'boolean')
266			this.linkedCalendars = options.linkedCalendars;
267
268		if (typeof options.isInvalidDate === 'function')
269			this.isInvalidDate = options.isInvalidDate;
270
271		if (typeof options.isCustomDate === 'function')
272			this.isCustomDate = options.isCustomDate;
273
274		if (typeof options.alwaysShowCalendars === 'boolean')
275			this.alwaysShowCalendars = options.alwaysShowCalendars;
276
277		// update day names order to firstDay
278		if (this.locale.firstDay != 0) {
279			var iterator = this.locale.firstDay;
280			while (iterator > 0) {
281				this.locale.daysOfWeek.push(this.locale.daysOfWeek.shift());
282				iterator--;
283			}
284		}
285
286		var start, end, range;
287
288		//if no start/end dates set, check if an input element contains initial values
289		if (typeof options.startDate === 'undefined' && typeof options.endDate === 'undefined') {
290			if ($(this.element).is('input[type=text]')) {
291				var val = $(this.element).val(),
292					split = val.split(this.locale.separator);
293
294				start = end = null;
295
296				if (split.length == 2) {
297					start = moment(split[0], this.locale.format);
298					end = moment(split[1], this.locale.format);
299				} else if (this.singleDatePicker && val !== "") {
300					start = moment(val, this.locale.format);
301					end = moment(val, this.locale.format);
302				}
303				if (start !== null && end !== null) {
304					this.setStartDate(start);
305					this.setEndDate(end);
306				}
307			}
308		}
309
310		if (typeof options.ranges === 'object') {
311			for (range in options.ranges) {
312
313				if (typeof options.ranges[range][0] === 'string')
314					start = moment(options.ranges[range][0], this.locale.format);
315				else
316					start = moment(options.ranges[range][0]);
317
318				if (typeof options.ranges[range][1] === 'string')
319					end = moment(options.ranges[range][1], this.locale.format);
320				else
321					end = moment(options.ranges[range][1]);
322
323				// If the start or end date exceed those allowed by the minDate or dateLimit
324				// options, shorten the range to the allowable period.
325				if (this.minDate && start.isBefore(this.minDate))
326					start = this.minDate.clone();
327
328				var maxDate = this.maxDate;
329				if (this.dateLimit && maxDate && start.clone().add(this.dateLimit).isAfter(maxDate))
330					maxDate = start.clone().add(this.dateLimit);
331				if (maxDate && end.isAfter(maxDate))
332					end = maxDate.clone();
333
334				// If the end of the range is before the minimum or the start of the range is
335				// after the maximum, don't display this range option at all.
336				if ((this.minDate && end.isBefore(this.minDate, this.timepicker ? 'minute' : 'day'))
337					|| (maxDate && start.isAfter(maxDate, this.timepicker ? 'minute' : 'day')))
338					continue;
339
340				//Support unicode chars in the range names.
341				var elem = document.createElement('textarea');
342				elem.innerHTML = range;
343				var rangeHtml = elem.value;
344
345				this.ranges[rangeHtml] = [start, end];
346			}
347
348			var list = '<ul>';
349			for (range in this.ranges) {
350				list += '<li data-range-key="' + range + '">' + range + '</li>';
351			}
352			if (this.showCustomRangeLabel) {
353				list += '<li data-range-key="' + this.locale.customRangeLabel + '">' + this.locale.customRangeLabel + '</li>';
354			}
355			list += '</ul>';
356			this.container.find('.ranges').prepend(list);
357		}
358
359		if (typeof cb === 'function') {
360			this.callback = cb;
361		}
362
363		if (!this.timePicker) {
364			this.startDate = this.startDate.startOf('day');
365			this.endDate = this.endDate.endOf('day');
366			this.container.find('.calendar-time').hide();
367		}
368
369		//can't be used together for now
370		if (this.timePicker && this.autoApply)
371			this.autoApply = false;
372
373		if (this.autoApply && typeof options.ranges !== 'object') {
374			this.container.find('.ranges').hide();
375		} else if (this.autoApply) {
376			this.container.find('.applyBtn, .cancelBtn').addClass('hide');
377		}
378
379		if (this.singleDatePicker) {
380			this.container.addClass('single');
381			this.container.find('.calendar.left').addClass('single');
382			this.container.find('.calendar.left').show();
383			this.container.find('.calendar.right').hide();
384			this.container.find('.daterangepicker_input input, .daterangepicker_input > i').hide();
385			if (this.timePicker) {
386				this.container.find('.ranges ul').hide();
387			} else {
388				this.container.find('.ranges').hide();
389			}
390		}
391
392		if ((typeof options.ranges === 'undefined' && !this.singleDatePicker) || this.alwaysShowCalendars) {
393			this.container.addClass('show-calendar');
394		}
395
396		this.container.addClass('opens' + this.opens);
397
398		//swap the position of the predefined ranges if opens right
399		if (typeof options.ranges !== 'undefined' && this.opens == 'right') {
400			this.container.find('.ranges').prependTo( this.container.find('.calendar.left').parent() );
401		}
402
403		//apply CSS classes and labels to buttons
404		this.container.find('.applyBtn, .cancelBtn').addClass(this.buttonClasses);
405		if (this.applyClass.length)
406			this.container.find('.applyBtn').addClass(this.applyClass);
407		if (this.cancelClass.length)
408			this.container.find('.cancelBtn').addClass(this.cancelClass);
409		this.container.find('.applyBtn').html(this.locale.applyLabel);
410		this.container.find('.cancelBtn').html(this.locale.cancelLabel);
411
412		//
413		// event listeners
414		//
415
416		this.container.find('.calendar')
417			.on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this))
418			.on('click.daterangepicker', '.next', $.proxy(this.clickNext, this))
419			.on('mousedown.daterangepicker', 'td.available', $.proxy(this.clickDate, this))
420			.on('mouseenter.daterangepicker', 'td.available', $.proxy(this.hoverDate, this))
421			.on('mouseleave.daterangepicker', 'td.available', $.proxy(this.updateFormInputs, this))
422			.on('change.daterangepicker', 'select.yearselect', $.proxy(this.monthOrYearChanged, this))
423			.on('change.daterangepicker', 'select.monthselect', $.proxy(this.monthOrYearChanged, this))
424			.on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', $.proxy(this.timeChanged, this))
425			.on('click.daterangepicker', '.daterangepicker_input input', $.proxy(this.showCalendars, this))
426			.on('focus.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsFocused, this))
427			.on('blur.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsBlurred, this))
428			.on('change.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsChanged, this));
429
430		this.container.find('.ranges')
431			.on('click.daterangepicker', 'button.applyBtn', $.proxy(this.clickApply, this))
432			.on('click.daterangepicker', 'button.cancelBtn', $.proxy(this.clickCancel, this))
433			.on('click.daterangepicker', 'li', $.proxy(this.clickRange, this))
434			.on('mouseenter.daterangepicker', 'li', $.proxy(this.hoverRange, this))
435			.on('mouseleave.daterangepicker', 'li', $.proxy(this.updateFormInputs, this));
436
437		if (this.element.is('input') || this.element.is('button')) {
438			this.element.on({
439				'click.daterangepicker': $.proxy(this.show, this),
vendor: 18,547 bytes, lines 440-977
440				'focus.daterangepicker': $.proxy(this.show, this),
441				'keyup.daterangepicker': $.proxy(this.elementChanged, this),
442				'keydown.daterangepicker': $.proxy(this.keydown, this)
443			});
444		} else {
445			this.element.on('click.daterangepicker', $.proxy(this.toggle, this));
446		}
447
448		//
449		// if attached to a text input, set the initial value
450		//
451
452		if (this.element.is('input') && !this.singleDatePicker && this.autoUpdateInput) {
453			this.element.val(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format));
454			this.element.trigger('change');
455		} else if (this.element.is('input') && this.autoUpdateInput) {
456			this.element.val(this.startDate.format(this.locale.format));
457			this.element.trigger('change');
458		}
459
460	};
461
462	DateRangePicker.prototype = {
463
464		constructor: DateRangePicker,
465
466		setStartDate: function(startDate) {
467			if (typeof startDate === 'string')
468				this.startDate = moment(startDate, this.locale.format);
469
470			if (typeof startDate === 'object')
471				this.startDate = moment(startDate);
472
473			if (!this.timePicker)
474				this.startDate = this.startDate.startOf('day');
475
476			if (this.timePicker && this.timePickerIncrement)
477				this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);
478
479			if (this.minDate && this.startDate.isBefore(this.minDate)) {
480				this.startDate = this.minDate.clone();
481				if (this.timePicker && this.timePickerIncrement)
482					this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);
483			}
484
485			if (this.maxDate && this.startDate.isAfter(this.maxDate)) {
486				this.startDate = this.maxDate.clone();
487				if (this.timePicker && this.timePickerIncrement)
488					this.startDate.minute(Math.floor(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);
489			}
490
491			if (!this.isShowing)
492				this.updateElement();
493
494			this.updateMonthsInView();
495		},
496
497		setEndDate: function(endDate) {
498			if (typeof endDate === 'string')
499				this.endDate = moment(endDate, this.locale.format);
500
501			if (typeof endDate === 'object')
502				this.endDate = moment(endDate);
503
504			if (!this.timePicker)
505				this.endDate = this.endDate.endOf('day');
506
507			if (this.timePicker && this.timePickerIncrement)
508				this.endDate.minute(Math.round(this.endDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);
509
510			if (this.endDate.isBefore(this.startDate))
511				this.endDate = this.startDate.clone();
512
513			if (this.maxDate && this.endDate.isAfter(this.maxDate))
514				this.endDate = this.maxDate.clone();
515
516			if (this.dateLimit && this.startDate.clone().add(this.dateLimit).isBefore(this.endDate))
517				this.endDate = this.startDate.clone().add(this.dateLimit);
518
519			this.previousRightTime = this.endDate.clone();
520
521			if (!this.isShowing)
522				this.updateElement();
523
524			this.updateMonthsInView();
525		},
526
527		isInvalidDate: function() {
528			return false;
529		},
530
531		isCustomDate: function() {
532			return false;
533		},
534
535		updateView: function() {
536			if (this.timePicker) {
537				this.renderTimePicker('left');
538				this.renderTimePicker('right');
539				if (!this.endDate) {
540					this.container.find('.right .calendar-time select').attr('disabled', 'disabled').addClass('disabled');
541				} else {
542					this.container.find('.right .calendar-time select').removeAttr('disabled').removeClass('disabled');
543				}
544			}
545			if (this.endDate) {
546				this.container.find('input[name="daterangepicker_end"]').removeClass('active');
547				this.container.find('input[name="daterangepicker_start"]').addClass('active');
548			} else {
549				this.container.find('input[name="daterangepicker_end"]').addClass('active');
550				this.container.find('input[name="daterangepicker_start"]').removeClass('active');
551			}
552			this.updateMonthsInView();
553			this.updateCalendars();
554			this.updateFormInputs();
555		},
556
557		updateMonthsInView: function() {
558			if (this.endDate) {
559
560				//if both dates are visible already, do nothing
561				if (!this.singleDatePicker && this.leftCalendar.month && this.rightCalendar.month &&
562					(this.startDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.startDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM'))
563					&&
564					(this.endDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.endDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM'))
565				) {
566					return;
567				}
568
569				this.leftCalendar.month = this.startDate.clone().date(2);
570				if (!this.linkedCalendars && (this.endDate.month() != this.startDate.month() || this.endDate.year() != this.startDate.year())) {
571					this.rightCalendar.month = this.endDate.clone().date(2);
572				} else {
573					this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month');
574				}
575
576			} else {
577				if (this.leftCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM') && this.rightCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM')) {
578					this.leftCalendar.month = this.startDate.clone().date(2);
579					this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month');
580				}
581			}
582			if (this.maxDate && this.linkedCalendars && !this.singleDatePicker && this.rightCalendar.month > this.maxDate) {
583				this.rightCalendar.month = this.maxDate.clone().date(2);
584				this.leftCalendar.month = this.maxDate.clone().date(2).subtract(1, 'month');
585			}
586		},
587
588		updateCalendars: function() {
589
590			if (this.timePicker) {
591				var hour, minute, second;
592				if (this.endDate) {
593					hour = parseInt(this.container.find('.left .hourselect').val(), 10);
594					minute = parseInt(this.container.find('.left .minuteselect').val(), 10);
595					second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0;
596					if (!this.timePicker24Hour) {
597						var ampm = this.container.find('.left .ampmselect').val();
598						if (ampm === 'PM' && hour < 12)
599							hour += 12;
600						if (ampm === 'AM' && hour === 12)
601							hour = 0;
602					}
603				} else {
604					hour = parseInt(this.container.find('.right .hourselect').val(), 10);
605					minute = parseInt(this.container.find('.right .minuteselect').val(), 10);
606					second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0;
607					if (!this.timePicker24Hour) {
608						var ampm = this.container.find('.right .ampmselect').val();
609						if (ampm === 'PM' && hour < 12)
610							hour += 12;
611						if (ampm === 'AM' && hour === 12)
612							hour = 0;
613					}
614				}
615				this.leftCalendar.month.hour(hour).minute(minute).second(second);
616				this.rightCalendar.month.hour(hour).minute(minute).second(second);
617			}
618
619			this.renderCalendar('left');
620			this.renderCalendar('right');
621
622			//highlight any predefined range matching the current start and end dates
623			this.container.find('.ranges li').removeClass('active');
624			if (this.endDate == null) return;
625
626			this.calculateChosenLabel();
627		},
628
629		renderCalendar: function(side) {
630
631			//
632			// Build the matrix of dates that will populate the calendar
633			//
634
635			var calendar = side == 'left' ? this.leftCalendar : this.rightCalendar;
636			var month = calendar.month.month();
637			var year = calendar.month.year();
638			var hour = calendar.month.hour();
639			var minute = calendar.month.minute();
640			var second = calendar.month.second();
641			var daysInMonth = moment([year, month]).daysInMonth();
642			var firstDay = moment([year, month, 1]);
643			var lastDay = moment([year, month, daysInMonth]);
644			var lastMonth = moment(firstDay).subtract(1, 'month').month();
645			var lastYear = moment(firstDay).subtract(1, 'month').year();
646			var daysInLastMonth = moment([lastYear, lastMonth]).daysInMonth();
647			var dayOfWeek = firstDay.day();
648
649			//initialize a 6 rows x 7 columns array for the calendar
650			var calendar = [];
651			calendar.firstDay = firstDay;
652			calendar.lastDay = lastDay;
653
654			for (var i = 0; i < 6; i++) {
655				calendar[i] = [];
656			}
657
658			//populate the calendar with date objects
659			var startDay = daysInLastMonth - dayOfWeek + this.locale.firstDay + 1;
660			if (startDay > daysInLastMonth)
661				startDay -= 7;
662
663			if (dayOfWeek == this.locale.firstDay)
664				startDay = daysInLastMonth - 6;
665
666			var curDate = moment([lastYear, lastMonth, startDay, 12, minute, second]);
667
668			var col, row;
669			for (var i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add(24, 'hour')) {
670				if (i > 0 && col % 7 === 0) {
671					col = 0;
672					row++;
673				}
674				calendar[row][col] = curDate.clone().hour(hour).minute(minute).second(second);
675				curDate.hour(12);
676
677				if (this.minDate && calendar[row][col].format('YYYY-MM-DD') == this.minDate.format('YYYY-MM-DD') && calendar[row][col].isBefore(this.minDate) && side == 'left') {
678					calendar[row][col] = this.minDate.clone();
679				}
680
681				if (this.maxDate && calendar[row][col].format('YYYY-MM-DD') == this.maxDate.format('YYYY-MM-DD') && calendar[row][col].isAfter(this.maxDate) && side == 'right') {
682					calendar[row][col] = this.maxDate.clone();
683				}
684
685			}
686
687			//make the calendar object available to hoverDate/clickDate
688			if (side == 'left') {
689				this.leftCalendar.calendar = calendar;
690			} else {
691				this.rightCalendar.calendar = calendar;
692			}
693
694			//
695			// Display the calendar
696			//
697
698			var minDate = side == 'left' ? this.minDate : this.startDate;
699			var maxDate = this.maxDate;
700			var selected = side == 'left' ? this.startDate : this.endDate;
701			var arrow = this.locale.direction == 'ltr' ? {left: 'chevron-left', right: 'chevron-right'} : {left: 'chevron-right', right: 'chevron-left'};
702
703			var html = '<table class="table-condensed">';
704			html += '<thead>';
705			html += '<tr>';
706
707			// add empty cell for week number
708			if (this.showWeekNumbers || this.showISOWeekNumbers)
709				html += '<th></th>';
710
711			if ((!minDate || minDate.isBefore(calendar.firstDay)) && (!this.linkedCalendars || side == 'left')) {
712				html += '<th class="prev available"><i class="fa fa-' + arrow.left + ' glyphicon glyphicon-' + arrow.left + '"></i></th>';
713			} else {
714				html += '<th></th>';
715			}
716
717			var dateHtml = this.locale.monthNames[calendar[1][1].month()] + calendar[1][1].format(" YYYY");
718
719			if (this.showDropdowns) {
720				var currentMonth = calendar[1][1].month();
721				var currentYear = calendar[1][1].year();
722				var maxYear = (maxDate && maxDate.year()) || (currentYear + 5);
723				var minYear = (minDate && minDate.year()) || (currentYear - 50);
724				var inMinYear = currentYear == minYear;
725				var inMaxYear = currentYear == maxYear;
726
727				var monthHtml = '<select class="monthselect">';
728				for (var m = 0; m < 12; m++) {
729					if ((!inMinYear || m >= minDate.month()) && (!inMaxYear || m <= maxDate.month())) {
730						monthHtml += "<option value='" + m + "'" +
731							(m === currentMonth ? " selected='selected'" : "") +
732							">" + this.locale.monthNames[m] + "</option>";
733					} else {
734						monthHtml += "<option value='" + m + "'" +
735							(m === currentMonth ? " selected='selected'" : "") +
736							" disabled='disabled'>" + this.locale.monthNames[m] + "</option>";
737					}
738				}
739				monthHtml += "</select>";
740
741				var yearHtml = '<select class="yearselect">';
742				for (var y = minYear; y <= maxYear; y++) {
743					yearHtml += '<option value="' + y + '"' +
744						(y === currentYear ? ' selected="selected"' : '') +
745						'>' + y + '</option>';
746				}
747				yearHtml += '</select>';
748
749				dateHtml = monthHtml + yearHtml;
750			}
751
752			html += '<th colspan="5" class="month">' + dateHtml + '</th>';
753			if ((!maxDate || maxDate.isAfter(calendar.lastDay)) && (!this.linkedCalendars || side == 'right' || this.singleDatePicker)) {
754				html += '<th class="next available"><i class="fa fa-' + arrow.right + ' glyphicon glyphicon-' + arrow.right + '"></i></th>';
755			} else {
756				html += '<th></th>';
757			}
758
759			html += '</tr>';
760			html += '<tr>';
761
762			// add week number label
763			if (this.showWeekNumbers || this.showISOWeekNumbers)
764				html += '<th class="week">' + this.locale.weekLabel + '</th>';
765
766			$.each(this.locale.daysOfWeek, function(index, dayOfWeek) {
767				html += '<th>' + dayOfWeek + '</th>';
768			});
769
770			html += '</tr>';
771			html += '</thead>';
772			html += '<tbody>';
773
774			//adjust maxDate to reflect the dateLimit setting in order to
775			//grey out end dates beyond the dateLimit
776			if (this.endDate == null && this.dateLimit) {
777				var maxLimit = this.startDate.clone().add(this.dateLimit).endOf('day');
778				if (!maxDate || maxLimit.isBefore(maxDate)) {
779					maxDate = maxLimit;
780				}
781			}
782
783			for (var row = 0; row < 6; row++) {
784				html += '<tr>';
785
786				// add week number
787				if (this.showWeekNumbers)
788					html += '<td class="week">' + calendar[row][0].week() + '</td>';
789				else if (this.showISOWeekNumbers)
790					html += '<td class="week">' + calendar[row][0].isoWeek() + '</td>';
791
792				for (var col = 0; col < 7; col++) {
793
794					var classes = [];
795
796					//highlight today's date
797					if (calendar[row][col].isSame(new Date(), "day"))
798						classes.push('today');
799
800					//highlight weekends
801					if (calendar[row][col].isoWeekday() > 5)
802						classes.push('weekend');
803
804					//grey out the dates in other months displayed at beginning and end of this calendar
805					if (calendar[row][col].month() != calendar[1][1].month())
806						classes.push('off');
807
808					//don't allow selection of dates before the minimum date
809					if (this.minDate && calendar[row][col].isBefore(this.minDate, 'day'))
810						classes.push('off', 'disabled');
811
812					//don't allow selection of dates after the maximum date
813					if (maxDate && calendar[row][col].isAfter(maxDate, 'day'))
814						classes.push('off', 'disabled');
815
816					//don't allow selection of date if a custom function decides it's invalid
817					if (this.isInvalidDate(calendar[row][col]))
818						classes.push('off', 'disabled');
819
820					//highlight the currently selected start date
821					if (calendar[row][col].format('YYYY-MM-DD') == this.startDate.format('YYYY-MM-DD'))
822						classes.push('active', 'start-date');
823
824					//highlight the currently selected end date
825					if (this.endDate != null && calendar[row][col].format('YYYY-MM-DD') == this.endDate.format('YYYY-MM-DD'))
826						classes.push('active', 'end-date');
827
828					//highlight dates in-between the selected dates
829					if (this.endDate != null && calendar[row][col] > this.startDate && calendar[row][col] < this.endDate)
830						classes.push('in-range');
831
832					//apply custom classes for this date
833					var isCustom = this.isCustomDate(calendar[row][col]);
834					if (isCustom !== false) {
835						if (typeof isCustom === 'string')
836							classes.push(isCustom);
837						else
838							Array.prototype.push.apply(classes, isCustom);
839					}
840
841					var cname = '', disabled = false;
842					for (var i = 0; i < classes.length; i++) {
843						cname += classes[i] + ' ';
844						if (classes[i] == 'disabled')
845							disabled = true;
846					}
847					if (!disabled)
848						cname += 'available';
849
850					html += '<td class="' + cname.replace(/^\s+|\s+$/g, '') + '" data-title="' + 'r' + row + 'c' + col + '">' + calendar[row][col].date() + '</td>';
851
852				}
853				html += '</tr>';
854			}
855
856			html += '</tbody>';
857			html += '</table>';
858
859			this.container.find('.calendar.' + side + ' .calendar-table').html(html);
860
861		},
862
863		renderTimePicker: function(side) {
864
865			// Don't bother updating the time picker if it's currently disabled
866			// because an end date hasn't been clicked yet
867			if (side == 'right' && !this.endDate) return;
868
869			var html, selected, minDate, maxDate = this.maxDate;
870
871			if (this.dateLimit && (!this.maxDate || this.startDate.clone().add(this.dateLimit).isAfter(this.maxDate)))
872				maxDate = this.startDate.clone().add(this.dateLimit);
873
874			if (side == 'left') {
875				selected = this.startDate.clone();
876				minDate = this.minDate;
877			} else if (side == 'right') {
878				selected = this.endDate.clone();
879				minDate = this.startDate;
880
881				//Preserve the time already selected
882				var timeSelector = this.container.find('.calendar.right .calendar-time div');
883				if (timeSelector.html() != '') {
884
885					selected.hour(timeSelector.find('.hourselect option:selected').val() || selected.hour());
886					selected.minute(timeSelector.find('.minuteselect option:selected').val() || selected.minute());
887					selected.second(timeSelector.find('.secondselect option:selected').val() || selected.second());
888
889					if (!this.timePicker24Hour) {
890						var ampm = timeSelector.find('.ampmselect option:selected').val();
891						if (ampm === 'PM' && selected.hour() < 12)
892							selected.hour(selected.hour() + 12);
893						if (ampm === 'AM' && selected.hour() === 12)
894							selected.hour(0);
895					}
896
897				}
898
899				if (selected.isBefore(this.startDate))
900					selected = this.startDate.clone();
901
902				if (maxDate && selected.isAfter(maxDate))
903					selected = maxDate.clone();
904
905			}
906
907			//
908			// hours
909			//
910
911			html = '<select class="hourselect">';
912
913			var start = this.timePicker24Hour ? 0 : 1;
914			var end = this.timePicker24Hour ? 23 : 12;
915
916			for (var i = start; i <= end; i++) {
917				var i_in_24 = i;
918				if (!this.timePicker24Hour)
919					i_in_24 = selected.hour() >= 12 ? (i == 12 ? 12 : i + 12) : (i == 12 ? 0 : i);
920
921				var time = selected.clone().hour(i_in_24);
922				var disabled = false;
923				if (minDate && time.minute(59).isBefore(minDate))
924					disabled = true;
925				if (maxDate && time.minute(0).isAfter(maxDate))
926					disabled = true;
927
928				if (i_in_24 == selected.hour() && !disabled) {
929					html += '<option value="' + i + '" selected="selected">' + i + '</option>';
930				} else if (disabled) {
931					html += '<option value="' + i + '" disabled="disabled" class="disabled">' + i + '</option>';
932				} else {
933					html += '<option value="' + i + '">' + i + '</option>';
934				}
935			}
936
937			html += '</select> ';
938
939			//
940			// minutes
941			//
942
943			html += ': <select class="minuteselect">';
944
945			for (var i = 0; i < 60; i += this.timePickerIncrement) {
946				var padded = i < 10 ? '0' + i : i;
947				var time = selected.clone().minute(i);
948
949				var disabled = false;
950				if (minDate && time.second(59).isBefore(minDate))
951					disabled = true;
952				if (maxDate && time.second(0).isAfter(maxDate))
953					disabled = true;
954
955				if (selected.minute() == i && !disabled) {
956					html += '<option value="' + i + '" selected="selected">' + padded + '</option>';
957				} else if (disabled) {
958					html += '<option value="' + i + '" disabled="disabled" class="disabled">' + padded + '</option>';
959				} else {
960					html += '<option value="' + i + '">' + padded + '</option>';
961				}
962			}
963
964			html += '</select> ';
965
966			//
967			// seconds
968			//
969
970			if (this.timePickerSeconds) {
971				html += ': <select class="secondselect">';
972
973				for (var i = 0; i < 60; i++) {
974					var padded = i < 10 ? '0' + i : i;
975					var time = selected.clone().second(i);
976
977					var disabled = false;
978					if (minDate && time.isBefore(minDate))
979						disabled = true;
980					if (maxDate && time.isAfter(maxDate))
981						disabled = true;
982
983					if (selected.second() == i && !disabled) {
984						html += '<option value="' + i + '" selected="selected">' + padded + '</option>';
985					} else if (disabled) {
986						html += '<option value="' + i + '" disabled="disabled" class="disabled">' + padded + '</option>';
987					} else {
988						html += '<option value="' + i + '">' + padded + '</option>';
989					}
990				}
991
992				html += '</select> ';
993			}
994
995			//
996			// AM/PM
997			//
998
999			if (!this.timePicker24Hour) {
1000				html += '<select class="ampmselect">';
1001
1002				var am_html = '';
1003				var pm_html = '';
1004
1005				if (minDate && selected.clone().hour(12).minute(0).second(0).isBefore(minDate))
1006					am_html = ' disabled="disabled" class="disabled"';
1007
1008				if (maxDate && selected.clone().hour(0).minute(0).second(0).isAfter(maxDate))
1009					pm_html = ' disabled="disabled" class="disabled"';
1010
1011				if (selected.hour() >= 12) {
1012					html += '<option value="AM"' + am_html + '>AM</option><option value="PM" selected="selected"' + pm_html + '>PM</option>';
1013				} else {
1014					html += '<option value="AM" selected="selected"' + am_html + '>AM</option><option value="PM"' + pm_html + '>PM</option>';
1015				}
1016
1017				html += '</select>';
1018			}
1019
1020			this.container.find('.calendar.' + side + ' .calendar-time div').html(html);
1021
1022		},
1023
1024		updateFormInputs: function() {
1025
1026			//ignore mouse movements while an above-calendar text input has focus
1027			if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus"))
1028				return;
1029
1030			this.container.find('input[name=daterangepicker_start]').val(this.startDate.format(this.locale.format));
1031			if (this.endDate)
1032				this.container.find('input[name=daterangepicker_end]').val(this.endDate.format(this.locale.format));
1033
1034			if (this.singleDatePicker || (this.endDate && (this.startDate.isBefore(this.endDate) || this.startDate.isSame(this.endDate)))) {
1035				this.container.find('button.applyBtn').removeAttr('disabled');
1036			} else {
1037				this.container.find('button.applyBtn').attr('disabled', 'disabled');
1038			}
1039
1040		},
1041
1042		move: function() {
1043			var parentOffset = { top: 0, left: 0 },
1044				containerTop;
1045			var parentRightEdge = $(window).width();
1046			if (!this.parentEl.is('body')) {
1047				parentOffset = {
1048					top: this.parentEl.offset().top - this.parentEl.scrollTop(),
1049					left: this.parentEl.offset().left - this.parentEl.scrollLeft()
1050				};
1051				parentRightEdge = this.parentEl[0].clientWidth + this.parentEl.offset().left;
1052			}
1053
1054			if (this.drops == 'up')
1055				containerTop = this.element.offset().top - this.container.outerHeight() - parentOffset.top;
1056			else
1057				containerTop = this.element.offset().top + this.element.outerHeight() - parentOffset.top;
1058			this.container[this.drops == 'up' ? 'addClass' : 'removeClass']('dropup');
1059
1060			if (this.opens == 'left') {
1061				this.container.css({
1062					top: containerTop,
1063					right: parentRightEdge - this.element.offset().left - this.element.outerWidth(),
1064					left: 'auto'
1065				});
1066				if (this.container.offset().left < 0) {
1067					this.container.css({
1068						right: 'auto',
1069						left: 9
1070					});
1071				}
1072			} else if (this.opens == 'center') {
1073				this.container.css({
1074					top: containerTop,
1075					left: this.element.offset().left - parentOffset.left + this.element.outerWidth() / 2
1076						- this.container.outerWidth() / 2,
1077					right: 'auto'
1078				});
1079				if (this.container.offset().left < 0) {
1080					this.container.css({
1081						right: 'auto',
1082						left: 9
1083					});
1084				}
1085			} else {
1086				this.container.css({
1087					top: containerTop,
1088					left: this.element.offset().left - parentOffset.left,
1089					right: 'auto'
1090				});
1091				if (this.container.offset().left + this.container.outerWidth() > $(window).width()) {
1092					this.container.css({
1093						left: 'auto',
1094						right: 0
1095					});
1096				}
1097			}
1098		},
1099
1100		show: function(e) {
1101			if (this.isShowing) return;
1102
1103			// Create a click proxy that is private to this instance of datepicker, for unbinding
1104			this._outsideClickProxy = $.proxy(function(e) { this.outsideClick(e); }, this);
1105
1106			// Bind global datepicker mousedown for hiding and
1107			$(document)
1108				.on('mousedown.daterangepicker', this._outsideClickProxy)
1109				// also support mobile devices
1110				.on('touchend.daterangepicker', this._outsideClickProxy)
1111				// also explicitly play nice with Bootstrap dropdowns, which stopPropagation when clicking them
1112				.on('click.daterangepicker', '[data-toggle=dropdown]', this._outsideClickProxy)
vendor: 9,126 bytes, lines 1113-1378
1113				// and also close when focus changes to outside the picker (eg. tabbing between controls)
1114				.on('focusin.daterangepicker', this._outsideClickProxy);
1115
1116			// Reposition the picker if the window is resized while it's open
1117			$(window).on('resize.daterangepicker', $.proxy(function(e) { this.move(e); }, this));
1118
1119			this.oldStartDate = this.startDate.clone();
1120			this.oldEndDate = this.endDate.clone();
1121			this.previousRightTime = this.endDate.clone();
1122
1123			this.updateView();
1124			this.container.show();
1125			this.move();
1126			this.element.trigger('show.daterangepicker', this);
1127			this.isShowing = true;
1128		},
1129
1130		hide: function(e) {
1131			if (!this.isShowing) return;
1132
1133			//incomplete date selection, revert to last values
1134			if (!this.endDate) {
1135				this.startDate = this.oldStartDate.clone();
1136				this.endDate = this.oldEndDate.clone();
1137			}
1138
1139			//if a new date range was selected, invoke the user callback function
1140			if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate))
1141				this.callback(this.startDate, this.endDate, this.chosenLabel);
1142
1143			//if picker is attached to a text input, update it
1144			this.updateElement();
1145
1146			$(document).off('.daterangepicker');
1147			$(window).off('.daterangepicker');
1148			this.container.hide();
1149			this.element.trigger('hide.daterangepicker', this);
1150			this.isShowing = false;
1151		},
1152
1153		toggle: function(e) {
1154			if (this.isShowing) {
1155				this.hide();
1156			} else {
1157				this.show();
1158			}
1159		},
1160
1161		outsideClick: function(e) {
1162			var target = $(e.target);
1163			// if the page is clicked anywhere except within the daterangerpicker/button
1164			// itself then call this.hide()
1165			if (
1166				// ie modal dialog fix
1167				e.type == "focusin" ||
1168				target.closest(this.element).length ||
1169				target.closest(this.container).length ||
1170				target.closest('.calendar-table').length
1171			) return;
1172			this.hide();
1173			this.element.trigger('outsideClick.daterangepicker', this);
1174		},
1175
1176		showCalendars: function() {
1177			this.container.addClass('show-calendar');
1178			this.move();
1179			this.element.trigger('showCalendar.daterangepicker', this);
1180		},
1181
1182		hideCalendars: function() {
1183			this.container.removeClass('show-calendar');
1184			this.element.trigger('hideCalendar.daterangepicker', this);
1185		},
1186
1187		hoverRange: function(e) {
1188
1189			//ignore mouse movements while an above-calendar text input has focus
1190			if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus"))
1191				return;
1192
1193			var label = e.target.getAttribute('data-range-key');
1194
1195			if (label == this.locale.customRangeLabel) {
1196				this.updateView();
1197			} else {
1198				var dates = this.ranges[label];
1199				this.container.find('input[name=daterangepicker_start]').val(dates[0].format(this.locale.format));
1200				this.container.find('input[name=daterangepicker_end]').val(dates[1].format(this.locale.format));
1201			}
1202
1203		},
1204
1205		clickRange: function(e) {
1206			var label = e.target.getAttribute('data-range-key');
1207			this.chosenLabel = label;
1208			if (label == this.locale.customRangeLabel) {
1209				this.showCalendars();
1210			} else {
1211				var dates = this.ranges[label];
1212				this.startDate = dates[0];
1213				this.endDate = dates[1];
1214
1215				if (!this.timePicker) {
1216					this.startDate.startOf('day');
1217					this.endDate.endOf('day');
1218				}
1219
1220				if (!this.alwaysShowCalendars)
1221					this.hideCalendars();
1222				this.clickApply();
1223			}
1224		},
1225
1226		clickPrev: function(e) {
1227			var cal = $(e.target).parents('.calendar');
1228			if (cal.hasClass('left')) {
1229				this.leftCalendar.month.subtract(1, 'month');
1230				if (this.linkedCalendars)
1231					this.rightCalendar.month.subtract(1, 'month');
1232			} else {
1233				this.rightCalendar.month.subtract(1, 'month');
1234			}
1235			this.updateCalendars();
1236		},
1237
1238		clickNext: function(e) {
1239			var cal = $(e.target).parents('.calendar');
1240			if (cal.hasClass('left')) {
1241				this.leftCalendar.month.add(1, 'month');
1242			} else {
1243				this.rightCalendar.month.add(1, 'month');
1244				if (this.linkedCalendars)
1245					this.leftCalendar.month.add(1, 'month');
1246			}
1247			this.updateCalendars();
1248		},
1249
1250		hoverDate: function(e) {
1251
1252			//ignore mouse movements while an above-calendar text input has focus
1253			//if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus"))
1254			//    return;
1255
1256			//ignore dates that can't be selected
1257			if (!$(e.target).hasClass('available')) return;
1258
1259			//have the text inputs above calendars reflect the date being hovered over
1260			var title = $(e.target).attr('data-title');
1261			var row = title.substr(1, 1);
1262			var col = title.substr(3, 1);
1263			var cal = $(e.target).parents('.calendar');
1264			var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col];
1265
1266			if (this.endDate && !this.container.find('input[name=daterangepicker_start]').is(":focus")) {
1267				this.container.find('input[name=daterangepicker_start]').val(date.format(this.locale.format));
1268			} else if (!this.endDate && !this.container.find('input[name=daterangepicker_end]').is(":focus")) {
1269				this.container.find('input[name=daterangepicker_end]').val(date.format(this.locale.format));
1270			}
1271
1272			//highlight the dates between the start date and the date being hovered as a potential end date
1273			var leftCalendar = this.leftCalendar;
1274			var rightCalendar = this.rightCalendar;
1275			var startDate = this.startDate;
1276			if (!this.endDate) {
1277				this.container.find('.calendar tbody td').each(function(index, el) {
1278
1279					//skip week numbers, only look at dates
1280					if ($(el).hasClass('week')) return;
1281
1282					var title = $(el).attr('data-title');
1283					var row = title.substr(1, 1);
1284					var col = title.substr(3, 1);
1285					var cal = $(el).parents('.calendar');
1286					var dt = cal.hasClass('left') ? leftCalendar.calendar[row][col] : rightCalendar.calendar[row][col];
1287
1288					if ((dt.isAfter(startDate) && dt.isBefore(date)) || dt.isSame(date, 'day')) {
1289						$(el).addClass('in-range');
1290					} else {
1291						$(el).removeClass('in-range');
1292					}
1293
1294				});
1295			}
1296
1297		},
1298
1299		clickDate: function(e) {
1300
1301			if (!$(e.target).hasClass('available')) return;
1302
1303			var title = $(e.target).attr('data-title');
1304			var row = title.substr(1, 1);
1305			var col = title.substr(3, 1);
1306			var cal = $(e.target).parents('.calendar');
1307			var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col];
1308
1309			//
1310			// this function needs to do a few things:
1311			// * alternate between selecting a start and end date for the range,
1312			// * if the time picker is enabled, apply the hour/minute/second from the select boxes to the clicked date
1313			// * if autoapply is enabled, and an end date was chosen, apply the selection
1314			// * if single date picker mode, and time picker isn't enabled, apply the selection immediately
1315			// * if one of the inputs above the calendars was focused, cancel that manual input
1316			//
1317
1318			if (this.endDate || date.isBefore(this.startDate, 'day')) { //picking start
1319				if (this.timePicker) {
1320					var hour = parseInt(this.container.find('.left .hourselect').val(), 10);
1321					if (!this.timePicker24Hour) {
1322						var ampm = this.container.find('.left .ampmselect').val();
1323						if (ampm === 'PM' && hour < 12)
1324							hour += 12;
1325						if (ampm === 'AM' && hour === 12)
1326							hour = 0;
1327					}
1328					var minute = parseInt(this.container.find('.left .minuteselect').val(), 10);
1329					var second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0;
1330					date = date.clone().hour(hour).minute(minute).second(second);
1331				}
1332				this.endDate = null;
1333				this.setStartDate(date.clone());
1334			} else if (!this.endDate && date.isBefore(this.startDate)) {
1335				//special case: clicking the same date for start/end,
1336				//but the time of the end date is before the start date
1337				this.setEndDate(this.startDate.clone());
1338			} else { // picking end
1339				if (this.timePicker) {
1340					var hour = parseInt(this.container.find('.right .hourselect').val(), 10);
1341					if (!this.timePicker24Hour) {
1342						var ampm = this.container.find('.right .ampmselect').val();
1343						if (ampm === 'PM' && hour < 12)
1344							hour += 12;
1345						if (ampm === 'AM' && hour === 12)
1346							hour = 0;
1347					}
1348					var minute = parseInt(this.container.find('.right .minuteselect').val(), 10);
1349					var second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0;
1350					date = date.clone().hour(hour).minute(minute).second(second);
1351				}
1352				this.setEndDate(date.clone());
1353				if (this.autoApply) {
1354					this.calculateChosenLabel();
1355					this.clickApply();
1356				}
1357			}
1358
1359			if (this.singleDatePicker) {
1360				this.setEndDate(this.startDate);
1361				if (!this.timePicker)
1362					this.clickApply();
1363			}
1364
1365			this.updateView();
1366
1367			//This is to cancel the blur event handler if the mouse was in one of the inputs
1368			e.stopPropagation();
1369
1370		},
1371
1372		calculateChosenLabel: function () {
1373			var customRange = true;
1374			var i = 0;
1375			for (var range in this.ranges) {
1376				if (this.timePicker) {
1377					if (this.startDate.isSame(this.ranges[range][0]) && this.endDate.isSame(this.ranges[range][1])) {
1378						customRange = false;
1379						this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').html();
1380						break;
1381					}
1382				} else {
1383					//ignore times when comparing dates if time picker is not enabled
1384					if (this.startDate.format('YYYY-MM-DD') == this.ranges[range][0].format('YYYY-MM-DD') && this.endDate.format('YYYY-MM-DD') == this.ranges[range][1].format('YYYY-MM-DD')) {
1385						customRange = false;
1386						this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').html();
1387						break;
1388					}
1389				}
1390				i++;
1391			}
1392			if (customRange) {
1393				if (this.showCustomRangeLabel) {
1394					this.chosenLabel = this.container.find('.ranges li:last').addClass('active').html();
1395				} else {
1396					this.chosenLabel = null;
1397				}
1398				this.showCalendars();
1399			}
1400		},
1401
1402		clickApply: function(e) {
1403			this.hide();
1404			this.element.trigger('apply.daterangepicker', this);
1405		},
1406
1407		clickCancel: function(e) {
1408			this.startDate = this.oldStartDate;
1409			this.endDate = this.oldEndDate;
1410			this.hide();
1411			this.element.trigger('cancel.daterangepicker', this);
1412		},
1413
1414		monthOrYearChanged: function(e) {
1415			var isLeft = $(e.target).closest('.calendar').hasClass('left'),
1416				leftOrRight = isLeft ? 'left' : 'right',
1417				cal = this.container.find('.calendar.'+leftOrRight);
1418
1419			// Month must be Number for new moment versions
1420			var month = parseInt(cal.find('.monthselect').val(), 10);
1421			var year = cal.find('.yearselect').val();
1422
1423			if (!isLeft) {
1424				if (year < this.startDate.year() || (year == this.startDate.year() && month < this.startDate.month())) {
1425					month = this.startDate.month();
1426					year = this.startDate.year();
1427				}
1428			}
1429
1430			if (this.minDate) {
1431				if (year < this.minDate.year() || (year == this.minDate.year() && month < this.minDate.month())) {
1432					month = this.minDate.month();
1433					year = this.minDate.year();
1434				}
1435			}
1436
1437			if (this.maxDate) {
1438				if (year > this.maxDate.year() || (year == this.maxDate.year() && month > this.maxDate.month())) {
1439					month = this.maxDate.month();
1440					year = this.maxDate.year();
1441				}
1442			}
1443
1444			if (isLeft) {
1445				this.leftCalendar.month.month(month).year(year);
1446				if (this.linkedCalendars)
1447					this.rightCalendar.month = this.leftCalendar.month.clone().add(1, 'month');
1448			} else {
1449				this.rightCalendar.month.month(month).year(year);
1450				if (this.linkedCalendars)
1451					this.leftCalendar.month = this.rightCalendar.month.clone().subtract(1, 'month');
1452			}
1453			this.updateCalendars();
1454		},
1455
1456		timeChanged: function(e) {
1457
1458			var cal = $(e.target).closest('.calendar'),
1459				isLeft = cal.hasClass('left');
1460
1461			var hour = parseInt(cal.find('.hourselect').val(), 10);
1462			var minute = parseInt(cal.find('.minuteselect').val(), 10);
1463			var second = this.timePickerSeconds ? parseInt(cal.find('.secondselect').val(), 10) : 0;
1464
1465			if (!this.timePicker24Hour) {
1466				var ampm = cal.find('.ampmselect').val();
1467				if (ampm === 'PM' && hour < 12)
1468					hour += 12;
1469				if (ampm === 'AM' && hour === 12)
1470					hour = 0;
1471			}
1472
1473			if (isLeft) {
1474				var start = this.startDate.clone();
1475				start.hour(hour);
1476				start.minute(minute);
1477				start.second(second);
1478				this.setStartDate(start);
1479				if (this.singleDatePicker) {
1480					this.endDate = this.startDate.clone();
1481				} else if (this.endDate && this.endDate.format('YYYY-MM-DD') == start.format('YYYY-MM-DD') && this.endDate.isBefore(start)) {
1482					this.setEndDate(start.clone());
1483				}
1484			} else if (this.endDate) {
1485				var end = this.endDate.clone();
1486				end.hour(hour);
1487				end.minute(minute);
1488				end.second(second);
1489				this.setEndDate(end);
1490			}
1491
1492			//update the calendars so all clickable dates reflect the new time component
1493			this.updateCalendars();
1494
1495			//update the form inputs above the calendars with the new time
1496			this.updateFormInputs();
1497
1498			//re-render the time pickers because changing one selection can affect what's enabled in another
1499			this.renderTimePicker('left');
1500			this.renderTimePicker('right');
1501
1502		},
1503
1504		formInputsChanged: function(e) {
1505			var isRight = $(e.target).closest('.calendar').hasClass('right');
1506			var start = moment(this.container.find('input[name="daterangepicker_start"]').val(), this.locale.format);
1507			var end = moment(this.container.find('input[name="daterangepicker_end"]').val(), this.locale.format);
1508
1509			if (start.isValid() && end.isValid()) {
1510
1511				if (isRight && end.isBefore(start))
1512					start = end.clone();
1513
1514				this.setStartDate(start);
1515				this.setEndDate(end);
1516
1517				if (isRight) {
1518					this.container.find('input[name="daterangepicker_start"]').val(this.startDate.format(this.locale.format));
1519				} else {
1520					this.container.find('input[name="daterangepicker_end"]').val(this.endDate.format(this.locale.format));
1521				}
1522
1523			}
1524
1525			this.updateView();
1526		},
1527
1528		formInputsFocused: function(e) {
1529
1530			// Highlight the focused input
1531			this.container.find('input[name="daterangepicker_start"], input[name="daterangepicker_end"]').removeClass('active');
1532			$(e.target).addClass('active');
1533
1534			// Set the state such that if the user goes back to using a mouse,
1535			// the calendars are aware we're selecting the end of the range, not
1536			// the start. This allows someone to edit the end of a date range without
1537			// re-selecting the beginning, by clicking on the end date input then
1538			// using the calendar.
1539			var isRight = $(e.target).closest('.calendar').hasClass('right');
1540			if (isRight) {
1541				this.endDate = null;
1542				this.setStartDate(this.startDate.clone());
1543				this.updateView();
1544			}
1545
1546		},
1547
1548		formInputsBlurred: function(e) {
1549
1550			// this function has one purpose right now: if you tab from the first
1551			// text input to the second in the UI, the endDate is nulled so that
1552			// you can click another, but if you tab out without clicking anything
1553			// or changing the input value, the old endDate should be retained
1554
1555			if (!this.endDate) {
1556				var val = this.container.find('input[name="daterangepicker_end"]').val();
1557				var end = moment(val, this.locale.format);
1558				if (end.isValid()) {
1559					this.setEndDate(end);
1560					this.updateView();
1561				}
1562			}
1563
1564		},
1565
1566		elementChanged: function() {
1567			if (!this.element.is('input')) return;
1568			if (!this.element.val().length) return;
1569			if (this.element.val().length < this.locale.format.length) return;
1570
1571			var dateString = this.element.val().split(this.locale.separator),
1572				start = null,
1573				end = null;
1574
1575			if (dateString.length === 2) {
1576				start = moment(dateString[0], this.locale.format);
1577				end = moment(dateString[1], this.locale.format);
1578			}
1579
1580			if (this.singleDatePicker || start === null || end === null) {
1581				start = moment(this.element.val(), this.locale.format);
1582				end = start;
1583			}
1584
1585			if (!start.isValid() || !end.isValid()) return;
1586
1587			this.setStartDate(start);
1588			this.setEndDate(end);
1589			this.updateView();
1590		},
1591
1592		keydown: function(e) {
1593			//hide on tab or enter
1594			if ((e.keyCode === 9) || (e.keyCode === 13)) {
1595				this.hide();
1596			}
1597		},
1598
1599		updateElement: function() {
1600			if (this.element.is('input') && !this.singleDatePicker && this.autoUpdateInput) {
1601				this.element.val(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format));
1602				this.element.trigger('change');
1603			} else if (this.element.is('input') && this.autoUpdateInput) {
1604				this.element.val(this.startDate.format(this.locale.format));
1605				this.element.trigger('change');
1606			}
1607		},
1608
1609		remove: function() {
1610			this.container.remove();
1611			this.element.off('.daterangepicker');
1612			this.element.removeData();
1613		}
1614
1615	};
1616
1617	$.fn.daterangepicker = function(options, callback) {
1618		this.each(function() {
1619			var el = $(this);
1620			if (el.data('daterangepicker'))
1621				el.data('daterangepicker').remove();
1622			el.data('daterangepicker', new DateRangePicker(el, options, callback));
1623		});
1624		return this;
1625	};
1626
1627	return DateRangePicker;
1628
1629}));
1630

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.