UNPKG

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
'use strict'; 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(); };