123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360 |
- /*!
- * datepair.js v0.4.16 - A javascript plugin for intelligently selecting date and time ranges inspired by Google Calendar.
- * Copyright (c) 2018 Jon Thornton - http://jonthornton.github.com/Datepair.js
- * License: MIT
- */
- (function(window, document) {
- 'use strict';
- var _ONE_DAY = 86400000;
- var jq = window.Zepto || window.jQuery;
- function simpleExtend(obj1, obj2) {
- var out = obj2 || {};
- for (var i in obj1) {
- if (!(i in out)) {
- out[i] = obj1[i];
- }
- }
- return out;
- }
- // IE's custom event support is totally borked.
- // Use jQuery if possible
- function triggerSimpleCustomEvent(el, eventName) {
- if (jq) {
- jq(el).trigger(eventName);
- } else {
- var event = document.createEvent('CustomEvent');
- event.initCustomEvent(eventName, true, true, {});
- el.dispatchEvent(event);
- }
- }
- // el.classList not supported by < IE10
- // use jQuery if available
- function hasClass(el, className) {
- if (jq) {
- return jq(el).hasClass(className);
- } else {
- return el.classList.contains(className);
- }
- }
- function Datepair(container, options) {
- this.dateDelta = null;
- this.timeDelta = null;
- this._defaults = {
- startClass: 'start',
- endClass: 'end',
- timeClass: 'time',
- dateClass: 'date',
- defaultDateDelta: 0,
- defaultTimeDelta: 3600000,
- anchor: 'start',
- // defaults for jquery-timepicker; override when using other input widgets
- parseTime: function(input){
- return jq(input).timepicker('getTime');
- },
- updateTime: function(input, dateObj){
- jq(input).timepicker('setTime', dateObj);
- },
- setMinTime: function(input, dateObj){
- jq(input).timepicker('option', 'minTime', dateObj);
- },
- // defaults for bootstrap datepicker; override when using other input widgets
- parseDate: function(input){
- return input.value && jq(input).datepicker('getDate');
- },
- updateDate: function(input, dateObj){
- jq(input).datepicker('update', dateObj);
- }
- };
- this.container = container;
- this.settings = simpleExtend(this._defaults, options);
- this.startDateInput = this.container.querySelector('.'+this.settings.startClass+'.'+this.settings.dateClass);
- this.endDateInput = this.container.querySelector('.'+this.settings.endClass+'.'+this.settings.dateClass);
- this.startTimeInput = this.container.querySelector('.'+this.settings.startClass+'.'+this.settings.timeClass);
- this.endTimeInput = this.container.querySelector('.'+this.settings.endClass+'.'+this.settings.timeClass);
- // initialize date and time deltas
- this.refresh();
- // init starts here
- this._bindChangeHandler();
- }
- Datepair.prototype = {
- constructor: Datepair,
- option: function(key, value)
- {
- if (typeof key == 'object') {
- this.settings = simpleExtend(this.settings, key);
- } else if (typeof key == 'string' && typeof value != 'undefined') {
- this.settings[key] = value;
- } else if (typeof key == 'string') {
- return this.settings[key];
- }
- this._updateEndMintime();
- },
- getTimeDiff: function()
- {
- // due to the fact that times can wrap around, timeDiff for any
- // time-only pair will always be >= 0
- var delta = this.dateDelta + this.timeDelta;
- if (delta < 0 && (!this.startDateInput || !this.endDateInput) ) {
- delta += _ONE_DAY;
- }
- return delta;
- },
- refresh: function()
- {
- if (this.startDateInput && this.startDateInput.value && this.endDateInput && this.endDateInput.value) {
- var startDate = this.settings.parseDate(this.startDateInput);
- var endDate = this.settings.parseDate(this.endDateInput);
- if (startDate && endDate) {
- this.dateDelta = endDate.getTime() - startDate.getTime();
- }
- }
- if (this.startTimeInput && this.startTimeInput.value && this.endTimeInput && this.endTimeInput.value) {
- var startTime = this.settings.parseTime(this.startTimeInput);
- var endTime = this.settings.parseTime(this.endTimeInput);
- if (startTime && endTime) {
- this.timeDelta = endTime.getTime() - startTime.getTime();
- this._updateEndMintime();
- }
- }
- },
- remove: function()
- {
- this._unbindChangeHandler();
- },
- _bindChangeHandler: function(){
- // addEventListener doesn't work with synthetic "change" events
- // fired by jQuery's trigger() functioin. If jQuery is present,
- // use that for event binding
- if (jq) {
- jq(this.container).on('change.datepair', jq.proxy(this.handleEvent, this));
- } else {
- this.container.addEventListener('change', this, false);
- }
- },
- _unbindChangeHandler: function(){
- if (jq) {
- jq(this.container).off('change.datepair');
- } else {
- this.container.removeEventListener('change', this, false);
- }
- },
- // This function will be called when passing 'this' to addEventListener
- handleEvent: function(e){
- // temporarily unbind the change handler to prevent triggering this
- // if we update other inputs
- this._unbindChangeHandler();
- if (hasClass(e.target, this.settings.dateClass)) {
- if (e.target.value != '') {
- this._dateChanged(e.target);
- this._timeChanged(e.target);
- } else {
- this.dateDelta = null;
- }
- } else if (hasClass(e.target, this.settings.timeClass)) {
- if (e.target.value != '') {
- this._timeChanged(e.target);
- } else {
- this.timeDelta = null;
- }
- }
- this._validateRanges();
- this._updateEndMintime();
- this._bindChangeHandler();
- },
- _dateChanged: function(target){
- if (!this.startDateInput || !this.endDateInput) {
- return;
- }
- var startDate = this.settings.parseDate(this.startDateInput);
- var endDate = this.settings.parseDate(this.endDateInput);
- if (!startDate || !endDate) {
- if (this.settings.defaultDateDelta !== null) {
- if (startDate) {
- var newEnd = new Date(startDate.getTime() + this.settings.defaultDateDelta * _ONE_DAY);
- this.settings.updateDate(this.endDateInput, newEnd);
- } else if (endDate) {
- var newStart = new Date(endDate.getTime() - this.settings.defaultDateDelta * _ONE_DAY);
- this.settings.updateDate(this.startDateInput, newStart);
- }
- this.dateDelta = this.settings.defaultDateDelta * _ONE_DAY;
- } else {
- this.dateDelta = null;
- }
- return;
- }
- if (this.settings.anchor == 'start' && hasClass(target, this.settings.startClass)) {
- var newDate = new Date(startDate.getTime() + this.dateDelta);
- this.settings.updateDate(this.endDateInput, newDate);
- } else if (this.settings.anchor == 'end' && hasClass(target, this.settings.endClass)) {
- var newDate = new Date(endDate.getTime() - this.dateDelta);
- this.settings.updateDate(this.startDateInput, newDate);
- } else {
- if (endDate < startDate) {
- var otherInput = hasClass(target, this.settings.startClass) ? this.endDateInput : this.startDateInput;
- var selectedDate = this.settings.parseDate(target);
- this.dateDelta = 0;
- this.settings.updateDate(otherInput, selectedDate);
- } else {
- this.dateDelta = endDate.getTime() - startDate.getTime();
- }
- }
- },
- _timeChanged: function(target){
- if (!this.startTimeInput || !this.endTimeInput) {
- return;
- }
- var startTime = this.settings.parseTime(this.startTimeInput);
- var endTime = this.settings.parseTime(this.endTimeInput);
- if (!startTime || !endTime) {
- if (this.settings.defaultTimeDelta !== null) {
- this.timeDelta = this.settings.defaultTimeDelta;
- if (startTime) {
- endTime = this._setTimeAndReturn(this.endTimeInput, new Date(startTime.getTime() + this.settings.defaultTimeDelta));
- this._doMidnightRollover(startTime, endTime);
- } else if (endTime) {
- startTime = this._setTimeAndReturn(this.startTimeInput, new Date(endTime.getTime() - this.settings.defaultTimeDelta));
- this._doMidnightRollover(startTime, endTime);
- }
- } else {
- this.timeDelta = null;
- }
- return;
- }
- if (this.settings.anchor == 'start' && hasClass(target, this.settings.startClass)) {
- endTime = this._setTimeAndReturn(this.endTimeInput, new Date(startTime.getTime() + this.timeDelta));
- this._doMidnightRollover(startTime, endTime);
- } else if (this.settings.anchor == 'end' && hasClass(target, this.settings.endClass)) {
- startTime = this._setTimeAndReturn(this.startTimeInput, new Date(endTime.getTime() - this.timeDelta));
- this._doMidnightRollover(startTime, endTime);
- } else {
- this._doMidnightRollover(startTime, endTime);
- var startDate, endDate;
- if (this.startDateInput && this.endDateInput) {
- startDate = this.settings.parseDate(this.startDateInput);
- endDate = this.settings.parseDate(this.endDateInput);
- }
- if ((+startDate == +endDate) && (endTime < startTime)) {
- var thisInput = hasClass(target, this.settings.endClass) ? this.endTimeInput : this.startTimeInput;
- var otherInput = hasClass(target, this.settings.startClass) ? this.endTimeInput : this.startTimeInput;
- var selectedTime = this.settings.parseTime(thisInput);
- this.timeDelta = 0;
- this.settings.updateTime(otherInput, selectedTime);
- } else {
- this.timeDelta = endTime.getTime() - startTime.getTime();
- }
- }
- },
- _setTimeAndReturn: function(input, newTime) {
- this.settings.updateTime(input, newTime);
- return this.settings.parseTime(input);
- },
- _doMidnightRollover: function(startTime, endTime) {
- if (!this.startDateInput || !this.endDateInput) {
- return;
- }
- var endDate = this.settings.parseDate(this.endDateInput);
- var startDate = this.settings.parseDate(this.startDateInput);
- var newDelta = endTime.getTime() - startTime.getTime();
- var offset = (endTime < startTime) ? _ONE_DAY : -1 * _ONE_DAY;
- if (this.dateDelta !== null
- && this.dateDelta + this.timeDelta <= _ONE_DAY
- && this.dateDelta + newDelta != 0
- && (offset > 0 || this.dateDelta != 0)
- && ((newDelta >= 0 && this.timeDelta < 0) || (newDelta < 0 && this.timeDelta >= 0))) {
- if (this.settings.anchor == 'start') {
- this.settings.updateDate(this.endDateInput, new Date(endDate.getTime() + offset));
- this._dateChanged(this.endDateInput);
- } else if (this.settings.anchor == 'end') {
- this.settings.updateDate(this.startDateInput, new Date(startDate.getTime() - offset));
- this._dateChanged(this.startDateInput);
- }
- }
- this.timeDelta = newDelta;
- },
- _updateEndMintime: function(){
- if (typeof this.settings.setMinTime != 'function') return;
- var baseTime = null;
- if (this.settings.anchor == 'start' && (!this.dateDelta || this.dateDelta < _ONE_DAY || (this.timeDelta && this.dateDelta + this.timeDelta < _ONE_DAY))) {
- baseTime = this.settings.parseTime(this.startTimeInput);
- }
- this.settings.setMinTime(this.endTimeInput, baseTime);
- },
- _validateRanges: function(){
- if (this.startTimeInput && this.endTimeInput && this.timeDelta === null) {
- triggerSimpleCustomEvent(this.container, 'rangeIncomplete');
- return;
- }
- if (this.startDateInput && this.endDateInput && this.dateDelta === null) {
- triggerSimpleCustomEvent(this.container, 'rangeIncomplete');
- return;
- }
- // due to the fact that times can wrap around, any time-only pair will be considered valid
- if (!this.startDateInput || !this.endDateInput || this.dateDelta + this.timeDelta >= 0) {
- triggerSimpleCustomEvent(this.container, 'rangeSelected');
- } else {
- triggerSimpleCustomEvent(this.container, 'rangeError');
- }
- }
- };
- window.Datepair = Datepair;
- }(window, document));
|