Skip to content
This repository has been archived by the owner on Apr 13, 2022. It is now read-only.
Permalink
240c20134f
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
791 lines (625 sloc) 25.7 KB
'use strict';
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery', 'moment'], factory);
} else if (typeof exports === 'object') {
// Node/CommonJS
module.exports = factory(require('jquery'), require('moment'));
} else {
// Browser globals
root.Calendar = factory(jQuery, moment);
}
} (this, function ($, moment) {
function Calendar(settings) {
var self = this;
this.settings = settings;
this.calIsOpen = false;
this.presetIsOpen = false;
this.sameDayRange = settings.same_day_range || false;
this.element = settings.element || $('.daterange');
this.selected = null;
this.type = this.element.hasClass('daterange--single') ? 'single' : 'double';
this.required = settings.required == false ? false : true;
this.format = settings.format || {};
this.format.input = settings.format && settings.format.input || 'MMMM D, YYYY';
this.format.preset = settings.format && settings.format.preset || 'll';
this.format.jump_month = settings.format && settings.format.jump_month || 'MMMM';
this.format.jump_year = settings.format && settings.format.jump_year || 'YYYY';
this.placeholder = settings.placeholder || this.format.input;
this.days_array = settings.days_array && settings.days_array.length == 7 ?
settings.days_array : moment.weekdaysMin();
this.orig_start_date = null;
this.orig_end_date = null;
this.orig_current_date = null;
this.earliest_date = settings.earliest_date ? moment(settings.earliest_date)
: moment('1900-01-01', 'YYYY-MM-DD');
this.latest_date = settings.latest_date ? moment(settings.latest_date)
: moment('2900-12-31', 'YYYY-MM-DD');
this.end_date = settings.end_date ? moment(settings.end_date)
: (this.type == 'double' ? moment() : null);
this.start_date = settings.start_date ? moment(settings.start_date)
: (this.type == 'double' ? this.end_date.clone().subtract(1, 'month') : null);
this.current_date = settings.current_date ? moment(settings.current_date)
: (this.type == 'single' ? moment() : null);
this.presets = settings.presets == false || this.type == 'single' ? false : true;
this.callback = settings.callback || this.calendarSetDates;
this.calendarHTML(this.type);
$('.dr-presets', this.element).click(function() {
self.presetToggle();
});
$('.dr-list-item', this.element).click(function() {
var start = $('.dr-item-aside', this).data('start');
var end = $('.dr-item-aside', this).data('end');
self.start_date = self.calendarCheckDate(start);
self.end_date = self.calendarCheckDate(end);
self.calendarSetDates();
self.presetToggle();
self.calendarSaveDates();
});
$('.dr-date', this.element).on({
'click': function() {
self.calendarOpen(this);
},
'keyup': function(event) {
if (event.keyCode == 9 && !self.calIsOpen && !self.start_date && !self.end_date)
self.calendarOpen(this);
},
'keydown': function(event) {
switch (event.keyCode) {
case 9: // Tab
if ($(self.selected).hasClass('dr-date-start')) {
event.preventDefault();
self.calendarCheckDates();
self.calendarSetDates();
$('.dr-date-end', self.element).trigger('click');
} else {
self.calendarCheckDates();
self.calendarSetDates();
self.calendarSaveDates();
self.calendarClose('force');
}
break;
case 13: // Enter
event.preventDefault();
self.calendarCheckDates();
self.calendarSetDates();
self.calendarSaveDates();
self.calendarClose('force');
break;
case 27: // ESC
self.calendarSetDates();
self.calendarClose('force');
break;
case 38: // Up
event.preventDefault();
var timeframe = 'day';
if (event.shiftKey)
timeframe = 'week';
if (event.metaKey)
timeframe = 'month';
var back = moment(self.current_date).subtract(1, timeframe);
$(this).html(back.format(self.format.input));
self.current_date = back;
break;
case 40: // Down
event.preventDefault();
var timeframe = 'day';
if (event.shiftKey)
timeframe = 'week';
if (event.metaKey)
timeframe = 'month';
var forward = moment(self.current_date).add(1, timeframe);
$(this).html(forward.format(self.format.input));
self.current_date = forward;
break;
}
}
});
$('.dr-month-switcher i', this.element).click(function() {
var m = $('.dr-month-switcher span', self.element).data('month');
var y = $('.dr-year-switcher span', self.element).data('year');
var this_moment = moment([y, m, 1]);
var back = this_moment.clone().subtract(1, 'month');
var forward = this_moment.clone().add(1, 'month').startOf('day');
if ($(this).hasClass('dr-left')) {
self.calendarOpen(self.selected, back);
} else if ($(this).hasClass('dr-right')) {
self.calendarOpen(self.selected, forward);
}
});
$('.dr-year-switcher i', this.element).click(function() {
var m = $('.dr-month-switcher span', self.element).data('month');
var y = $('.dr-year-switcher span', self.element).data('year');
var this_moment = moment([y, m, 1]);
var back = this_moment.clone().subtract(1, 'year');
var forward = this_moment.clone().add(1, 'year').startOf('day');
if ($(this).hasClass('dr-left')) {
self.calendarOpen(self.selected, back);
} else if ($(this).hasClass('dr-right')) {
self.calendarOpen(self.selected, forward);
}
});
$('.dr-dates-dash', this.element).click(function() {
$('.dr-date-start', self.element).trigger('click');
});
// Once you click into a selection.. this lets you click out
var clickHandler = function(event) {
var contains = $(event.target).parent().closest(self.element);
if (!contains.length) {
document.removeEventListener('click', clickHandler, false);
if (self.presetIsOpen)
self.presetToggle();
if (self.calIsOpen) {
if ($(self.selected).hasClass('dr-date-end'))
self.calendarSaveDates();
self.calendarSetDates();
self.calendarClose('force');
}
}
}
this.element.on('click', function() {
document.addEventListener('click', clickHandler, false);
});
}
Calendar.prototype.presetToggle = function() {
if (this.presetIsOpen == false) {
this.orig_start_date = this.start_date;
this.orig_end_date = this.end_date;
this.orig_current_date = this.current_date;
this.presetIsOpen = true;
} else if (this.presetIsOpen) {
this.presetIsOpen = false;
}
if (this.calIsOpen == true)
this.calendarClose();
$('.dr-preset-list', this.element).slideToggle(200);
$('.dr-input', this.element).toggleClass('dr-active');
$('.dr-presets', this.element).toggleClass('dr-active');
this.element.toggleClass('dr-active');
}
Calendar.prototype.presetCreate = function() {
var self = this;
var ul_presets = $('<ul class="dr-preset-list" style="display: none;"></ul>');
var presets = typeof self.settings.presets === 'object' ? self.settings.presets :
[{
label: 'Last 30 days',
start: moment(self.latest_date).subtract(29, 'days'),
end: self.latest_date
},{
label: 'Last month',
start: moment(self.latest_date).subtract(1, 'month').startOf('month'),
end: moment(self.latest_date).subtract(1, 'month').endOf('month')
},{
label: 'Last 3 months',
start: moment(self.latest_date).subtract(3, 'month').startOf('month'),
end: moment(self.latest_date).subtract(1, 'month').endOf('month')
},{
label: 'Last 6 months',
start: moment(self.latest_date).subtract(6, 'month').startOf('month'),
end: moment(self.latest_date).subtract(1, 'month').endOf('month')
},{
label: 'Last year',
start: moment(self.latest_date).subtract(1, 'year').startOf('year'),
end: moment(self.latest_date).subtract(1, 'year').endOf('year')
},{
label: 'All time',
start: self.earliest_date,
end: self.latest_date
}];
if (moment(self.latest_date).diff(moment(self.latest_date).startOf('month'), 'days') >= 6 &&
typeof self.settings.presets !== 'object'
) {
presets.splice(1, 0, {
label: 'This month',
start: moment(self.latest_date).startOf('month'),
end: self.latest_date
});
}
$.each(presets, function(i, d) {
if (moment(d.start).isBefore(self.earliest_date)) {
d.start = self.earliest_date;
}
if (moment(d.start).isAfter(self.latest_date)) {
d.start = self.latest_date;
}
if (moment(d.end).isBefore(self.earliest_date)) {
d.end = self.earliest_date;
}
if (moment(d.end).isAfter(self.latest_date)) {
d.end = self.latest_date;
}
var startISO = moment(d.start).toISOString();
var endISO = moment(d.end).toISOString();
var string = moment(d.start).format(self.format.preset) +' &ndash; '+ moment(d.end).format(self.format.preset);
if ($('.dr-preset-list', self.element).length) {
var item = $('.dr-preset-list .dr-list-item:nth-of-type('+ (i + 1) +') .dr-item-aside', self.element);
item.data('start', startISO);
item.data('end', endISO);
item.html(string);
} else {
ul_presets.append('<li class="dr-list-item">'+ d.label +
'<span class="dr-item-aside" data-start="'+ startISO +'" data-end="'+ endISO +'">'+ string +'</span>'+
'</li>');
}
});
return ul_presets;
}
Calendar.prototype.calendarSetDates = function() {
$('.dr-date-start', this.element).html(moment(this.start_date).format(this.format.input));
$('.dr-date-end', this.element).html(moment(this.end_date).format(this.format.input));
if (!this.start_date && !this.end_date) {
var old_date = $('.dr-date', this.element).html();
var new_date = moment(this.current_date).format(this.format.input);
if (old_date.length === 0 && !this.required)
new_date = '';
if (old_date != new_date)
$('.dr-date', this.element).html(new_date);
}
}
Calendar.prototype.calendarSaveDates = function() {
if (this.type === 'double') {
if (!moment(this.orig_end_date).isSame(this.end_date) || !moment(this.orig_start_date).isSame(this.start_date))
return this.callback();
} else {
if (!this.required || !moment(this.orig_current_date).isSame(this.current_date))
return this.callback();
}
}
Calendar.prototype.calendarCheckDate = function(d) {
// Today
if (d === 'today' || d === 'now')
return moment().isAfter(this.latest_date) ? this.latest_date :
moment().isBefore(this.earliest_date) ? this.earliest_date : moment();
// Earliest
if (d === 'earliest')
return this.earliest_date;
// Latest
if (d === 'latest')
return this.latest_date;
// Convert string to a date if keyword ago or ahead exists
if (d && (/\bago\b/.test(d) || /\bahead\b/.test(d)))
return this.stringToDate(d);
var regex = /(?:\d)((?:st|nd|rd|th)?,?)/;
var d_array = d ? d.replace(regex, '').split(' ') : [];
// Add current year if year is not included
if (d_array.length == 2) {
d_array.push(moment().format(this.format.jump_year));
d = d_array.join(' ');
}
// Convert using settings format
var parsed_d = this.parseDate(d);
if (!parsed_d.isValid())
return moment(d); // occurs when parsing preset dates
return parsed_d;
}
Calendar.prototype.calendarCheckDates = function() {
var startTxt = $('.dr-date-start', this.element).html();
var endTxt = $('.dr-date-end', this.element).html();
var c = this.calendarCheckDate($(this.selected).html());
var s;
var e;
// Modify strings via some specific keywords to create valid dates
// Finally set all strings as dates
if (startTxt === 'ytd' || endTxt === 'ytd') { // Year to date
s = moment().startOf('year');
e = moment().endOf('year');
} else {
s = this.calendarCheckDate(startTxt);
e = this.calendarCheckDate(endTxt);
}
if (c.isBefore(this.earliest_date))
c = this.earliest_date;
if (s.isBefore(this.earliest_date))
s = this.earliest_date;
if (e.isBefore(this.earliest_date) || e.isBefore(s))
e = s.clone().add(6, 'day');
if (c.isAfter(this.latest_date))
c = this.latest_date;
if (e.isAfter(this.latest_date))
e = this.latest_date;
if (s.isAfter(this.latest_date) || s.isAfter(e))
s = e.clone().subtract(6, 'day');
// Push and save if it's valid otherwise return to previous state
if (this.type === 'double') {
// Is this a valid date?
if (s.isSame(e) && !this.sameDayRange)
return this.calendarSetDates();
this.start_date = s.isValid() ? s : this.start_date;
this.end_date = e.isValid() ? e : this.end_date;
}
this.current_date = c.isValid() ? c : this.current_date;
}
Calendar.prototype.stringToDate = function(str) {
var date_arr = str.split(' ');
if (date_arr[2] === 'ago') {
return moment(this.current_date).subtract(date_arr[0], date_arr[1]);
}
else if (date_arr[2] === 'ahead') {
return moment(this.current_date).add(date_arr[0], date_arr[1]);
}
return this.current_date;
}
Calendar.prototype.calendarOpen = function(selected, switcher) {
var self = this;
var other;
var cal_width = $('.dr-dates', this.element).innerWidth() - 8;
this.selected = selected || this.selected;
if (this.presetIsOpen == true)
this.presetToggle();
if (this.calIsOpen == true) {
this.calendarClose(switcher ? 'switcher' : undefined);
} else if ($(this.selected).html().length) {
this.orig_start_date = this.start_date;
this.orig_end_date = this.end_date;
this.orig_current_date = this.current_date;
}
this.calendarCheckDates();
this.calendarCreate(switcher);
this.calendarSetDates();
var next_month = moment(switcher || this.current_date).add(1, 'month').startOf('month').startOf('day');
var past_month = moment(switcher || this.current_date).subtract(1, 'month').endOf('month');
var next_year = moment(switcher || this.current_date).add(1, 'year').startOf('month').startOf('day');
var past_year = moment(switcher || this.current_date).subtract(1, 'year').endOf('month');
var this_moment = moment(switcher || this.current_date);
$('.dr-month-switcher span', this.element)
.data('month', this_moment.month())
.html(this_moment.format(this.format.jump_month));
$('.dr-year-switcher span', this.element)
.data('year', this_moment.year())
.html(this_moment.format(this.format.jump_year));
$('.dr-switcher i', this.element).removeClass('dr-disabled');
if (next_month.isAfter(this.latest_date))
$('.dr-month-switcher .dr-right', this.element).addClass('dr-disabled');
if (past_month.isBefore(this.earliest_date))
$('.dr-month-switcher .dr-left', this.element).addClass('dr-disabled');
if (next_year.isAfter(this.latest_date))
$('.dr-year-switcher .dr-right', this.element).addClass('dr-disabled');
if (past_year.isBefore(this.earliest_date))
$('.dr-year-switcher .dr-left', this.element).addClass('dr-disabled');
$('.dr-day', this.element).on({
mouseenter: function() {
var selected = $(this);
var start_date = moment(self.start_date);
var end_date = moment(self.end_date);
var current_date = moment(self.current_date);
if ($(self.selected).hasClass("dr-date-start")) {
selected.addClass('dr-hover dr-hover-before');
$('.dr-start', self.element).css({'border': 'none', 'padding-left': '0.3125rem'});
setMaybeRange('start');
}
if ($(self.selected).hasClass("dr-date-end")) {
selected.addClass('dr-hover dr-hover-after');
$('.dr-end', self.element).css({'border': 'none', 'padding-right': '0.3125rem'});
setMaybeRange('end');
}
if (!self.start_date && !self.end_date)
selected.addClass('dr-maybe');
$('.dr-selected', self.element).css('background-color', 'transparent');
function setMaybeRange(type) {
other = undefined;
self.range(6 * 7).forEach(function(i) {
var next = selected.next().data('date');
var prev = selected.prev().data('date');
var curr = selected.data('date');
if (!curr)
return false;
if (!prev)
prev = curr;
if (!next)
next = curr;
if (type == 'start') {
if (moment(next).isSame(self.end_date) || (self.sameDayRange && moment(curr).isSame(self.end_date)))
return false;
if (moment(curr).isAfter(self.end_date)) {
other = other || moment(curr).add(6, 'day').startOf('day');
if (i > 5 || (next ? moment(next).isAfter(self.latest_date) : false)) {
$(selected).addClass('dr-end');
other = moment(curr);
return false;
}
}
selected = selected.next().addClass('dr-maybe');
} else if (type == 'end') {
if (moment(prev).isSame(self.start_date) || (self.sameDayRange && moment(curr).isSame(self.start_date)))
return false;
if (moment(curr).isBefore(self.start_date)) {
other = other || moment(curr).subtract(6, 'day');
if (i > 5 || (prev ? moment(prev).isBefore(self.earliest_date) : false)) {
$(selected).addClass('dr-start');
other = moment(curr);
return false;
}
}
selected = selected.prev().addClass('dr-maybe');
}
});
}
},
mouseleave: function() {
if ($(this).hasClass('dr-hover-before dr-end'))
$(this).removeClass('dr-end');
if ($(this).hasClass('dr-hover-after dr-start'))
$(this).removeClass('dr-start');
$(this).removeClass('dr-hover dr-hover-before dr-hover-after');
$('.dr-start, .dr-end', self.element).css({'border': '', 'padding': ''});
$('.dr-maybe:not(.dr-current)', self.element).removeClass('dr-start dr-end');
$('.dr-day', self.element).removeClass('dr-maybe');
$('.dr-selected', self.element).css('background-color', '');
}
});
if (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) {
$('.dr-day', this.element).on({
touchstart: function() {
self.selectOneDate(other, self, $(this).data('date'));
}
});
$('div[contenteditable]', this.element).removeAttr('contenteditable');
} else {
$('.dr-day', this.element).on({
mousedown: function () {
self.selectOneDate(other, self, $(this).data('date'));
}
});
}
$('.dr-calendar', this.element)
.css('width', cal_width)
.slideDown(200);
$('.dr-input', this.element).addClass('dr-active');
$(selected).addClass('dr-active').focus();
this.element.addClass('dr-active');
this.calIsOpen = true;
}
Calendar.prototype.calendarClose = function(type) {
var self = this;
if (!this.calIsOpen || this.presetIsOpen || type == 'force') {
$('.dr-calendar', this.element).slideUp(200, function() {
$('.dr-day', self.element).remove();
});
} else {
$('.dr-day', this.element).remove();
}
if (type == 'switcher') {
return false;
}
$('.dr-input, .dr-date', this.element).removeClass('dr-active');
this.element.removeClass('dr-active');
this.calIsOpen = false;
}
Calendar.prototype.calendarCreate = function(switcher) {
var self = this;
var array = this.calendarArray(this.start_date, this.end_date, this.current_date, switcher);
array.forEach(function(d, i) {
var classString = "dr-day";
if (d.fade)
classString += " dr-fade";
if (d.start)
classString += " dr-start";
if (d.end)
classString += " dr-end";
if (d.current)
classString += " dr-current";
if (d.selected)
classString += " dr-selected";
if (d.outside)
classString += " dr-outside";
$('.dr-day-list', self.element).append('<li class="'+ classString +'" data-date="'+ d.date +'">'+ d.str +'</li>');
});
}
Calendar.prototype.calendarArray = function(start, end, current, switcher) {
var self = this;
current = moment(current || start || end).startOf('day');
var reference = switcher || current || start || end;
var startRange = moment(reference).startOf('month').startOf('week');
var endRange = moment(startRange).add(6*7 - 1, 'days').endOf('day');
var daysInRange = [];
var d = moment(startRange);
while ( d.isBefore(endRange) ) {
daysInRange.push( {
str: +d.format('D'),
start: start && d.isSame(start, 'day'),
end: end && d.isSame(end, 'day'),
current: current && d.isSame(current, 'day'),
selected: start && end && d.isBetween(start, end),
date: d.toISOString(),
outside: d.isBefore(self.earliest_date) || d.isAfter(self.latest_date),
fade: !d.isSame(reference, 'month')
} );
d.add(1, 'd');
}
return daysInRange;
}
Calendar.prototype.calendarHTML = function(type) {
var ul_days_of_the_week = $('<ul class="dr-days-of-week-list"></ul>');
var days = this.days_array.splice(moment.localeData().firstDayOfWeek()).concat(this.days_array.splice(0, moment.localeData().firstDayOfWeek()));
$.each(days, function(i, elem) {
ul_days_of_the_week.append('<li class="dr-day-of-week">' + elem + '</li>');
});
if (type == "double")
return this.element.append('<div class="dr-input">' +
'<div class="dr-dates">' +
'<div class="dr-date dr-date-start" contenteditable>'+ moment(this.start_date).format(this.format.input) +'</div>' +
'<span class="dr-dates-dash">&ndash;</span>' +
'<div class="dr-date dr-date-end" contenteditable>'+ moment(this.end_date).format(this.format.input) +'</div>' +
'</div>' +
(this.presets ? '<div class="dr-presets">' +
'<span class="dr-preset-bar"></span>' +
'<span class="dr-preset-bar"></span>' +
'<span class="dr-preset-bar"></span>' +
'</div>' : '') +
'</div>' +
'<div class="dr-selections">' +
'<div class="dr-calendar" style="display: none;">' +
'<div class="dr-range-switcher">' +
'<div class="dr-switcher dr-month-switcher">' +
'<i class="dr-left"></i>' +
'<span>April</span>' +
'<i class="dr-right"></i>' +
'</div>' +
'<div class="dr-switcher dr-year-switcher">' +
'<i class="dr-left"></i>' +
'<span>2015</span>' +
'<i class="dr-right"></i>' +
'</div>' +
'</div>' +
ul_days_of_the_week[0].outerHTML +
'<ul class="dr-day-list"></ul>' +
'</div>' +
(this.presets ? this.presetCreate()[0].outerHTML : '') +
'</div>');
return this.element.append('<div class="dr-input">' +
'<div class="dr-dates">' +
'<div class="dr-date" contenteditable placeholder="'+ this.placeholder +'">'+ (this.settings.current_date ? moment(this.current_date).format(this.format.input) : '') +'</div>' +
'</div>' +
'</div>' +
'<div class="dr-selections">' +
'<div class="dr-calendar" style="display: none;">' +
'<div class="dr-range-switcher">' +
'<div class="dr-switcher dr-month-switcher">' +
'<i class="dr-left"></i>' +
'<span></span>' +
'<i class="dr-right"></i>' +
'</div>' +
'<div class="dr-switcher dr-year-switcher">' +
'<i class="dr-left"></i>' +
'<span></span>' +
'<i class="dr-right"></i>' +
'</div>' +
'</div>' +
ul_days_of_the_week[0].outerHTML +
'<ul class="dr-day-list"></ul>' +
'</div>' +
'</div>');
}
Calendar.prototype.parseDate = function(d) {
if (moment.defaultZone !== null && moment.hasOwnProperty('tz')) {
return moment.tz(d, this.format.input, moment.defaultZone.name);
} else {
return moment(d, this.format.input);
}
}
Calendar.prototype.range = function(length) {
var range = new Array(length);
for (var idx = 0; idx < length; idx++) {
range[idx] = idx;
}
return range;
}
Calendar.prototype.selectOneDate = function(other, cal, date) {
var string = moment(date).format(cal.format.input);
if (other) {
$('.dr-date', cal.element)
.not(cal.selected)
.html(other.format(cal.format.input));
}
$(cal.selected).html(string);
cal.calendarOpen(cal.selected);
if ($(cal.selected).hasClass('dr-date-start')) {
$('.dr-date-end', cal.element).trigger('click');
} else {
cal.calendarSaveDates();
cal.calendarClose('force');
}
}
return Calendar;
}));