@coreui/coreui-pro
Version:
The most popular front-end framework for developing responsive, mobile-first projects on the web rewritten by the CoreUI Team
951 lines (932 loc) • 37.5 kB
JavaScript
/*!
* CoreUI date-range-picker.js v5.23.0 (https://coreui.io)
* Copyright 2025 The CoreUI Team (https://github.com/orgs/coreui/people)
* Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('@popperjs/core'), require('./base-component.js'), require('./calendar.js'), require('./time-picker.js'), require('./dom/event-handler.js'), require('./dom/manipulator.js'), require('./dom/selector-engine.js'), require('./util/index.js'), require('./util/calendar.js'), require('./util/focustrap.js')) :
typeof define === 'function' && define.amd ? define(['@popperjs/core', './base-component', './calendar', './time-picker', './dom/event-handler', './dom/manipulator', './dom/selector-engine', './util/index', './util/calendar', './util/focustrap'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.DateRangePicker = factory(global["@popperjs/core"], global.BaseComponent, global.Calendar, global.TimePicker, global.EventHandler, global.Manipulator, global.SelectorEngine, global.Index, global.Calendar, global.Focustrap));
})(this, (function (Popper, BaseComponent, Calendar, TimePicker, EventHandler, Manipulator, SelectorEngine, index_js, calendar_js, FocusTrap) { 'use strict';
function _interopNamespaceDefault(e) {
const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } });
if (e) {
for (const k in e) {
if (k !== 'default') {
const d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: () => e[k]
});
}
}
}
n.default = e;
return Object.freeze(n);
}
const Popper__namespace = /*#__PURE__*/_interopNamespaceDefault(Popper);
/**
* --------------------------------------------------------------------------
* CoreUI PRO date-range-picker.js
* License (https://coreui.io/pro/license/)
* --------------------------------------------------------------------------
*/
/**
* Constants
*/
const NAME = 'date-range-picker';
const DATA_KEY = 'coreui.date-range-picker';
const EVENT_KEY = `.${DATA_KEY}`;
const DATA_API_KEY = '.data-api';
const ENTER_KEY = 'Enter';
const ESCAPE_KEY = 'Escape';
const TAB_KEY = 'Tab';
const RIGHT_MOUSE_BUTTON = 2;
const EVENT_CLICK = `click${EVENT_KEY}`;
const EVENT_END_DATE_CHANGE = `endDateChange${EVENT_KEY}`;
const EVENT_HIDE = `hide${EVENT_KEY}`;
const EVENT_HIDDEN = `hidden${EVENT_KEY}`;
const EVENT_INPUT = `input${EVENT_KEY}`;
const EVENT_KEYDOWN = `keydown${EVENT_KEY}`;
const EVENT_RESIZE = 'resize';
const EVENT_SHOW = `show${EVENT_KEY}`;
const EVENT_SHOWN = `shown${EVENT_KEY}`;
const EVENT_SUBMIT = 'submit';
const EVENT_START_DATE_CHANGE = `startDateChange${EVENT_KEY}`;
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`;
const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`;
const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`;
const CLASS_NAME_BODY = 'date-picker-body';
const CLASS_NAME_CALENDAR = 'date-picker-calendar';
const CLASS_NAME_CALENDARS = 'date-picker-calendars';
const CLASS_NAME_CLEANER = 'date-picker-cleaner';
const CLASS_NAME_DATE_PICKER = 'date-picker';
const CLASS_NAME_DATE_RANGE_PICKER = 'date-range-picker';
const CLASS_NAME_DISABLED = 'disabled';
const CLASS_NAME_DROPDOWN = 'date-picker-dropdown';
const CLASS_NAME_INDICATOR = 'date-picker-indicator';
const CLASS_NAME_INPUT = 'date-picker-input';
const CLASS_NAME_INPUT_GROUP = 'date-picker-input-group';
const CLASS_NAME_INPUT_PREVIEW = 'date-picker-input-preview';
const CLASS_NAME_INPUT_WRAPPER = 'date-picker-input-wrapper';
const CLASS_NAME_IS_INVALID = 'is-invalid';
const CLASS_NAME_IS_VALID = 'is-valid';
const CLASS_NAME_FOOTER = 'date-picker-footer';
const CLASS_NAME_RANGES = 'date-picker-ranges';
const CLASS_NAME_SEPARATOR = 'date-picker-separator';
const CLASS_NAME_SHOW = 'show';
const CLASS_NAME_TIME_PICKER = 'time-picker';
const CLASS_NAME_TIME_PICKERS = 'date-picker-timepickers';
const CLASS_NAME_WAS_VALIDATED = 'was-validated';
const SELECTOR_CALENDAR = '.calendars';
const SELECTOR_DATA_TOGGLE = '[data-coreui-toggle="date-range-picker"]:not(.disabled):not(:disabled)';
const SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE}.${CLASS_NAME_SHOW}`;
const SELECTOR_INPUT = '.date-picker-input';
const SELECTOR_WAS_VALIDATED = 'form.was-validated';
const Default = {
ariaNavNextMonthLabel: 'Next month',
ariaNavNextYearLabel: 'Next year',
ariaNavPrevMonthLabel: 'Previous month',
ariaNavPrevYearLabel: 'Previous year',
calendarDate: null,
calendars: 2,
cancelButton: 'Cancel',
cancelButtonClasses: ['btn', 'btn-sm', 'btn-ghost-primary'],
confirmButton: 'OK',
confirmButtonClasses: ['btn', 'btn-sm', 'btn-primary'],
cleaner: true,
container: false,
date: null,
disabled: false,
disabledDates: null,
endDate: null,
endName: null,
firstDayOfWeek: 1,
footer: false,
inputDateFormat: null,
inputDateParse: null,
inputOnChangeDelay: 750,
inputReadOnly: false,
invalid: false,
indicator: true,
locale: 'default',
maxDate: null,
minDate: null,
name: null,
placeholder: ['Start date', 'End date'],
previewDateOnHover: true,
range: true,
ranges: {},
rangesButtonsClasses: ['btn', 'btn-ghost-secondary'],
required: true,
separator: true,
size: null,
startDate: null,
startName: null,
selectAdjacementDays: false,
selectEndDate: false,
selectionType: 'day',
showAdjacementDays: true,
showWeekNumber: false,
timepicker: false,
todayButton: 'Today',
todayButtonClasses: ['btn', 'btn-sm', 'btn-primary', 'me-auto'],
valid: false,
weekdayFormat: 2,
weekNumbersLabel: null
};
const DefaultType = {
ariaNavNextMonthLabel: 'string',
ariaNavNextYearLabel: 'string',
ariaNavPrevMonthLabel: 'string',
ariaNavPrevYearLabel: 'string',
calendarDate: '(date|number|string|null)',
calendars: 'number',
cancelButton: '(boolean|string)',
cancelButtonClasses: '(array|string)',
cleaner: 'boolean',
confirmButton: '(boolean|string)',
confirmButtonClasses: '(array|string)',
container: '(string|element|boolean)',
date: '(date|number|string|null)',
disabledDates: '(array|date|function|null)',
disabled: 'boolean',
endDate: '(date|number|string|null)',
endName: '(string|null)',
firstDayOfWeek: 'number',
footer: 'boolean',
indicator: 'boolean',
inputDateFormat: '(function|null)',
inputDateParse: '(function|null)',
inputOnChangeDelay: 'number',
inputReadOnly: 'boolean',
invalid: 'boolean',
locale: 'string',
maxDate: '(date|number|string|null)',
minDate: '(date|number|string|null)',
name: '(string|null)',
placeholder: '(array|string)',
previewDateOnHover: 'boolean',
range: 'boolean',
ranges: 'object',
rangesButtonsClasses: '(array|string)',
required: 'boolean',
separator: 'boolean',
size: '(string|null)',
startDate: '(date|number|string|null)',
startName: '(string|null)',
selectAdjacementDays: 'boolean',
selectEndDate: 'boolean',
selectionType: 'string',
showAdjacementDays: 'boolean',
showWeekNumber: 'boolean',
timepicker: 'boolean',
todayButton: '(boolean|string)',
todayButtonClasses: '(array|string)',
valid: 'boolean',
weekdayFormat: '(number|string)',
weekNumbersLabel: '(string|null)'
};
/**
* Class definition
*/
class DateRangePicker extends BaseComponent {
constructor(element, config) {
super(element);
this._config = this._getConfig(config);
this._calendarDate = this._config.calendarDate;
this._startDate = this._config.date || this._config.startDate;
this._endDate = this._config.endDate;
this._initialStartDate = null;
this._initialEndDate = null;
this._mobile = window.innerWidth < 768;
this._popper = null;
this._selectEndDate = this._config.selectEndDate;
this._calendar = null;
this._calendars = null;
this._endInput = null;
this._endInputTimeout = null;
this._endPreviewInput = null;
this._indicatorElement = null;
this._menu = null;
this._startInput = null;
this._startInputTimeout = null;
this._startPreviewInput = null;
this._timepickers = null;
this._timePickerEnd = null;
this._timePickerStart = null;
this._togglerElement = null;
this._createDateRangePicker();
this._createDateRangePickerCalendars();
this._addEventListeners();
this._addCalendarEventListeners();
this._focustrap = this._initializeFocusTrap();
}
// Getters
static get Default() {
return Default;
}
static get DefaultType() {
return DefaultType;
}
static get NAME() {
return NAME;
}
// Public
toggle() {
return this._isShown() ? this.hide() : this.show();
}
show() {
if (this._config.disabled || this._isShown()) {
return;
}
this._initialStartDate = this._startDate ? new Date(this._startDate) : null;
this._initialEndDate = this._endDate ? new Date(this._endDate) : null;
EventHandler.trigger(this._element, EVENT_SHOW);
this._element.classList.add(CLASS_NAME_SHOW);
this._element.setAttribute('aria-expanded', true);
if (this._config.container) {
this._menu.classList.add(CLASS_NAME_SHOW);
}
this._focustrap.activate();
EventHandler.trigger(this._element, EVENT_SHOWN);
this._createPopper();
}
hide() {
EventHandler.trigger(this._element, EVENT_HIDE);
if (this._popper) {
this._popper.destroy();
}
this._element.classList.remove(CLASS_NAME_SHOW);
this._element.setAttribute('aria-expanded', 'false');
if (this._config.container) {
this._menu.classList.remove(CLASS_NAME_SHOW);
}
this._focustrap.deactivate();
EventHandler.trigger(this._element, EVENT_HIDDEN);
}
dispose() {
if (this._popper) {
this._popper.destroy();
}
if (this._startInputTimeout) {
clearTimeout(this._startInputTimeout);
}
if (this._endInputTimeout) {
clearTimeout(this._endInputTimeout);
}
this._focustrap.deactivate();
super.dispose();
}
cancel() {
this.hide();
if (this._initialStartDate) {
this._changeStartDate(this._initialStartDate);
}
if (this._config.range && this._initialEndDate) {
this._changeEndDate(this._initialEndDate);
}
if (this._initialStartDate || this._initialEndDate) {
this._calendar.update(this._getCalendarConfig);
}
}
clear() {
this._changeStartDate(null);
this._changeEndDate(null);
this._calendar.update(this._getCalendarConfig());
}
reset() {
this._changeStartDate(this._config.startDate);
this._changeEndDate(this._config.endDate);
this._calendar.update(this._getCalendarConfig());
}
update(config) {
this._config = this._getConfig(config);
this._calendarDate = this._config.calendarDate;
this._startDate = this._config.date || this._config.startDate;
this._endDate = this._config.endDate;
this._selectEndDate = this._config.selectEndDate;
this._element.innerHTML = '';
this._createDateRangePicker();
this._createDateRangePickerCalendars();
this._addEventListeners();
this._addCalendarEventListeners();
}
// Private
_initializeFocusTrap() {
return new FocusTrap({
additionalElement: this._config.container ? this._menu : null,
trapElement: this._element
});
}
_addEventListeners() {
EventHandler.on(this._indicatorElement, EVENT_CLICK, () => {
if (!this._config.disabled) {
this.toggle();
}
});
EventHandler.on(this._indicatorElement, EVENT_KEYDOWN, event => {
if (!this._config.disabled && event.key === ENTER_KEY) {
this.toggle();
}
});
EventHandler.on(this._togglerElement, EVENT_CLICK, event => {
if (!this._config.disabled && event.target !== this._indicatorElement) {
this.show();
}
});
EventHandler.on(this._element, EVENT_KEYDOWN, event => {
if (event.key === ESCAPE_KEY) {
this.hide();
this._startInput.focus();
}
});
EventHandler.on(this._startInput, EVENT_CLICK, () => {
this._selectEndDate = false;
this._calendar.update(this._getCalendarConfig());
});
EventHandler.on(this._startInput, EVENT_INPUT, event => {
if (this._startInputTimeout) {
clearTimeout(this._startInputTimeout);
}
this._startInputTimeout = setTimeout(() => {
const date = this._parseDate(event.target.value);
let formatedDate = date;
if (date instanceof Date && date.getTime()) {
if (calendar_js.isDateDisabled(date, this._config.minDate, this._config.maxDate, this._config.disabledDates)) {
return; // Don't update if date is disabled
}
if (this._config.selectionType !== 'day') {
formatedDate = calendar_js.getDateBySelectionType(date, this._config.selectionType);
}
this._calendarDate = formatedDate;
this._startInput.value = this._setInputValue(formatedDate);
}
this._startDate = formatedDate;
this._calendar.update(this._getCalendarConfig());
if (this._timePickerStart) {
this._timePickerStart.update(this._getTimePickerConfig(true));
}
EventHandler.trigger(this._element, EVENT_START_DATE_CHANGE, {
date: formatedDate
});
}, this._config.inputOnChangeDelay);
});
EventHandler.on(this._startInput.form, EVENT_SUBMIT, () => {
if (this._startInput.form.classList.contains(CLASS_NAME_WAS_VALIDATED)) {
if (this._config.range && (Number.isNaN(Date.parse(this._startInput.value)) || Number.isNaN(Date.parse(this._endInput.value)))) {
return this._element.classList.add(CLASS_NAME_IS_INVALID);
}
if (this._config.range && this._startDate instanceof Date && this._endDate instanceof Date) {
return this._element.classList.add(CLASS_NAME_IS_VALID);
}
if (!this._config.range && Number.isNaN(Date.parse(this._startInput.value))) {
return this._element.classList.add(CLASS_NAME_IS_INVALID);
}
if (!this._config.range && this._startDate instanceof Date) {
return this._element.classList.add(CLASS_NAME_IS_VALID);
}
this._element.classList.add(CLASS_NAME_IS_INVALID);
}
});
EventHandler.on(this._endInput, EVENT_CLICK, () => {
this._selectEndDate = true;
this._calendar.update(this._getCalendarConfig());
});
EventHandler.on(this._endInput, EVENT_INPUT, event => {
if (this._endInputTimeout) {
clearTimeout(this._endInputTimeout);
}
this._endInputTimeout = setTimeout(() => {
const date = this._parseDate(event.target.value);
let formatedDate = date;
if (date instanceof Date && date.getTime()) {
if (date && calendar_js.isDateDisabled(date, this._config.minDate, this._config.maxDate, this._config.disabledDates)) {
return; // Don't update if date is disabled
}
if (this._config.selectionType !== 'day') {
formatedDate = calendar_js.getDateBySelectionType(date, this._config.selectionType);
}
this._calendarDate = formatedDate;
this._endInput.value = this._setInputValue(formatedDate);
}
this._endDate = formatedDate;
this._calendar.update(this._getCalendarConfig());
if (this._timePickerEnd) {
this._timePickerEnd.update(this._getTimePickerConfig(false));
}
EventHandler.trigger(this._element, EVENT_END_DATE_CHANGE, {
date: formatedDate
});
}, this._config.inputOnChangeDelay);
});
EventHandler.on(window, EVENT_RESIZE, () => {
this._mobile = window.innerWidth < 768;
});
}
_addCalendarEventListeners() {
for (const calendar of SelectorEngine.find(SELECTOR_CALENDAR, this._menu)) {
EventHandler.on(calendar, 'startDateChange.coreui.calendar', event => {
this._changeStartDate(event.date);
if (!this._config.range && !this._config.footer && !this._config.timepicker) {
this.hide();
}
});
EventHandler.on(calendar, 'endDateChange.coreui.calendar', event => {
this._changeEndDate(event.date);
if (this._startDate && !this._config.footer && !this._config.timepicker) {
this.hide();
}
});
if (this._config.previewDateOnHover && !this._config.disabled) {
EventHandler.on(calendar, 'cellHover.coreui.calendar', event => {
if (this._selectEndDate) {
const previewValue = event.date ? this._setInputValue(event.date) : this._setInputValue(this._endDate);
this._updatePreviewInputVisibility(this._endPreviewInput, event.date ? previewValue : '');
return;
}
const previewValue = event.date ? this._setInputValue(event.date) : this._setInputValue(this._startDate);
this._updatePreviewInputVisibility(this._startPreviewInput, event.date ? previewValue : '');
});
}
EventHandler.on(calendar, 'selectEndChange.coreui.calendar', event => {
this._selectEndDate = event.value;
});
}
}
_changeStartDate(value, skipTimePickerUpdate = false) {
this._startDate = value;
this._startInput.value = this._setInputValue(value);
this._startInput.dispatchEvent(new Event('change'));
EventHandler.trigger(this._element, EVENT_START_DATE_CHANGE, {
date: value
});
if (this._timePickerStart && !skipTimePickerUpdate) {
this._timePickerStart.update(this._getTimePickerConfig(true));
}
}
_changeEndDate(value, skipTimePickerUpdate = false) {
this._endDate = value;
this._endInput.value = this._setInputValue(value);
this._endInput.dispatchEvent(new Event('change'));
EventHandler.trigger(this._element, EVENT_END_DATE_CHANGE, {
date: value
});
if (this._timePickerEnd && !skipTimePickerUpdate) {
this._timePickerEnd.update(this._getTimePickerConfig(false));
}
}
_getCalendarConfig() {
return {
ariaNavNextMonthLabel: this._config.ariaNavNextMonthLabel,
ariaNavNextYearLabel: this._config.ariaNavNextYearLabel,
ariaNavPrevMonthLabel: this._config.ariaNavPrevMonthLabel,
ariaNavPrevYearLabel: this._config.ariaNavPrevYearLabel,
calendarDate: this._calendarDate,
calendars: this._mobile ? 1 : this._config.calendars,
disabledDates: this._config.disabledDates,
endDate: this._endDate,
firstDayOfWeek: this._config.firstDayOfWeek,
locale: this._config.locale,
maxDate: this._config.maxDate,
minDate: this._config.minDate,
range: this._config.range,
selectAdjacementDays: this._config.selectAdjacementDays,
selectEndDate: this._selectEndDate,
selectionType: this._config.selectionType,
showAdjacementDays: this._config.showAdjacementDays,
showWeekNumber: this._config.showWeekNumber,
startDate: this._startDate,
weekdayFormat: this._config.weekdayFormat,
weekNumbersLabel: this._config.weekNumbersLabel
};
}
_getTimePickerConfig(start) {
return {
disabled: start ? !this._startDate : !this._endDate,
locale: this._config.locale,
time: start ? this._startDate && new Date(this._startDate) : this._endDate && new Date(this._endDate),
type: 'inline',
variant: 'select'
};
}
_createDateRangePicker() {
this._element.classList.add(CLASS_NAME_DATE_PICKER);
Manipulator.setDataAttribute(this._element, 'toggle', this._config.range ? CLASS_NAME_DATE_RANGE_PICKER : CLASS_NAME_DATE_PICKER);
if (this._config.size) {
this._element.classList.add(`date-picker-${this._config.size}`);
}
if (this._config.disabled) {
this._element.classList.add(CLASS_NAME_DISABLED);
}
this._element.classList.toggle(CLASS_NAME_IS_INVALID, this._config.invalid);
this._element.classList.toggle(CLASS_NAME_IS_VALID, this._config.valid);
this._element.append(this._createDateRangePickerInputGroup());
const dropdownEl = document.createElement('div');
dropdownEl.classList.add(CLASS_NAME_DROPDOWN);
dropdownEl.append(this._createDateRangePickerBody());
if (this._config.footer || this._config.timepicker) {
dropdownEl.append(this._createDateRangeFooter());
}
const {
container
} = this._config;
if (container) {
container.append(dropdownEl);
} else {
this._element.append(dropdownEl);
}
this._menu = dropdownEl;
}
_updatePreviewInputVisibility(previewInput, value) {
if (!previewInput) {
return;
}
if (value && value.trim() !== '') {
previewInput.style.display = 'block';
previewInput.value = value;
} else {
previewInput.style.display = 'none';
previewInput.value = '';
}
}
_createInputWrapper(inputEl, isStart = true) {
if (!this._config.previewDateOnHover || this._config.disabled) {
return inputEl;
}
const wrapperEl = document.createElement('div');
wrapperEl.classList.add(CLASS_NAME_INPUT_WRAPPER);
wrapperEl.append(inputEl);
const previewInputEl = document.createElement('input');
previewInputEl.classList.add(CLASS_NAME_INPUT, CLASS_NAME_INPUT_PREVIEW);
previewInputEl.type = 'text';
previewInputEl.readOnly = true;
previewInputEl.tabIndex = -1;
previewInputEl.style.display = 'none';
if (isStart) {
this._startPreviewInput = previewInputEl;
} else {
this._endPreviewInput = previewInputEl;
}
wrapperEl.append(previewInputEl);
return wrapperEl;
}
_createDateRangePickerInputGroup() {
const inputGroupEl = document.createElement('div');
inputGroupEl.classList.add(CLASS_NAME_INPUT_GROUP);
let startInputName = null;
if (this._config.name || this._config.startName || this._element.id) {
startInputName = this._config.name || this._config.startName || (this._config.range ? `date-range-picker-start-date-${this._element.id}` : `date-picker-${this._element.id}`);
}
const startInputEl = this._createInput(startInputName, this._getPlaceholder()[0], this._setInputValue(this._startDate));
let endInputName = null;
if (this._config.endName || this._element.id) {
endInputName = this._config.endName || `date-range-picker-end-date-${this._element.id}`;
}
const endInputEl = this._createInput(endInputName, this._getPlaceholder()[1], this._setInputValue(this._endDate));
const inputGroupTextSeparatorEl = document.createElement('div');
inputGroupTextSeparatorEl.classList.add(CLASS_NAME_SEPARATOR);
this._startInput = startInputEl;
this._endInput = endInputEl;
const startInputWrapper = this._createInputWrapper(startInputEl, true);
inputGroupEl.append(startInputWrapper);
if (this._config.separator) {
inputGroupEl.append(inputGroupTextSeparatorEl);
}
if (this._config.range) {
const endInputWrapper = this._createInputWrapper(endInputEl, false);
inputGroupEl.append(endInputWrapper);
}
if (this._config.indicator) {
const inputGroupIndicatorEl = document.createElement('div');
inputGroupIndicatorEl.classList.add(CLASS_NAME_INDICATOR);
if (!this._config.disabled) {
inputGroupIndicatorEl.tabIndex = 0;
}
inputGroupEl.append(inputGroupIndicatorEl);
this._indicatorElement = inputGroupIndicatorEl;
}
if (this._config.cleaner) {
const inputGroupCleanerEl = document.createElement('div');
inputGroupCleanerEl.classList.add(CLASS_NAME_CLEANER);
inputGroupCleanerEl.addEventListener('click', event => {
event.stopPropagation();
this.clear();
});
inputGroupEl.append(inputGroupCleanerEl);
}
this._togglerElement = inputGroupEl;
return inputGroupEl;
}
_createDateRangePickerBody() {
const dateRangePickerBodyEl = document.createElement('div');
dateRangePickerBodyEl.classList.add(CLASS_NAME_BODY);
if (Object.keys(this._config.ranges).length) {
const dateRangePickerRangesEl = document.createElement('div');
dateRangePickerRangesEl.classList.add(CLASS_NAME_RANGES);
for (const key of Object.keys(this._config.ranges)) {
const buttonEl = document.createElement('button');
buttonEl.classList.add(...this._getButtonClasses(this._config.rangesButtonsClasses));
buttonEl.role = 'button';
buttonEl.addEventListener('click', () => {
this._changeStartDate(this._config.ranges[key][0]);
this._changeEndDate(this._config.ranges[key][1]);
this._calendar.update(this._getCalendarConfig());
});
buttonEl.innerHTML = key;
dateRangePickerRangesEl.append(buttonEl);
}
dateRangePickerBodyEl.append(dateRangePickerRangesEl);
}
const calendarsEl = document.createElement('div');
calendarsEl.classList.add(CLASS_NAME_CALENDARS);
this._calendars = calendarsEl;
dateRangePickerBodyEl.append(calendarsEl);
if (this._config.timepicker) {
const timepickersEl = document.createElement('div');
timepickersEl.classList.add(CLASS_NAME_TIME_PICKERS);
this._timepickers = timepickersEl;
dateRangePickerBodyEl.append(timepickersEl);
}
return dateRangePickerBodyEl;
}
_createDateRangePickerCalendars() {
const calendarEl = document.createElement('div');
calendarEl.classList.add(CLASS_NAME_CALENDAR);
this._calendars.append(calendarEl);
this._calendar = new Calendar(calendarEl, this._getCalendarConfig());
EventHandler.on(calendarEl, 'calendarDateChange.coreui.calendar', event => {
this._calendarDate = event.date;
});
EventHandler.on(calendarEl, 'calendarMouseleave.coreui.calendar', () => {
this._updatePreviewInputVisibility(this._startPreviewInput, '');
this._updatePreviewInputVisibility(this._endPreviewInput, '');
});
if (this._config.timepicker) {
if (this._mobile && this._config.range || this._config.range && this._config.calendars === 1) {
const timePickerStartEl = document.createElement('div');
timePickerStartEl.classList.add(CLASS_NAME_TIME_PICKER);
this._timePickerStart = new TimePicker(timePickerStartEl, this._getTimePickerConfig(true));
this._timepickers.append(timePickerStartEl);
EventHandler.on(timePickerStartEl, 'timeChange.coreui.time-picker', event => {
this._changeStartDate(event.date, true);
this._calendar.update(this._getCalendarConfig());
});
const timePickerEndEl = document.createElement('div');
timePickerEndEl.classList.add(CLASS_NAME_TIME_PICKER);
this._timePickerEnd = new TimePicker(timePickerEndEl, this._getTimePickerConfig(false));
this._timepickers.append(timePickerEndEl);
EventHandler.on(timePickerEndEl, 'timeChange.coreui.time-picker', event => {
this._changeEndDate(event.date, true);
this._calendar.update(this._getCalendarConfig());
});
} else {
for (const [index, _] of Array.from({
length: this._config.calendars
}).entries()) {
const timePickerEl = document.createElement('div');
timePickerEl.classList.add(CLASS_NAME_TIME_PICKER);
const _timepicker = new TimePicker(timePickerEl, this._getTimePickerConfig(index === 0));
if (index === 0) {
this._timePickerStart = _timepicker;
} else {
this._timePickerEnd = _timepicker;
}
this._timepickers.append(timePickerEl);
EventHandler.on(timePickerEl, 'timeChange.coreui.time-picker', event => {
if (index === 0) {
this._changeStartDate(event.date, true);
} else {
this._changeEndDate(event.date, true);
}
this._calendar.update(this._getCalendarConfig());
});
}
}
}
}
_createDateRangeFooter() {
const footerEl = document.createElement('div');
footerEl.classList.add(CLASS_NAME_FOOTER);
if (this._config.todayButton) {
const todayButtonEl = document.createElement('button');
todayButtonEl.classList.add(...this._getButtonClasses(this._config.todayButtonClasses));
todayButtonEl.type = 'button';
todayButtonEl.innerHTML = this._config.todayButton;
todayButtonEl.addEventListener('click', () => {
const date = new Date();
this._calendarDate = date;
this._changeStartDate(date);
if (this._config.range) {
this._changeEndDate(date);
}
this._calendar.update(this._getCalendarConfig());
});
footerEl.append(todayButtonEl);
}
if (this._config.cancelButton) {
const cancelButtonEl = document.createElement('button');
cancelButtonEl.classList.add(...this._getButtonClasses(this._config.cancelButtonClasses));
cancelButtonEl.type = 'button';
cancelButtonEl.innerHTML = this._config.cancelButton;
cancelButtonEl.addEventListener('click', () => {
this.cancel();
});
footerEl.append(cancelButtonEl);
}
if (this._config.confirmButton) {
const confirmButtonEl = document.createElement('button');
confirmButtonEl.classList.add(...this._getButtonClasses(this._config.confirmButtonClasses));
confirmButtonEl.type = 'button';
confirmButtonEl.innerHTML = this._config.confirmButton;
confirmButtonEl.addEventListener('click', () => {
this.hide();
});
footerEl.append(confirmButtonEl);
}
return footerEl;
}
_createInput(name, placeholder, value) {
const inputEl = document.createElement('input');
inputEl.classList.add(CLASS_NAME_INPUT);
inputEl.autocomplete = 'off';
inputEl.disabled = this._config.disabled;
inputEl.placeholder = placeholder;
inputEl.readOnly = this._config.inputReadOnly;
inputEl.required = this._config.required;
inputEl.type = 'text';
inputEl.value = value;
if (name) {
inputEl.name = name;
}
const events = ['change', 'keyup', 'paste'];
for (const event of events) {
inputEl.addEventListener(event, ({
target
}) => {
if (target.closest(SELECTOR_WAS_VALIDATED)) {
const inputs = SelectorEngine.find(SELECTOR_INPUT, this._element);
for (const input of inputs) {
if (Number.isNaN(Date.parse(input.value))) {
this._element.classList.add(CLASS_NAME_IS_INVALID);
this._element.classList.remove(CLASS_NAME_IS_VALID);
return;
}
}
if (this._config.range && this._startDate instanceof Date && this._endDate instanceof Date) {
this._element.classList.add(CLASS_NAME_IS_VALID);
this._element.classList.remove(CLASS_NAME_IS_INVALID);
return;
}
if (!this._config.range && this._startDate instanceof Date) {
this._element.classList.add(CLASS_NAME_IS_VALID);
this._element.classList.remove(CLASS_NAME_IS_INVALID);
return;
}
this._element.classList.add(CLASS_NAME_IS_INVALID);
this._element.classList.remove(CLASS_NAME_IS_VALID);
}
});
}
return inputEl;
}
_createPopper() {
if (typeof Popper__namespace === 'undefined') {
throw new TypeError('CoreUI\'s date picker require Popper (https://popper.js.org)');
}
const popperConfig = {
modifiers: [{
name: 'preventOverflow',
options: {
boundary: 'clippingParents'
}
}, {
name: 'offset',
options: {
offset: [0, 2]
}
}],
placement: index_js.isRTL() ? 'bottom-end' : 'bottom-start'
};
this._popper = Popper__namespace.createPopper(this._togglerElement, this._menu, popperConfig);
}
_parseDate(str) {
if (!str) {
return null;
}
if (this._config.inputDateParse) {
return this._config.inputDateParse(str);
}
if (this._config.selectionType === 'day') {
return calendar_js.getLocalDateFromString(str, this._config.locale, this._config.timepicker);
}
return calendar_js.convertToDateObject(str, this._config.selectionType);
}
_formatDate(date) {
if (!date) {
return '';
}
if (this._config.inputDateFormat) {
return this._config.inputDateFormat(date instanceof Date ? new Date(date) : calendar_js.convertToDateObject(date, this._config.selectionType));
}
if (this._config.selectionType !== 'day') {
return date;
}
const _date = new Date(date);
return this._config.timepicker ? _date.toLocaleString(this._config.locale) : _date.toLocaleDateString(this._config.locale);
}
_getButtonClasses(classes) {
if (typeof classes === 'string') {
return classes.split(' ');
}
return classes;
}
_getPlaceholder() {
const {
placeholder
} = this._config;
if (typeof placeholder === 'string') {
return placeholder.split(',');
}
return placeholder;
}
_isShown() {
return this._element.classList.contains(CLASS_NAME_SHOW);
}
_setInputValue(date) {
if (date) {
return this._formatDate(date);
}
return '';
}
_configAfterMerge(config) {
if (config.container === true) {
config.container = document.body;
}
if (typeof config.container === 'object' || typeof config.container === 'string') {
config.container = index_js.getElement(config.container);
}
return config;
}
// Static
static dateRangePickerInterface(element, config) {
const data = DateRangePicker.getOrCreateInstance(element, config);
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
}
}
static jQueryInterface(config) {
return this.each(function () {
const data = DateRangePicker.getOrCreateInstance(this, config);
if (typeof config !== 'string') {
return;
}
if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
throw new TypeError(`No method named "${config}"`);
}
data[config](this);
});
}
static clearMenus(event) {
if (event.button === RIGHT_MOUSE_BUTTON || event.type === 'keyup' && event.key !== TAB_KEY) {
return;
}
const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN);
for (const toggle of openToggles) {
const context = DateRangePicker.getInstance(toggle);
if (!context) {
continue;
}
const composedPath = event.composedPath();
if (composedPath.includes(context._element) || composedPath.includes(context._menu)) {
continue;
}
({
relatedTarget: context._element
});
if (event.type === 'click') ;
context.hide();
}
}
}
/**
* Data API implementation
*/
EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
const dateRangePickers = SelectorEngine.find(SELECTOR_DATA_TOGGLE);
for (let i = 0, len = dateRangePickers.length; i < len; i++) {
DateRangePicker.dateRangePickerInterface(dateRangePickers[i]);
}
});
EventHandler.on(document, EVENT_CLICK_DATA_API, DateRangePicker.clearMenus);
EventHandler.on(document, EVENT_KEYUP_DATA_API, DateRangePicker.clearMenus);
/**
* jQuery
*/
index_js.defineJQueryPlugin(DateRangePicker);
return DateRangePicker;
}));
//# sourceMappingURL=date-range-picker.js.map