js-custom-datepicker
Version:
Сalendar was written on javascript using es6 format and was redone to es5 using webpack and babel tools. There are many classes for easy styling for the desired website design.
505 lines (386 loc) • 16.8 kB
JavaScript
;
import DOM from '../lib/dom';
import * as i18n from './i18n';
import * as cls from '../lib/class';
import * as _ from '../lib/helper';
export const Calendar = (options, globalFn) => {
const _document = document;
const input = options.element;
const _inputVal = options.getDateIsoFormat(input.value, true);
const month_prev = new Date(options.current_year, options.current_month - 1, 1, 0, 0, 0, 0);
const day_count = new Date(month_prev.getDate(), month_prev.getMonth() + 1, 0).getDate();
const firstDay = new Date(options.current_year, options.current_month - 1, 1, 0, 0, 0);
const minDate = options.minDate ? options.getDateIsoFormat(options.minDate) : false;
const maxDate = options.maxDate ? options.getDateIsoFormat(options.maxDate) : false;
var selectedDate, _hover, between = false, _tr, i = 0;
var arrayPos = new Array();
var _id = null, _inputStartDay = null, tbody;
if (options.between) {
between = input.getAttribute('data-between');
try {
between = JSON.parse(between);
} catch (e) {
between = null;
}
}
if (options.binderID) {
_id = _document.getElementById(options.binderID);
if (!_id || _id.id === input.id) {
_id = null;
}
}
if (input.getAttribute('data-binderID')) {
_inputStartDay = _document.getElementById(input.getAttribute('data-binderID'));
}
function setup() {
let tr = DOM.createTag('tr', {'class': 'datepicker-week'});
let weekday = month_prev.getDay();
if (weekday === 0) {
weekday = 7;
}
let start = -(weekday - 2);
let last = (day_count + weekday - 1) % 7;
let end = last === 0 ? day_count : day_count + 7 - last;
for (let key = 1; key <= 7; key++) {
let _td = DOM.createTag('td');
let _lg = typeof i18n[options.language] === 'object' ? i18n[options.language] : i18n.de;
_td.innerHTML = _lg.dayNames.short[key];
tr.appendChild(_td);
}
let thead = DOM.createTag('thead');
thead.appendChild(tr);
tbody = DOM.createTag('tbody');
for (let day = start; day <= end; day++) {
createCalendarDay(day);
}
let table = DOM.createTag('table');
table.appendChild(thead);
table.appendChild(tbody);
let div = DOM.createTag('div', {'class': 'datepicker-calendar'});
div.appendChild(table);
return div;
}
function createCalendarDay(day) {
if (!(i++ % 7)) {
_tr = DOM.createTag('tr', {'class': 'datepicker-days'});
}
let selectDate = new Date(firstDay.format('YYYY-mm-dd')).adjustDate(day - 1);
let view_day = selectDate.getDate();
let selectDateFormat = selectDate.format(options.dateFormat);
arrayPos[selectDateFormat] = i;
let attrs = {
'data-date': selectDateFormat
};
let disabled = false;
if (day > 0 && day < day_count && selectDateFormat === input.value) {
attrs.class = 'current';
} else if ((day < 1 || day > day_count)) {
attrs.class = 'disabled';
disabled = true;
}
if (minDate && !disabled) {
if (minDate.getTime() > selectDate.getTime()) {
if (typeof attrs.class === 'string') {
attrs.class += ' disabled';
} else {
attrs.class = 'disabled';
}
disabled = true;
}
}
if (maxDate && !disabled) {
if (maxDate.getTime() < selectDate.getTime()) {
if (typeof attrs.class === 'string') {
attrs.class += ' disabled';
} else {
attrs.class = 'disabled';
}
disabled = true;
}
}
let today = new Date();
if (selectDateFormat === today.format(options.dateFormat)) {
if (typeof attrs.class === 'string') {
attrs.class += ' today';
} else {
attrs.class = 'today';
}
}
let _bindInputVal = _inputVal;
if (between) {
if (!disabled) {
if (between.from === selectDateFormat) {
attrs.class = 'current';
}
if (between.to === selectDateFormat) {
attrs.class = 'current';
}
}
if (between.from && between.to) {
let _from = options.getDateIsoFormat(between.from);
let _to = options.getDateIsoFormat(between.to);
if (!disabled) {
if (selectDate.getTime() > _from.getTime() && selectDate.getTime() < _to.getTime()) {
attrs.class = 'hovering';
}
if (selectDate.getTime() > _to.getTime() && selectDate.getTime() < _from.getTime()) {
attrs.class = 'hovering';
}
}
}
} else if (_id || _inputStartDay) {
let _bindInput_ = _id ? _id.value : _inputStartDay.value;
_bindInputVal = options.getDateIsoFormat(_bindInput_, true);
if (_bindInputVal instanceof Object) {
if (!disabled && selectDate.getTime() === _bindInputVal.getTime()) {
attrs.class = 'current hovering';
}
if (_inputVal instanceof Object) {
if (!disabled) {
if (selectDate.getTime() > _inputVal.getTime() && selectDate.getTime() < _bindInputVal.getTime()) {
attrs.class = 'hovering';
_hover = false;
}
if (selectDate.getTime() > _bindInputVal.getTime() && selectDate.getTime() < _inputVal.getTime()) {
attrs.class = 'hovering';
_hover = false;
}
}
if (!disabled && selectDate.getTime() === _inputVal.getTime()) {
attrs.class = 'current';
}
} else {
_hover = true;
}
}
}
let td = DOM.createTag('td', attrs);
if (!disabled) {
td.onclick = onSelect;
td.onmouseenter = function () {
if (_hover) {
let _current = tbody.querySelector('.current');
let _startDay = _current ? _current.getAttribute('data-date') : _bindInputVal || input.value;
if (_startDay instanceof Object) {
_startDay = _startDay.format(options.dateFormat);
}
_selectedRange(this, _startDay);
}
if (between && (between.from && !between.to)) {
_selectedRange(this, between.from);
}
};
}
td.onmouseout = function () {
if (_hover || between) {
_unSelectedRange(this, true);
}
};
td.innerHTML = view_day;
_tr.appendChild(td);
if (!(i % 7)) {
tbody.appendChild(_tr);
}
}
function _selectedRange(tag, _end) {
let _child = tbody.getElementsByTagName('td');
let end = arrayPos[tag.getAttribute('data-date')] - 1;
if (_end) {
let _pos = arrayPos[_end] - 1;
if (!_pos) {
let _from = options.getDateIsoFormat(tag.getAttribute('data-date')).getTime();
_end = _end instanceof Object ? _end.getTime() : options.getDateIsoFormat(_end).getTime();
let _td = tbody.querySelectorAll('td:not(.disabled)');
if (_end > _from) {
end = arrayPos[_td[_td.length - 1].getAttribute('data-date')] - 1;
} else {
end = arrayPos[_td[0].getAttribute('data-date')] - 1;
}
} else {
end = _pos;
}
}
let __tr = tbody.getElementsByClassName('current');
if (__tr.length === 0 && !end) {
return;
}
let start = arrayPos[tag.getAttribute('data-date')] - 1;
_unSelectedRange(tag);
for (let key = Math.min(start, end); key <= Math.max(start, end); key++) {
if (_child[key]) {
cls.add(_child[key], 'hovering');
}
}
}
function _unSelectedRange() {
let _child = tbody.getElementsByTagName('td');
for (let key = 0; key < _child.length; key++) {
cls.remove(_child[key], 'hovering');
}
}
function _unCheckedCurrent(tag, last) {
let _child = tbody.getElementsByClassName('current');
if (_child.length) {
for (let key = 0; key <= _child.length; key++) {
if (!last && key === _child.length) {
continue;
}
cls.remove(_child[0], 'current');
}
}
}
function onSelect(e) {
selectedDate = this.getAttribute('data-date');
let tbody = this.closest('tbody');
let _current = tbody.getElementsByClassName('current');
if (options.between) {
isBetween(this);
} else {
isBinderID(this);
}
function isBetween(td) {
if (between && between.from && between.to) {
_unCheckedCurrent(td, true);
_unSelectedRange(td, true);
between = null;
}
if (between) {
cls.add(td, 'current');
let _from = options.getDateIsoFormat(between.from || selectedDate);
let _to = options.getDateIsoFormat(between.to || selectedDate);
between.from = new Date(Math.min(_from.getTime(), _to.getTime())).format(options.dateFormat);
between.to = new Date(Math.max(_from.getTime(), _to.getTime())).format(options.dateFormat);
removeMouseEvent(td);
input.setAttribute('data-between', JSON.stringify(between));
// Function is executed after selecting second value
if (options.between.end && options.between.end.onSelect) {
options.between.end.call(e, input, selectedDate);
}
// Function is executed after selecting range
if (options.onSelect) {
options.onSelect.call(e, input, between);
}
} else {
cls.add(td, 'current');
between = {
from: selectedDate,
to: null
};
input.setAttribute('data-between', JSON.stringify(between));
let _child = tbody.querySelectorAll('td:not(.disabled)');
for (let i = 0; i < _child.length; i++) {
_child[i].onmouseenter = function () {
_selectedRange(this, selectedDate);
};
}
// Function is executed after selecting first value
if (options.between.start && options.between.start.onSelect) {
options.between.start.call(e, input, selectedDate);
}
}
}
function isBinderID(td) {
if (options.binderID && _id) {
_hover = true;
let _bindInputVal = options.getDateIsoFormat(_id.value, true);
if (_bindInputVal instanceof Object && _bindInputVal.toString() !== 'Invalid Date') {
if (options.getDateIsoFormat(selectedDate).getTime() < options.getDateIsoFormat(_id.value).getTime()) {
// click on start date and changing the calendar start date
_unCheckedCurrent(td);
_unSelectedRange(td);
cls.add(td, 'current');
if (arrayPos[_id.value]) {
cls.add(tbody.querySelectorAll('td')[arrayPos[_id.value] - 1], 'current');
}
_selectedRange(td, _id.value);
input.value = selectedDate;
removeMouseEvent(td);
if (options.onSelect) {
options.onSelect.call(e, input, selectedDate);
}
globalFn.close(options.dragAutoClose);
_hover = false;
} else {
// setting the end date when changing the start date beyond the current selection
_unCheckedCurrent(td, true);
_unSelectedRange(td);
cls.add(td, 'current');
input.value = selectedDate;
_id.value = _id.getAttribute('value'); //setting default value
if (options.onSelect) {
options.onSelect.call(e, input, selectedDate);
}
}
return;
}
// setting the calendar start date
if (_id && options.getDateIsoFormat(input.value, true)) {
if (options.getDateIsoFormat(input.value).getTime() > options.getDateIsoFormat(selectedDate).getTime()) {
_id.value = input.value;
input.value = selectedDate;
} else {
_id.value = selectedDate;
}
cls.add(td, 'current');
removeMouseEvent(td);
if (options.onSelect) {
options.onSelect.call(e, _id, selectedDate);
}
globalFn.close(options.dragAutoClose);
return;
}
cls.add(td, 'current');
input.value = selectedDate;
if (options.onSelect) {
options.onSelect.call(e, input, selectedDate);
}
return;
} else if (_inputStartDay) {
// click on input end date and setting the calendar end date
if (arrayPos[input.value] !== undefined) {
let _endCurrent = tbody.querySelector('[data-date="' + input.value + '"]');
if (_endCurrent) {
cls.remove(_endCurrent, 'current');
}
}
let _startDay = options.getDateIsoFormat(_inputStartDay.value, true) ? options.getDateIsoFormat(_inputStartDay.value, true) : (_current[0] ? _current[0].getAttribute('data-date') : null);
if (_startDay instanceof Object) {
_startDay = _startDay.format(options.dateFormat);
}
cls.add(td, 'current');
cls.add(_inputStartDay, 'current');
if (_startDay && options.getDateIsoFormat(_startDay).getTime() > options.getDateIsoFormat(selectedDate).getTime()) {
input.value = _inputStartDay.value;
_inputStartDay.value = selectedDate;
} else {
input.value = selectedDate;
}
removeMouseEvent(td);
_selectedRange(td, _startDay);
if (options.onSelect) {
options.onSelect.call(e, input, selectedDate);
}
globalFn.close(options.dragAutoClose);
return;
} else {
_unCheckedCurrent(td, true);
cls.add(td, 'current');
}
input.value = selectedDate;
if (options.onSelect) {
options.onSelect.call(e, input, selectedDate);
}
if (options.autoclose) {
globalFn.close(options.dragAutoClose);
}
}
function removeMouseEvent(td) {
let _child = td.closest('tbody').querySelectorAll('td');
for (let i = 0; i < _child.length; i++) {
_child[i].onmouseenter = null;
_child[i].onmouseout = null;
}
}
}
return setup();
};