Advertisement
ab_tanjir

daterangepicker.extended.js

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