PageSourceSearch

https://rehab.ie/wp-content/plugins/wc-frontend-manager/includes/l…/jquery.daterangepicker.js?ver=6.8.1

js rehab.ie collected 2026-10-02 03:03:54 UTC 51,365 bytes, 1,841 lines download raw bytes

1// jquery.daterangepicker.js
2// author : Chunlong Liu
3// license : MIT
4// www.jszen.com
5
6(function (factory) {
7		if (typeof define === 'function' && define.amd) {
8			// AMD. Register as an anonymous module.
9			define(['jquery', 'moment'], factory);
10		} else if (typeof exports === 'object' && typeof module !== 'undefined') {
11			// CommonJS. Register as a module
12			module.exports = factory(require('jquery'), require('moment'));
13		} else {
14			// Browser globals
15			factory(jQuery, moment);
16		}
17}(function ($, moment)
18{
19    'use strict';
20	$.dateRangePickerLanguages =
21	{
22		'default':  //default language: English
23		{
24			'selected': 'Selected:',
25			'day':'Day',
26			'days': 'Days',
27			'apply': 'Close',
28			'week-1' : 'mo',
29			'week-2' : 'tu',
30			'week-3' : 'we',
31			'week-4' : 'th',
32			'week-5' : 'fr',
33			'week-6' : 'sa',
34			'week-7' : 'su',
35			'week-number': 'W',
36			'month-name': ['january','february','march','april','may','june','july','august','september','october','november','december'],
37			'shortcuts' : 'Shortcuts',
38			'custom-values': 'Custom Values',
39			'past': 'Past',
40			'following':'Following',
41			'previous' : 'Previous',
42			'prev-week' : 'Week',
43			'prev-month' : 'Month',
44			'prev-year' : 'Year',
45			'next':'Next',
46			'next-week':'Week',
47			'next-month':'Month',
48			'next-year':'Year',
49			'less-than' : 'Date range should not be more than %d days',
50			'more-than' : 'Date range should not be less than %d days',
51			'default-more' : 'Please select a date range longer than %d days',
52			'default-single' : 'Please select a date',
53			'default-less' : 'Please select a date range less than %d days',
54			'default-range' : 'Please select a date range between %d and %d days',
55			'default-default': 'Please select a date range',
56			'time':'Time',
57			'hour':'Hour',
58			'minute':'Minute'
59		},
60	};
61
62	$.fn.dateRangePicker = function(opt)
63	{
64		if (!opt) opt = {};
65		opt = $.extend(true,
66		{
67			autoClose: false,
68			format: 'YYYY-MM-DD',
69			separator: ' to ',
70			language: 'auto',
71			startOfWeek: 'sunday',// or monday
72			getValue: function()
73			{
74				return $(this).val();
75			},
76			setValue: function(s)
77			{
78				if(!$(this).attr('readonly') && !$(this).is(':disabled') && s != $(this).val())
79				{
80					$(this).val(s);
81				}
82			},
83			startDate: false,
84			endDate: false,
85			time: {
86				enabled: false
87			},
88			minDays: 0,
89			maxDays: 0,
90			showShortcuts: false,
91			shortcuts:
92			{
93				//'prev-days': [1,3,5,7],
94				// 'next-days': [3,5,7],
95				//'prev' : ['week','month','year'],
96				// 'next' : ['week','month','year']
97			},
98			customShortcuts : [],
99			inline:false,
100			container:'body',
101			alwaysOpen:false,
102			singleDate:false,
103			lookBehind: false,
104			batchMode: false,
105			duration: 200,
106			stickyMonths: false,
107			dayDivAttrs: [],
108			dayTdAttrs: [],
109			selectForward: false,
110			selectBackward: false,
111			applyBtnClass: '',
112			singleMonth: 'auto',
113			hoveringTooltip: function(days, startTime, hoveringTime)
114			{
115				return days > 1 ? days + ' ' + lang('days') : '';
116			},
117			showTopbar: true,
118			swapTime: false,
119			showWeekNumbers: false,
120			getWeekNumber: function(date) //date will be the first day of a week
121			{
122				return moment(date).format('w');
123			},
124			customOpenAnimation: null,
125			customCloseAnimation: null
126		},opt);
127
128		opt.start = false;
129		opt.end = false;
130
131		opt.startWeek = false;
132
133		//detect a touch device
134		opt.isTouchDevice = 'ontouchstart' in window || navigator.msMaxTouchPoints;
135
136		//if it is a touch device, hide hovering tooltip
137		if (opt.isTouchDevice) opt.hoveringTooltip = false;
138
139		//show one month on mobile devices
140		if (opt.singleMonth == 'auto') opt.singleMonth = $(window).width() < 480;
141		if (opt.singleMonth) opt.stickyMonths = false;
142
143		if (!opt.showTopbar) opt.autoClose = true;
144
145		if (opt.startDate && typeof opt.startDate == 'string') opt.startDate = moment(opt.startDate,opt.format).toDate();
146		if (opt.endDate && typeof opt.endDate == 'string') opt.endDate = moment(opt.endDate,opt.format).toDate();
147
148		var langs = getLanguages();
149		var box;
150		var initiated = false;
151		var self = this;
152		var selfDom = $(self).get(0);
153		var domChangeTimer;
154
155		$(this).unbind('.datepicker').bind('click.datepicker',function(evt)
156		{
157			var isOpen = box.is(':visible');
158			if(!isOpen) open(opt.duration);
159		}).bind('change.datepicker', function(evt)
160		{
161			checkAndSetDefaultValue();
162		}).bind('keyup.datepicker',function()
163		{
164			try{ clearTimeout(domChangeTimer); }catch(e){}
165			domChangeTimer = setTimeout(function()
166			{
167				checkAndSetDefaultValue();
168			},2000);
169		});
170
171		init_datepicker.call(this);
172
173		if (opt.alwaysOpen)
174		{
175			open(0);
176		}
177
178		// expose some api
179		$(this).data('dateRangePicker',
180		{
181			setDateRange : function(d1,d2,silent)
182			{
183				if (typeof d1 == 'string' && typeof d2 == 'string')
184				{
185					d1 = moment(d1,opt.format).toDate();
186					d2 = moment(d2,opt.format).toDate();
187				}
188				setDateRange(d1,d2,silent);
189			},
190			clear: clearSelection,
191			close: closeDatePicker,
192			open: open,
193			redraw: redrawDatePicker,
194			getDatePicker: getDatePicker,
195			resetMonthsView: resetMonthsView,
196			destroy: function()
197			{
198				$(self).unbind('.datepicker');
199				$(self).data('dateRangePicker','');
200				$(self).data('date-picker-opened',null);
201				box.remove();
202				$(window).unbind('resize.datepicker',calcPosition);
203				$(document).unbind('click.datepicker',closeDatePicker);
204			}
205		});
206
207		$(window).bind('resize.datepicker',calcPosition);
208
209		return this;
210
211		function IsOwnDatePickerClicked(evt, selfObj)
212		{
213			return ( selfObj.contains(evt.target) || evt.target == selfObj  || (selfObj.childNodes != undefined && $.inArray(evt.target, selfObj.childNodes)>=0));
214		}
215
216		function init_datepicker()
217		{
218			var self = this;
219
220			if ($(this).data('date-picker-opened'))
221			{
222				closeDatePicker();
223				return;
224			}
225			$(this).data('date-picker-opened',true);
226
227
228			box = createDom().hide();
229			box.append('<div class="date-range-length-tip"></div>');
230			box.delegate('.day', 'mouseleave', function()
231			{
232				box.find('.date-range-length-tip').hide();
233				if (opt.singleDate) {
234				    clearHovering();
235				}
236			});
237
238			$(opt.container).append(box);
239
240			if (!opt.inline)
241			{
242				calcPosition();
243			}
244			else
245			{
246				box.addClass('inline-wrapper');
247			}
248
249			if (opt.alwaysOpen)
250			{
251				box.find('.apply-btn').hide();
252			}
253
254			var defaultTime = getDefaultTime();
255			resetMonthsView(defaultTime);
256
257			if (opt.time.enabled)
258			{
259				if ((opt.startDate && opt.endDate) || (opt.start && opt.end)) {
260					showTime(moment(opt.start || opt.startDate).toDate(),'time1');
261					showTime(moment(opt.end || opt.endDate).toDate(),'time2');
262				} else {
263					var defaultEndTime = opt.defaultEndTime ? opt.defaultEndTime : defaultTime;
264					showTime(defaultTime,'time1');
265					showTime(defaultEndTime,'time2');
266				}
267			}
268
269			//showSelectedInfo();
270
271
272			var defaultTopText = '';
273			if (opt.singleDate)
274				defaultTopText = lang('default-single');
275			else if (opt.minDays && opt.maxDays)
276				defaultTopText = lang('default-range');
277			else if (opt.minDays)
278				defaultTopText = lang('default-more');
279			else if (opt.maxDays)
280				defaultTopText = lang('default-less');
281			else
282				defaultTopText = lang('default-default');
283
284			box.find('.default-top').html( defaultTopText.replace(/\%d/,opt.minDays).replace(/\%d/,opt.maxDays));
285			if (opt.singleMonth)
286			{
287				box.addClass('single-month');
288			}
289			else
290			{
291				box.addClass('two-months');
292			}
293
294
295			setTimeout(function()
296			{
297				updateCalendarWidth();
298				initiated = true;
299			},0);
300
301			box.click(function(evt)
302			{
303				evt.stopPropagation();
304			});
305
306			//if user click other place of the webpage, close date range picker window
307			$(document).bind('click.datepicker',function(evt)
308			{
309				if (!IsOwnDatePickerClicked(evt, self[0])) {
310					if (box.is(':visible')) closeDatePicker();
311				}
312			});
313
314			box.find('.next').click(function()
315			{
316				if(!opt.stickyMonths)
317					gotoNextMonth(this);
318				else
319					gotoNextMonth_stickily(this);
320			});
321
322			function gotoNextMonth(self)
323			{
324				var isMonth2 = $(self).parents('table').hasClass('month2');
325				var month = isMonth2 ? opt.month2 : opt.month1;
326				month = nextMonth(month);
327				if (!opt.singleMonth && !opt.singleDate && !isMonth2 && compare_month(month,opt.month2) >= 0 || isMonthOutOfBounds(month)) return;
328				showMonth(month,isMonth2 ? 'month2' : 'month1');
329				showGap();
330			}
331
332			function gotoNextMonth_stickily(self) {
333				var nextMonth1 = nextMonth(opt.month1);
334				var nextMonth2 = nextMonth(opt.month2);
335				if(isMonthOutOfBounds(nextMonth2)) return;
336				if (!opt.singleDate && compare_month(nextMonth1,nextMonth2) >= 0) return;
337				showMonth(nextMonth1, 'month1');
338				showMonth(nextMonth2, 'month2');
339				showSelectedDays();
340			}
341
342
343			box.find('.prev').click(function()
344			{
345				if(!opt.stickyMonths)
346					gotoPrevMonth(this);
347				else
348					gotoPrevMonth_stickily(this);
349			});
350
351			function gotoPrevMonth(self) {
352				var isMonth2 = $(self).parents('table').hasClass('month2');
353				var month = isMonth2 ? opt.month2 : opt.month1;
354				month = prevMonth(month);
355				if (isMonth2 && compare_month(month,opt.month1) <= 0 || isMonthOutOfBounds(month)) return;
356				showMonth(month,isMonth2 ? 'month2' : 'month1');
357				showGap();
358			}
359
360			function gotoPrevMonth_stickily(self)
361			{
362				var prevMonth1 = prevMonth(opt.month1);
363				var prevMonth2 = prevMonth(opt.month2);
364				if(isMonthOutOfBounds(prevMonth1)) return;
365				if(!opt.singleDate && compare_month(prevMonth2,prevMonth1) <= 0) return;
366				showMonth(prevMonth2, 'month2');
367				showMonth(prevMonth1, 'month1');
368				showSelectedDays();
369			}
370
371			box.delegate('.day','click', function(evt)
372			{
373				dayClicked($(this));
374			});
375
376			box.delegate('.day','mouseenter',function(evt)
377			{
378				dayHovering($(this));
379			});
380
381			box.delegate('.week-number', 'click', function(evt)
382			{
383				weekNumberClicked($(this));
384			});
385
386			box.attr('unselectable', 'on')
387			.css('user-select', 'none')
388			.bind('selectstart', function(e)
389			{
390				e.preventDefault(); return false;
391			});
392
393			box.find('.apply-btn').click(function()
394			{
395				closeDatePicker();
396				var dateRange = getDateString(new Date(opt.start))+ opt.separator +getDateString(new Date(opt.end));
397				$(self).trigger('datepicker-apply',
398				{
399					'value': dateRange,
400					'date1' : new Date(opt.start),
401					'date2' : new Date(opt.end)
402				});
403			});
404
405			box.find('[custom]').click(function()
406			{
407				var valueName = $(this).attr('custom');
408				opt.start = false;
409				opt.end = false;
410				box.find('.day.checked').removeClass('checked');
411				opt.setValue.call(selfDom, valueName);
412				checkSelectionValid();
413				showSelectedInfo(true);
414				showSelectedDays();
415				if (opt.autoClose) closeDatePicker();
416			});
417
418			box.find('[shortcut]').click(function()
419			{
420				var shortcut = $(this).attr('shortcut');
421				var end = new Date(),start = false;
422                var dir;
423				if (shortcut.indexOf('day') != -1)
424				{
425					var day = parseInt(shortcut.split(',',2)[1],10);
426					start = new Date(new Date().getTime() + 86400000*day);
427					end = new Date(end.getTime() + 86400000*(day>0?1:-1) );
428				}
429				else if (shortcut.indexOf('week')!= -1)
430				{
431					dir = shortcut.indexOf('prev,') != -1 ? -1 : 1;
432                    var stopDay;
433					if (dir == 1)
434						 stopDay = opt.startOfWeek == 'monday' ? 1 : 0;
435					else
436						 stopDay = opt.startOfWeek == 'monday' ? 0 : 6;
437
438					end = new Date(end.getTime() - 86400000);
439					while(end.getDay() != stopDay) end = new Date(end.getTime() + dir*86400000);
440					start = new Date(end.getTime() + dir*86400000*6);
441				}
442				else if (shortcut.indexOf('month') != -1)
443				{
444					dir = shortcut.indexOf('prev,') != -1 ? -1 : 1;
445					if (dir == 1)
446						start = nextMonth(end);
447					else
448						start = prevMonth(end);
449					start.setDate(1);
450					end = nextMonth(start);
451					end.setDate(1);
452					end = new Date(end.getTime() - 86400000);
453				}
454				else if (shortcut.indexOf('year') != -1)
455				{
456					dir = shortcut.indexOf('prev,') != -1 ? -1 : 1;
457					start = new Date();
458					start.setFullYear(end.getFullYear() + dir);
459					start.setMonth(0);
460					start.setDate(1);
461					end.setFullYear(end.getFullYear() + dir);
462					end.setMonth(11);
463					end.setDate(31);
464				}
465				else if (shortcut == 'custom')
466				{
467					var name = $(this).html();
468					if (opt.customShortcuts && opt.customShortcuts.length > 0)
469					{
470						for(var i=0;i<opt.customShortcuts.length;i++)
471						{
472							var sh = opt.customShortcuts[i];
473							if (sh.name == name)
474							{
475								var data = [];
476								// try
477								// {
478									data = sh['dates'].call();
479								//}catch(e){}
480								if (data && data.length == 2)
481								{
482									start = data[0];
483									end = data[1];
484								}
485
486								// if only one date is specified then just move calendars there
487								// move calendars to show this date's month and next months
488								if (data && data.length == 1)
489								{
490									var movetodate = data[0];
491									showMonth(movetodate,'month1');
492									showMonth(nextMonth(movetodate),'month2');
493									showGap();
494								}
495
496								break;
497							}
498						}
499					}
500				}
501				if (start && end)
502				{
503					setDateRange(start,end);
504					checkSelectionValid();
505				}
506			});
507
508			box.find('.time1 input[type=range]').bind('change touchmove mousemove', function (e) {
509				var target = e.target,
510					hour = target.name == 'hour' ? $(target).val().replace(/^(\d{1})$/, '0$1') : undefined,
511					min = target.name == 'minute' ? $(target).val().replace(/^(\d{1})$/, '0$1') : undefined;
512				setTime('time1', hour, min);
513			});
514
515			box.find('.time2 input[type=range]').bind('change touchmove mousemove', function (e) {
516				var target = e.target,
517					hour = target.name == 'hour' ? $(target).val().replace(/^(\d{1})$/, '0$1') : undefined,
518					min = target.name == 'minute' ? $(target).val().replace(/^(\d{1})$/, '0$1') : undefined;
519				setTime('time2', hour, min);
520			});
521
522		}
523
524
525		function calcPosition()
526		{
527			if (!opt.inline)
528			{
529				var offset = $(self).offset();
530				if ($(opt.container).css('position') == 'relative')
531				{
532					var containerOffset = $(opt.container).offset();
533					box.css(
534					{
535						top: offset.top - containerOffset.top + $(self).outerHeight() + 4,
536						left: offset.left - containerOffset.left
537					});
538				}
539				else
540				{
541					if (offset.left < 460) //left to right
542					{
543						box.css(
544						{
545							top: offset.top+$(self).outerHeight() + parseInt($('body').css('border-top') || 0,10 ),
546							left: offset.left
547						});
548					}
549					else
550					{
551						box.css(
552						{
553							top: offset.top+$(self).outerHeight() + parseInt($('body').css('border-top') || 0,10 ),
554							left: offset.left + $(self).width() - box.width() - 16
555						});
556					}
557				}
558			}
559		}
560
561		// Return the date picker wrapper element
562		function getDatePicker()
563		{
564			return box;
565		}
566
567		function open(animationTime)
568		{
569			calcPosition();
570			redrawDatePicker();
571			checkAndSetDefaultValue();
572			if (opt.customOpenAnimation)
573			{
574				opt.customOpenAnimation.call(box.get(0), function()
575				{
576					$(self).trigger('datepicker-opened', {relatedTarget: box});
577				});
578			}
579			else
580			{
581				box.slideDown(animationTime, function(){
582					$(self).trigger('datepicker-opened', {relatedTarget: box});
583				});
584			}
585			$(self).trigger('datepicker-open', {relatedTarget: box});
586			showGap();
587			updateCalendarWidth();
588		}
589
590		function checkAndSetDefaultValue()
591		{
592			var __default_string = opt.getValue.call(selfDom);
593			var defaults = __default_string ? __default_string.split( opt.separator ) : '';
594
595			if (defaults && ((defaults.length==1 && opt.singleDate) || defaults.length>=2))
596			{
597				var ___format = opt.format;
598				if (___format.match(/Do/))
599				{
600
601					___format = ___format.replace(/Do/,'D');
602					defaults[0] = defaults[0].replace(/(\d+)(th|nd|st)/,'$1');
603					if(defaults.length >= 2){
604						defaults[1] = defaults[1].replace(/(\d+)(th|nd|st)/,'$1');
605					}
606				}
607				// set initiated  to avoid triggerring datepicker-change event
608				initiated = false;
609				if(defaults.length >= 2){
610					setDateRange(getValidValue(defaults[0], ___format, moment.locale(opt.language)),getValidValue(defaults[1], ___format, moment.locale(opt.language)));
611				}
612				else if(defaults.length==1 && opt.singleDate){
613					setSingleDate(getValidValue(defaults[0], ___format, moment.locale(opt.language)));
614				}
615
616				initiated = true;
617			}
618		}
619
620		function getValidValue(date, format, locale) {
621			if (moment(date, format, locale).isValid()) {
622				return moment(date, format, locale).toDate();
623			} else {
624				return moment().toDate();
625			}
626		}
627
628		function updateCalendarWidth()
629		{
630			var gapMargin = box.find('.gap').css('margin-left');
631			if (gapMargin) gapMargin = parseInt(gapMargin);
632			var w1 = box.find('.month1').width();
633			var w2 = box.find('.gap').width() + ( gapMargin ? gapMargin*2 : 0 );
634			var w3 = box.find('.month2').width();
635			box.find('.month-wrapper').width(w1 + w2 + w3);
636		}
637
638		function renderTime (name, date) {
639			box.find('.' + name + ' input[type=range].hour-range').val(moment(date).hours());
640			box.find('.' + name + ' input[type=range].minute-range').val(moment(date).minutes());
641			setTime(name, moment(date).format('HH'), moment(date).format('mm'));
642		}
643
644		function changeTime (name, date) {
645			opt[name] = parseInt(
646				moment(parseInt(date))
647					.startOf('day')
648					.add(moment(opt[name + 'Time']).format('HH'), 'h')
649					.add(moment(opt[name + 'Time']).format('mm'), 'm').valueOf()
650				);
651		}
652
653		function swapTime () {
654			renderTime('time1', opt.start);
655			renderTime('time2', opt.end);
656		}
657
658		function setTime (name, hour, minute)
659		{
660			hour && (box.find('.' + name + ' .hour-val').text(hour));
661			minute && (box.find('.' + name + ' .minute-val').text(minute));
662			switch (name) {
663				case 'time1':
664					if (opt.start) {
665						setRange('start', moment(opt.start));
666					}
667					setRange('startTime', moment(opt.startTime || moment().valueOf()));
668					break;
669				case 'time2':
670					if (opt.end) {
671						setRange('end', moment(opt.end));
672					}
673					setRange('endTime', moment(opt.endTime || moment().valueOf()));
674					break;
675			}
676			function setRange(name, timePoint) {
677				var h = timePoint.format('HH'),
678					m = timePoint.format('mm');
679				opt[name] = timePoint
680					.startOf('day')
681					.add(hour || h, 'h')
682					.add(minute || m, 'm')
683					.valueOf();
684			}
685			checkSelectionValid();
686			showSelectedInfo();
687			showSelectedDays();
688		}
689
690		function clearSelection()
691		{
692			opt.start = false;
693			opt.end = false;
694			box.find('.day.checked').removeClass('checked');
695			box.find('.day.last-date-selected').removeClass('last-date-selected');
696			box.find('.day.first-date-selected').removeClass('first-date-selected');
697			opt.setValue.call(selfDom, '');
698			checkSelectionValid();
699			showSelectedInfo();
700			showSelectedDays();
701		}
702
703		function handleStart(time)
704		{
705			var r = time;
706			if  (opt.batchMode === 'week-range')
707			{
708				if (opt.startOfWeek === 'monday')
709				{
710					r = moment(parseInt(time)).startOf('isoweek').valueOf();
711				}
712				else
713				{
714					r = moment(parseInt(time)).startOf('week').valueOf();
715				}
716			}
717			else if (opt.batchMode === 'month-range')
718			{
719				r = moment(parseInt(time)).startOf('month').valueOf();
720			}
721			return r;
722		}
723
724		function handleEnd(time)
725		{
726			var r = time;
727			if  (opt.batchMode === 'week-range')
728			{
729				if (opt.startOfWeek === 'monday')
730				{
731					r = moment(parseInt(time)).endOf('isoweek').valueOf();
732				}
733				else
734				{
735					r = moment(parseInt(time)).endOf('week').valueOf();
736				}
737			}
738			else if (opt.batchMode === 'month-range')
739			{
740				r = moment(parseInt(time)).endOf('month').valueOf();
741			}
742			return r;
743		}
744
745
746		function dayClicked(day)
747		{
748			if (day.hasClass('invalid')) return;
749			var time = day.attr('time');
750			day.addClass('checked');
751			if ( opt.singleDate )
752			{
753				opt.start = time;
754				opt.end = false;
755			}
756			else if  (opt.batchMode === 'week')
757			{
758				if (opt.startOfWeek === 'monday') {
759					opt.start = moment(parseInt(time)).startOf('isoweek').valueOf();
760					opt.end = moment(parseInt(time)).endOf('isoweek').valueOf();
761				} else {
762					opt.end = moment(parseInt(time)).endOf('week').valueOf();
763					opt.start = moment(parseInt(time)).startOf('week').valueOf();
764				}
765			}
766			else if  (opt.batchMode === 'workweek')
767			{
768				opt.start = moment(parseInt(time)).day(1).valueOf();
769				opt.end = moment(parseInt(time)).day(5).valueOf();
770			}
771			else if  (opt.batchMode === 'weekend')
772			{
773				opt.start = moment(parseInt(time)).day(6).valueOf();
774				opt.end = moment(parseInt(time)).day(7).valueOf();
775			}
776			else if (opt.batchMode === 'month')
777			{
778				opt.start = moment(parseInt(time)).startOf('month').valueOf();
779				opt.end = moment(parseInt(time)).endOf('month').valueOf();
780			}
781			else if ((opt.start && opt.end) || (!opt.start && !opt.end) )
782			{
783				opt.start = handleStart(time);
784				opt.end = false;
785			}
786			else if (opt.start)
787			{
788				opt.end = handleEnd(time);
789				if (opt.time.enabled) {
790					changeTime('end', opt.end);
791				}
792			}
793
794			//Update time in case it is enabled and timestamps are available
795			if(opt.time.enabled) {
796				if(opt.start) {
797					changeTime('start', opt.start);
798				}
799				if(opt.end) {
800					changeTime('end', opt.end);
801				}
802			}
803
804			//In case the start is after the end, swap the timestamps
805			if (!opt.singleDate && opt.start && opt.end && opt.start > opt.end)
806			{
807				var tmp = opt.end;
808				opt.end = handleEnd(opt.start);
809				opt.start = handleStart(tmp);
810				if (opt.time.enabled && opt.swapTime) {
811					swapTime();
812				}
813			}
814
815			opt.start = parseInt(opt.start);
816			opt.end = parseInt(opt.end);
817
818			clearHovering();
819			if (opt.start && !opt.end)
820			{
821				$(self).trigger('datepicker-first-date-selected',
822				{
823					'date1' : new Date(opt.start)
824				});
825				dayHovering(day);
826			}
827			updateSelectableRange(time);
828
829			checkSelectionValid();
830			showSelectedInfo();
831			showSelectedDays();
832			autoclose();
833		}
834
835
836		function weekNumberClicked(weekNumberDom)
837		{
838			var thisTime = parseInt(weekNumberDom.attr('data-start-time'),10);
839            var date1,date2;
840			if (!opt.startWeek)
841			{
842				opt.startWeek = thisTime;
843				weekNumberDom.addClass('week-number-selected');
844				date1 = new Date(thisTime);
845				opt.start = moment(date1).day(opt.startOfWeek == 'monday' ? 1 : 0).valueOf();
846				opt.end = moment(date1).day(opt.startOfWeek == 'monday' ? 7 : 6).valueOf();
847			}
848			else
849			{
850				box.find('.week-number-selected').removeClass('week-number-selected');
851				date1 = new Date(thisTime < opt.startWeek ? thisTime : opt.startWeek);
852				date2 = new Date(thisTime < opt.startWeek ? opt.startWeek : thisTime);
853				opt.startWeek = false;
854				opt.start = moment(date1).day(opt.startOfWeek == 'monday' ? 1 : 0).valueOf();
855				opt.end = moment(date2).day(opt.startOfWeek == 'monday' ? 7 : 6).valueOf();
856			}
857			updateSelectableRange();
858			checkSelectionValid();
859			showSelectedInfo();
860			showSelectedDays();
861			autoclose();
862		}
863
864		function isValidTime(time)
865		{
866			time = parseInt(time, 10);
867			if (opt.startDate && compare_day(time, opt.startDate) < 0) return false;
868			if (opt.endDate && compare_day(time, opt.endDate) > 0) return false;
869
870			if (opt.start && !opt.end && !opt.singleDate)
871			{
872				//check maxDays and minDays setting
873				if (opt.maxDays > 0 && countDays(time, opt.start) > opt.maxDays) return false;
874				if (opt.minDays > 0 && countDays(time, opt.start) < opt.minDays) return false;
875
876				//check selectForward and selectBackward
877				if (opt.selectForward && time < opt.start ) return false;
878				if (opt.selectBackward && time > opt.start) return false;
879
880				//check disabled days
881				if (opt.beforeShowDay && typeof opt.beforeShowDay == 'function')
882				{
883					var valid = true;
884					var timeTmp = time;
885					while( countDays(timeTmp, opt.start) > 1 )
886					{
887						var arr = opt.beforeShowDay( new Date(timeTmp) );
888						if (!arr[0])
889						{
890							valid = false;
891							break;
892						}
893						if (Math.abs(timeTmp - opt.start) < 86400000) break;
894						if (timeTmp > opt.start) timeTmp -= 86400000;
895						if (timeTmp < opt.start) timeTmp += 86400000;
896					}
897					if (!valid) return false;
898				}
899			}
900			return true;
901		}
902
903
904		function updateSelectableRange()
905		{
906			box.find('.day.invalid.tmp').removeClass('tmp invalid').addClass('valid');
907			if (opt.start && !opt.end)
908			{
909				box.find('.day.toMonth.valid').each(function()
910				{
911					var time = parseInt($(this).attr('time'), 10);
912					if (!isValidTime(time))
913						$(this).addClass('invalid tmp').removeClass('valid');
914					else
915						$(this).addClass('valid tmp').removeClass('invalid');
916				});
917			}
918
919			return true;
920		}
921
922
923		function dayHovering(day)
924		{
925			var hoverTime = parseInt(day.attr('time'));
926			var tooltip = '';
927
928			if (day.hasClass('has-tooltip') && day.attr('data-tooltip'))
929			{
930				tooltip = '<span style="white-space:nowrap">'+day.attr('data-tooltip')+'</span>';
931			}
932			else if (!day.hasClass('invalid'))
933			{
934				if (opt.singleDate)
935				{
936					box.find('.day.hovering').removeClass('hovering');
937					day.addClass('hovering');
938				}
939				else
940				{
941					box.find('.day').each(function()
942					{
943						var time = parseInt($(this).attr('time')),
944							start = opt.start,
945							end = opt.end;
946
947						if ( time == hoverTime )
948						{
949							$(this).addClass('hovering');
950						}
951						else
952						{
953							$(this).removeClass('hovering');
954						}
955
956						if (
957							( opt.start && !opt.end ) &&
958							(
959								( opt.start < time && hoverTime >= time ) ||
960								( opt.start > time && hoverTime <= time )
961							)
962						)
963						{
964							$(this).addClass('hovering');
965						}
966						else
967						{
968							$(this).removeClass('hovering');
969						}
970					});
971
972					if (opt.start && !opt.end)
973					{
974						var days = countDays(hoverTime, opt.start);
975						if (opt.hoveringTooltip)
976						{
977							if (typeof opt.hoveringTooltip == 'function')
978							{
979								tooltip = opt.hoveringTooltip(days, opt.start, hoverTime);
980							}
981							else if (opt.hoveringTooltip === true && days > 1)
982							{
983								tooltip = days + ' ' + lang('days');
984							}
985						}
986					}
987				}
988			}
989
990			if (tooltip)
991			{
992				var posDay = day.offset();
993				var posBox = box.offset();
994
995				var _left = posDay.left - posBox.left;
996				var _top = posDay.top - posBox.top;
997				_left += day.width()/2;
998
999
1000				var $tip = box.find('.date-range-length-tip');
1001				var w = $tip.css({'visibility':'hidden', 'display':'none'}).html(tooltip).width();
1002				var h = $tip.height();
1003				_left -= w/2;
1004				_top -= h;
1005				setTimeout(function()
1006				{
1007					$tip.css({left:_left, top:_top, display:'block','visibility':'visible'});
1008				},10);
1009			}
1010			else
1011			{
1012				box.find('.date-range-length-tip').hide();
1013			}
1014		}
1015
1016		function clearHovering()
1017		{
1018			box.find('.day.hovering').removeClass('hovering');
1019			box.find('.date-range-length-tip').hide();
1020		}
1021
1022		function autoclose () {
1023			if (opt.singleDate === true) {
1024				if (initiated && opt.start )
1025				{
1026					if (opt.autoClose) closeDatePicker();
1027				}
1028			} else {
1029				if (initiated && opt.start && opt.end)
1030				{
1031					if (opt.autoClose) closeDatePicker();
1032				}
1033			}
1034		}
1035
1036		function checkSelectionValid()
1037		{
1038			var days = Math.ceil( (opt.end - opt.start) / 86400000 ) + 1;
1039			if (opt.singleDate) { // Validate if only start is there
1040				if (opt.start && !opt.end)
1041					box.find('.drp_top-bar').removeClass('error').addClass('normal');
1042				else
1043					box.find('.drp_top-bar').removeClass('error').removeClass('normal');
1044			}
1045			else if ( opt.maxDays && days > opt.maxDays)
1046			{
1047				opt.start = false;
1048				opt.end = false;
1049				box.find('.day').removeClass('checked');
1050				box.find('.drp_top-bar').removeClass('normal').addClass('error').find('.error-top').html( lang('less-than').replace('%d',opt.maxDays) );
1051			}
1052			else if ( opt.minDays && days < opt.minDays)
1053			{
1054				opt.start = false;
1055				opt.end = false;
1056				box.find('.day').removeClass('checked');
1057				box.find('.drp_top-bar').removeClass('normal').addClass('error').find('.error-top').html( lang('more-than').replace('%d',opt.minDays) );
1058			}
1059			else
1060			{
1061				if (opt.start || opt.end)
1062					box.find('.drp_top-bar').removeClass('error').addClass('normal');
1063				else
1064					box.find('.drp_top-bar').removeClass('error').removeClass('normal');
1065			}
1066
1067			if ( (opt.singleDate && opt.start && !opt.end) || (!opt.singleDate && opt.start && opt.end) )
1068			{
1069				box.find('.apply-btn').removeClass('disabled');
1070			}
1071			else
1072			{
1073				box.find('.apply-btn').addClass('disabled');
1074			}
1075
1076			if (opt.batchMode)
1077			{
1078				if (
1079					(opt.start && opt.startDate && compare_day(opt.start, opt.startDate) < 0) ||
1080					(opt.end && opt.endDate && compare_day(opt.end, opt.endDate) > 0)
1081				) {
1082					opt.start = false;
1083					opt.end = false;
1084					box.find('.day').removeClass('checked');
1085				}
1086			}
1087		}
1088
1089		function showSelectedInfo(forceValid,silent)
1090		{
1091			box.find('.start-day').html('...');
1092			box.find('.end-day').html('...');
1093			box.find('.selected-days').hide();
1094			if (opt.start)
1095			{
1096				box.find('.start-day').html(getDateString(new Date(parseInt(opt.start))));
1097			}
1098			if (opt.end)
1099			{
1100				box.find('.end-day').html(getDateString(new Date(parseInt(opt.end))));
1101			}
1102            var dateRange;
1103			if (opt.start && opt.singleDate)
1104			{
1105				box.find('.apply-btn').removeClass('disabled');
1106				dateRange = getDateString(new Date(opt.start));
1107				opt.setValue.call(selfDom, dateRange, getDateString(new Date(opt.start)), getDateString(new Date(opt.end)));
1108
1109				if (initiated && !silent)
1110				{
1111					$(self).trigger('datepicker-change',
1112					{
1113						'value': dateRange,
1114						'date1' : new Date(opt.start)
1115					});
1116				}
1117			}
1118			else if (opt.start && opt.end)
1119			{
1120				box.find('.selected-days').show().find('.selected-days-num').html(countDays(opt.end, opt.start));
1121				box.find('.apply-btn').removeClass('disabled');
1122				dateRange = getDateString(new Date(opt.start))+ opt.separator +getDateString(new Date(opt.end));
1123				opt.setValue.call(selfDom,dateRange, getDateString(new Date(opt.start)), getDateString(new Date(opt.end)));
1124				if (initiated && !silent)
1125				{
1126					$(self).trigger('datepicker-change',
1127					{
1128						'value': dateRange,
1129						'date1' : new Date(opt.start),
1130						'date2' : new Date(opt.end)
1131					});
1132				}
1133			}
1134			else if (forceValid)
1135			{
1136				box.find('.apply-btn').removeClass('disabled');
1137			}
1138			else
1139			{
1140				box.find('.apply-btn').addClass('disabled');
1141			}
1142		}
1143
1144		function countDays(start,end)
1145		{
1146			return Math.abs( daysFrom1970(start) - daysFrom1970(end) ) + 1;
1147		}
1148
1149		function setDateRange(date1,date2,silent)
1150		{
1151			if (date1.getTime() > date2.getTime())
1152			{
1153				var tmp = date2;
1154				date2 = date1;
1155				date1 = tmp;
1156				tmp = null;
1157			}
1158			var valid = true;
1159			if (opt.startDate && compare_day(date1,opt.startDate) < 0) valid = false;
1160			if (opt.endDate && compare_day(date2,opt.endDate) > 0) valid = false;
1161			if (!valid)
1162			{
1163				showMonth(opt.startDate,'month1');
1164				showMonth(nextMonth(opt.startDate),'month2');
1165				showGap();
1166				return;
1167			}
1168
1169			opt.start = date1.getTime();
1170			opt.end = date2.getTime();
1171
1172			if (opt.time.enabled)
1173			{
1174				renderTime('time1', date1);
1175				renderTime('time2', date2);
1176			}
1177
1178			if (opt.stickyMonths || (compare_day(date1,date2) > 0 && compare_month(date1,date2) === 0))
1179			{
1180				if (opt.lookBehind) {
1181					date1 = prevMonth(date2);
1182				} else {
1183					date2 = nextMonth(date1);
1184				}
1185			}
1186
1187			if(opt.stickyMonths && opt.endDate !== false && compare_month(date2,opt.endDate) > 0) {
1188				date1 = prevMonth(date1);
1189				date2 = prevMonth(date2);
1190			}
1191
1192			if (!opt.stickyMonths) {
1193				if (compare_month(date1,date2) === 0)
1194				{
1195					if (opt.lookBehind) {
1196						date1 = prevMonth(date2);
1197					} else {
1198						date2 = nextMonth(date1);
1199					}
1200				}
1201			}
1202
1203			showMonth(date1,'month1');
1204			showMonth(date2,'month2');
1205			showGap();
1206			checkSelectionValid();
1207			showSelectedInfo(false,silent);
1208			autoclose();
1209		}
1210
1211		function setSingleDate(date1)
1212		{
1213
1214			var valid = true;
1215			if (opt.startDate && compare_day(date1,opt.startDate) < 0) valid = false;
1216			if (opt.endDate && compare_day(date1,opt.endDate) > 0) valid = false;
1217			if (!valid)
1218			{
1219				showMonth(opt.startDate,'month1');
1220				return;
1221			}
1222
1223			opt.start = date1.getTime();
1224
1225
1226			if (opt.time.enabled) {
1227				renderTime('time1', date1);
1228
1229			}
1230			showMonth(date1,'month1');
1231			if (opt.singleMonth !== true) {
1232      				var date2 = nextMonth(date1);
1233      				showMonth(date2, 'month2');
1234    			}
1235			showGap();
1236			showSelectedInfo();
1237			autoclose();
1238		}
1239
1240		function showSelectedDays()
1241		{
1242			if (!opt.start && !opt.end) return;
1243			box.find('.day').each(function()
1244			{
1245				var time = parseInt($(this).attr('time')),
1246					start = opt.start,
1247					end = opt.end;
1248				if (opt.time.enabled) {
1249					time = moment(time).startOf('day').valueOf();
1250					start = moment(start || moment().valueOf()).startOf('day').valueOf();
1251					end = moment(end || moment().valueOf()).startOf('day').valueOf();
1252				}
1253				if (
1254					(opt.start && opt.end && end >= time && start <= time ) ||
1255					( opt.start && !opt.end && moment(start).format('YYYY-MM-DD') == moment(time).format('YYYY-MM-DD') )
1256				)
1257				{
1258					$(this).addClass('checked');
1259				}
1260				else
1261				{
1262					$(this).removeClass('checked');
1263				}
1264
1265				//add first-date-selected class name to the first date selected
1266				if ( opt.start && moment(start).format('YYYY-MM-DD') == moment(time).format('YYYY-MM-DD') )
1267				{
1268					$(this).addClass('first-date-selected');
1269				}
1270				else
1271				{
1272					$(this).removeClass('first-date-selected');
1273				}
1274				//add last-date-selected
1275				if ( opt.end && moment(end).format('YYYY-MM-DD') == moment(time).format('YYYY-MM-DD') )
1276				{
1277					$(this).addClass('last-date-selected');
1278				}
1279				else
1280				{
1281					$(this).removeClass('last-date-selected');
1282				}
1283			});
1284
1285			box.find('.week-number').each(function()
1286			{
1287				if ($(this).attr('data-start-time') == opt.startWeek)
1288				{
1289					$(this).addClass('week-number-selected');
1290				}
1291			});
1292		}
1293
1294		function showMonth(date,month)
1295		{
1296			date = moment(date).toDate();
1297			var monthName = nameMonth(date.getMonth());
1298			box.find('.'+month+' .month-name').html(monthName+' '+date.getFullYear());
1299			box.find('.'+month+' tbody').html(createMonthHTML(date));
1300			opt[month] = date;
1301			updateSelectableRange();
1302		}
1303
1304		function showTime(date,name)
1305		{
1306			box.find('.' + name).append(getTimeHTML());
1307			renderTime(name, date);
1308		}
1309
1310		function nameMonth(m)
1311		{
1312			return lang('month-name')[m];
1313		}
1314
1315		function getDateString(d)
1316		{
1317			return moment(d).format(opt.format);
1318		}
1319
1320		function showGap()
1321		{
1322			showSelectedDays();
1323			var m1 = parseInt(moment(opt.month1).format('YYYYMM'));
1324			var m2 = parseInt(moment(opt.month2).format('YYYYMM'));
1325			var p = Math.abs(m1 - m2);
1326			var shouldShow = (p > 1 && p !=89);
1327			if (shouldShow)
1328			{
1329				box.addClass('has-gap').removeClass('no-gap').find('.gap').css('visibility','visible');
1330			}
1331			else
1332			{
1333				box.removeClass('has-gap').addClass('no-gap').find('.gap').css('visibility','hidden');
1334			}
1335			var h1 = box.find('table.month1').height();
1336			var h2 = box.find('table.month2').height();
1337			box.find('.gap').height(Math.max(h1,h2)+10);
1338		}
1339
1340		function closeDatePicker()
1341		{
1342			if (opt.alwaysOpen) return;
1343
1344			var afterAnim = function()
1345			{
1346				$(self).data('date-picker-opened',false);
1347				$(self).trigger('datepicker-closed', {relatedTarget: box});
1348			};
1349			if (opt.customCloseAnimation)
1350			{
1351				opt.customCloseAnimation.call(box.get(0), afterAnim);
1352			}
1353			else
1354			{
1355				$(box).slideUp(opt.duration, afterAnim);
1356			}
1357			$(self).trigger('datepicker-close', {relatedTarget: box});
1358		}
1359
1360		function redrawDatePicker()
1361		{
1362			showMonth(opt.month1, 'month1');
1363			showMonth(opt.month2, 'month2');
1364		}
1365
1366		function compare_month(m1,m2)
1367		{
1368			var p = parseInt(moment(m1).format('YYYYMM')) - parseInt(moment(m2).format('YYYYMM'));
1369			if (p > 0 ) return 1;
1370			if (p === 0) return 0;
1371			return -1;
1372		}
1373
1374		function compare_day(m1,m2)
1375		{
1376			var p = parseInt(moment(m1).format('YYYYMMDD')) - parseInt(moment(m2).format('YYYYMMDD'));
1377			if (p > 0 ) return 1;
1378			if (p === 0) return 0;
1379			return -1;
1380		}
1381
1382		function nextMonth(month)
1383		{
1384			return moment(month).add(1, 'months').toDate();
1385		}
1386
1387		function prevMonth(month)
1388		{
1389			return moment(month).add(-1, 'months').toDate();
1390		}
1391
1392		function getTimeHTML()
1393		{
1394			return '<div>' +
1395					'<span>'+lang('Time')+': <span class="hour-val">00</span>:<span class="minute-val">00</span></span>' +
1396				'</div>' +
1397				'<div class="hour">' +
1398					'<label>'+lang('Hour')+': <input type="range" class="hour-range" name="hour" min="0" max="23"></label>' +
1399				'</div>' +
1400				'<div class="minute">' +
1401					'<label>'+lang('Minute')+': <input type="range" class="minute-range" name="minute" min="0" max="59"></label>' +
1402				'</div>';
1403		}
1404
1405		function createDom()
1406		{
1407			var html = '<div class="date-picker-wrapper';
1408			if ( opt.extraClass ) html += ' '+opt.extraClass+' ';
1409			if ( opt.singleDate ) html += ' single-date ';
1410			if ( !opt.showShortcuts ) html += ' no-shortcuts ';
1411			if ( !opt.showTopbar ) html += ' no-topbar ';
1412			if ( opt.customTopBar) html += ' custom-topbar ';
1413			html += '">';
1414
1415			if (opt.showTopbar)
1416			{
1417				html += '<div class="drp_top-bar">';
1418
1419				if (opt.customTopBar)
1420				{
1421					if (typeof opt.customTopBar == 'function') opt.customTopBar = opt.customTopBar();
1422					html += '<div class="custom-top">'+opt.customTopBar+'</div>';
1423				}
1424				else
1425				{
1426					html += '<div class="normal-top">' +
1427							'<span style="color:#333">'+lang('selected')+' </span> <b class="start-day">...</b>';
1428					if ( ! opt.singleDate ) {
1429						html += ' <span class="separator-day">'+opt.separator+'</span> <b class="end-day">...</b> <i class="selected-days">(<span class="selected-days-num">3</span> '+lang('days')+')</i>';
1430					}
1431					html += '</div>';
1432					html += '<div class="error-top">error</div>' +
1433						'<div class="default-top">default</div>';
1434				}
1435
1436				html += '<input type="button" class="apply-btn disabled'+ getApplyBtnClass() +'" value="'+lang('apply')+'" />';
1437				html += '</div>';
1438			}
1439
1440			var _colspan = opt.showWeekNumbers ? 6 : 5;
1441			html += '<div class="month-wrapper">' +
1442				'<table class="month1" cellspacing="0" border="0" cellpadding="0"><thead><tr class="caption"><th style="width:27px;"><span class="prev">&lt;</span></th><th colspan="'+_colspan+'" class="month-name"></th><th style="width:27px;">' + (opt.singleDate || !opt.stickyMonths ? '<span class="next">&gt;</span>': '') + '</th></tr><tr class="week-name">'+getWeekHead()+'</thead><tbody></tbody></table>';
1443
1444			if ( hasMonth2() )
1445			{
1446				html += '<div class="gap">'+getGapHTML()+'</div>' +
1447					'<table class="month2" cellspacing="0" border="0" cellpadding="0"><thead><tr class="caption"><th style="width:27px;">' + (!opt.stickyMonths ? '<span class="prev">&lt;</span>': '') + '</th><th colspan="'+_colspan+'" class="month-name"></th><th style="width:27px;"><span class="next">&gt;</span></th></tr><tr class="week-name">'+getWeekHead()+'</thead><tbody></tbody></table>';
1448			}
1449				//+'</div>'
1450			html +=	'<div style="clear:both;height:0;font-size:0;"></div>' +
1451				'<div class="time">' +
1452				'<div class="time1"></div>';
1453			if ( ! opt.singleDate ) {
1454				html += '<div class="time2"></div>';
1455			}
1456			html += '</div>' +
1457				'<div style="clear:both;height:0;font-size:0;"></div>' +
1458				'</div>';
1459
1460			html += '<div class="footer">';
1461			if (opt.showShortcuts)
1462			{
1463				html += '<div class="shortcuts"><b>'+lang('shortcuts')+'</b>';
1464
1465				var data = opt.shortcuts;
1466				if (data)
1467				{   var name;
1468					if (data['prev-days'] && data['prev-days'].length > 0)
1469					{
1470						html += '&nbsp;<span class="prev-days">'+lang('past');
1471						for(var i=0;i<data['prev-days'].length; i++)
1472						{
1473							name = data['prev-days'][i];
1474							name += (data['prev-days'][i] > 1) ? lang('days') : lang('day');
1475							html += ' <a href="javascript:;" shortcut="day,-'+data['prev-days'][i]+'">'+name+'</a>';
1476						}
1477						html+='</span>';
1478					}
1479
1480					if (data['next-days'] && data['next-days'].length > 0)
1481					{
1482						html += '&nbsp;
1482<span class="next-days">'+lang('following');
1483						for(var i=0;i<data['next-days'].length; i++)
1484						{
1485							name = data['next-days'][i];
1486							name += (data['next-days'][i] > 1) ? lang('days') : lang('day');
1487							html += ' <a href="javascript:;" shortcut="day,'+data['next-days'][i]+'">'+name+'</a>';
1488						}
1489						html+= '</span>';
1490					}
1491
1492					if (data.prev && data.prev.length > 0)
1493					{
1494						html += '&nbsp;<span class="prev-buttons">'+lang('previous');
1495						for(var i=0;i<data.prev.length; i++)
1496						{
1497							name = lang('prev-'+data.prev[i]);
1498							html += ' <a href="javascript:;" shortcut="prev,'+data.prev[i]+'">'+name+'</a>';
1499						}
1500						html+='</span>';
1501					}
1502
1503					if (data.next && data.next.length > 0)
1504					{
1505						html += '&nbsp;<span class="next-buttons">'+lang('next');
1506						for(var i=0;i<data.next.length; i++)
1507						{
1508							name = lang('next-'+data.next[i]);
1509							html += ' <a href="javascript:;" shortcut="next,'+data.next[i]+'">'+name+'</a>';
1510						}
1511						html+='</span>';
1512					}
1513				}
1514
1515				if (opt.customShortcuts)
1516				{
1517					for(var i=0;i<opt.customShortcuts.length; i++)
1518					{
1519						var sh = opt.customShortcuts[i];
1520						html+= '&nbsp;<span class="custom-shortcut"><a href="javascript:;" shortcut="custom">'+sh.name+'</a></span>';
1521					}
1522				}
1523				html += '</div>';
1524			}
1525
1526			// Add Custom Values Dom
1527			if (opt.showCustomValues)
1528			{
1529				html += '<div class="customValues"><b>'+(opt.customValueLabel || lang('custom-values'))+'</b>';
1530
1531				if (opt.customValues)
1532				{
1533					for(var i=0;i<opt.customValues.length;i++)
1534					{
1535						var val = opt.customValues[i];
1536							html+= '&nbsp;<span class="custom-value"><a href="javascript:;" custom="'+ val.value+'">'+val.name+'</a></span>';
1537					}
1538				}
1539			}
1540
1541			html += '</div></div>';
1542
1543
1544			return $(html);
1545		}
1546
1547		function getApplyBtnClass()
1548		{
1549			var klass = '';
1550			if (opt.autoClose === true) {
1551				klass += ' hide';
1552			}
1553			if (opt.applyBtnClass !== '') {
1554				klass += ' ' + opt.applyBtnClass;
1555			}
1556			return klass;
1557		}
1558
1559		function getWeekHead()
1560		{
1561			var prepend = opt.showWeekNumbers ? '<th>'+lang('week-number')+'</th>' : '';
1562			if (opt.startOfWeek == 'monday')
1563			{
1564				return prepend+'<th>'+lang('week-1')+'</th>' +
1565					'<th>'+lang('week-2')+'</th>' +
1566					'<th>'+lang('week-3')+'</th>' +
1567					'<th>'+lang('week-4')+'</th>' +
1568					'<th>'+lang('week-5')+'</th>' +
1569					'<th>'+lang('week-6')+'</th>' +
1570					'<th>'+lang('week-7')+'</th>';
1571			}
1572			else
1573			{
1574				return prepend+'<th>'+lang('week-7')+'</th>' +
1575					'<th>'+lang('week-1')+'</th>' +
1576					'<th>'+lang('week-2')+'</th>' +
1577					'<th>'+lang('week-3')+'</th>' +
1578					'<th>'+lang('week-4')+'</th>' +
1579					'<th>'+lang('week-5')+'</th>' +
1580					'<th>'+lang('week-6')+'</th>';
1581			}
1582		}
1583
1584		function isMonthOutOfBounds(month)
1585		{
1586			month = moment(month);
1587			if (opt.startDate && month.endOf('month').isBefore(opt.startDate))
1588			{
1589				return true;
1590			}
1591			if (opt.endDate && month.startOf('month').isAfter(opt.endDate))
1592			{
1593				return true;
1594			}
1595			return false;
1596		}
1597
1598		function getGapHTML()
1599		{
1600			var html = ['<div class="gap-top-mask"></div><div class="gap-bottom-mask"></div><div class="gap-lines">'];
1601			for(var i=0;i<20;i++)
1602			{
1603				html.push('<div class="gap-line">' +
1604					'<div class="gap-1"></div>' +
1605					'<div class="gap-2"></div>' +
1606					'<div class="gap-3"></div>' +
1607				'</div>');
1608			}
1609			html.push('</div>');
1610			return html.join('');
1611		}
1612
1613		function hasMonth2()
1614		{
1615			return (!opt.singleMonth);
1616		}
1617
1618		function attributesCallbacks(initialObject,callbacksArray,today)
1619		{
1620			var resultObject = $.extend(true, {}, initialObject);
1621
1622			$.each(callbacksArray, function(cbAttrIndex, cbAttr){
1623				var addAttributes = cbAttr(today);
1624				for(var attr in addAttributes){
1625					if(resultObject.hasOwnProperty(attr)){
1626						resultObject[attr] += addAttributes[attr];
1627					}else{
1628						resultObject[attr] = addAttributes[attr];
1629					}
1630				}
1631			});
1632
1633			var attrString = '';
1634
1635			for(var attr in resultObject){
1636				if(resultObject.hasOwnProperty(attr)){
1637					attrString += attr + '="' + resultObject[attr] + '" ';
1638				}
1639			}
1640
1641			return attrString;
1642		}
1643
1644		function daysFrom1970(t)
1645		{
1646			return Math.floor(toLocalTimestamp(t) / 86400000);
1647		}
1648
1649		function toLocalTimestamp(t)
1650		{
1651			if (moment.isMoment(t)) t = t.toDate().getTime();
1652			if (typeof t == 'object' && t.getTime) t = t.getTime();
1653			if (typeof t == 'string' && !t.match(/\d{13}/)) t = moment(t,opt.format).toDate().getTime();
1654			t = parseInt(t, 10) - new Date().getTimezoneOffset()*60*1000;
1655			return t;
1656		}
1657
1658		function createMonthHTML(d)
1659		{
1660			var days = [];
1661			d.setDate(1);
1662			var lastMonth = new Date(d.getTime() - 86400000);
1663			var now = new Date();
1664
1665			var dayOfWeek = d.getDay();
1666			if((dayOfWeek === 0) && (opt.startOfWeek === 'monday')) {
1667				// add one week
1668				dayOfWeek = 7;
1669			}
1670            var today,valid;
1671
1672			if (dayOfWeek > 0)
1673			{
1674				for (var i = dayOfWeek; i > 0; i--)
1675				{
1676					var day = new Date(d.getTime() - 86400000*i);
1677					valid = isValidTime(day.getTime());
1678					if (opt.startDate && compare_day(day,opt.startDate) < 0) valid = false;
1679					if (opt.endDate && compare_day(day,opt.endDate) > 0) valid = false;
1680					days.push(
1681					{
1682						date: day,
1683						type:'lastMonth',
1684						day: day.getDate(),
1685						time:day.getTime(),
1686						valid:valid
1687					});
1688				}
1689			}
1690			var toMonth = d.getMonth();
1691			for(var i=0; i<40; i++)
1692			{
1693				today = moment(d).add(i, 'days').toDate();
1694				valid = isValidTime(today.getTime());
1695				if (opt.startDate && compare_day(today,opt.startDate) < 0) valid = false;
1696				if (opt.endDate && compare_day(today,opt.endDate) > 0) valid = false;
1697				days.push(
1698				{
1699					date: today,
1700					type: today.getMonth() == toMonth ? 'toMonth' : 'nextMonth',
1701					day: today.getDate(),
1702					time:today.getTime(),
1703					valid:valid
1704				});
1705			}
1706			var html = [];
1707			for(var week=0; week<6; week++)
1708			{
1709				if (days[week*7].type == 'nextMonth') break;
1710				html.push('<tr>');
1711
1712				for(var day = 0; day<7; day++)
1713				{
1714					var _day = (opt.startOfWeek == 'monday') ? day+1 : day;
1715					today = days[week*7+_day];
1716					var highlightToday = moment(today.time).format('L') == moment(now).format('L');
1717					today.extraClass = '';
1718					today.tooltip = '';
1719					if(today.valid && opt.beforeShowDay && typeof opt.beforeShowDay == 'function')
1720					{
1721						var _r = opt.beforeShowDay(moment(today.time).toDate());
1722						today.valid = _r[0];
1723						today.extraClass = _r[1] || '';
1724						today.tooltip = _r[2] || '';
1725						if (today.tooltip !== '') today.extraClass += ' has-tooltip ';
1726					}
1727
1728					var todayDivAttr = {
1729						time: today.time,
1730						'data-tooltip': today.tooltip,
1731						'class': 'day '+today.type+' '+today.extraClass+' '+(today.valid ? 'valid' : 'invalid')+' '+(highlightToday?'real-today':'')
1732					};
1733
1734					if (day === 0 && opt.showWeekNumbers)
1735					{
1736						html.push('<td><div class="week-number" data-start-time="'+today.time+'">'+opt.getWeekNumber(today.date)+'</div></td>');
1737					}
1738
1739					html.push('<td ' + attributesCallbacks({},opt.dayTdAttrs,today) + '><div ' + attributesCallbacks(todayDivAttr,opt.dayDivAttrs,today) + '>'+showDayHTML(today.time, today.day)+'</div></td>');
1740				}
1741				html.push('</tr>');
1742			}
1743			return html.join('');
1744		}
1745
1746		function showDayHTML(time, date)
1747		{
1748			if (opt.showDateFilter && typeof opt.showDateFilter == 'function') return opt.showDateFilter(time, date);
1749			return date;
1750		}
1751
1752		function getLanguages()
1753		{
1754			if (opt.language == 'auto')
1755			{
1756				var language = navigator.language ? navigator.language : navigator.browserLanguage;
1757				if (!language) return $.dateRangePickerLanguages['default'];
1758				language = language.toLowerCase();
1759				for(var key in $.dateRangePickerLanguages)
1760				{
1761					if (language.indexOf(key) !== -1)
1762					{
1763						return $.dateRangePickerLanguages[key];
1764					}
1765				}
1766				return $.dateRangePickerLanguages['default'];
1767			}
1768			else if ( opt.language && opt.language in $.dateRangePickerLanguages)
1769			{
1770				return $.dateRangePickerLanguages[opt.language];
1771			}
1772			else
1773			{
1774				return $.dateRangePickerLanguages['default'];
1775			}
1776		}
1777
1778		/**
1779		 * translate language string
1780		 */
1781		function lang(t)
1782		{
1783			var _t = t.toLowerCase();
1784			var re = (t in langs) ? langs[t] : ( _t in langs) ? langs[_t] : null;
1785			var defaultLanguage = $.dateRangePickerLanguages['default'];
1786			if (re == null) re = (t in defaultLanguage) ? defaultLanguage[t] : ( _t in defaultLanguage) ? defaultLanguage[_t] : '';
1787			return re;
1788		}
1789
1790		function getDefaultTime()
1791		{
1792			var defaultTime = opt.defaultTime ? opt.defaultTime : new Date();
1793
1794			if (opt.lookBehind)
1795			{
1796				if (opt.startDate && compare_month(defaultTime, opt.startDate) < 0 ) defaultTime = nextMonth(moment(opt.startDate).toDate());
1797				if (opt.endDate && compare_month(defaultTime,opt.endDate) > 0 ) defaultTime = moment(opt.endDate).toDate();
1798			}
1799			else
1800			{
1801				if (opt.startDate && compare_month(defaultTime,opt.startDate) < 0 ) defaultTime = moment(opt.startDate).toDate();
1802				if (opt.endDate && compare_month(nextMonth(defaultTime),opt.endDate) >
1802 0 ) defaultTime = prevMonth(moment(opt.endDate).toDate());
1803			}
1804
1805			if (opt.singleDate)
1806			{
1807				if (opt.startDate && compare_month(defaultTime,opt.startDate) < 0 ) defaultTime = moment(opt.startDate).toDate();
1808				if (opt.endDate && compare_month(defaultTime,opt.endDate) > 0 ) defaultTime = moment(opt.endDate).toDate();
1809			}
1810
1811			return defaultTime;
1812		}
1813
1814		function resetMonthsView(time)
1815		{
1816			if (!time) {
1817				time = getDefaultTime();
1818			}
1819
1820			if (opt.lookBehind)
1821			{
1822				showMonth(prevMonth(time),'month1');
1823				showMonth(time,'month2');
1824			}
1825			else
1826			{
1827				showMonth(time,'month1');
1828				showMonth(nextMonth(time),'month2');
1829			}
1830
1831			if (opt.singleDate)
1832			{
1833				showMonth(time,'month1');
1834			}
1835
1836			showSelectedDays();
1837			showGap();
1838		}
1839
1840	};
1841}));

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.