Path: blob/master/web-gui/buildyourownbotnet/assets/js/daterangepicker/daterangepicker.js
1293 views
/**1* @version: 1.3.212* @author: Dan Grossman http://www.dangrossman.info/3* @copyright: Copyright (c) 2012-2015 Dan Grossman. All rights reserved.4* @license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php5* @website: https://www.improvely.com/6*/78(function(root, factory) {910if (typeof define === 'function' && define.amd) {11define(['moment', 'jquery', 'exports'], function(momentjs, $, exports) {12root.daterangepicker = factory(root, exports, momentjs, $);13});1415} else if (typeof exports !== 'undefined') {16var momentjs = require('moment');17var jQuery;18try {19jQuery = require('jquery');20} catch (err) {21jQuery = window.jQuery;22if (!jQuery) throw new Error('jQuery dependency not found');23}2425factory(root, exports, momentjs, jQuery);2627// Finally, as a browser global.28} else {29root.daterangepicker = factory(root, {}, root.moment, (root.jQuery || root.Zepto || root.ender || root.$));30}3132}(this, function(root, daterangepicker, moment, $) {3334var DateRangePicker = function (element, options, cb) {3536// by default, the daterangepicker element is placed at the bottom of HTML body37this.parentEl = 'body';3839//element that triggered the date range picker40this.element = $(element);4142//tracks visible state43this.isShowing = false;4445//create the picker HTML object46var DRPTemplate = '<div class="daterangepicker dropdown-menu">' +47'<div class="calendar first left"></div>' +48'<div class="calendar second right"></div>' +49'<div class="ranges">' +50'<div class="range_inputs">' +51'<div class="daterangepicker_start_input">' +52'<label for="daterangepicker_start"></label>' +53'<input class="input-mini" type="text" name="daterangepicker_start" value="" />' +54'</div>' +55'<div class="daterangepicker_end_input">' +56'<label for="daterangepicker_end"></label>' +57'<input class="input-mini" type="text" name="daterangepicker_end" value="" />' +58'</div>' +59'<button class="applyBtn" disabled="disabled"></button> ' +60'<button class="cancelBtn"></button>' +61'</div>' +62'</div>' +63'</div>';6465//custom options66if (typeof options !== 'object' || options === null)67options = {};6869this.parentEl = (typeof options === 'object' && options.parentEl && $(options.parentEl).length) ? $(options.parentEl) : $(this.parentEl);70this.container = $(DRPTemplate).appendTo(this.parentEl);7172this.setOptions(options, cb);7374//event listeners75this.container.find('.calendar')76.on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this))77.on('click.daterangepicker', '.next', $.proxy(this.clickNext, this))78.on('click.daterangepicker', 'td.available', $.proxy(this.clickDate, this))79.on('mouseenter.daterangepicker', 'td.available', $.proxy(this.hoverDate, this))80.on('mouseleave.daterangepicker', 'td.available', $.proxy(this.updateFormInputs, this))81.on('change.daterangepicker', 'select.yearselect', $.proxy(this.updateMonthYear, this))82.on('change.daterangepicker', 'select.monthselect', $.proxy(this.updateMonthYear, this))83.on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', $.proxy(this.updateTime, this));8485this.container.find('.ranges')86.on('click.daterangepicker', 'button.applyBtn', $.proxy(this.clickApply, this))87.on('click.daterangepicker', 'button.cancelBtn', $.proxy(this.clickCancel, this))88.on('click.daterangepicker', '.daterangepicker_start_input,.daterangepicker_end_input', $.proxy(this.showCalendars, this))89.on('change.daterangepicker', '.daterangepicker_start_input,.daterangepicker_end_input', $.proxy(this.inputsChanged, this))90.on('keydown.daterangepicker', '.daterangepicker_start_input,.daterangepicker_end_input', $.proxy(this.inputsKeydown, this))91.on('click.daterangepicker', 'li', $.proxy(this.clickRange, this))92.on('mouseenter.daterangepicker', 'li', $.proxy(this.enterRange, this))93.on('mouseleave.daterangepicker', 'li', $.proxy(this.updateFormInputs, this));9495if (this.element.is('input')) {96this.element.on({97'click.daterangepicker': $.proxy(this.show, this),98'focus.daterangepicker': $.proxy(this.show, this),99'keyup.daterangepicker': $.proxy(this.updateFromControl, this),100'keydown.daterangepicker': $.proxy(this.keydown, this)101});102} else {103this.element.on('click.daterangepicker', $.proxy(this.toggle, this));104}105106};107108DateRangePicker.prototype = {109110constructor: DateRangePicker,111112setOptions: function(options, callback) {113114this.startDate = moment().startOf('day');115this.endDate = moment().endOf('day');116this.timeZone = moment().utcOffset();117this.minDate = false;118this.maxDate = false;119this.dateLimit = false;120121this.showDropdowns = false;122this.showWeekNumbers = false;123this.timePicker = false;124this.timePickerSeconds = false;125this.timePickerIncrement = 30;126this.timePicker12Hour = true;127this.singleDatePicker = false;128this.ranges = {};129130this.opens = 'right';131if (this.element.hasClass('pull-right'))132this.opens = 'left';133134this.drops = 'down';135if (this.element.hasClass('dropup'))136this.drops = 'up';137138this.buttonClasses = ['btn', 'btn-small btn-sm'];139this.applyClass = 'btn-success';140this.cancelClass = 'btn-default';141142this.format = 'MM/DD/YYYY';143this.separator = ' - ';144145this.locale = {146applyLabel: 'Apply',147cancelLabel: 'Cancel',148fromLabel: 'From',149toLabel: 'To',150weekLabel: 'W',151customRangeLabel: 'Custom Range',152daysOfWeek: moment.weekdaysMin(),153monthNames: moment.monthsShort(),154firstDay: moment.localeData()._week.dow155};156157this.cb = function () { };158159if (typeof options.format === 'string')160this.format = options.format;161162if (typeof options.separator === 'string')163this.separator = options.separator;164165if (typeof options.startDate === 'string')166this.startDate = moment(options.startDate, this.format);167168if (typeof options.endDate === 'string')169this.endDate = moment(options.endDate, this.format);170171if (typeof options.minDate === 'string')172this.minDate = moment(options.minDate, this.format);173174if (typeof options.maxDate === 'string')175this.maxDate = moment(options.maxDate, this.format);176177if (typeof options.startDate === 'object')178this.startDate = moment(options.startDate);179180if (typeof options.endDate === 'object')181this.endDate = moment(options.endDate);182183if (typeof options.minDate === 'object')184this.minDate = moment(options.minDate);185186if (typeof options.maxDate === 'object')187this.maxDate = moment(options.maxDate);188189if (typeof options.applyClass === 'string')190this.applyClass = options.applyClass;191192if (typeof options.cancelClass === 'string')193this.cancelClass = options.cancelClass;194195if (typeof options.dateLimit === 'object')196this.dateLimit = options.dateLimit;197198if (typeof options.locale === 'object') {199200if (typeof options.locale.daysOfWeek === 'object') {201// Create a copy of daysOfWeek to avoid modification of original202// options object for reusability in multiple daterangepicker instances203this.locale.daysOfWeek = options.locale.daysOfWeek.slice();204}205206if (typeof options.locale.monthNames === 'object') {207this.locale.monthNames = options.locale.monthNames.slice();208}209210if (typeof options.locale.firstDay === 'number') {211this.locale.firstDay = options.locale.firstDay;212}213214if (typeof options.locale.applyLabel === 'string') {215this.locale.applyLabel = options.locale.applyLabel;216}217218if (typeof options.locale.cancelLabel === 'string') {219this.locale.cancelLabel = options.locale.cancelLabel;220}221222if (typeof options.locale.fromLabel === 'string') {223this.locale.fromLabel = options.locale.fromLabel;224}225226if (typeof options.locale.toLabel === 'string') {227this.locale.toLabel = options.locale.toLabel;228}229230if (typeof options.locale.weekLabel === 'string') {231this.locale.weekLabel = options.locale.weekLabel;232}233234if (typeof options.locale.customRangeLabel === 'string') {235this.locale.customRangeLabel = options.locale.customRangeLabel;236}237}238239if (typeof options.opens === 'string')240this.opens = options.opens;241242if (typeof options.drops === 'string')243this.drops = options.drops;244245if (typeof options.showWeekNumbers === 'boolean') {246this.showWeekNumbers = options.showWeekNumbers;247}248249if (typeof options.buttonClasses === 'string') {250this.buttonClasses = [options.buttonClasses];251}252253if (typeof options.buttonClasses === 'object') {254this.buttonClasses = options.buttonClasses;255}256257if (typeof options.showDropdowns === 'boolean') {258this.showDropdowns = options.showDropdowns;259}260261if (typeof options.singleDatePicker === 'boolean') {262this.singleDatePicker = options.singleDatePicker;263if (this.singleDatePicker) {264this.endDate = this.startDate.clone();265}266}267268if (typeof options.timePicker === 'boolean') {269this.timePicker = options.timePicker;270}271272if (typeof options.timePickerSeconds === 'boolean') {273this.timePickerSeconds = options.timePickerSeconds;274}275276if (typeof options.timePickerIncrement === 'number') {277this.timePickerIncrement = options.timePickerIncrement;278}279280if (typeof options.timePicker12Hour === 'boolean') {281this.timePicker12Hour = options.timePicker12Hour;282}283284// update day names order to firstDay285if (this.locale.firstDay != 0) {286var iterator = this.locale.firstDay;287while (iterator > 0) {288this.locale.daysOfWeek.push(this.locale.daysOfWeek.shift());289iterator--;290}291}292293var start, end, range;294295//if no start/end dates set, check if an input element contains initial values296if (typeof options.startDate === 'undefined' && typeof options.endDate === 'undefined') {297if ($(this.element).is('input[type=text]')) {298var val = $(this.element).val(),299split = val.split(this.separator);300301start = end = null;302303if (split.length == 2) {304start = moment(split[0], this.format);305end = moment(split[1], this.format);306} else if (this.singleDatePicker && val !== "") {307start = moment(val, this.format);308end = moment(val, this.format);309}310if (start !== null && end !== null) {311this.startDate = start;312this.endDate = end;313}314}315}316317// bind the time zone used to build the calendar to either the timeZone passed in through the options or the zone of the startDate (which will be the local time zone by default)318if (typeof options.timeZone === 'string' || typeof options.timeZone === 'number') {319if (typeof options.timeZone === 'string' && typeof moment.tz !== 'undefined') {320this.timeZone = moment.tz.zone(options.timeZone).parse(new Date) * -1; // Offset is positive if the timezone is behind UTC and negative if it is ahead.321} else {322this.timeZone = options.timeZone;323}324this.startDate.utcOffset(this.timeZone);325this.endDate.utcOffset(this.timeZone);326} else {327this.timeZone = moment(this.startDate).utcOffset();328}329330if (typeof options.ranges === 'object') {331for (range in options.ranges) {332333if (typeof options.ranges[range][0] === 'string')334start = moment(options.ranges[range][0], this.format);335else336start = moment(options.ranges[range][0]);337338if (typeof options.ranges[range][1] === 'string')339end = moment(options.ranges[range][1], this.format);340else341end = moment(options.ranges[range][1]);342343// If we have a min/max date set, bound this range344// to it, but only if it would otherwise fall345// outside of the min/max.346if (this.minDate && start.isBefore(this.minDate))347start = moment(this.minDate);348349if (this.maxDate && end.isAfter(this.maxDate))350end = moment(this.maxDate);351352// If the end of the range is before the minimum (if min is set) OR353// the start of the range is after the max (also if set) don't display this354// range option.355if ((this.minDate && end.isBefore(this.minDate)) || (this.maxDate && start.isAfter(this.maxDate))) {356continue;357}358359this.ranges[range] = [start, end];360}361362var list = '<ul>';363for (range in this.ranges) {364list += '<li>' + range + '</li>';365}366list += '<li>' + this.locale.customRangeLabel + '</li>';367list += '</ul>';368this.container.find('.ranges ul').remove();369this.container.find('.ranges').prepend(list);370}371372if (typeof callback === 'function') {373this.cb = callback;374}375376if (!this.timePicker) {377this.startDate = this.startDate.startOf('day');378this.endDate = this.endDate.endOf('day');379}380381if (this.singleDatePicker) {382this.opens = 'right';383this.container.addClass('single');384this.container.find('.calendar.right').show();385this.container.find('.calendar.left').hide();386if (!this.timePicker) {387this.container.find('.ranges').hide();388} else {389this.container.find('.ranges .daterangepicker_start_input, .ranges .daterangepicker_end_input').hide();390}391if (!this.container.find('.calendar.right').hasClass('single'))392this.container.find('.calendar.right').addClass('single');393} else {394this.container.removeClass('single');395this.container.find('.calendar.right').removeClass('single');396this.container.find('.ranges').show();397}398399this.oldStartDate = this.startDate.clone();400this.oldEndDate = this.endDate.clone();401this.oldChosenLabel = this.chosenLabel;402403this.leftCalendar = {404month: moment([this.startDate.year(), this.startDate.month(), 1, this.startDate.hour(), this.startDate.minute(), this.startDate.second()]),405calendar: []406};407408this.rightCalendar = {409month: moment([this.endDate.year(), this.endDate.month(), 1, this.endDate.hour(), this.endDate.minute(), this.endDate.second()]),410calendar: []411};412413if (this.opens == 'right' || this.opens == 'center') {414//swap calendar positions415var first = this.container.find('.calendar.first');416var second = this.container.find('.calendar.second');417418if (second.hasClass('single')) {419second.removeClass('single');420first.addClass('single');421}422423first.removeClass('left').addClass('right');424second.removeClass('right').addClass('left');425426if (this.singleDatePicker) {427first.show();428second.hide();429}430}431432if (typeof options.ranges === 'undefined' && !this.singleDatePicker) {433this.container.addClass('show-calendar');434}435436this.container.removeClass('opensleft opensright').addClass('opens' + this.opens);437438this.updateView();439this.updateCalendars();440441//apply CSS classes and labels to buttons442var c = this.container;443$.each(this.buttonClasses, function (idx, val) {444c.find('button').addClass(val);445});446this.container.find('.daterangepicker_start_input label').html(this.locale.fromLabel);447this.container.find('.daterangepicker_end_input label').html(this.locale.toLabel);448if (this.applyClass.length)449this.container.find('.applyBtn').addClass(this.applyClass);450if (this.cancelClass.length)451this.container.find('.cancelBtn').addClass(this.cancelClass);452this.container.find('.applyBtn').html(this.locale.applyLabel);453this.container.find('.cancelBtn').html(this.locale.cancelLabel);454},455456setStartDate: function(startDate) {457if (typeof startDate === 'string')458this.startDate = moment(startDate, this.format).utcOffset(this.timeZone);459460if (typeof startDate === 'object')461this.startDate = moment(startDate);462463if (!this.timePicker)464this.startDate = this.startDate.startOf('day');465466this.oldStartDate = this.startDate.clone();467468this.updateView();469this.updateCalendars();470this.updateInputText();471},472473setEndDate: function(endDate) {474if (typeof endDate === 'string')475this.endDate = moment(endDate, this.format).utcOffset(this.timeZone);476477if (typeof endDate === 'object')478this.endDate = moment(endDate);479480if (!this.timePicker)481this.endDate = this.endDate.endOf('day');482483this.oldEndDate = this.endDate.clone();484485this.updateView();486this.updateCalendars();487this.updateInputText();488},489490updateView: function () {491this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year()).hour(this.startDate.hour()).minute(this.startDate.minute());492this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year()).hour(this.endDate.hour()).minute(this.endDate.minute());493this.updateFormInputs();494},495496updateFormInputs: function () {497this.container.find('input[name=daterangepicker_start]').val(this.startDate.format(this.format));498this.container.find('input[name=daterangepicker_end]').val(this.endDate.format(this.format));499500if (this.startDate.isSame(this.endDate) || this.startDate.isBefore(this.endDate)) {501this.container.find('button.applyBtn').removeAttr('disabled');502} else {503this.container.find('button.applyBtn').attr('disabled', 'disabled');504}505},506507updateFromControl: function () {508if (!this.element.is('input')) return;509if (!this.element.val().length) return;510511var dateString = this.element.val().split(this.separator),512start = null,513end = null;514515if(dateString.length === 2) {516start = moment(dateString[0], this.format).utcOffset(this.timeZone);517end = moment(dateString[1], this.format).utcOffset(this.timeZone);518}519520if (this.singleDatePicker || start === null || end === null) {521start = moment(this.element.val(), this.format).utcOffset(this.timeZone);522end = start;523}524525if (end.isBefore(start)) return;526527this.oldStartDate = this.startDate.clone();528this.oldEndDate = this.endDate.clone();529530this.startDate = start;531this.endDate = end;532533if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate))534this.notify();535536this.updateCalendars();537},538539keydown: function (e) {540//hide on tab or enter541if ((e.keyCode === 9) || (e.keyCode === 13)) {542this.hide();543}544},545546notify: function () {547this.updateView();548this.cb(this.startDate, this.endDate, this.chosenLabel);549},550551move: function () {552var parentOffset = { top: 0, left: 0 },553containerTop;554var parentRightEdge = $(window).width();555if (!this.parentEl.is('body')) {556parentOffset = {557top: this.parentEl.offset().top - this.parentEl.scrollTop(),558left: this.parentEl.offset().left - this.parentEl.scrollLeft()559};560parentRightEdge = this.parentEl[0].clientWidth + this.parentEl.offset().left;561}562563if (this.drops == 'up')564containerTop = this.element.offset().top - this.container.outerHeight() - parentOffset.top;565else566containerTop = this.element.offset().top + this.element.outerHeight() - parentOffset.top;567this.container[this.drops == 'up' ? 'addClass' : 'removeClass']('dropup');568569if (this.opens == 'left') {570this.container.css({571top: containerTop,572right: parentRightEdge - this.element.offset().left - this.element.outerWidth(),573left: 'auto'574});575if (this.container.offset().left < 0) {576this.container.css({577right: 'auto',578left: 9579});580}581} else if (this.opens == 'center') {582this.container.css({583top: containerTop,584left: this.element.offset().left - parentOffset.left + this.element.outerWidth() / 2585- this.container.outerWidth() / 2,586right: 'auto'587});588if (this.container.offset().left < 0) {589this.container.css({590right: 'auto',591left: 9592});593}594} else {595this.container.css({596top: containerTop,597left: this.element.offset().left - parentOffset.left,598right: 'auto'599});600if (this.container.offset().left + this.container.outerWidth() > $(window).width()) {601this.container.css({602left: 'auto',603right: 0604});605}606}607},608609toggle: function (e) {610if (this.element.hasClass('active')) {611this.hide();612} else {613this.show();614}615},616617show: function (e) {618if (this.isShowing) return;619620this.element.addClass('active');621this.container.show();622this.move();623624// Create a click proxy that is private to this instance of datepicker, for unbinding625this._outsideClickProxy = $.proxy(function (e) { this.outsideClick(e); }, this);626// Bind global datepicker mousedown for hiding and627$(document)628.on('mousedown.daterangepicker', this._outsideClickProxy)629// also support mobile devices630.on('touchend.daterangepicker', this._outsideClickProxy)631// also explicitly play nice with Bootstrap dropdowns, which stopPropagation when clicking them632.on('click.daterangepicker', '[data-toggle=dropdown]', this._outsideClickProxy)633// and also close when focus changes to outside the picker (eg. tabbing between controls)634.on('focusin.daterangepicker', this._outsideClickProxy);635636this.isShowing = true;637this.element.trigger('show.daterangepicker', this);638},639640outsideClick: function (e) {641var target = $(e.target);642// if the page is clicked anywhere except within the daterangerpicker/button643// itself then call this.hide()644if (645// ie modal dialog fix646e.type == "focusin" ||647target.closest(this.element).length ||648target.closest(this.container).length ||649target.closest('.calendar-date').length650) return;651this.hide();652},653654hide: function (e) {655if (!this.isShowing) return;656657$(document)658.off('.daterangepicker');659660this.element.removeClass('active');661this.container.hide();662663if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate))664this.notify();665666this.oldStartDate = this.startDate.clone();667this.oldEndDate = this.endDate.clone();668669this.isShowing = false;670this.element.trigger('hide.daterangepicker', this);671},672673enterRange: function (e) {674// mouse pointer has entered a range label675var label = e.target.innerHTML;676if (label == this.locale.customRangeLabel) {677this.updateView();678} else {679var dates = this.ranges[label];680this.container.find('input[name=daterangepicker_start]').val(dates[0].format(this.format));681this.container.find('input[name=daterangepicker_end]').val(dates[1].format(this.format));682}683},684685showCalendars: function() {686this.container.addClass('show-calendar');687this.move();688this.element.trigger('showCalendar.daterangepicker', this);689},690691hideCalendars: function() {692this.container.removeClass('show-calendar');693this.element.trigger('hideCalendar.daterangepicker', this);694},695696// when a date is typed into the start to end date textboxes697inputsChanged: function (e) {698var el = $(e.target);699var date = moment(el.val(), this.format);700if (!date.isValid()) return;701702var startDate, endDate;703if (el.attr('name') === 'daterangepicker_start') {704startDate = (false !== this.minDate && date.isBefore(this.minDate)) ? this.minDate : date;705endDate = this.endDate;706} else {707startDate = this.startDate;708endDate = (false !== this.maxDate && date.isAfter(this.maxDate)) ? this.maxDate : date;709}710this.setCustomDates(startDate, endDate);711},712713inputsKeydown: function(e) {714if (e.keyCode === 13) {715this.inputsChanged(e);716this.notify();717}718},719720updateInputText: function() {721if (this.element.is('input') && !this.singleDatePicker) {722this.element.val(this.startDate.format(this.format) + this.separator + this.endDate.format(this.format));723this.element.trigger('change');724} else if (this.element.is('input')) {725this.element.val(this.endDate.format(this.format));726this.element.trigger('change');727}728},729730clickRange: function (e) {731var label = e.target.innerHTML;732this.chosenLabel = label;733if (label == this.locale.customRangeLabel) {734this.showCalendars();735} else {736var dates = this.ranges[label];737738this.startDate = dates[0];739this.endDate = dates[1];740741if (!this.timePicker) {742this.startDate.startOf('day');743this.endDate.endOf('day');744}745746this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year()).hour(this.startDate.hour()).minute(this.startDate.minute());747this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year()).hour(this.endDate.hour()).minute(this.endDate.minute());748this.updateCalendars();749750this.updateInputText();751752this.hideCalendars();753this.hide();754this.element.trigger('apply.daterangepicker', this);755}756},757758clickPrev: function (e) {759var cal = $(e.target).parents('.calendar');760if (cal.hasClass('left')) {761this.leftCalendar.month.subtract(1, 'month');762} else {763this.rightCalendar.month.subtract(1, 'month');764}765this.updateCalendars();766},767768clickNext: function (e) {769var cal = $(e.target).parents('.calendar');770if (cal.hasClass('left')) {771this.leftCalendar.month.add(1, 'month');772} else {773this.rightCalendar.month.add(1, 'month');774}775this.updateCalendars();776},777778hoverDate: function (e) {779var title = $(e.target).attr('data-title');780var row = title.substr(1, 1);781var col = title.substr(3, 1);782var cal = $(e.target).parents('.calendar');783784if (cal.hasClass('left')) {785this.container.find('input[name=daterangepicker_start]').val(this.leftCalendar.calendar[row][col].format(this.format));786} else {787this.container.find('input[name=daterangepicker_end]').val(this.rightCalendar.calendar[row][col].format(this.format));788}789},790791setCustomDates: function(startDate, endDate) {792this.chosenLabel = this.locale.customRangeLabel;793if (startDate.isAfter(endDate)) {794var difference = this.endDate.diff(this.startDate);795endDate = moment(startDate).add(difference, 'ms');796if (this.maxDate && endDate.isAfter(this.maxDate)) {797endDate = this.maxDate.clone();798}799}800this.startDate = startDate;801this.endDate = endDate;802803this.updateView();804this.updateCalendars();805},806807clickDate: function (e) {808var title = $(e.target).attr('data-title');809var row = title.substr(1, 1);810var col = title.substr(3, 1);811var cal = $(e.target).parents('.calendar');812813var startDate, endDate;814if (cal.hasClass('left')) {815startDate = this.leftCalendar.calendar[row][col];816endDate = this.endDate;817if (typeof this.dateLimit === 'object') {818var maxDate = moment(startDate).add(this.dateLimit).startOf('day');819if (endDate.isAfter(maxDate)) {820endDate = maxDate;821}822}823} else {824startDate = this.startDate;825endDate = this.rightCalendar.calendar[row][col];826if (typeof this.dateLimit === 'object') {827var minDate = moment(endDate).subtract(this.dateLimit).startOf('day');828if (startDate.isBefore(minDate)) {829startDate = minDate;830}831}832}833834if (this.singleDatePicker && cal.hasClass('left')) {835endDate = startDate.clone();836} else if (this.singleDatePicker && cal.hasClass('right')) {837startDate = endDate.clone();838}839840cal.find('td').removeClass('active');841842$(e.target).addClass('active');843844this.setCustomDates(startDate, endDate);845846if (!this.timePicker)847endDate.endOf('day');848849if (this.singleDatePicker && !this.timePicker)850this.clickApply();851},852853clickApply: function (e) {854this.updateInputText();855this.hide();856this.element.trigger('apply.daterangepicker', this);857},858859clickCancel: function (e) {860this.startDate = this.oldStartDate;861this.endDate = this.oldEndDate;862this.chosenLabel = this.oldChosenLabel;863this.updateView();864this.updateCalendars();865this.hide();866this.element.trigger('cancel.daterangepicker', this);867},868869updateMonthYear: function (e) {870var isLeft = $(e.target).closest('.calendar').hasClass('left'),871leftOrRight = isLeft ? 'left' : 'right',872cal = this.container.find('.calendar.'+leftOrRight);873874// Month must be Number for new moment versions875var month = parseInt(cal.find('.monthselect').val(), 10);876var year = cal.find('.yearselect').val();877878if (!isLeft && !this.singleDatePicker) {879if (year < this.startDate.year() || (year == this.startDate.year() && month < this.startDate.month())) {880month = this.startDate.month();881year = this.startDate.year();882}883}884885if (this.minDate) {886if (year < this.minDate.year() || (year == this.minDate.year() && month < this.minDate.month())) {887month = this.minDate.month();888year = this.minDate.year();889}890}891892if (this.maxDate) {893if (year > this.maxDate.year() || (year == this.maxDate.year() && month > this.maxDate.month())) {894month = this.maxDate.month();895year = this.maxDate.year();896}897}898899900this[leftOrRight+'Calendar'].month.month(month).year(year);901this.updateCalendars();902},903904updateTime: function(e) {905906var cal = $(e.target).closest('.calendar'),907isLeft = cal.hasClass('left');908909var hour = parseInt(cal.find('.hourselect').val(), 10);910var minute = parseInt(cal.find('.minuteselect').val(), 10);911var second = 0;912913if (this.timePickerSeconds) {914second = parseInt(cal.find('.secondselect').val(), 10);915}916917if (this.timePicker12Hour) {918var ampm = cal.find('.ampmselect').val();919if (ampm === 'PM' && hour < 12)920hour += 12;921if (ampm === 'AM' && hour === 12)922hour = 0;923}924925if (isLeft) {926var start = this.startDate.clone();927start.hour(hour);928start.minute(minute);929start.second(second);930this.startDate = start;931this.leftCalendar.month.hour(hour).minute(minute).second(second);932if (this.singleDatePicker)933this.endDate = start.clone();934} else {935var end = this.endDate.clone();936end.hour(hour);937end.minute(minute);938end.second(second);939this.endDate = end;940if (this.singleDatePicker)941this.startDate = end.clone();942this.rightCalendar.month.hour(hour).minute(minute).second(second);943}944945this.updateView();946this.updateCalendars();947},948949updateCalendars: function () {950this.leftCalendar.calendar = this.buildCalendar(this.leftCalendar.month.month(), this.leftCalendar.month.year(), this.leftCalendar.month.hour(), this.leftCalendar.month.minute(), this.leftCalendar.month.second(), 'left');951this.rightCalendar.calendar = this.buildCalendar(this.rightCalendar.month.month(), this.rightCalendar.month.year(), this.rightCalendar.month.hour(), this.rightCalendar.month.minute(), this.rightCalendar.month.second(), 'right');952this.container.find('.calendar.left').empty().html(this.renderCalendar(this.leftCalendar.calendar, this.startDate, this.minDate, this.maxDate, 'left'));953this.container.find('.calendar.right').empty().html(this.renderCalendar(this.rightCalendar.calendar, this.endDate, this.singleDatePicker ? this.minDate : this.startDate, this.maxDate, 'right'));954955this.container.find('.ranges li').removeClass('active');956var customRange = true;957var i = 0;958for (var range in this.ranges) {959if (this.timePicker) {960if (this.startDate.isSame(this.ranges[range][0]) && this.endDate.isSame(this.ranges[range][1])) {961customRange = false;962this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')')963.addClass('active').html();964}965} else {966//ignore times when comparing dates if time picker is not enabled967if (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')) {968customRange = false;969this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')')970.addClass('active').html();971}972}973i++;974}975if (customRange) {976this.chosenLabel = this.container.find('.ranges li:last').addClass('active').html();977this.showCalendars();978}979},980981buildCalendar: function (month, year, hour, minute, second, side) {982var daysInMonth = moment([year, month]).daysInMonth();983var firstDay = moment([year, month, 1]);984var lastDay = moment([year, month, daysInMonth]);985var lastMonth = moment(firstDay).subtract(1, 'month').month();986var lastYear = moment(firstDay).subtract(1, 'month').year();987988var daysInLastMonth = moment([lastYear, lastMonth]).daysInMonth();989990var dayOfWeek = firstDay.day();991992var i;993994//initialize a 6 rows x 7 columns array for the calendar995var calendar = [];996calendar.firstDay = firstDay;997calendar.lastDay = lastDay;998999for (i = 0; i < 6; i++) {1000calendar[i] = [];1001}10021003//populate the calendar with date objects1004var startDay = daysInLastMonth - dayOfWeek + this.locale.firstDay + 1;1005if (startDay > daysInLastMonth)1006startDay -= 7;10071008if (dayOfWeek == this.locale.firstDay)1009startDay = daysInLastMonth - 6;10101011var curDate = moment([lastYear, lastMonth, startDay, 12, minute, second]).utcOffset(this.timeZone);10121013var col, row;1014for (i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add(24, 'hour')) {1015if (i > 0 && col % 7 === 0) {1016col = 0;1017row++;1018}1019calendar[row][col] = curDate.clone().hour(hour);1020curDate.hour(12);10211022if (this.minDate && calendar[row][col].format('YYYY-MM-DD') == this.minDate.format('YYYY-MM-DD') && calendar[row][col].isBefore(this.minDate) && side == 'left') {1023calendar[row][col] = this.minDate.clone();1024}10251026if (this.maxDate && calendar[row][col].format('YYYY-MM-DD') == this.maxDate.format('YYYY-MM-DD') && calendar[row][col].isAfter(this.maxDate) && side == 'right') {1027calendar[row][col] = this.maxDate.clone();1028}10291030}10311032return calendar;1033},10341035renderDropdowns: function (selected, minDate, maxDate) {1036var currentMonth = selected.month();1037var currentYear = selected.year();1038var maxYear = (maxDate && maxDate.year()) || (currentYear + 5);1039var minYear = (minDate && minDate.year()) || (currentYear - 50);10401041var monthHtml = '<select class="monthselect">';1042var inMinYear = currentYear == minYear;1043var inMaxYear = currentYear == maxYear;10441045for (var m = 0; m < 12; m++) {1046if ((!inMinYear || m >= minDate.month()) && (!inMaxYear || m <= maxDate.month())) {1047monthHtml += "<option value='" + m + "'" +1048(m === currentMonth ? " selected='selected'" : "") +1049">" + this.locale.monthNames[m] + "</option>";1050}1051}1052monthHtml += "</select>";10531054var yearHtml = '<select class="yearselect">';10551056for (var y = minYear; y <= maxYear; y++) {1057yearHtml += '<option value="' + y + '"' +1058(y === currentYear ? ' selected="selected"' : '') +1059'>' + y + '</option>';1060}10611062yearHtml += '</select>';10631064return monthHtml + yearHtml;1065},10661067renderCalendar: function (calendar, selected, minDate, maxDate, side) {10681069var html = '<div class="calendar-date">';1070html += '<table class="table-condensed">';1071html += '<thead>';1072html += '<tr>';10731074// add empty cell for week number1075if (this.showWeekNumbers)1076html += '<th></th>';10771078if (!minDate || minDate.isBefore(calendar.firstDay)) {1079html += '<th class="prev available"><i class="fa fa-arrow-left icon icon-arrow-left glyphicon glyphicon-arrow-left"></i></th>';1080} else {1081html += '<th></th>';1082}10831084var dateHtml = this.locale.monthNames[calendar[1][1].month()] + calendar[1][1].format(" YYYY");10851086if (this.showDropdowns) {1087dateHtml = this.renderDropdowns(calendar[1][1], minDate, maxDate);1088}10891090html += '<th colspan="5" class="month">' + dateHtml + '</th>';1091if (!maxDate || maxDate.isAfter(calendar.lastDay)) {1092html += '<th class="next available"><i class="fa fa-arrow-right icon icon-arrow-right glyphicon glyphicon-arrow-right"></i></th>';1093} else {1094html += '<th></th>';1095}10961097html += '</tr>';1098html += '<tr>';10991100// add week number label1101if (this.showWeekNumbers)1102html += '<th class="week">' + this.locale.weekLabel + '</th>';11031104$.each(this.locale.daysOfWeek, function (index, dayOfWeek) {1105html += '<th>' + dayOfWeek + '</th>';1106});11071108html += '</tr>';1109html += '</thead>';1110html += '<tbody>';11111112for (var row = 0; row < 6; row++) {1113html += '<tr>';11141115// add week number1116if (this.showWeekNumbers)1117html += '<td class="week">' + calendar[row][0].week() + '</td>';11181119for (var col = 0; col < 7; col++) {1120var cname = 'available ';1121cname += (calendar[row][col].month() == calendar[1][1].month()) ? '' : 'off';11221123if ((minDate && calendar[row][col].isBefore(minDate, 'day')) || (maxDate && calendar[row][col].isAfter(maxDate, 'day'))) {1124cname = ' off disabled ';1125} else if (calendar[row][col].format('YYYY-MM-DD') == selected.format('YYYY-MM-DD')) {1126cname += ' active ';1127if (calendar[row][col].format('YYYY-MM-DD') == this.startDate.format('YYYY-MM-DD')) {1128cname += ' start-date ';1129}1130if (calendar[row][col].format('YYYY-MM-DD') == this.endDate.format('YYYY-MM-DD')) {1131cname += ' end-date ';1132}1133} else if (calendar[row][col] >= this.startDate && calendar[row][col] <= this.endDate) {1134cname += ' in-range ';1135if (calendar[row][col].isSame(this.startDate)) { cname += ' start-date '; }1136if (calendar[row][col].isSame(this.endDate)) { cname += ' end-date '; }1137}11381139var title = 'r' + row + 'c' + col;1140html += '<td class="' + cname.replace(/\s+/g, ' ').replace(/^\s?(.*?)\s?$/, '$1') + '" data-title="' + title + '">' + calendar[row][col].date() + '</td>';1141}1142html += '</tr>';1143}11441145html += '</tbody>';1146html += '</table>';1147html += '</div>';11481149var i;1150if (this.timePicker) {11511152html += '<div class="calendar-time">';1153html += '<select class="hourselect">';11541155// Disallow selections before the minDate or after the maxDate1156var min_hour = 0;1157var max_hour = 23;11581159if (minDate && (side == 'left' || this.singleDatePicker) && selected.format('YYYY-MM-DD') == minDate.format('YYYY-MM-DD')) {1160min_hour = minDate.hour();1161if (selected.hour() < min_hour)1162selected.hour(min_hour);1163if (this.timePicker12Hour && min_hour >= 12 && selected.hour() >= 12)1164min_hour -= 12;1165if (this.timePicker12Hour && min_hour == 12)1166min_hour = 1;1167}11681169if (maxDate && (side == 'right' || this.singleDatePicker) && selected.format('YYYY-MM-DD') == maxDate.format('YYYY-MM-DD')) {1170max_hour = maxDate.hour();1171if (selected.hour() > max_hour)1172selected.hour(max_hour);1173if (this.timePicker12Hour && max_hour >= 12 && selected.hour() >= 12)1174max_hour -= 12;1175}11761177var start = 0;1178var end = 23;1179var selected_hour = selected.hour();1180if (this.timePicker12Hour) {1181start = 1;1182end = 12;1183if (selected_hour >= 12)1184selected_hour -= 12;1185if (selected_hour === 0)1186selected_hour = 12;1187}11881189for (i = start; i <= end; i++) {11901191if (i == selected_hour) {1192html += '<option value="' + i + '" selected="selected">' + i + '</option>';1193} else if (i < min_hour || i > max_hour) {1194html += '<option value="' + i + '" disabled="disabled" class="disabled">' + i + '</option>';1195} else {1196html += '<option value="' + i + '">' + i + '</option>';1197}1198}11991200html += '</select> : ';12011202html += '<select class="minuteselect">';12031204// Disallow selections before the minDate or after the maxDate1205var min_minute = 0;1206var max_minute = 59;12071208if (minDate && (side == 'left' || this.singleDatePicker) && selected.format('YYYY-MM-DD h A') == minDate.format('YYYY-MM-DD h A')) {1209min_minute = minDate.minute();1210if (selected.minute() < min_minute)1211selected.minute(min_minute);1212}12131214if (maxDate && (side == 'right' || this.singleDatePicker) && selected.format('YYYY-MM-DD h A') == maxDate.format('YYYY-MM-DD h A')) {1215max_minute = maxDate.minute();1216if (selected.minute() > max_minute)1217selected.minute(max_minute);1218}12191220for (i = 0; i < 60; i += this.timePickerIncrement) {1221var num = i;1222if (num < 10)1223num = '0' + num;1224if (i == selected.minute()) {1225html += '<option value="' + i + '" selected="selected">' + num + '</option>';1226} else if (i < min_minute || i > max_minute) {1227html += '<option value="' + i + '" disabled="disabled" class="disabled">' + num + '</option>';1228} else {1229html += '<option value="' + i + '">' + num + '</option>';1230}1231}12321233html += '</select> ';12341235if (this.timePickerSeconds) {1236html += ': <select class="secondselect">';12371238for (i = 0; i < 60; i += this.timePickerIncrement) {1239var num = i;1240if (num < 10)1241num = '0' + num;1242if (i == selected.second()) {1243html += '<option value="' + i + '" selected="selected">' + num + '</option>';1244} else {1245html += '<option value="' + i + '">' + num + '</option>';1246}1247}12481249html += '</select>';1250}12511252if (this.timePicker12Hour) {1253html += '<select class="ampmselect">';12541255// Disallow selection before the minDate or after the maxDate1256var am_html = '';1257var pm_html = '';12581259if (minDate && (side == 'left' || this.singleDatePicker) && selected.format('YYYY-MM-DD') == minDate.format('YYYY-MM-DD') && minDate.hour() >= 12) {1260am_html = ' disabled="disabled" class="disabled"';1261}12621263if (maxDate && (side == 'right' || this.singleDatePicker) && selected.format('YYYY-MM-DD') == maxDate.format('YYYY-MM-DD') && maxDate.hour() < 12) {1264pm_html = ' disabled="disabled" class="disabled"';1265}12661267if (selected.hour() >= 12) {1268html += '<option value="AM"' + am_html + '>AM</option><option value="PM" selected="selected"' + pm_html + '>PM</option>';1269} else {1270html += '<option value="AM" selected="selected"' + am_html + '>AM</option><option value="PM"' + pm_html + '>PM</option>';1271}1272html += '</select>';1273}12741275html += '</div>';12761277}12781279return html;12801281},12821283remove: function() {12841285this.container.remove();1286this.element.off('.daterangepicker');1287this.element.removeData('daterangepicker');12881289}12901291};12921293$.fn.daterangepicker = function (options, cb) {1294this.each(function () {1295var el = $(this);1296if (el.data('daterangepicker'))1297el.data('daterangepicker').remove();1298el.data('daterangepicker', new DateRangePicker(el, options, cb));1299});1300return this;1301};13021303}));130413051306