diff --git a/public/css/daterangepicker-bs3.css b/public/css/daterangepicker-bs3.css index 1410a87a..b5df93b7 100644 --- a/public/css/daterangepicker-bs3.css +++ b/public/css/daterangepicker-bs3.css @@ -8,237 +8,255 @@ * Built for http://www.improvely.com */ - .daterangepicker.dropdown-menu { - max-width: none; +.daterangepicker.dropdown-menu { + max-width: none; + z-index: 3000; } .daterangepicker.opensleft .ranges, .daterangepicker.opensleft .calendar { - float: left; - margin: 4px; + float: left; + margin: 4px; } .daterangepicker.opensright .ranges, .daterangepicker.opensright .calendar { - float: right; - margin: 4px; + float: right; + margin: 4px; } .daterangepicker .ranges { - width: 160px; - text-align: left; + width: 160px; + text-align: left; } .daterangepicker .ranges .range_inputs>div { - float: left; + float: left; } .daterangepicker .ranges .range_inputs>div:nth-child(2) { - padding-left: 11px; + padding-left: 11px; } .daterangepicker .calendar { - display: none; - max-width: 270px; + display: none; + max-width: 270px; +} + +.daterangepicker .calendar.single .calendar-date { + border: none; } .daterangepicker .calendar th, .daterangepicker .calendar td { - font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; - white-space: nowrap; - text-align: center; - min-width: 32px; + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; + white-space: nowrap; + text-align: center; + min-width: 32px; } .daterangepicker .ranges label { - color: #333; - display: block; - font-size: 11px; - font-weight: normal; - height: 20px; - line-height: 20px; - margin-bottom: 2px; - text-shadow: #fff 1px 1px 0px; - text-transform: uppercase; - width: 74px; + color: #333; + display: block; + font-size: 11px; + font-weight: normal; + height: 20px; + line-height: 20px; + margin-bottom: 2px; + text-shadow: #fff 1px 1px 0px; + text-transform: uppercase; + width: 74px; } .daterangepicker .ranges input { - font-size: 11px; + font-size: 11px; } .daterangepicker .ranges .input-mini { - background-color: #eee; - border: 1px solid #ccc; - border-radius: 4px; - color: #555; - display: block; - font-size: 11px; - height: 30px; - line-height: 30px; - vertical-align: middle; - margin: 0 0 10px 0; - padding: 0 6px; - width: 74px; + background-color: #eee; + border: 1px solid #ccc; + border-radius: 4px; + color: #555; + display: block; + font-size: 11px; + height: 30px; + line-height: 30px; + vertical-align: middle; + margin: 0 0 10px 0; + padding: 0 6px; + width: 74px; } .daterangepicker .ranges ul { - list-style: none; - margin: 0; - padding: 0; + list-style: none; + margin: 0; + padding: 0; } .daterangepicker .ranges li { - font-size: 13px; - background: #f5f5f5; - border: 1px solid #f5f5f5; - color: #08c; - padding: 3px 12px; - margin-bottom: 8px; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - border-radius: 5px; - cursor: pointer; + font-size: 13px; + background: #f5f5f5; + border: 1px solid #f5f5f5; + color: #08c; + padding: 3px 12px; + margin-bottom: 8px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + cursor: pointer; } .daterangepicker .ranges li.active, .daterangepicker .ranges li:hover { - background: #08c; - border: 1px solid #08c; - color: #fff; + background: #08c; + border: 1px solid #08c; + color: #fff; } .daterangepicker .calendar-date { - border: 1px solid #ddd; - padding: 4px; - border-radius: 4px; - background: #fff; + border: 1px solid #ddd; + padding: 4px; + border-radius: 4px; + background: #fff; } .daterangepicker .calendar-time { - text-align: center; - margin: 8px auto 0 auto; - line-height: 30px; + text-align: center; + margin: 8px auto 0 auto; + line-height: 30px; } .daterangepicker { - position: absolute; - background: #fff; - top: 100px; - left: 20px; - padding: 4px; - margin-top: 1px; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; + position: absolute; + background: #fff; + top: 100px; + left: 20px; + padding: 4px; + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; } .daterangepicker.opensleft:before { - position: absolute; - top: -7px; - right: 9px; - display: inline-block; - border-right: 7px solid transparent; - border-bottom: 7px solid #ccc; - border-left: 7px solid transparent; - border-bottom-color: rgba(0, 0, 0, 0.2); - content: ''; + position: absolute; + top: -7px; + right: 9px; + display: inline-block; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-left: 7px solid transparent; + border-bottom-color: rgba(0, 0, 0, 0.2); + content: ''; } .daterangepicker.opensleft:after { - position: absolute; - top: -6px; - right: 10px; - display: inline-block; - border-right: 6px solid transparent; - border-bottom: 6px solid #fff; - border-left: 6px solid transparent; - content: ''; + position: absolute; + top: -6px; + right: 10px; + display: inline-block; + border-right: 6px solid transparent; + border-bottom: 6px solid #fff; + border-left: 6px solid transparent; + content: ''; } .daterangepicker.opensright:before { - position: absolute; - top: -7px; - left: 9px; - display: inline-block; - border-right: 7px solid transparent; - border-bottom: 7px solid #ccc; - border-left: 7px solid transparent; - border-bottom-color: rgba(0, 0, 0, 0.2); - content: ''; + position: absolute; + top: -7px; + left: 9px; + display: inline-block; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-left: 7px solid transparent; + border-bottom-color: rgba(0, 0, 0, 0.2); + content: ''; } .daterangepicker.opensright:after { - position: absolute; - top: -6px; - left: 10px; - display: inline-block; - border-right: 6px solid transparent; - border-bottom: 6px solid #fff; - border-left: 6px solid transparent; - content: ''; + position: absolute; + top: -6px; + left: 10px; + display: inline-block; + border-right: 6px solid transparent; + border-bottom: 6px solid #fff; + border-left: 6px solid transparent; + content: ''; } .daterangepicker table { - width: 100%; - margin: 0; + width: 100%; + margin: 0; } .daterangepicker td, .daterangepicker th { - text-align: center; - width: 20px; - height: 20px; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - cursor: pointer; - white-space: nowrap; + text-align: center; + width: 20px; + height: 20px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + cursor: pointer; + white-space: nowrap; } .daterangepicker td.off { - color: #999; + color: #999; } .daterangepicker td.disabled { - color: #999; + color: #999; } .daterangepicker td.available:hover, .daterangepicker th.available:hover { - background: #eee; + background: #eee; } .daterangepicker td.in-range { - background: #ebf4f8; - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; + background: #ebf4f8; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; } .daterangepicker td.active, .daterangepicker td.active:hover { - background-color: #357ebd; - border-color: #3071a9; - color: #fff; + background-color: #357ebd; + border-color: #3071a9; + color: #fff; } .daterangepicker td.week, .daterangepicker th.week { - font-size: 80%; - color: #ccc; + font-size: 80%; + color: #ccc; } .daterangepicker select.monthselect, .daterangepicker select.yearselect { - font-size: 12px; - padding: 1px; - height: auto; - margin: 0; - cursor: default; + font-size: 12px; + padding: 1px; + height: auto; + margin: 0; + cursor: default; } .daterangepicker select.monthselect { - margin-right: 2%; - width: 56%; + margin-right: 2%; + width: 56%; } .daterangepicker select.yearselect { - width: 40%; + width: 40%; } .daterangepicker select.hourselect, .daterangepicker select.minuteselect, .daterangepicker select.ampmselect { - width: 50px; - margin-bottom: 0; -} \ No newline at end of file + width: 50px; + margin-bottom: 0; +} + +.daterangepicker_start_input { + float: left; +} + +.daterangepicker_end_input { + float: left; + padding-left: 11px +} + +.daterangepicker th.month { + width: auto; +} diff --git a/public/js/daterangepicker-1.2.js b/public/js/daterangepicker-1.3.2.js similarity index 64% rename from public/js/daterangepicker-1.2.js rename to public/js/daterangepicker-1.3.2.js index df976e5f..465ec41f 100644 --- a/public/js/daterangepicker-1.2.js +++ b/public/js/daterangepicker-1.3.2.js @@ -1,109 +1,140 @@ /** -* @version: 1.2 -* @author: Dan Grossman http://www.dangrossman.info/ -* @date: 2013-07-25 -* @copyright: Copyright (c) 2012-2013 Dan Grossman. All rights reserved. -* @license: Licensed under Apache License v2.0. See http://www.apache.org/licenses/LICENSE-2.0 -* @website: http://www.improvely.com/ -*/ + * @version: 1.3.2 + * @author: Dan Grossman http://www.dangrossman.info/ + * @date: 2014-01-22 + * @copyright: Copyright (c) 2012-2014 Dan Grossman. All rights reserved. + * @license: Licensed under Apache License v2.0. See http://www.apache.org/licenses/LICENSE-2.0 + * @website: http://www.improvely.com/ + */ !function ($) { var DateRangePicker = function (element, options, cb) { - var hasOptions = typeof options == 'object'; - var localeObject; - - //option defaults - - this.startDate = moment().startOf('day'); - this.endDate = moment().startOf('day'); - this.minDate = false; - this.maxDate = false; - this.dateLimit = false; - - this.showDropdowns = false; - this.showWeekNumbers = false; - this.timePicker = false; - this.timePickerIncrement = 30; - this.timePicker12Hour = true; - this.ranges = {}; - this.opens = 'right'; - - this.buttonClasses = ['btn', 'btn-small']; - this.applyClass = 'btn-success'; - this.cancelClass = 'btn-default'; - - this.format = 'MM/DD/YYYY'; - this.separator = ' - '; - - this.locale = { - applyLabel: 'Apply', - cancelLabel: 'Cancel', - fromLabel: 'From', - toLabel: 'To', - weekLabel: 'W', - customRangeLabel: 'Custom Range', - daysOfWeek: moment()._lang._weekdaysMin.slice(), - monthNames: moment()._lang._monthsShort.slice(), - firstDay: 0 - }; - - this.cb = function () { }; + + // by default, the daterangepicker element is placed at the bottom of HTML body + this.parentEl = 'body'; //element that triggered the date range picker this.element = $(element); - if (this.element.hasClass('pull-right')) - this.opens = 'left'; + //create the picker HTML object + var DRPTemplate = ''; + + this.parentEl = (typeof options == 'object' && options.parentEl && $(options.parentEl)) || $(this.parentEl); + this.container = $(DRPTemplate).appendTo(this.parentEl); + + //custom options + if (typeof options != 'object') + options = {}; + this.setOptions(options, cb); + + //apply CSS classes and labels to buttons + var c = this.container; + $.each(this.buttonClasses, function (idx, val) { + c.find('button').addClass(val); + }); + this.container.find('.daterangepicker_start_input label').html(this.locale.fromLabel); + this.container.find('.daterangepicker_end_input label').html(this.locale.toLabel); + if (this.applyClass.length) + this.container.find('.applyBtn').addClass(this.applyClass); + if (this.cancelClass.length) + this.container.find('.cancelBtn').addClass(this.cancelClass); + this.container.find('.applyBtn').html(this.locale.applyLabel); + this.container.find('.cancelBtn').html(this.locale.cancelLabel); + + //event listeners + this.container.on('mousedown', $.proxy(this.mousedown, this)); + + this.container.find('.calendar') + .on('click', '.prev', $.proxy(this.clickPrev, this)) + .on('click', '.next', $.proxy(this.clickNext, this)) + .on('click', 'td.available', $.proxy(this.clickDate, this)) + .on('mouseenter', 'td.available', $.proxy(this.enterDate, this)) + .on('mouseleave', 'td.available', $.proxy(this.updateFormInputs, this)) + .on('change', 'select.yearselect', $.proxy(this.updateMonthYear, this)) + .on('change', 'select.monthselect', $.proxy(this.updateMonthYear, this)) + .on('change', 'select.hourselect,select.minuteselect,select.ampmselect', $.proxy(this.updateTime, this)); + + this.container.find('.ranges') + .on('click', 'button.applyBtn', $.proxy(this.clickApply, this)) + .on('click', 'button.cancelBtn', $.proxy(this.clickCancel, this)) + .on('click', '.daterangepicker_start_input,.daterangepicker_end_input', $.proxy(this.showCalendars, this)) + .on('click', 'li', $.proxy(this.clickRange, this)) + .on('mouseenter', 'li', $.proxy(this.enterRange, this)) + .on('mouseleave', 'li', $.proxy(this.updateFormInputs, this)); if (this.element.is('input')) { this.element.on({ - click: $.proxy(this.show, this), - focus: $.proxy(this.show, this) + 'click.daterangepicker': $.proxy(this.show, this), + 'focus.daterangepicker': $.proxy(this.show, this), + 'keyup.daterangepicker': $.proxy(this.updateFromControl, this) }); } else { - this.element.on('click', $.proxy(this.show, this)); + this.element.on('click.daterangepicker', $.proxy(this.show, this)); } - localeObject = this.locale; - - if (hasOptions) { - if (typeof options.locale == 'object') { - $.each(localeObject, function (property, value) { - localeObject[property] = options.locale[property] || value; - }); - } + }; - if (options.applyClass) { - this.applyClass = options.applyClass; - } + DateRangePicker.prototype = { - if (options.cancelClass) { - this.cancelClass = options.cancelClass; - } - } + constructor: DateRangePicker, - var DRPTemplate = ''; - - this.container = $(DRPTemplate).appendTo('body'); - - if (hasOptions) { + setOptions: function(options, callback) { + + this.startDate = moment().startOf('day'); + this.endDate = moment().startOf('day'); + this.minDate = false; + this.maxDate = false; + this.dateLimit = false; + + this.showDropdowns = false; + this.showWeekNumbers = false; + this.timePicker = false; + this.timePickerIncrement = 30; + this.timePicker12Hour = true; + this.singleDatePicker = false; + this.ranges = {}; + + this.opens = 'right'; + if (this.element.hasClass('pull-right')) + this.opens = 'left'; + + this.buttonClasses = ['btn', 'btn-small']; + this.applyClass = 'btn-success'; + this.cancelClass = 'btn-default'; + + this.format = 'MM/DD/YYYY'; + this.separator = ' - '; + + this.locale = { + applyLabel: 'Apply', + cancelLabel: 'Cancel', + fromLabel: 'From', + toLabel: 'To', + weekLabel: 'W', + customRangeLabel: 'Custom Range', + daysOfWeek: moment()._lang._weekdaysMin.slice(), + monthNames: moment()._lang._monthsShort.slice(), + firstDay: 0 + }; + + this.cb = function () { }; if (typeof options.format == 'string') this.format = options.format; @@ -135,45 +166,28 @@ if (typeof options.maxDate == 'object') this.maxDate = moment(options.maxDate); - if (typeof options.ranges == 'object') { - for (var range in options.ranges) { - - var start = moment(options.ranges[range][0]); - var end = moment(options.ranges[range][1]); + if (typeof options.applyClass == 'string') + this.applyClass = options.applyClass; - // If we have a min/max date set, bound this range - // to it, but only if it would otherwise fall - // outside of the min/max. - if (this.minDate && start.isBefore(this.minDate)) - start = moment(this.minDate); + if (typeof options.cancelClass == 'string') + this.cancelClass = options.cancelClass; - if (this.maxDate && end.isAfter(this.maxDate)) - end = moment(this.maxDate); + if (typeof options.dateLimit == 'object') + this.dateLimit = options.dateLimit; - // If the end of the range is before the minimum (if min is set) OR - // the start of the range is after the max (also if set) don't display this - // range option. - if ((this.minDate && end.isBefore(this.minDate)) || (this.maxDate && start.isAfter(this.maxDate))) { - continue; - } + // update day names order to firstDay + if (typeof options.locale == 'object') { - this.ranges[range] = [start, end]; + if (typeof options.locale.daysOfWeek == 'object') { + // Create a copy of daysOfWeek to avoid modification of original + // options object for reusability in multiple daterangepicker instances + this.locale.daysOfWeek = options.locale.daysOfWeek.slice(); } - var list = ''; - this.container.find('.ranges').prepend(list); - } - - if (typeof options.dateLimit == 'object') - this.dateLimit = options.dateLimit; - // update day names order to firstDay - if (typeof options.locale == 'object') { if (typeof options.locale.firstDay == 'number') { this.locale.firstDay = options.locale.firstDay; var iterator = options.locale.firstDay; @@ -182,6 +196,30 @@ iterator--; } } + + if (typeof options.locale.applyLabel == 'string') { + this.locale.applyLabel = options.locale.applyLabel; + } + + if (typeof options.locale.cancelLabel == 'string') { + this.locale.cancelLabel = options.locale.cancelLabel; + } + + if (typeof options.locale.fromLabel == 'string') { + this.locale.fromLabel = options.locale.fromLabel; + } + + if (typeof options.locale.toLabel == 'string') { + this.locale.toLabel = options.locale.toLabel; + } + + if (typeof options.locale.weekLabel == 'string') { + this.locale.weekLabel = options.locale.weekLabel; + } + + if (typeof options.locale.customRangeLabel == 'string') { + this.locale.customRangeLabel = options.locale.customRangeLabel; + } } if (typeof options.opens == 'string') @@ -203,6 +241,10 @@ this.showDropdowns = options.showDropdowns; } + if (typeof options.singleDatePicker == 'boolean') { + this.singleDatePicker = options.singleDatePicker; + } + if (typeof options.timePicker == 'boolean') { this.timePicker = options.timePicker; } @@ -215,103 +257,145 @@ this.timePicker12Hour = options.timePicker12Hour; } - } - - if (!this.timePicker) { - this.startDate = this.startDate.startOf('day'); - this.endDate = this.endDate.startOf('day'); - } + //if no start/end dates set, check if an input element contains initial values + if (typeof options.startDate == 'undefined' && typeof options.endDate == 'undefined') { + if ($(this.element).is('input[type=text]')) { + var val = $(this.element).val(); + var split = val.split(this.separator); + var start, end; + if (split.length == 2) { + start = moment(split[0], this.format); + end = moment(split[1], this.format); + } else if (this.singleDatePicker) { + start = moment(val, this.format); + end = moment(val, this.format); + } + if (start != null && end != null) { + this.startDate = start; + this.endDate = end; + } + } + } - //apply CSS classes to buttons - var c = this.container; - $.each(this.buttonClasses, function (idx, val) { - c.find('button').addClass(val); - }); + if (typeof options.ranges == 'object') { + for (var range in options.ranges) { - if (this.opens == 'right') { - //swap calendar positions - var left = this.container.find('.calendar.left'); - var right = this.container.find('.calendar.right'); - left.removeClass('left').addClass('right'); - right.removeClass('right').addClass('left'); - } + var start = moment(options.ranges[range][0]); + var end = moment(options.ranges[range][1]); - if (typeof options == 'undefined' || typeof options.ranges == 'undefined') { - this.container.find('.calendar').show(); - this.move(); - } + // If we have a min/max date set, bound this range + // to it, but only if it would otherwise fall + // outside of the min/max. + if (this.minDate && start.isBefore(this.minDate)) + start = moment(this.minDate); - if (typeof cb == 'function') - this.cb = cb; + if (this.maxDate && end.isAfter(this.maxDate)) + end = moment(this.maxDate); - this.container.addClass('opens' + this.opens); + // If the end of the range is before the minimum (if min is set) OR + // the start of the range is after the max (also if set) don't display this + // range option. + if ((this.minDate && end.isBefore(this.minDate)) || (this.maxDate && start.isAfter(this.maxDate))) { + continue; + } - //try parse date if in text input - if (!hasOptions || (typeof options.startDate == 'undefined' && typeof options.endDate == 'undefined')) { - if ($(this.element).is('input[type=text]')) { - var val = $(this.element).val(); - var split = val.split(this.separator); - var start, end; - if (split.length == 2) { - start = moment(split[0], this.format); - end = moment(split[1], this.format); + this.ranges[range] = [start, end]; } - if (start != null && end != null) { - this.startDate = start; - this.endDate = end; + + var list = ''; + this.container.find('.ranges ul').remove(); + this.container.find('.ranges').prepend(list); } - } - //state - this.oldStartDate = this.startDate.clone(); - this.oldEndDate = this.endDate.clone(); + if (typeof callback == 'function') { + this.cb = callback; + } - this.leftCalendar = { - month: moment([this.startDate.year(), this.startDate.month(), 1, this.startDate.hour(), this.startDate.minute()]), - calendar: [] - }; + if (!this.timePicker) { + this.startDate = this.startDate.startOf('day'); + this.endDate = this.endDate.startOf('day'); + } - this.rightCalendar = { - month: moment([this.endDate.year(), this.endDate.month(), 1, this.endDate.hour(), this.endDate.minute()]), - calendar: [] - }; + if (this.singleDatePicker) { + this.opens = 'right'; + this.container.find('.calendar.right').show(); + this.container.find('.calendar.left').hide(); + this.container.find('.ranges').hide(); + if (!this.container.find('.calendar.right').hasClass('single')) + this.container.find('.calendar.right').addClass('single'); + } else { + this.container.find('.calendar.right').removeClass('single'); + this.container.find('.ranges').show(); + } - //event listeners - this.container.on('mousedown', $.proxy(this.mousedown, this)); - this.container.find('.calendar').on('click', '.prev', $.proxy(this.clickPrev, this)); - this.container.find('.calendar').on('click', '.next', $.proxy(this.clickNext, this)); - this.container.find('.ranges').on('click', 'button.applyBtn', $.proxy(this.clickApply, this)); - this.container.find('.ranges').on('click', 'button.cancelBtn', $.proxy(this.clickCancel, this)); + this.oldStartDate = this.startDate.clone(); + this.oldEndDate = this.endDate.clone(); - this.container.find('.ranges').on('click', '.daterangepicker_start_input', $.proxy(this.showCalendars, this)); - this.container.find('.ranges').on('click', '.daterangepicker_end_input', $.proxy(this.showCalendars, this)); + this.leftCalendar = { + month: moment([this.startDate.year(), this.startDate.month(), 1, this.startDate.hour(), this.startDate.minute()]), + calendar: [] + }; - this.container.find('.calendar').on('click', 'td.available', $.proxy(this.clickDate, this)); - this.container.find('.calendar').on('mouseenter', 'td.available', $.proxy(this.enterDate, this)); - this.container.find('.calendar').on('mouseleave', 'td.available', $.proxy(this.updateView, this)); + this.rightCalendar = { + month: moment([this.endDate.year(), this.endDate.month(), 1, this.endDate.hour(), this.endDate.minute()]), + calendar: [] + }; - this.container.find('.ranges').on('click', 'li', $.proxy(this.clickRange, this)); - this.container.find('.ranges').on('mouseenter', 'li', $.proxy(this.enterRange, this)); - this.container.find('.ranges').on('mouseleave', 'li', $.proxy(this.updateView, this)); + if (this.opens == 'right') { + //swap calendar positions + var left = this.container.find('.calendar.left'); + var right = this.container.find('.calendar.right'); + left.removeClass('left').addClass('right'); + right.removeClass('right').addClass('left'); + } - this.container.find('.calendar').on('change', 'select.yearselect', $.proxy(this.updateMonthYear, this)); - this.container.find('.calendar').on('change', 'select.monthselect', $.proxy(this.updateMonthYear, this)); + if (typeof options.ranges == 'undefined' && !this.singleDatePicker) { + this.container.find('.calendar').show(); + } - this.container.find('.calendar').on('change', 'select.hourselect', $.proxy(this.updateTime, this)); - this.container.find('.calendar').on('change', 'select.minuteselect', $.proxy(this.updateTime, this)); - this.container.find('.calendar').on('change', 'select.ampmselect', $.proxy(this.updateTime, this)); + this.container.addClass('opens' + this.opens); - this.element.on('keyup', $.proxy(this.updateFromControl, this)); + this.updateView(); + this.updateCalendars() - this.updateView(); - this.updateCalendars(); + }, - }; + setStartDate: function(startDate) { + if (typeof startDate == 'string') + this.startDate = moment(startDate, this.format); - DateRangePicker.prototype = { + if (typeof startDate == 'object') + this.startDate = moment(startDate); - constructor: DateRangePicker, + if (!this.timePicker) + this.startDate = this.startDate.startOf('day'); + + this.oldStartDate = this.startDate.clone(); + + this.updateView(); + this.updateCalendars(); + }, + + setEndDate: function(endDate) { + if (typeof endDate == 'string') + this.endDate = moment(endDate, this.format); + + if (typeof endDate == 'object') + this.endDate = moment(endDate); + + if (!this.timePicker) + this.endDate = this.endDate.startOf('day'); + + this.oldEndDate = this.endDate.clone(); + + this.updateView(); + this.updateCalendars(); + }, mousedown: function (e) { e.stopPropagation(); @@ -320,7 +404,10 @@ updateView: function () { this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year()); this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year()); + this.updateFormInputs(); + }, + updateFormInputs: function () { this.container.find('input[name=daterangepicker_start]').val(this.startDate.format(this.format)); this.container.find('input[name=daterangepicker_end]').val(this.endDate.format(this.format)); @@ -339,13 +426,23 @@ var start = moment(dateString[0], this.format); var end = moment(dateString[1], this.format); + if (this.singleDatePicker) { + start = moment(this.element.val(), this.format); + end = start; + } + if (start == null || end == null) return; if (end.isBefore(start)) return; + this.oldStartDate = this.startDate.clone(); + this.oldEndDate = this.endDate.clone(); + this.startDate = start; this.endDate = end; - this.notify(); + if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate)) + this.notify(); + this.updateCalendars(); }, @@ -355,17 +452,19 @@ }, move: function () { - var minWidth = $(this.container).find('.ranges').outerWidth(); - if ($(this.container).find('.calendar').is(':visible')) { - var padding = 24; // FIXME: this works for the default styling, but isn't flexible - minWidth += $(this.container).find('.calendar').outerWidth() * 2 + padding; + var parentOffset = { top: 0, left: 0 }; + if (!this.parentEl.is('body')) { + parentOffset = { + top: this.parentEl.offset().top - this.parentEl.scrollTop(), + left: this.parentEl.offset().left - this.parentEl.scrollLeft() + }; } + if (this.opens == 'left') { this.container.css({ - top: this.element.offset().top + this.element.outerHeight(), - right: $(window).width() - this.element.offset().left - this.element.outerWidth(), - left: 'auto', - 'min-width': minWidth + top: this.element.offset().top + this.element.outerHeight() - parentOffset.top, + right: $(window).width() - this.element.offset().left - this.element.outerWidth() - parentOffset.left, + left: 'auto' }); if (this.container.offset().left < 0) { this.container.css({ @@ -375,10 +474,9 @@ } } else { this.container.css({ - top: this.element.offset().top + this.element.outerHeight(), - left: this.element.offset().left, - right: 'auto', - 'min-width': minWidth + top: this.element.offset().top + this.element.outerHeight() - parentOffset.top, + left: this.element.offset().left - parentOffset.left, + right: 'auto' }); if (this.container.offset().left + this.container.outerWidth() > $(window).width()) { this.container.css({ @@ -399,7 +497,7 @@ } $(document).on('mousedown', $.proxy(this.hide, this)); - this.element.trigger('shown', {target: e.target, picker: this}); + this.element.trigger('show', this); }, hide: function (e) { @@ -412,7 +510,7 @@ this.oldEndDate = this.endDate.clone(); $(document).off('mousedown', this.hide); - this.element.trigger('hidden', { picker: this }); + this.element.trigger('hide', this); }, enterRange: function (e) { @@ -432,8 +530,12 @@ }, updateInputText: function() { - if (this.element.is('input')) + if (this.element.is('input') && !this.singleDatePicker) { this.element.val(this.startDate.format(this.format) + this.separator + this.endDate.format(this.format)); + } else if (this.element.is('input')) { + this.element.val(this.startDate.format(this.format)); + } + }, clickRange: function (e) { @@ -459,6 +561,7 @@ this.container.find('.calendar').hide(); this.hide(); + this.element.trigger('apply', this); } }, @@ -523,6 +626,12 @@ } } + if (this.singleDatePicker && cal.hasClass('left')) { + endDate = startDate; + } else if (this.singleDatePicker && cal.hasClass('right')) { + startDate = endDate; + } + cal.find('td').removeClass('active'); if (startDate.isSame(endDate) || startDate.isBefore(endDate)) { @@ -538,11 +647,15 @@ this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year()); this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year()); this.updateCalendars(); + + if (this.singleDatePicker) + this.clickApply(); }, clickApply: function (e) { this.updateInputText(); this.hide(); + this.element.trigger('apply', this); }, clickCancel: function (e) { @@ -551,6 +664,7 @@ this.updateView(); this.updateCalendars(); this.hide(); + this.element.trigger('cancel', this); }, updateMonthYear: function (e) { @@ -560,7 +674,8 @@ if (!isLeft) cal = this.container.find('.calendar.right'); - var month = cal.find('.monthselect').val(); + // Month must be Number for new moment versions + var month = parseInt(cal.find('.monthselect').val(), 10); var year = cal.find('.yearselect').val(); if (isLeft) { @@ -592,13 +707,13 @@ } if (isLeft) { - var start = this.startDate; + var start = this.startDate.clone(); start.hour(hour); start.minute(minute); this.startDate = start; this.leftCalendar.month.hour(hour).minute(minute); } else { - var end = this.endDate; + var end = this.endDate.clone(); end.hour(hour); end.minute(minute); this.endDate = end; @@ -661,13 +776,14 @@ if (dayOfWeek == this.locale.firstDay) startDay = daysInLastMonth - 6; - var curDate = moment([lastYear, lastMonth, startDay, hour, minute]); - for (var i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add('day', 1)) { + var curDate = moment([lastYear, lastMonth, startDay, 12, minute]); + for (var i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add('hour', 24)) { if (i > 0 && col % 7 == 0) { col = 0; row++; } - calendar[row][col] = curDate; + calendar[row][col] = curDate.clone().hour(hour); + curDate.hour(12); } return calendar; @@ -692,7 +808,7 @@ var currentYear = selected.year(); var maxYear = (maxDate && maxDate.year()) || (currentYear + 5); var minYear = (minDate && minDate.year()) || (currentYear - 50); - var yearHtml = ''; for (var y = minYear; y <= maxYear; y++) { yearHtml += '