From 851cb83bbbf8a6dbf164b4407d2dad64584738cb Mon Sep 17 00:00:00 2001 From: Deimantas Wurster Date: Fri, 9 Nov 2018 17:33:45 +0100 Subject: [PATCH 1/4] do not update start/end date input fields when hovering over calendar --- daterangepicker.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/daterangepicker.js b/daterangepicker.js index 44f0e97f..8cdfa184 100644 --- a/daterangepicker.js +++ b/daterangepicker.js @@ -1266,11 +1266,6 @@ }, hoverDate: function(e) { - - //ignore mouse movements while an above-calendar text input has focus - //if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus")) - // return; - //ignore dates that can't be selected if (!$(e.target).hasClass('available')) return; @@ -1281,12 +1276,6 @@ var cal = $(e.target).parents('.calendar'); var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col]; - if (this.endDate && !this.container.find('input[name=daterangepicker_start]').is(":focus")) { - this.container.find('input[name=daterangepicker_start]').val(date.format(this.locale.format)); - } else if (!this.endDate && !this.container.find('input[name=daterangepicker_end]').is(":focus")) { - this.container.find('input[name=daterangepicker_end]').val(date.format(this.locale.format)); - } - //highlight the dates between the start date and the date being hovered as a potential end date var leftCalendar = this.leftCalendar; var rightCalendar = this.rightCalendar; From 21250849bcbf509edf20b5c428333e0d44e19770 Mon Sep 17 00:00:00 2001 From: Deimantas Wurster Date: Tue, 13 Nov 2018 17:16:17 +0100 Subject: [PATCH 2/4] apply some refactoring and implement requirements from AIT-2554 --- daterangepicker.js | 217 ++++++++++++++++++++++----------------------- 1 file changed, 107 insertions(+), 110 deletions(-) diff --git a/daterangepicker.js b/daterangepicker.js index 8cdfa184..fc9377ca 100644 --- a/daterangepicker.js +++ b/daterangepicker.js @@ -296,7 +296,7 @@ start = end = null; - if (split.length == 2) { + if (split.length === 2) { start = moment(split[0], this.locale.format); end = moment(split[1], this.locale.format); } else if (this.singleDatePicker && val !== "") { @@ -401,7 +401,7 @@ this.container.addClass('opens' + this.opens); //swap the position of the predefined ranges if opens right - if (typeof options.ranges !== 'undefined' && this.opens == 'right') { + if (typeof options.ranges !== 'undefined' && this.opens === 'right') { this.container.find('.ranges').prependTo( this.container.find('.calendar.left').parent() ); } @@ -452,18 +452,8 @@ this.element.on('keydown.daterangepicker', $.proxy(this.toggle, this)); } - // // if attached to a text input, set the initial value - // - - if (this.element.is('input') && !this.singleDatePicker && this.autoUpdateInput) { - this.element.val(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format)); - this.element.trigger('change'); - } else if (this.element.is('input') && this.autoUpdateInput) { - this.element.val(this.startDate.format(this.locale.format)); - this.element.trigger('change'); - } - + this.updateElement(); }; DateRangePicker.prototype = { @@ -539,7 +529,7 @@ return false; }, - updateView: function(options) { + updateView: function() { if (this.timePicker) { this.renderTimePicker('left'); @@ -554,19 +544,6 @@ this.updateMonthsInView(); this.updateCalendars(); this.updateFormInputs(); - - if (options && options.actionType === 'keyup') { - return; - } - - if (this.endDate) { - this.container.find('input[name="daterangepicker_start"]').addClass('active'); - this.container.find('input[name="daterangepicker_end"]').removeClass('active'); - } else { - this.container.find('input[name="daterangepicker_start"]').removeClass('active'); - this.container.find('input[name="daterangepicker_end"]').addClass('active'); - } - }, updateMonthsInView: function() { @@ -1037,23 +1014,16 @@ }, updateFormInputs: function() { - - //comment out this behaviour according to requested change in AIT-2454 - - //ignore mouse movements while an above-calendar text input has focus - // if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus")) - // return; - - this.container.find('input[name=daterangepicker_start]').val(this.startDate.format(this.locale.format)); - if (this.endDate) - this.container.find('input[name=daterangepicker_end]').val(this.endDate.format(this.locale.format)); + this.startDateInputEl.val(this.startDate.format(this.locale.format)); + if (this.endDate) { + this.endDateInputEl.val(this.endDate.format(this.locale.format)); + } if (this.singleDatePicker || (this.endDate && (this.startDate.isBefore(this.endDate) || this.startDate.isSame(this.endDate)))) { this.container.find('button.applyBtn').removeAttr('disabled'); } else { this.container.find('button.applyBtn').attr('disabled', 'disabled'); } - }, move: function() { @@ -1068,13 +1038,13 @@ parentRightEdge = this.parentEl[0].clientWidth + this.parentEl.offset().left; } - if (this.drops == 'up') + if (this.drops === 'up') containerTop = this.element.offset().top - this.container.outerHeight() - parentOffset.top; else containerTop = this.element.offset().top + this.element.outerHeight() - parentOffset.top; - this.container[this.drops == 'up' ? 'addClass' : 'removeClass']('dropup'); + this.container[this.drops === 'up' ? 'addClass' : 'removeClass']('dropup'); - if (this.opens == 'left') { + if (this.opens === 'left') { this.container.css({ top: containerTop, right: parentRightEdge - this.element.offset().left - this.element.outerWidth(), @@ -1086,7 +1056,7 @@ left: 9 }); } - } else if (this.opens == 'center') { + } else if (this.opens === 'center') { this.container.css({ top: containerTop, left: this.element.offset().left - parentOffset.left + this.element.outerWidth() / 2 @@ -1178,15 +1148,17 @@ outsideClick: function(e) { var target = $(e.target); + // if the page is clicked anywhere except within the daterangerpicker/button // itself then call this.hide() - if ( - // ie modal dialog fix - e.type == "focusin" || - target.closest(this.element).length || - target.closest(this.container).length || - target.closest('.calendar-table').length - ) return; + if (e.type === 'focusin' // ie modal dialog fix + || target.closest(this.element).length + || target.closest(this.container).length + || target.closest('.calendar-table').length + ) { + return; + } + this.hide(); this.element.trigger('outsideClick.daterangepicker', this); }, @@ -1205,17 +1177,17 @@ hoverRange: function(e) { //ignore mouse movements while an above-calendar text input has focus - if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus")) + if (this.startDateInputEl.is(':focus') || this.endDateInputEl.is(':focus')) return; var label = e.target.getAttribute('data-range-key'); - if (label == this.locale.customRangeLabel) { + if (label === this.locale.customRangeLabel) { this.updateView(); } else { var dates = this.ranges[label]; - this.container.find('input[name=daterangepicker_start]').val(dates[0].format(this.locale.format)); - this.container.find('input[name=daterangepicker_end]').val(dates[1].format(this.locale.format)); + this.startDateInputEl.val(dates[0].format(this.locale.format)); + this.endDateInputEl.val(dates[1].format(this.locale.format)); } }, @@ -1270,11 +1242,7 @@ if (!$(e.target).hasClass('available')) return; //have the text inputs above calendars reflect the date being hovered over - var title = $(e.target).attr('data-title'); - var row = title.substr(1, 1); - var col = title.substr(3, 1); - var cal = $(e.target).parents('.calendar'); - var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col]; + var date = this.getCalendarDate(e.target); //highlight the dates between the start date and the date being hovered as a potential end date var leftCalendar = this.leftCalendar; @@ -1307,11 +1275,7 @@ if (!$(e.target).hasClass('available')) return; - var title = $(e.target).attr('data-title'); - var row = title.substr(1, 1); - var col = title.substr(3, 1); - var cal = $(e.target).parents('.calendar'); - var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col]; + var clickedDate = this.getCalendarDate(e.target); // // this function needs to do a few things: @@ -1322,43 +1286,32 @@ // * if one of the inputs above the calendars was focused, cancel that manual input // - if (this.endDate || date.isBefore(this.startDate, 'day')) { //picking start + if (this.startDateInputEl.hasClass('active')) { //picking start if (this.timePicker) { - var hour = parseInt(this.container.find('.left .hourselect').val(), 10); - if (!this.timePicker24Hour) { - var ampm = this.container.find('.left .ampmselect').val(); - if (ampm === 'PM' && hour < 12) - hour += 12; - if (ampm === 'AM' && hour === 12) - hour = 0; - } - var minute = parseInt(this.container.find('.left .minuteselect').val(), 10); - var second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0; - date = date.clone().hour(hour).minute(minute).second(second); + clickedDate = this.deserializeSelectedTime(clickedDate, 'left'); } + if (clickedDate.isAfter(this.endDate)) { + this.setStartDate(this.endDate.clone()); + this.setEndDate(clickedDate.clone()); + } else { + this.setStartDate(clickedDate.clone()); + this.endDateInputEl.trigger('focus.daterangepicker', this); + } + } else if (this.endDateInputEl.hasClass('active') && clickedDate.isBefore(this.startDate)) { - this.endDate = null; - this.setStartDate(date.clone()); - - } else if (!this.endDate && date.isBefore(this.startDate)) { //special case: clicking the same date for start/end, //but the time of the end date is before the start date this.setEndDate(this.startDate.clone()); + this.setStartDate(clickedDate); + } else { // picking end if (this.timePicker) { - var hour = parseInt(this.container.find('.right .hourselect').val(), 10); - if (!this.timePicker24Hour) { - var ampm = this.container.find('.right .ampmselect').val(); - if (ampm === 'PM' && hour < 12) - hour += 12; - if (ampm === 'AM' && hour === 12) - hour = 0; - } - var minute = parseInt(this.container.find('.right .minuteselect').val(), 10); - var second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0; - date = date.clone().hour(hour).minute(minute).second(second); + clickedDate = this.deserializeSelectedTime(clickedDate, 'right'); } - this.setEndDate(date.clone()); + + this.setEndDate(clickedDate.clone()); + this.startDateInputEl.trigger('focus.daterangepicker'); + if (this.autoApply) { this.calculateChosenLabel(); this.clickApply(); @@ -1432,21 +1385,21 @@ var year = cal.find('.yearselect').val(); if (!isLeft) { - if (year < this.startDate.year() || (year == this.startDate.year() && month < this.startDate.month())) { + if (year < this.startDate.year() || (year === this.startDate.year() && month < this.startDate.month())) { month = this.startDate.month(); year = this.startDate.year(); } } if (this.minDate) { - if (year < this.minDate.year() || (year == this.minDate.year() && month < this.minDate.month())) { + if (year < this.minDate.year() || (year === this.minDate.year() && month < this.minDate.month())) { month = this.minDate.month(); year = this.minDate.year(); } } if (this.maxDate) { - if (year > this.maxDate.year() || (year == this.maxDate.year() && month > this.maxDate.month())) { + if (year > this.maxDate.year() || (year === this.maxDate.year() && month > this.maxDate.month())) { month = this.maxDate.month(); year = this.maxDate.year(); } @@ -1514,8 +1467,8 @@ formInputsChanged: function(e) { var isRight = $(e.target).closest('.calendar').hasClass('right'); - var start = moment(this.container.find('input[name="daterangepicker_start"]').val(), this.locale.format); - var end = moment(this.container.find('input[name="daterangepicker_end"]').val(), this.locale.format); + var start = moment(this.startDateInputEl.val(), this.locale.format); + var end = moment(this.endDateInputEl.val(), this.locale.format); if (start.isValid() && end.isValid()) { @@ -1526,9 +1479,9 @@ this.setEndDate(end); if (isRight) { - this.container.find('input[name="daterangepicker_start"]').val(this.startDate.format(this.locale.format)); + this.startDateInputEl.val(this.startDate.format(this.locale.format)); } else { - this.container.find('input[name="daterangepicker_end"]').val(this.endDate.format(this.locale.format)); + this.endDateInputEl.val(this.endDate.format(this.locale.format)); } } @@ -1549,7 +1502,6 @@ // using the calendar. var isRight = $(e.target).closest('.calendar').hasClass('right'); if (isRight) { - this.endDate = null; this.setStartDate(this.startDate.clone()); this.updateView(); } @@ -1604,7 +1556,7 @@ this.setStartDate(date); } - this.updateView({ actionType: 'keyup' }); + this.updateView(); } }, @@ -1616,7 +1568,7 @@ // This behaviour is automatic in Chrome/Firefox/Edge but not in IE 11 hence why this exists. // Other browsers and versions of IE are untested and the behaviour is unknown. - var manager = this + var manager = this; if (event.keyCode === 13 && event.target.getAttribute('name') === 'daterangepicker_start') { // Prevent the calendar from being updated twice on Chrome/Firefox/Edge @@ -1625,20 +1577,17 @@ } if (event.target.getAttribute('name') === 'daterangepicker_end') { - var allowedInactivityTime = 500; var debouncedInputChangeHandler = this.debounceAction( - function () { return manager.handleInputDateChange(event.target.value, 'end') }, allowedInactivityTime - ) + function () { + return manager.handleInputDateChange(event.target.value, 'end') + }, allowedInactivityTime + ); - setTimeout(function(){ - debouncedInputChangeHandler(); - }.bind(this), 100) + setTimeout(debouncedInputChangeHandler.bind(this), 100); } - }, - elementChanged: function() { if (!this.element.is('input')) return; if (!this.element.val().length) return; @@ -1693,8 +1642,56 @@ this.container.remove(); this.element.off('.daterangepicker'); this.element.removeData(); - } + }, + get startDateInputEl() { + return this.container.find('input[name=daterangepicker_start]'); + }, + + get endDateInputEl() { + return this.container.find('input[name=daterangepicker_end]'); + }, + + toInt: function (value) { + return parseInt(value, 10); + }, + + /** + * @param {Element} element browser's native DOM element + * @returns {moment.Moment} + */ + getCalendarDate: function (element) { + var title = $(element).data('title'), + row = title.substr(1, 1), + col = title.substr(3, 1), + isLeft = $(element).parents('.calendar').hasClass('left'); + return isLeft ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col]; + }, + + /** + * @param {moment.Moment} date + * @param {string} side 'left' or 'right' + * @returns {moment.Moment} + */ + deserializeSelectedTime: function (date, side) { + if (!['right', 'left'].includes(side) || !moment.isMoment(date)) { + throw new Error('Bad method invocation'); + } + var calendarSelector = '.' + side, + calendarEl = this.container.find(calendarSelector), + hour = this.toInt(calendarEl.find('.hourselect').val()); + if (!this.timePicker24Hour) { + var ampm = calendarEl.find('.ampmselect').val(); + if (ampm === 'PM' && hour < 12) + hour += 12; + if (ampm === 'AM' && hour === 12) + hour = 0; + } + var minute = this.toInt(calendarEl.find('.minuteselect').val()); + var second = this.timePickerSeconds ? this.toInt(calendarEl.find('.secondselect').val()) : 0; + + return date.clone().hour(hour).minute(minute).second(second); + } }; $.fn.daterangepicker = function(options, callback) { From 890d752a71cfba927d6d93f47dd1cfc7f35d8726 Mon Sep 17 00:00:00 2001 From: Deimantas Wurster Date: Wed, 14 Nov 2018 17:22:33 +0100 Subject: [PATCH 3/4] fix broken date picker when used in single mode --- daterangepicker.js | 87 ++++++++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 46 deletions(-) diff --git a/daterangepicker.js b/daterangepicker.js index fc9377ca..38363cbb 100644 --- a/daterangepicker.js +++ b/daterangepicker.js @@ -96,35 +96,36 @@ //html template for the picker UI if (typeof options.template !== 'string' && !(options.template instanceof $)) - options.template = '