Path: blob/master/sites/tiktok/vendor/daterangepicker/daterangepicker.js
740 views
/**1* @version: 2.1.252* @author: Dan Grossman http://www.dangrossman.info/3* @copyright: Copyright (c) 2012-2017 Dan Grossman. All rights reserved.4* @license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php5* @website: http://www.daterangepicker.com/6*/7// Follow the UMD template https://github.com/umdjs/umd/blob/master/templates/returnExportsGlobal.js8(function (root, factory) {9if (typeof define === 'function' && define.amd) {10// AMD. Make globaly available as well11define(['moment', 'jquery'], function (moment, jquery) {12if (!jquery.fn) jquery.fn = {}; // webpack server rendering13return (root.daterangepicker = factory(moment, jquery));14});15} else if (typeof module === 'object' && module.exports) {16// Node / Browserify17//isomorphic issue18var jQuery = (typeof window != 'undefined') ? window.jQuery : undefined;19if (!jQuery) {20jQuery = require('jquery');21if (!jQuery.fn) jQuery.fn = {};22}23var moment = (typeof window != 'undefined' && typeof window.moment != 'undefined') ? window.moment : require('moment');24module.exports = factory(moment, jQuery);25} else {26// Browser globals27root.daterangepicker = factory(root.moment, root.jQuery);28}29}(this, function(moment, $) {30var DateRangePicker = function(element, options, cb) {3132//default settings for options33this.parentEl = 'body';34this.element = $(element);35this.startDate = moment().startOf('day');36this.endDate = moment().endOf('day');37this.minDate = false;38this.maxDate = false;39this.dateLimit = false;40this.autoApply = false;41this.singleDatePicker = false;42this.showDropdowns = false;43this.showWeekNumbers = false;44this.showISOWeekNumbers = false;45this.showCustomRangeLabel = true;46this.timePicker = false;47this.timePicker24Hour = false;48this.timePickerIncrement = 1;49this.timePickerSeconds = false;50this.linkedCalendars = true;51this.autoUpdateInput = true;52this.alwaysShowCalendars = false;53this.ranges = {};5455this.opens = 'right';56if (this.element.hasClass('pull-right'))57this.opens = 'left';5859this.drops = 'down';60if (this.element.hasClass('dropup'))61this.drops = 'up';6263this.buttonClasses = 'btn btn-sm';64this.applyClass = 'btn-success';65this.cancelClass = 'btn-default';6667this.locale = {68direction: 'ltr',69format: moment.localeData().longDateFormat('L'),70separator: ' - ',71applyLabel: 'Apply',72cancelLabel: 'Cancel',73weekLabel: 'W',74customRangeLabel: 'Custom Range',75daysOfWeek: moment.weekdaysMin(),76monthNames: moment.monthsShort(),77firstDay: moment.localeData().firstDayOfWeek()78};7980this.callback = function() { };8182//some state information83this.isShowing = false;84this.leftCalendar = {};85this.rightCalendar = {};8687//custom options from user88if (typeof options !== 'object' || options === null)89options = {};9091//allow setting options with data attributes92//data-api options will be overwritten with custom javascript options93options = $.extend(this.element.data(), options);9495//html template for the picker UI96if (typeof options.template !== 'string' && !(options.template instanceof $))97options.template = '<div class="daterangepicker dropdown-menu">' +98'<div class="calendar left">' +99'<div class="daterangepicker_input">' +100'<input class="input-mini form-control" type="text" name="daterangepicker_start" value="" />' +101'<i class="fa fa-calendar glyphicon glyphicon-calendar"></i>' +102'<div class="calendar-time">' +103'<div></div>' +104'<i class="fa fa-clock-o glyphicon glyphicon-time"></i>' +105'</div>' +106'</div>' +107'<div class="calendar-table"></div>' +108'</div>' +109'<div class="calendar right">' +110'<div class="daterangepicker_input">' +111'<input class="input-mini form-control" type="text" name="daterangepicker_end" value="" />' +112'<i class="fa fa-calendar glyphicon glyphicon-calendar"></i>' +113'<div class="calendar-time">' +114'<div></div>' +115'<i class="fa fa-clock-o glyphicon glyphicon-time"></i>' +116'</div>' +117'</div>' +118'<div class="calendar-table"></div>' +119'</div>' +120'<div class="ranges">' +121'<div class="range_inputs">' +122'<button class="applyBtn" disabled="disabled" type="button"></button> ' +123'<button class="cancelBtn" type="button"></button>' +124'</div>' +125'</div>' +126'</div>';127128this.parentEl = (options.parentEl && $(options.parentEl).length) ? $(options.parentEl) : $(this.parentEl);129this.container = $(options.template).appendTo(this.parentEl);130131//132// handle all the possible options overriding defaults133//134135if (typeof options.locale === 'object') {136137if (typeof options.locale.direction === 'string')138this.locale.direction = options.locale.direction;139140if (typeof options.locale.format === 'string')141this.locale.format = options.locale.format;142143if (typeof options.locale.separator === 'string')144this.locale.separator = options.locale.separator;145146if (typeof options.locale.daysOfWeek === 'object')147this.locale.daysOfWeek = options.locale.daysOfWeek.slice();148149if (typeof options.locale.monthNames === 'object')150this.locale.monthNames = options.locale.monthNames.slice();151152if (typeof options.locale.firstDay === 'number')153this.locale.firstDay = options.locale.firstDay;154155if (typeof options.locale.applyLabel === 'string')156this.locale.applyLabel = options.locale.applyLabel;157158if (typeof options.locale.cancelLabel === 'string')159this.locale.cancelLabel = options.locale.cancelLabel;160161if (typeof options.locale.weekLabel === 'string')162this.locale.weekLabel = options.locale.weekLabel;163164if (typeof options.locale.customRangeLabel === 'string'){165//Support unicode chars in the custom range name.166var elem = document.createElement('textarea');167elem.innerHTML = options.locale.customRangeLabel;168var rangeHtml = elem.value;169this.locale.customRangeLabel = rangeHtml;170}171}172this.container.addClass(this.locale.direction);173174if (typeof options.startDate === 'string')175this.startDate = moment(options.startDate, this.locale.format);176177if (typeof options.endDate === 'string')178this.endDate = moment(options.endDate, this.locale.format);179180if (typeof options.minDate === 'string')181this.minDate = moment(options.minDate, this.locale.format);182183if (typeof options.maxDate === 'string')184this.maxDate = moment(options.maxDate, this.locale.format);185186if (typeof options.startDate === 'object')187this.startDate = moment(options.startDate);188189if (typeof options.endDate === 'object')190this.endDate = moment(options.endDate);191192if (typeof options.minDate === 'object')193this.minDate = moment(options.minDate);194195if (typeof options.maxDate === 'object')196this.maxDate = moment(options.maxDate);197198// sanity check for bad options199if (this.minDate && this.startDate.isBefore(this.minDate))200this.startDate = this.minDate.clone();201202// sanity check for bad options203if (this.maxDate && this.endDate.isAfter(this.maxDate))204this.endDate = this.maxDate.clone();205206if (typeof options.applyClass === 'string')207this.applyClass = options.applyClass;208209if (typeof options.cancelClass === 'string')210this.cancelClass = options.cancelClass;211212if (typeof options.dateLimit === 'object')213this.dateLimit = options.dateLimit;214215if (typeof options.opens === 'string')216this.opens = options.opens;217218if (typeof options.drops === 'string')219this.drops = options.drops;220221if (typeof options.showWeekNumbers === 'boolean')222this.showWeekNumbers = options.showWeekNumbers;223224if (typeof options.showISOWeekNumbers === 'boolean')225this.showISOWeekNumbers = options.showISOWeekNumbers;226227if (typeof options.buttonClasses === 'string')228this.buttonClasses = options.buttonClasses;229230if (typeof options.buttonClasses === 'object')231this.buttonClasses = options.buttonClasses.join(' ');232233if (typeof options.showDropdowns === 'boolean')234this.showDropdowns = options.showDropdowns;235236if (typeof options.showCustomRangeLabel === 'boolean')237this.showCustomRangeLabel = options.showCustomRangeLabel;238239if (typeof options.singleDatePicker === 'boolean') {240this.singleDatePicker = options.singleDatePicker;241if (this.singleDatePicker)242this.endDate = this.startDate.clone();243}244245if (typeof options.timePicker === 'boolean')246this.timePicker = options.timePicker;247248if (typeof options.timePickerSeconds === 'boolean')249this.timePickerSeconds = options.timePickerSeconds;250251if (typeof options.timePickerIncrement === 'number')252this.timePickerIncrement = options.timePickerIncrement;253254if (typeof options.timePicker24Hour === 'boolean')255this.timePicker24Hour = options.timePicker24Hour;256257if (typeof options.autoApply === 'boolean')258this.autoApply = options.autoApply;259260if (typeof options.autoUpdateInput === 'boolean')261this.autoUpdateInput = options.autoUpdateInput;262263if (typeof options.linkedCalendars === 'boolean')264this.linkedCalendars = options.linkedCalendars;265266if (typeof options.isInvalidDate === 'function')267this.isInvalidDate = options.isInvalidDate;268269if (typeof options.isCustomDate === 'function')270this.isCustomDate = options.isCustomDate;271272if (typeof options.alwaysShowCalendars === 'boolean')273this.alwaysShowCalendars = options.alwaysShowCalendars;274275// update day names order to firstDay276if (this.locale.firstDay != 0) {277var iterator = this.locale.firstDay;278while (iterator > 0) {279this.locale.daysOfWeek.push(this.locale.daysOfWeek.shift());280iterator--;281}282}283284var start, end, range;285286//if no start/end dates set, check if an input element contains initial values287if (typeof options.startDate === 'undefined' && typeof options.endDate === 'undefined') {288if ($(this.element).is('input[type=text]')) {289var val = $(this.element).val(),290split = val.split(this.locale.separator);291292start = end = null;293294if (split.length == 2) {295start = moment(split[0], this.locale.format);296end = moment(split[1], this.locale.format);297} else if (this.singleDatePicker && val !== "") {298start = moment(val, this.locale.format);299end = moment(val, this.locale.format);300}301if (start !== null && end !== null) {302this.setStartDate(start);303this.setEndDate(end);304}305}306}307308if (typeof options.ranges === 'object') {309for (range in options.ranges) {310311if (typeof options.ranges[range][0] === 'string')312start = moment(options.ranges[range][0], this.locale.format);313else314start = moment(options.ranges[range][0]);315316if (typeof options.ranges[range][1] === 'string')317end = moment(options.ranges[range][1], this.locale.format);318else319end = moment(options.ranges[range][1]);320321// If the start or end date exceed those allowed by the minDate or dateLimit322// options, shorten the range to the allowable period.323if (this.minDate && start.isBefore(this.minDate))324start = this.minDate.clone();325326var maxDate = this.maxDate;327if (this.dateLimit && maxDate && start.clone().add(this.dateLimit).isAfter(maxDate))328maxDate = start.clone().add(this.dateLimit);329if (maxDate && end.isAfter(maxDate))330end = maxDate.clone();331332// If the end of the range is before the minimum or the start of the range is333// after the maximum, don't display this range option at all.334if ((this.minDate && end.isBefore(this.minDate, this.timepicker ? 'minute' : 'day'))335|| (maxDate && start.isAfter(maxDate, this.timepicker ? 'minute' : 'day')))336continue;337338//Support unicode chars in the range names.339var elem = document.createElement('textarea');340elem.innerHTML = range;341var rangeHtml = elem.value;342343this.ranges[rangeHtml] = [start, end];344}345346var list = '<ul>';347for (range in this.ranges) {348list += '<li data-range-key="' + range + '">' + range + '</li>';349}350if (this.showCustomRangeLabel) {351list += '<li data-range-key="' + this.locale.customRangeLabel + '">' + this.locale.customRangeLabel + '</li>';352}353list += '</ul>';354this.container.find('.ranges').prepend(list);355}356357if (typeof cb === 'function') {358this.callback = cb;359}360361if (!this.timePicker) {362this.startDate = this.startDate.startOf('day');363this.endDate = this.endDate.endOf('day');364this.container.find('.calendar-time').hide();365}366367//can't be used together for now368if (this.timePicker && this.autoApply)369this.autoApply = false;370371if (this.autoApply && typeof options.ranges !== 'object') {372this.container.find('.ranges').hide();373} else if (this.autoApply) {374this.container.find('.applyBtn, .cancelBtn').addClass('hide');375}376377if (this.singleDatePicker) {378this.container.addClass('single');379this.container.find('.calendar.left').addClass('single');380this.container.find('.calendar.left').show();381this.container.find('.calendar.right').hide();382this.container.find('.daterangepicker_input input, .daterangepicker_input > i').hide();383if (this.timePicker) {384this.container.find('.ranges ul').hide();385} else {386this.container.find('.ranges').hide();387}388}389390if ((typeof options.ranges === 'undefined' && !this.singleDatePicker) || this.alwaysShowCalendars) {391this.container.addClass('show-calendar');392}393394this.container.addClass('opens' + this.opens);395396//swap the position of the predefined ranges if opens right397if (typeof options.ranges !== 'undefined' && this.opens == 'right') {398this.container.find('.ranges').prependTo( this.container.find('.calendar.left').parent() );399}400401//apply CSS classes and labels to buttons402this.container.find('.applyBtn, .cancelBtn').addClass(this.buttonClasses);403if (this.applyClass.length)404this.container.find('.applyBtn').addClass(this.applyClass);405if (this.cancelClass.length)406this.container.find('.cancelBtn').addClass(this.cancelClass);407this.container.find('.applyBtn').html(this.locale.applyLabel);408this.container.find('.cancelBtn').html(this.locale.cancelLabel);409410//411// event listeners412//413414this.container.find('.calendar')415.on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this))416.on('click.daterangepicker', '.next', $.proxy(this.clickNext, this))417.on('mousedown.daterangepicker', 'td.available', $.proxy(this.clickDate, this))418.on('mouseenter.daterangepicker', 'td.available', $.proxy(this.hoverDate, this))419.on('mouseleave.daterangepicker', 'td.available', $.proxy(this.updateFormInputs, this))420.on('change.daterangepicker', 'select.yearselect', $.proxy(this.monthOrYearChanged, this))421.on('change.daterangepicker', 'select.monthselect', $.proxy(this.monthOrYearChanged, this))422.on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', $.proxy(this.timeChanged, this))423.on('click.daterangepicker', '.daterangepicker_input input', $.proxy(this.showCalendars, this))424.on('focus.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsFocused, this))425.on('blur.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsBlurred, this))426.on('change.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsChanged, this));427428this.container.find('.ranges')429.on('click.daterangepicker', 'button.applyBtn', $.proxy(this.clickApply, this))430.on('click.daterangepicker', 'button.cancelBtn', $.proxy(this.clickCancel, this))431.on('click.daterangepicker', 'li', $.proxy(this.clickRange, this))432.on('mouseenter.daterangepicker', 'li', $.proxy(this.hoverRange, this))433.on('mouseleave.daterangepicker', 'li', $.proxy(this.updateFormInputs, this));434435if (this.element.is('input') || this.element.is('button')) {436this.element.on({437'click.daterangepicker': $.proxy(this.show, this),438'focus.daterangepicker': $.proxy(this.show, this),439'keyup.daterangepicker': $.proxy(this.elementChanged, this),440'keydown.daterangepicker': $.proxy(this.keydown, this)441});442} else {443this.element.on('click.daterangepicker', $.proxy(this.toggle, this));444}445446//447// if attached to a text input, set the initial value448//449450if (this.element.is('input') && !this.singleDatePicker && this.autoUpdateInput) {451this.element.val(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format));452this.element.trigger('change');453} else if (this.element.is('input') && this.autoUpdateInput) {454this.element.val(this.startDate.format(this.locale.format));455this.element.trigger('change');456}457458};459460DateRangePicker.prototype = {461462constructor: DateRangePicker,463464setStartDate: function(startDate) {465if (typeof startDate === 'string')466this.startDate = moment(startDate, this.locale.format);467468if (typeof startDate === 'object')469this.startDate = moment(startDate);470471if (!this.timePicker)472this.startDate = this.startDate.startOf('day');473474if (this.timePicker && this.timePickerIncrement)475this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);476477if (this.minDate && this.startDate.isBefore(this.minDate)) {478this.startDate = this.minDate.clone();479if (this.timePicker && this.timePickerIncrement)480this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);481}482483if (this.maxDate && this.startDate.isAfter(this.maxDate)) {484this.startDate = this.maxDate.clone();485if (this.timePicker && this.timePickerIncrement)486this.startDate.minute(Math.floor(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);487}488489if (!this.isShowing)490this.updateElement();491492this.updateMonthsInView();493},494495setEndDate: function(endDate) {496if (typeof endDate === 'string')497this.endDate = moment(endDate, this.locale.format);498499if (typeof endDate === 'object')500this.endDate = moment(endDate);501502if (!this.timePicker)503this.endDate = this.endDate.endOf('day');504505if (this.timePicker && this.timePickerIncrement)506this.endDate.minute(Math.round(this.endDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);507508if (this.endDate.isBefore(this.startDate))509this.endDate = this.startDate.clone();510511if (this.maxDate && this.endDate.isAfter(this.maxDate))512this.endDate = this.maxDate.clone();513514if (this.dateLimit && this.startDate.clone().add(this.dateLimit).isBefore(this.endDate))515this.endDate = this.startDate.clone().add(this.dateLimit);516517this.previousRightTime = this.endDate.clone();518519if (!this.isShowing)520this.updateElement();521522this.updateMonthsInView();523},524525isInvalidDate: function() {526return false;527},528529isCustomDate: function() {530return false;531},532533updateView: function() {534if (this.timePicker) {535this.renderTimePicker('left');536this.renderTimePicker('right');537if (!this.endDate) {538this.container.find('.right .calendar-time select').attr('disabled', 'disabled').addClass('disabled');539} else {540this.container.find('.right .calendar-time select').removeAttr('disabled').removeClass('disabled');541}542}543if (this.endDate) {544this.container.find('input[name="daterangepicker_end"]').removeClass('active');545this.container.find('input[name="daterangepicker_start"]').addClass('active');546} else {547this.container.find('input[name="daterangepicker_end"]').addClass('active');548this.container.find('input[name="daterangepicker_start"]').removeClass('active');549}550this.updateMonthsInView();551this.updateCalendars();552this.updateFormInputs();553},554555updateMonthsInView: function() {556if (this.endDate) {557558//if both dates are visible already, do nothing559if (!this.singleDatePicker && this.leftCalendar.month && this.rightCalendar.month &&560(this.startDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.startDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM'))561&&562(this.endDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.endDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM'))563) {564return;565}566567this.leftCalendar.month = this.startDate.clone().date(2);568if (!this.linkedCalendars && (this.endDate.month() != this.startDate.month() || this.endDate.year() != this.startDate.year())) {569this.rightCalendar.month = this.endDate.clone().date(2);570} else {571this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month');572}573574} else {575if (this.leftCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM') && this.rightCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM')) {576this.leftCalendar.month = this.startDate.clone().date(2);577this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month');578}579}580if (this.maxDate && this.linkedCalendars && !this.singleDatePicker && this.rightCalendar.month > this.maxDate) {581this.rightCalendar.month = this.maxDate.clone().date(2);582this.leftCalendar.month = this.maxDate.clone().date(2).subtract(1, 'month');583}584},585586updateCalendars: function() {587588if (this.timePicker) {589var hour, minute, second;590if (this.endDate) {591hour = parseInt(this.container.find('.left .hourselect').val(), 10);592minute = parseInt(this.container.find('.left .minuteselect').val(), 10);593second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0;594if (!this.timePicker24Hour) {595var ampm = this.container.find('.left .ampmselect').val();596if (ampm === 'PM' && hour < 12)597hour += 12;598if (ampm === 'AM' && hour === 12)599hour = 0;600}601} else {602hour = parseInt(this.container.find('.right .hourselect').val(), 10);603minute = parseInt(this.container.find('.right .minuteselect').val(), 10);604second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0;605if (!this.timePicker24Hour) {606var ampm = this.container.find('.right .ampmselect').val();607if (ampm === 'PM' && hour < 12)608hour += 12;609if (ampm === 'AM' && hour === 12)610hour = 0;611}612}613this.leftCalendar.month.hour(hour).minute(minute).second(second);614this.rightCalendar.month.hour(hour).minute(minute).second(second);615}616617this.renderCalendar('left');618this.renderCalendar('right');619620//highlight any predefined range matching the current start and end dates621this.container.find('.ranges li').removeClass('active');622if (this.endDate == null) return;623624this.calculateChosenLabel();625},626627renderCalendar: function(side) {628629//630// Build the matrix of dates that will populate the calendar631//632633var calendar = side == 'left' ? this.leftCalendar : this.rightCalendar;634var month = calendar.month.month();635var year = calendar.month.year();636var hour = calendar.month.hour();637var minute = calendar.month.minute();638var second = calendar.month.second();639var daysInMonth = moment([year, month]).daysInMonth();640var firstDay = moment([year, month, 1]);641var lastDay = moment([year, month, daysInMonth]);642var lastMonth = moment(firstDay).subtract(1, 'month').month();643var lastYear = moment(firstDay).subtract(1, 'month').year();644var daysInLastMonth = moment([lastYear, lastMonth]).daysInMonth();645var dayOfWeek = firstDay.day();646647//initialize a 6 rows x 7 columns array for the calendar648var calendar = [];649calendar.firstDay = firstDay;650calendar.lastDay = lastDay;651652for (var i = 0; i < 6; i++) {653calendar[i] = [];654}655656//populate the calendar with date objects657var startDay = daysInLastMonth - dayOfWeek + this.locale.firstDay + 1;658if (startDay > daysInLastMonth)659startDay -= 7;660661if (dayOfWeek == this.locale.firstDay)662startDay = daysInLastMonth - 6;663664var curDate = moment([lastYear, lastMonth, startDay, 12, minute, second]);665666var col, row;667for (var i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add(24, 'hour')) {668if (i > 0 && col % 7 === 0) {669col = 0;670row++;671}672calendar[row][col] = curDate.clone().hour(hour).minute(minute).second(second);673curDate.hour(12);674675if (this.minDate && calendar[row][col].format('YYYY-MM-DD') == this.minDate.format('YYYY-MM-DD') && calendar[row][col].isBefore(this.minDate) && side == 'left') {676calendar[row][col] = this.minDate.clone();677}678679if (this.maxDate && calendar[row][col].format('YYYY-MM-DD') == this.maxDate.format('YYYY-MM-DD') && calendar[row][col].isAfter(this.maxDate) && side == 'right') {680calendar[row][col] = this.maxDate.clone();681}682683}684685//make the calendar object available to hoverDate/clickDate686if (side == 'left') {687this.leftCalendar.calendar = calendar;688} else {689this.rightCalendar.calendar = calendar;690}691692//693// Display the calendar694//695696var minDate = side == 'left' ? this.minDate : this.startDate;697var maxDate = this.maxDate;698var selected = side == 'left' ? this.startDate : this.endDate;699var arrow = this.locale.direction == 'ltr' ? {left: 'chevron-left', right: 'chevron-right'} : {left: 'chevron-right', right: 'chevron-left'};700701var html = '<table class="table-condensed">';702html += '<thead>';703html += '<tr>';704705// add empty cell for week number706if (this.showWeekNumbers || this.showISOWeekNumbers)707html += '<th></th>';708709if ((!minDate || minDate.isBefore(calendar.firstDay)) && (!this.linkedCalendars || side == 'left')) {710html += '<th class="prev available"><i class="fa fa-' + arrow.left + ' glyphicon glyphicon-' + arrow.left + '"></i></th>';711} else {712html += '<th></th>';713}714715var dateHtml = this.locale.monthNames[calendar[1][1].month()] + calendar[1][1].format(" YYYY");716717if (this.showDropdowns) {718var currentMonth = calendar[1][1].month();719var currentYear = calendar[1][1].year();720var maxYear = (maxDate && maxDate.year()) || (currentYear + 5);721var minYear = (minDate && minDate.year()) || (currentYear - 50);722var inMinYear = currentYear == minYear;723var inMaxYear = currentYear == maxYear;724725var monthHtml = '<select class="monthselect">';726for (var m = 0; m < 12; m++) {727if ((!inMinYear || m >= minDate.month()) && (!inMaxYear || m <= maxDate.month())) {728monthHtml += "<option value='" + m + "'" +729(m === currentMonth ? " selected='selected'" : "") +730">" + this.locale.monthNames[m] + "</option>";731} else {732monthHtml += "<option value='" + m + "'" +733(m === currentMonth ? " selected='selected'" : "") +734" disabled='disabled'>" + this.locale.monthNames[m] + "</option>";735}736}737monthHtml += "</select>";738739var yearHtml = '<select class="yearselect">';740for (var y = minYear; y <= maxYear; y++) {741yearHtml += '<option value="' + y + '"' +742(y === currentYear ? ' selected="selected"' : '') +743'>' + y + '</option>';744}745yearHtml += '</select>';746747dateHtml = monthHtml + yearHtml;748}749750html += '<th colspan="5" class="month">' + dateHtml + '</th>';751if ((!maxDate || maxDate.isAfter(calendar.lastDay)) && (!this.linkedCalendars || side == 'right' || this.singleDatePicker)) {752html += '<th class="next available"><i class="fa fa-' + arrow.right + ' glyphicon glyphicon-' + arrow.right + '"></i></th>';753} else {754html += '<th></th>';755}756757html += '</tr>';758html += '<tr>';759760// add week number label761if (this.showWeekNumbers || this.showISOWeekNumbers)762html += '<th class="week">' + this.locale.weekLabel + '</th>';763764$.each(this.locale.daysOfWeek, function(index, dayOfWeek) {765html += '<th>' + dayOfWeek + '</th>';766});767768html += '</tr>';769html += '</thead>';770html += '<tbody>';771772//adjust maxDate to reflect the dateLimit setting in order to773//grey out end dates beyond the dateLimit774if (this.endDate == null && this.dateLimit) {775var maxLimit = this.startDate.clone().add(this.dateLimit).endOf('day');776if (!maxDate || maxLimit.isBefore(maxDate)) {777maxDate = maxLimit;778}779}780781for (var row = 0; row < 6; row++) {782html += '<tr>';783784// add week number785if (this.showWeekNumbers)786html += '<td class="week">' + calendar[row][0].week() + '</td>';787else if (this.showISOWeekNumbers)788html += '<td class="week">' + calendar[row][0].isoWeek() + '</td>';789790for (var col = 0; col < 7; col++) {791792var classes = [];793794//highlight today's date795if (calendar[row][col].isSame(new Date(), "day"))796classes.push('today');797798//highlight weekends799if (calendar[row][col].isoWeekday() > 5)800classes.push('weekend');801802//grey out the dates in other months displayed at beginning and end of this calendar803if (calendar[row][col].month() != calendar[1][1].month())804classes.push('off');805806//don't allow selection of dates before the minimum date807if (this.minDate && calendar[row][col].isBefore(this.minDate, 'day'))808classes.push('off', 'disabled');809810//don't allow selection of dates after the maximum date811if (maxDate && calendar[row][col].isAfter(maxDate, 'day'))812classes.push('off', 'disabled');813814//don't allow selection of date if a custom function decides it's invalid815if (this.isInvalidDate(calendar[row][col]))816classes.push('off', 'disabled');817818//highlight the currently selected start date819if (calendar[row][col].format('YYYY-MM-DD') == this.startDate.format('YYYY-MM-DD'))820classes.push('active', 'start-date');821822//highlight the currently selected end date823if (this.endDate != null && calendar[row][col].format('YYYY-MM-DD') == this.endDate.format('YYYY-MM-DD'))824classes.push('active', 'end-date');825826//highlight dates in-between the selected dates827if (this.endDate != null && calendar[row][col] > this.startDate && calendar[row][col] < this.endDate)828classes.push('in-range');829830//apply custom classes for this date831var isCustom = this.isCustomDate(calendar[row][col]);832if (isCustom !== false) {833if (typeof isCustom === 'string')834classes.push(isCustom);835else836Array.prototype.push.apply(classes, isCustom);837}838839var cname = '', disabled = false;840for (var i = 0; i < classes.length; i++) {841cname += classes[i] + ' ';842if (classes[i] == 'disabled')843disabled = true;844}845if (!disabled)846cname += 'available';847848html += '<td class="' + cname.replace(/^\s+|\s+$/g, '') + '" data-title="' + 'r' + row + 'c' + col + '">' + calendar[row][col].date() + '</td>';849850}851html += '</tr>';852}853854html += '</tbody>';855html += '</table>';856857this.container.find('.calendar.' + side + ' .calendar-table').html(html);858859},860861renderTimePicker: function(side) {862863// Don't bother updating the time picker if it's currently disabled864// because an end date hasn't been clicked yet865if (side == 'right' && !this.endDate) return;866867var html, selected, minDate, maxDate = this.maxDate;868869if (this.dateLimit && (!this.maxDate || this.startDate.clone().add(this.dateLimit).isAfter(this.maxDate)))870maxDate = this.startDate.clone().add(this.dateLimit);871872if (side == 'left') {873selected = this.startDate.clone();874minDate = this.minDate;875} else if (side == 'right') {876selected = this.endDate.clone();877minDate = this.startDate;878879//Preserve the time already selected880var timeSelector = this.container.find('.calendar.right .calendar-time div');881if (timeSelector.html() != '') {882883selected.hour(timeSelector.find('.hourselect option:selected').val() || selected.hour());884selected.minute(timeSelector.find('.minuteselect option:selected').val() || selected.minute());885selected.second(timeSelector.find('.secondselect option:selected').val() || selected.second());886887if (!this.timePicker24Hour) {888var ampm = timeSelector.find('.ampmselect option:selected').val();889if (ampm === 'PM' && selected.hour() < 12)890selected.hour(selected.hour() + 12);891if (ampm === 'AM' && selected.hour() === 12)892selected.hour(0);893}894895}896897if (selected.isBefore(this.startDate))898selected = this.startDate.clone();899900if (maxDate && selected.isAfter(maxDate))901selected = maxDate.clone();902903}904905//906// hours907//908909html = '<select class="hourselect">';910911var start = this.timePicker24Hour ? 0 : 1;912var end = this.timePicker24Hour ? 23 : 12;913914for (var i = start; i <= end; i++) {915var i_in_24 = i;916if (!this.timePicker24Hour)917i_in_24 = selected.hour() >= 12 ? (i == 12 ? 12 : i + 12) : (i == 12 ? 0 : i);918919var time = selected.clone().hour(i_in_24);920var disabled = false;921if (minDate && time.minute(59).isBefore(minDate))922disabled = true;923if (maxDate && time.minute(0).isAfter(maxDate))924disabled = true;925926if (i_in_24 == selected.hour() && !disabled) {927html += '<option value="' + i + '" selected="selected">' + i + '</option>';928} else if (disabled) {929html += '<option value="' + i + '" disabled="disabled" class="disabled">' + i + '</option>';930} else {931html += '<option value="' + i + '">' + i + '</option>';932}933}934935html += '</select> ';936937//938// minutes939//940941html += ': <select class="minuteselect">';942943for (var i = 0; i < 60; i += this.timePickerIncrement) {944var padded = i < 10 ? '0' + i : i;945var time = selected.clone().minute(i);946947var disabled = false;948if (minDate && time.second(59).isBefore(minDate))949disabled = true;950if (maxDate && time.second(0).isAfter(maxDate))951disabled = true;952953if (selected.minute() == i && !disabled) {954html += '<option value="' + i + '" selected="selected">' + padded + '</option>';955} else if (disabled) {956html += '<option value="' + i + '" disabled="disabled" class="disabled">' + padded + '</option>';957} else {958html += '<option value="' + i + '">' + padded + '</option>';959}960}961962html += '</select> ';963964//965// seconds966//967968if (this.timePickerSeconds) {969html += ': <select class="secondselect">';970971for (var i = 0; i < 60; i++) {972var padded = i < 10 ? '0' + i : i;973var time = selected.clone().second(i);974975var disabled = false;976if (minDate && time.isBefore(minDate))977disabled = true;978if (maxDate && time.isAfter(maxDate))979disabled = true;980981if (selected.second() == i && !disabled) {982html += '<option value="' + i + '" selected="selected">' + padded + '</option>';983} else if (disabled) {984html += '<option value="' + i + '" disabled="disabled" class="disabled">' + padded + '</option>';985} else {986html += '<option value="' + i + '">' + padded + '</option>';987}988}989990html += '</select> ';991}992993//994// AM/PM995//996997if (!this.timePicker24Hour) {998html += '<select class="ampmselect">';9991000var am_html = '';1001var pm_html = '';10021003if (minDate && selected.clone().hour(12).minute(0).second(0).isBefore(minDate))1004am_html = ' disabled="disabled" class="disabled"';10051006if (maxDate && selected.clone().hour(0).minute(0).second(0).isAfter(maxDate))1007pm_html = ' disabled="disabled" class="disabled"';10081009if (selected.hour() >= 12) {1010html += '<option value="AM"' + am_html + '>AM</option><option value="PM" selected="selected"' + pm_html + '>PM</option>';1011} else {1012html += '<option value="AM" selected="selected"' + am_html + '>AM</option><option value="PM"' + pm_html + '>PM</option>';1013}10141015html += '</select>';1016}10171018this.container.find('.calendar.' + side + ' .calendar-time div').html(html);10191020},10211022updateFormInputs: function() {10231024//ignore mouse movements while an above-calendar text input has focus1025if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus"))1026return;10271028this.container.find('input[name=daterangepicker_start]').val(this.startDate.format(this.locale.format));1029if (this.endDate)1030this.container.find('input[name=daterangepicker_end]').val(this.endDate.format(this.locale.format));10311032if (this.singleDatePicker || (this.endDate && (this.startDate.isBefore(this.endDate) || this.startDate.isSame(this.endDate)))) {1033this.container.find('button.applyBtn').removeAttr('disabled');1034} else {1035this.container.find('button.applyBtn').attr('disabled', 'disabled');1036}10371038},10391040move: function() {1041var parentOffset = { top: 0, left: 0 },1042containerTop;1043var parentRightEdge = $(window).width();1044if (!this.parentEl.is('body')) {1045parentOffset = {1046top: this.parentEl.offset().top - this.parentEl.scrollTop(),1047left: this.parentEl.offset().left - this.parentEl.scrollLeft()1048};1049parentRightEdge = this.parentEl[0].clientWidth + this.parentEl.offset().left;1050}10511052if (this.drops == 'up')1053containerTop = this.element.offset().top - this.container.outerHeight() - parentOffset.top;1054else1055containerTop = this.element.offset().top + this.element.outerHeight() - parentOffset.top;1056this.container[this.drops == 'up' ? 'addClass' : 'removeClass']('dropup');10571058if (this.opens == 'left') {1059this.container.css({1060top: containerTop,1061right: parentRightEdge - this.element.offset().left - this.element.outerWidth(),1062left: 'auto'1063});1064if (this.container.offset().left < 0) {1065this.container.css({1066right: 'auto',1067left: 91068});1069}1070} else if (this.opens == 'center') {1071this.container.css({1072top: containerTop,1073left: this.element.offset().left - parentOffset.left + this.element.outerWidth() / 21074- this.container.outerWidth() / 2,1075right: 'auto'1076});1077if (this.container.offset().left < 0) {1078this.container.css({1079right: 'auto',1080left: 91081});1082}1083} else {1084this.container.css({1085top: containerTop,1086left: this.element.offset().left - parentOffset.left,1087right: 'auto'1088});1089if (this.container.offset().left + this.container.outerWidth() > $(window).width()) {1090this.container.css({1091left: 'auto',1092right: 01093});1094}1095}1096},10971098show: function(e) {1099if (this.isShowing) return;11001101// Create a click proxy that is private to this instance of datepicker, for unbinding1102this._outsideClickProxy = $.proxy(function(e) { this.outsideClick(e); }, this);11031104// Bind global datepicker mousedown for hiding and1105$(document)1106.on('mousedown.daterangepicker', this._outsideClickProxy)1107// also support mobile devices1108.on('touchend.daterangepicker', this._outsideClickProxy)1109// also explicitly play nice with Bootstrap dropdowns, which stopPropagation when clicking them1110.on('click.daterangepicker', '[data-toggle=dropdown]', this._outsideClickProxy)1111// and also close when focus changes to outside the picker (eg. tabbing between controls)1112.on('focusin.daterangepicker', this._outsideClickProxy);11131114// Reposition the picker if the window is resized while it's open1115$(window).on('resize.daterangepicker', $.proxy(function(e) { this.move(e); }, this));11161117this.oldStartDate = this.startDate.clone();1118this.oldEndDate = this.endDate.clone();1119this.previousRightTime = this.endDate.clone();11201121this.updateView();1122this.container.show();1123this.move();1124this.element.trigger('show.daterangepicker', this);1125this.isShowing = true;1126},11271128hide: function(e) {1129if (!this.isShowing) return;11301131//incomplete date selection, revert to last values1132if (!this.endDate) {1133this.startDate = this.oldStartDate.clone();1134this.endDate = this.oldEndDate.clone();1135}11361137//if a new date range was selected, invoke the user callback function1138if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate))1139this.callback(this.startDate, this.endDate, this.chosenLabel);11401141//if picker is attached to a text input, update it1142this.updateElement();11431144$(document).off('.daterangepicker');1145$(window).off('.daterangepicker');1146this.container.hide();1147this.element.trigger('hide.daterangepicker', this);1148this.isShowing = false;1149},11501151toggle: function(e) {1152if (this.isShowing) {1153this.hide();1154} else {1155this.show();1156}1157},11581159outsideClick: function(e) {1160var target = $(e.target);1161// if the page is clicked anywhere except within the daterangerpicker/button1162// itself then call this.hide()1163if (1164// ie modal dialog fix1165e.type == "focusin" ||1166target.closest(this.element).length ||1167target.closest(this.container).length ||1168target.closest('.calendar-table').length1169) return;1170this.hide();1171this.element.trigger('outsideClick.daterangepicker', this);1172},11731174showCalendars: function() {1175this.container.addClass('show-calendar');1176this.move();1177this.element.trigger('showCalendar.daterangepicker', this);1178},11791180hideCalendars: function() {1181this.container.removeClass('show-calendar');1182this.element.trigger('hideCalendar.daterangepicker', this);1183},11841185hoverRange: function(e) {11861187//ignore mouse movements while an above-calendar text input has focus1188if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus"))1189return;11901191var label = e.target.getAttribute('data-range-key');11921193if (label == this.locale.customRangeLabel) {1194this.updateView();1195} else {1196var dates = this.ranges[label];1197this.container.find('input[name=daterangepicker_start]').val(dates[0].format(this.locale.format));1198this.container.find('input[name=daterangepicker_end]').val(dates[1].format(this.locale.format));1199}12001201},12021203clickRange: function(e) {1204var label = e.target.getAttribute('data-range-key');1205this.chosenLabel = label;1206if (label == this.locale.customRangeLabel) {1207this.showCalendars();1208} else {1209var dates = this.ranges[label];1210this.startDate = dates[0];1211this.endDate = dates[1];12121213if (!this.timePicker) {1214this.startDate.startOf('day');1215this.endDate.endOf('day');1216}12171218if (!this.alwaysShowCalendars)1219this.hideCalendars();1220this.clickApply();1221}1222},12231224clickPrev: function(e) {1225var cal = $(e.target).parents('.calendar');1226if (cal.hasClass('left')) {1227this.leftCalendar.month.subtract(1, 'month');1228if (this.linkedCalendars)1229this.rightCalendar.month.subtract(1, 'month');1230} else {1231this.rightCalendar.month.subtract(1, 'month');1232}1233this.updateCalendars();1234},12351236clickNext: function(e) {1237var cal = $(e.target).parents('.calendar');1238if (cal.hasClass('left')) {1239this.leftCalendar.month.add(1, 'month');1240} else {1241this.rightCalendar.month.add(1, 'month');1242if (this.linkedCalendars)1243this.leftCalendar.month.add(1, 'month');1244}1245this.updateCalendars();1246},12471248hoverDate: function(e) {12491250//ignore mouse movements while an above-calendar text input has focus1251//if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus"))1252// return;12531254//ignore dates that can't be selected1255if (!$(e.target).hasClass('available')) return;12561257//have the text inputs above calendars reflect the date being hovered over1258var title = $(e.target).attr('data-title');1259var row = title.substr(1, 1);1260var col = title.substr(3, 1);1261var cal = $(e.target).parents('.calendar');1262var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col];12631264if (this.endDate && !this.container.find('input[name=daterangepicker_start]').is(":focus")) {1265this.container.find('input[name=daterangepicker_start]').val(date.format(this.locale.format));1266} else if (!this.endDate && !this.container.find('input[name=daterangepicker_end]').is(":focus")) {1267this.container.find('input[name=daterangepicker_end]').val(date.format(this.locale.format));1268}12691270//highlight the dates between the start date and the date being hovered as a potential end date1271var leftCalendar = this.leftCalendar;1272var rightCalendar = this.rightCalendar;1273var startDate = this.startDate;1274if (!this.endDate) {1275this.container.find('.calendar tbody td').each(function(index, el) {12761277//skip week numbers, only look at dates1278if ($(el).hasClass('week')) return;12791280var title = $(el).attr('data-title');1281var row = title.substr(1, 1);1282var col = title.substr(3, 1);1283var cal = $(el).parents('.calendar');1284var dt = cal.hasClass('left') ? leftCalendar.calendar[row][col] : rightCalendar.calendar[row][col];12851286if ((dt.isAfter(startDate) && dt.isBefore(date)) || dt.isSame(date, 'day')) {1287$(el).addClass('in-range');1288} else {1289$(el).removeClass('in-range');1290}12911292});1293}12941295},12961297clickDate: function(e) {12981299if (!$(e.target).hasClass('available')) return;13001301var title = $(e.target).attr('data-title');1302var row = title.substr(1, 1);1303var col = title.substr(3, 1);1304var cal = $(e.target).parents('.calendar');1305var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col];13061307//1308// this function needs to do a few things:1309// * alternate between selecting a start and end date for the range,1310// * if the time picker is enabled, apply the hour/minute/second from the select boxes to the clicked date1311// * if autoapply is enabled, and an end date was chosen, apply the selection1312// * if single date picker mode, and time picker isn't enabled, apply the selection immediately1313// * if one of the inputs above the calendars was focused, cancel that manual input1314//13151316if (this.endDate || date.isBefore(this.startDate, 'day')) { //picking start1317if (this.timePicker) {1318var hour = parseInt(this.container.find('.left .hourselect').val(), 10);1319if (!this.timePicker24Hour) {1320var ampm = this.container.find('.left .ampmselect').val();1321if (ampm === 'PM' && hour < 12)1322hour += 12;1323if (ampm === 'AM' && hour === 12)1324hour = 0;1325}1326var minute = parseInt(this.container.find('.left .minuteselect').val(), 10);1327var second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0;1328date = date.clone().hour(hour).minute(minute).second(second);1329}1330this.endDate = null;1331this.setStartDate(date.clone());1332} else if (!this.endDate && date.isBefore(this.startDate)) {1333//special case: clicking the same date for start/end,1334//but the time of the end date is before the start date1335this.setEndDate(this.startDate.clone());1336} else { // picking end1337if (this.timePicker) {1338var hour = parseInt(this.container.find('.right .hourselect').val(), 10);1339if (!this.timePicker24Hour) {1340var ampm = this.container.find('.right .ampmselect').val();1341if (ampm === 'PM' && hour < 12)1342hour += 12;1343if (ampm === 'AM' && hour === 12)1344hour = 0;1345}1346var minute = parseInt(this.container.find('.right .minuteselect').val(), 10);1347var second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0;1348date = date.clone().hour(hour).minute(minute).second(second);1349}1350this.setEndDate(date.clone());1351if (this.autoApply) {1352this.calculateChosenLabel();1353this.clickApply();1354}1355}13561357if (this.singleDatePicker) {1358this.setEndDate(this.startDate);1359if (!this.timePicker)1360this.clickApply();1361}13621363this.updateView();13641365//This is to cancel the blur event handler if the mouse was in one of the inputs1366e.stopPropagation();13671368},13691370calculateChosenLabel: function () {1371var customRange = true;1372var i = 0;1373for (var range in this.ranges) {1374if (this.timePicker) {1375if (this.startDate.isSame(this.ranges[range][0]) && this.endDate.isSame(this.ranges[range][1])) {1376customRange = false;1377this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').html();1378break;1379}1380} else {1381//ignore times when comparing dates if time picker is not enabled1382if (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')) {1383customRange = false;1384this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').html();1385break;1386}1387}1388i++;1389}1390if (customRange) {1391if (this.showCustomRangeLabel) {1392this.chosenLabel = this.container.find('.ranges li:last').addClass('active').html();1393} else {1394this.chosenLabel = null;1395}1396this.showCalendars();1397}1398},13991400clickApply: function(e) {1401this.hide();1402this.element.trigger('apply.daterangepicker', this);1403},14041405clickCancel: function(e) {1406this.startDate = this.oldStartDate;1407this.endDate = this.oldEndDate;1408this.hide();1409this.element.trigger('cancel.daterangepicker', this);1410},14111412monthOrYearChanged: function(e) {1413var isLeft = $(e.target).closest('.calendar').hasClass('left'),1414leftOrRight = isLeft ? 'left' : 'right',1415cal = this.container.find('.calendar.'+leftOrRight);14161417// Month must be Number for new moment versions1418var month = parseInt(cal.find('.monthselect').val(), 10);1419var year = cal.find('.yearselect').val();14201421if (!isLeft) {1422if (year < this.startDate.year() || (year == this.startDate.year() && month < this.startDate.month())) {1423month = this.startDate.month();1424year = this.startDate.year();1425}1426}14271428if (this.minDate) {1429if (year < this.minDate.year() || (year == this.minDate.year() && month < this.minDate.month())) {1430month = this.minDate.month();1431year = this.minDate.year();1432}1433}14341435if (this.maxDate) {1436if (year > this.maxDate.year() || (year == this.maxDate.year() && month > this.maxDate.month())) {1437month = this.maxDate.month();1438year = this.maxDate.year();1439}1440}14411442if (isLeft) {1443this.leftCalendar.month.month(month).year(year);1444if (this.linkedCalendars)1445this.rightCalendar.month = this.leftCalendar.month.clone().add(1, 'month');1446} else {1447this.rightCalendar.month.month(month).year(year);1448if (this.linkedCalendars)1449this.leftCalendar.month = this.rightCalendar.month.clone().subtract(1, 'month');1450}1451this.updateCalendars();1452},14531454timeChanged: function(e) {14551456var cal = $(e.target).closest('.calendar'),1457isLeft = cal.hasClass('left');14581459var hour = parseInt(cal.find('.hourselect').val(), 10);1460var minute = parseInt(cal.find('.minuteselect').val(), 10);1461var second = this.timePickerSeconds ? parseInt(cal.find('.secondselect').val(), 10) : 0;14621463if (!this.timePicker24Hour) {1464var ampm = cal.find('.ampmselect').val();1465if (ampm === 'PM' && hour < 12)1466hour += 12;1467if (ampm === 'AM' && hour === 12)1468hour = 0;1469}14701471if (isLeft) {1472var start = this.startDate.clone();1473start.hour(hour);1474start.minute(minute);1475start.second(second);1476this.setStartDate(start);1477if (this.singleDatePicker) {1478this.endDate = this.startDate.clone();1479} else if (this.endDate && this.endDate.format('YYYY-MM-DD') == start.format('YYYY-MM-DD') && this.endDate.isBefore(start)) {1480this.setEndDate(start.clone());1481}1482} else if (this.endDate) {1483var end = this.endDate.clone();1484end.hour(hour);1485end.minute(minute);1486end.second(second);1487this.setEndDate(end);1488}14891490//update the calendars so all clickable dates reflect the new time component1491this.updateCalendars();14921493//update the form inputs above the calendars with the new time1494this.updateFormInputs();14951496//re-render the time pickers because changing one selection can affect what's enabled in another1497this.renderTimePicker('left');1498this.renderTimePicker('right');14991500},15011502formInputsChanged: function(e) {1503var isRight = $(e.target).closest('.calendar').hasClass('right');1504var start = moment(this.container.find('input[name="daterangepicker_start"]').val(), this.locale.format);1505var end = moment(this.container.find('input[name="daterangepicker_end"]').val(), this.locale.format);15061507if (start.isValid() && end.isValid()) {15081509if (isRight && end.isBefore(start))1510start = end.clone();15111512this.setStartDate(start);1513this.setEndDate(end);15141515if (isRight) {1516this.container.find('input[name="daterangepicker_start"]').val(this.startDate.format(this.locale.format));1517} else {1518this.container.find('input[name="daterangepicker_end"]').val(this.endDate.format(this.locale.format));1519}15201521}15221523this.updateView();1524},15251526formInputsFocused: function(e) {15271528// Highlight the focused input1529this.container.find('input[name="daterangepicker_start"], input[name="daterangepicker_end"]').removeClass('active');1530$(e.target).addClass('active');15311532// Set the state such that if the user goes back to using a mouse,1533// the calendars are aware we're selecting the end of the range, not1534// the start. This allows someone to edit the end of a date range without1535// re-selecting the beginning, by clicking on the end date input then1536// using the calendar.1537var isRight = $(e.target).closest('.calendar').hasClass('right');1538if (isRight) {1539this.endDate = null;1540this.setStartDate(this.startDate.clone());1541this.updateView();1542}15431544},15451546formInputsBlurred: function(e) {15471548// this function has one purpose right now: if you tab from the first1549// text input to the second in the UI, the endDate is nulled so that1550// you can click another, but if you tab out without clicking anything1551// or changing the input value, the old endDate should be retained15521553if (!this.endDate) {1554var val = this.container.find('input[name="daterangepicker_end"]').val();1555var end = moment(val, this.locale.format);1556if (end.isValid()) {1557this.setEndDate(end);1558this.updateView();1559}1560}15611562},15631564elementChanged: function() {1565if (!this.element.is('input')) return;1566if (!this.element.val().length) return;1567if (this.element.val().length < this.locale.format.length) return;15681569var dateString = this.element.val().split(this.locale.separator),1570start = null,1571end = null;15721573if (dateString.length === 2) {1574start = moment(dateString[0], this.locale.format);1575end = moment(dateString[1], this.locale.format);1576}15771578if (this.singleDatePicker || start === null || end === null) {1579start = moment(this.element.val(), this.locale.format);1580end = start;1581}15821583if (!start.isValid() || !end.isValid()) return;15841585this.setStartDate(start);1586this.setEndDate(end);1587this.updateView();1588},15891590keydown: function(e) {1591//hide on tab or enter1592if ((e.keyCode === 9) || (e.keyCode === 13)) {1593this.hide();1594}1595},15961597updateElement: function() {1598if (this.element.is('input') && !this.singleDatePicker && this.autoUpdateInput) {1599this.element.val(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format));1600this.element.trigger('change');1601} else if (this.element.is('input') && this.autoUpdateInput) {1602this.element.val(this.startDate.format(this.locale.format));1603this.element.trigger('change');1604}1605},16061607remove: function() {1608this.container.remove();1609this.element.off('.daterangepicker');1610this.element.removeData();1611}16121613};16141615$.fn.daterangepicker = function(options, callback) {1616this.each(function() {1617var el = $(this);1618if (el.data('daterangepicker'))1619el.data('daterangepicker').remove();1620el.data('daterangepicker', new DateRangePicker(el, options, callback));1621});1622return this;1623};16241625return DateRangePicker;16261627}));162816291630