@senx/discovery-widgets
Version:
Discovery Widgets Elements
1,077 lines (1,073 loc) • 105 kB
JavaScript
import { proxyCustomElement, HTMLElement, createEvent, h } from '@stencil/core/internal/client';
import { m as moment, U as Utils, b as momentTimezone, P as Param, G as GTSLib } from './utils.js';
/*
* Copyright 2025 SenX S.A.S.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class DTPickerOptions {
}
/*
* Copyright 2025 SenX S.A.S.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// alternate jquery function (subset)
class JQ {
addClassSub(el, classes) {
const classsList = classes.split(' ');
for (const item of classsList) {
el.classList.add(item.trim());
}
}
addClass(el, classes) {
if (!el) {
return;
}
if (typeof el.length === 'number') {
for (const item of el) {
this.addClassSub(item, classes);
}
}
else {
this.addClassSub(el, classes);
}
}
findLast(el) {
if (!el) {
return null;
}
if (typeof el.length === 'number') {
if (el.length > 0) {
return el[el.length - 1];
}
else {
return null;
}
}
else {
return el;
}
}
findSelectedOption(el) {
if (!el || !el.options || !el.options.length) {
return null;
}
for (const opt of el.options) {
if (opt.selected) {
return opt;
}
}
return null;
}
getSelectorFromElement(el) {
if (!el || !(el instanceof Element)) {
return null;
}
let selector = el.nodeName.toLowerCase();
if (el.id) {
return selector + '#' + el.id;
}
for (const clazz of el.classList) {
selector += `.${clazz}`;
}
return selector;
}
html(el, html) {
if (el) {
el.innerHTML = html;
}
}
offset(el) {
if (!el) {
return { top: 0, left: 0 };
}
// Return zeros for disconnected and hidden (display: none) elements (gh-2310)
// Support: IE <=11 only
// Running getBoundingClientRect on a
// disconnected node in IE throws an error
if (!el.getClientRects().length) {
return { top: 0, left: 0 };
}
// Get document-relative position by adding viewport scroll to viewport-relative gBCR
const rect = el.getBoundingClientRect();
const win = el.ownerDocument.defaultView;
return {
top: rect.top + win.pageYOffset,
left: rect.left + win.pageXOffset,
};
}
offSub(el, event, listener) {
if (typeof el.length === 'number') {
for (const item of el) {
item.removeEventListener(event, listener);
}
}
else {
el.removeEventListener(event, listener);
}
}
off(el, event, param1, param2) {
if (!el) {
return;
}
if (typeof param1 === 'function') { // param is listener
this.offSub(el, event, param1);
}
else { // param is selector
if (typeof el.length === 'number') {
for (const item of el) {
this.offSub(item.querySelectorAll(param1), event, param2);
}
}
else {
this.offSub(el.querySelectorAll(param1), event, param2);
}
}
}
onSub(el, event, listener) {
if (typeof el.length === 'number') {
for (const item of el) {
item.addEventListener(event, listener);
}
}
else {
el.addEventListener(event, listener);
}
}
on(el, event, param1, param2) {
if (!el) {
return;
}
if (typeof param1 === 'function') { // param1 is listener
this.onSub(el, event, param1);
}
else { // param1 is selector
if (typeof el.length === 'number') {
for (const item of el) {
this.onSub(item.querySelectorAll(param1), event, param2);
}
}
else {
this.onSub(el.querySelectorAll(param1), event, param2);
}
}
}
}
// IE browser doesn't support "class"
class DateRangePicker {
constructor(element, options, cb) {
var _b, _c, _d, _f;
this.jq = new JQ();
this.startDate = moment();
this.endDate = moment();
this.oldStartDate = moment();
this.oldEndDate = moment();
this.outsideClickProxy = (e) => this.outsideClick(e);
this.moveProxy = (e) => this.move(e);
this.clickRangeProxy = (e) => this.clickRange(e);
this.clickApplyProxy = (e) => this.clickApply(e);
this.clickCancelProxy = (e) => this.clickCancel(e);
this.showProxy = (e) => this.show(e);
this.elementChangedProxy = (e) => this.elementChanged(e);
this.keydownProxy = (e) => this.keydown(e);
this.toggleProxy = (e) => this.toggle(e);
this.clickPrevProxy = (e) => this.clickPrev(e);
this.clickNextProxy = (e) => this.clickNext(e);
this.clickDateProxy = (e) => this.clickDate(e);
this.hoverDateProxy = (e) => this.hoverDate(e);
this.monthOrYearChangedProxy = (e) => this.monthOrYearChanged(e);
this.timeChangedProxy = (e) => this.timeChanged(e);
let rangeHtml;
let elem;
// default settings for options
this.parentEl = document.body;
if (typeof element === 'string') {
this.element = document.getElementById(element);
}
else {
this.element = element;
}
this.options = {
startDate: moment().startOf('day'),
endDate: moment().endOf('day'),
minDate: undefined,
maxDate: undefined,
maxSpan: undefined,
autoApply: false,
singleDatePicker: false,
showDropdowns: false,
minYear: moment().subtract(100, 'year').format('YYYY'),
maxYear: moment().add(100, 'year').format('YYYY'),
showWeekNumbers: false,
showISOWeekNumbers: false,
showCustomRangeLabel: true,
timePicker: false,
timePicker24Hour: false,
timePickerIncrement: 1,
timePickerSeconds: false,
linkedCalendars: true,
autoUpdateInput: true,
alwaysShowCalendars: false,
ranges: {},
opens: 'right',
drops: 'down',
buttonClasses: 'btn btn-sm',
applyButtonClasses: 'btn-primary',
cancelButtonClasses: 'btn-default',
wrapperClasses: '',
locale: {
locale: 'en',
direction: 'ltr',
format: moment.localeData().longDateFormat('L'),
separator: ' ➔ ',
applyLabel: 'Apply',
cancelLabel: 'Cancel',
weekLabel: 'W',
customRangeLabel: 'Custom Range',
daysOfWeek: moment.weekdaysMin(),
monthNames: moment.monthsShort(),
firstDay: moment.localeData().firstDayOfWeek(),
},
};
if (this.element.classList.contains('pull-right')) {
this.options.opens = 'left';
}
if (this.element.classList.contains('dropup')) {
this.options.drops = 'up';
}
this.callback = () => {
// empty
};
// some state information
this.isShowing = false;
this.leftCalendar = {};
this.rightCalendar = {};
// custom options from user
if (typeof options !== 'object' || options === null) {
options = new DTPickerOptions();
}
// allow setting options with data attributes
// data-api options will be overwritten with custom javascript options
// options = Object.assign(Object.assign({}, this.element.dataset), options);
// html template for the picker UI
if (typeof options.template !== 'string') {
options.template = `<div class="daterangepicker">
<div class="dp-wrapper">
<div class="ranges"></div>
<div class="drp-calendar left">
<div class="calendar-table"></div>
<div class="calendar-time"></div>
</div>
<div class="drp-calendar right">
<div class="calendar-table"></div>
<div class="calendar-time"></div>
</div>
</div>
<div class="drp-buttons">
<span class="drp-selected"></span>
<button class="cancelBtn" type="button"></button>
<button class="applyBtn" disabled="disabled" type="button"></button>
</div>
</div>`;
}
this.parentEl = options.parentEl ? options.parentEl : this.parentEl;
const templateWrapEl = document.createElement('div');
templateWrapEl.innerHTML = options.template.trim();
this.container = templateWrapEl.firstElementChild;
this.parentEl.insertAdjacentElement('beforeend', this.container);
// handle all the possible options overriding defaults
if (typeof options.locale === 'object') {
this.options.locale.locale = (_b = options.locale.locale) !== null && _b !== void 0 ? _b : 'en';
const loc = Utils.clone(moment.localeData((_c = options.locale.locale) !== null && _c !== void 0 ? _c : 'en'));
this.options.locale.timeZone = (_d = options.locale.timeZone) !== null && _d !== void 0 ? _d : 'UTC';
if (typeof options.locale.direction === 'string') {
this.options.locale.direction = options.locale.direction;
}
if (typeof options.locale.format === 'string') {
this.options.locale.format = options.locale.format;
}
if (typeof options.locale.separator === 'string') {
this.options.locale.separator = options.locale.separator;
}
this.options.locale.monthNames = loc.monthsShort();
this.options.locale.daysOfWeek = loc.weekdaysShort();
this.options.locale.firstDay = loc.firstDayOfWeek();
if (typeof options.locale.applyLabel === 'string') {
this.options.locale.applyLabel = options.locale.applyLabel;
}
if (typeof options.locale.cancelLabel === 'string') {
this.options.locale.cancelLabel = options.locale.cancelLabel;
}
if (typeof options.locale.weekLabel === 'string') {
this.options.locale.weekLabel = options.locale.weekLabel;
}
if (typeof options.locale.customRangeLabel === 'string') {
// Support Unicode chars in the custom range name.
elem = document.createElement('textarea');
elem.innerHTML = options.locale.customRangeLabel;
rangeHtml = elem.value;
this.options.locale.customRangeLabel = rangeHtml;
}
}
this.container.classList.add(this.options.locale.direction);
if (typeof options.startDate === 'object') {
this.options.startDate = moment(options.startDate);
}
if (typeof options.endDate === 'object') {
this.options.endDate = moment(options.endDate);
}
if (typeof options.minDate === 'object') {
this.options.minDate = moment(options.minDate);
}
if (typeof options.maxDate === 'object') {
this.options.maxDate = moment(options.maxDate);
}
// sanity check for bad options
if (this.options.minDate && this.options.startDate.isBefore(this.options.minDate)) {
this.options.startDate = this.options.minDate.clone();
}
// sanity check for bad options
if (this.options.maxDate && this.options.endDate.isAfter(this.options.maxDate)) {
this.options.endDate = this.options.maxDate.clone();
}
if (typeof options.applyButtonClasses === 'string') {
this.options.applyButtonClasses = options.applyButtonClasses;
}
if (typeof options.cancelButtonClasses === 'string') {
this.options.cancelButtonClasses = options.cancelButtonClasses;
}
if (typeof options.maxSpan === 'object') {
this.options.maxSpan = options.maxSpan;
}
if (typeof options.opens === 'string') {
this.options.opens = options.opens;
}
if (typeof options.drops === 'string') {
this.options.drops = options.drops;
}
if (typeof options.showWeekNumbers === 'boolean') {
this.options.showWeekNumbers = options.showWeekNumbers;
}
if (typeof options.showISOWeekNumbers === 'boolean') {
this.options.showISOWeekNumbers = options.showISOWeekNumbers;
}
if (typeof options.buttonClasses === 'string') {
this.options.buttonClasses = options.buttonClasses;
}
if (typeof options.buttonClasses === 'object') {
this.options.buttonClasses = ((_f = options.buttonClasses) !== null && _f !== void 0 ? _f : []).join(' ');
}
if (typeof options.showDropdowns === 'boolean') {
this.options.showDropdowns = options.showDropdowns;
}
if (typeof options.minYear === 'number') {
this.options.minYear = options.minYear;
}
if (typeof options.maxYear === 'number') {
this.options.maxYear = options.maxYear;
}
if (typeof options.showCustomRangeLabel === 'boolean') {
this.options.showCustomRangeLabel = options.showCustomRangeLabel;
}
if (typeof options.singleDatePicker === 'boolean') {
this.options.singleDatePicker = options.singleDatePicker;
if (this.options.singleDatePicker) {
this.options.endDate = this.options.startDate.clone();
}
}
if (typeof options.timePicker === 'boolean') {
this.options.timePicker = options.timePicker;
}
if (typeof options.timePickerSeconds === 'boolean') {
this.options.timePickerSeconds = options.timePickerSeconds;
}
if (typeof options.timePickerIncrement === 'number') {
this.options.timePickerIncrement = options.timePickerIncrement;
}
if (typeof options.timePicker24Hour === 'boolean') {
this.options.timePicker24Hour = options.timePicker24Hour;
}
if (typeof options.autoApply === 'boolean') {
this.options.autoApply = options.autoApply;
}
if (typeof options.autoUpdateInput === 'boolean') {
this.options.autoUpdateInput = options.autoUpdateInput;
}
if (typeof options.linkedCalendars === 'boolean') {
this.options.linkedCalendars = options.linkedCalendars;
}
if (typeof options.isInvalidDate === 'function') {
this.options.isInvalidDate = options.isInvalidDate;
}
if (typeof options.isCustomDate === 'function') {
this.options.isCustomDate = options.isCustomDate;
}
if (typeof options.alwaysShowCalendars === 'boolean') {
this.options.alwaysShowCalendars = options.alwaysShowCalendars;
}
// update day names order to firstDay
if (this.options.locale.firstDay !== 0) {
let iterator = this.options.locale.firstDay;
while (iterator > 0) {
this.options.locale.daysOfWeek.push(this.options.locale.daysOfWeek.shift());
iterator--;
}
}
let start;
let end;
let range;
// if no start/end dates set, check if an input element contains initial values
if (typeof options.startDate === 'undefined' && typeof options.endDate === 'undefined') {
if (this.element.tagName === 'INPUT' && this.element.type === 'text') {
const val = this.element.value;
const split = val.split(this.options.locale.separator);
start = end = null;
if (split.length === 2) {
start = moment(split[0], this.options.locale.format);
end = moment(split[1], this.options.locale.format);
}
else if (this.options.singleDatePicker && val !== '') {
start = moment(val, this.options.locale.format);
end = moment(val, this.options.locale.format);
}
if (start !== null && end !== null) {
this.setStartDate(start);
this.setEndDate(end);
}
}
}
else {
this.setStartDate(options.startDate);
this.setEndDate(options.endDate);
}
if (typeof options.ranges === 'object') {
const rangesKeys = Object.keys(options.ranges);
for (const range of rangesKeys) {
start = moment(options.ranges[range][0]);
if (typeof options.ranges[range][1] === 'string') {
end = moment(options.ranges[range][1], this.options.locale.format);
}
else {
end = moment(options.ranges[range][1]);
}
// If the start or end date exceed those allowed by the minDate or maxSpan
// options, shorten the range to the allowable period.
if (this.options.minDate && start.isBefore(this.options.minDate)) {
start = this.options.minDate.clone();
}
let maxDate = this.options.maxDate;
if (this.options.maxSpan && maxDate && start.clone().add(this.options.maxSpan).isAfter(maxDate)) {
maxDate = start.clone().add(this.options.maxSpan);
}
if (maxDate && end.isAfter(maxDate)) {
end = maxDate.clone();
}
// If the end of the range is before the minimum or the start of the range is
// after the maximum, don't display this range option at all.
if ((this.options.minDate && end.isBefore(this.options.minDate, this.timepicker ? 'minute' : 'day'))
|| (maxDate && start.isAfter(maxDate, this.timepicker ? 'minute' : 'day'))) {
continue;
}
// Support Unicode chars in the range names.
elem = document.createElement('textarea');
elem.innerHTML = range;
rangeHtml = elem.value;
this.options.ranges[rangeHtml] = [start, end];
}
let list = '<ul>';
for (range in this.options.ranges) {
if (range) {
list += `<li data-range-key="${range}">${range}</li>`;
}
}
if (this.options.showCustomRangeLabel) {
list += `<li data-range-key="${this.options.locale.customRangeLabel}">${this.options.locale.customRangeLabel}</li>`;
}
list += '</ul>';
this.container.querySelector('.ranges').insertAdjacentHTML('afterbegin', list);
}
if (typeof cb === 'function') {
this.callback = cb;
}
if (!this.options.timePicker) {
this.options.startDate = this.options.startDate.startOf('day');
this.options.endDate = this.options.endDate.endOf('day');
this.container.style.display = 'none';
}
// can't be used together for now
if (this.options.timePicker && this.options.autoApply) {
this.options.autoApply = false;
}
if (this.options.autoApply) {
this.container.classList.add('auto-apply');
}
if (typeof options.ranges === 'object') {
this.container.classList.add('show-ranges');
}
if (typeof options.wrapperClasses === 'string') {
options.wrapperClasses.split(' ').forEach((className) => {
if (className.trim()) {
this.container.classList.add(className);
}
});
}
if (this.options.singleDatePicker) {
this.container.classList.add('single');
this.container.querySelector('.drp-calendar.left').classList.add('single');
this.container.querySelector('.drp-calendar.left').style.display = 'block';
this.container.querySelector('.drp-calendar.right').style.display = 'none';
if (!this.options.timePicker && this.options.autoApply) {
this.container.classList.add('auto-apply');
}
}
if ((typeof options.ranges === 'undefined' && !this.options.singleDatePicker) || this.options.alwaysShowCalendars) {
this.container.classList.add('show-calendar');
}
this.container.classList.add('opens' + this.options.opens);
// apply CSS classes and labels to buttons
const applyBtnEl = this.container.querySelector('.applyBtn');
const cancelBtnEl = this.container.querySelector('.cancelBtn');
this.jq.addClass(applyBtnEl, this.options.buttonClasses);
this.jq.addClass(cancelBtnEl, this.options.buttonClasses);
if (this.options.applyButtonClasses.length) {
this.jq.addClass(applyBtnEl, this.options.applyButtonClasses);
}
if (this.options.cancelButtonClasses.length) {
this.jq.addClass(cancelBtnEl, this.options.cancelButtonClasses);
}
this.jq.html(applyBtnEl, this.options.locale.applyLabel);
this.jq.html(cancelBtnEl, this.options.locale.cancelLabel);
//
// event listeners
//
/*
-- Note: jquery can set event listner before the target element has not been build. Vanilla-JS set event listner LATER.--
this.container.find('.drp-calendar')
.on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this))
.on('click.daterangepicker', '.next', $.proxy(this.clickNext, this))
.on('mousedown.daterangepicker', 'td.available', $.proxy(this.clickDate, this))
.on('mouseenter.daterangepicker', 'td.available', $.proxy(this.hoverDate, this))
.on('change.daterangepicker', 'select.yearselect', $.proxy(this.monthOrYearChanged, this))
.on('change.daterangepicker', 'select.monthselect', $.proxy(this.monthOrYearChanged, this))
.on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', $.proxy(this.timeChanged, this));
--------------------------------------------------------------------------------------
*/
this.jq.on(this.container.querySelector('.ranges'), 'click', 'li', this.clickRangeProxy);
const drpButtonsEl = this.container.querySelector('.drp-buttons');
this.jq.on(drpButtonsEl, 'click', 'button.applyBtn', this.clickApplyProxy);
this.jq.on(drpButtonsEl, 'click', 'button.cancelBtn', this.clickCancelProxy);
if (this.element.tagName === 'INPUT' || this.element.tagName === 'BUTTON') {
this.jq.on(this.element, 'click', this.showProxy);
this.jq.on(this.element, 'focus', this.showProxy);
this.jq.on(this.element, 'keyup', this.elementChangedProxy);
this.jq.on(this.element, 'keydown', this.keydownProxy);
}
else {
this.jq.on(this.element, 'click', this.toggleProxy);
this.jq.on(this.element, 'keydown', this.toggleProxy);
}
//
// if attached to a text input, set the initial value
//
this.updateElement();
}
setStartDate(startDate) {
this.startDate = moment(startDate);
if (!this.options.timePicker) {
this.startDate = this.startDate.startOf('day');
}
if (this.options.timePicker && this.options.timePickerIncrement) {
this.startDate.minute(Math.round(this.startDate.minute() / this.options.timePickerIncrement) * this.options.timePickerIncrement);
}
if (this.options.minDate && this.startDate.isBefore(this.options.minDate)) {
this.startDate = this.options.minDate.clone();
if (this.options.timePicker && this.options.timePickerIncrement) {
this.startDate.minute(Math.round(this.startDate.minute() / this.options.timePickerIncrement) * this.options.timePickerIncrement);
}
}
if (this.options.maxDate && this.startDate.isAfter(this.options.maxDate)) {
this.startDate = this.options.maxDate.clone();
if (this.options.timePicker && this.options.timePickerIncrement) {
this.startDate.minute(Math.floor(this.startDate.minute() / this.options.timePickerIncrement) * this.options.timePickerIncrement);
}
}
if (!this.isShowing) {
this.updateElement();
}
this.updateMonthsInView();
}
setEndDate(endDate) {
this.endDate = moment(endDate);
if (!this.options.timePicker) {
this.endDate = this.endDate.endOf('day');
}
if (this.options.timePicker && this.options.timePickerIncrement) {
this.endDate.minute(Math.round(this.endDate.minute() / this.options.timePickerIncrement) * this.options.timePickerIncrement);
}
if (this.endDate.isBefore(this.startDate)) {
this.endDate = this.startDate.clone();
}
if (this.options.maxDate && this.endDate.isAfter(this.options.maxDate)) {
this.endDate = this.options.maxDate.clone();
}
if (this.options.maxSpan && this.startDate.clone().add(this.options.maxSpan).isBefore(this.endDate)) {
this.endDate = this.startDate.clone().add(this.options.maxSpan);
}
if (!this.isShowing) {
this.updateElement();
}
this.updateMonthsInView();
}
isInvalidDate(_a) {
return false;
}
isCustomDate(_a) {
return false;
}
updateView() {
if (this.options.timePicker) {
this.renderTimePicker('left');
this.renderTimePicker('right');
const selectElList = this.container.querySelectorAll('.right .calendar-time select');
if (!this.endDate) {
for (const item of selectElList) {
item.disabled = true;
item.classList.add('disabled');
}
}
else {
for (const item of selectElList) {
item.disabled = false;
item.classList.remove('disabled');
}
}
}
this.updateMonthsInView();
this.updateCalendars();
this.updateFormInputs();
}
updateMonthsInView() {
if (this.endDate) {
// if both dates are visible already, do nothing
if (!this.options.singleDatePicker && this.leftCalendar.month && this.rightCalendar.month &&
(this.startDate.format('YYYY-MM') === this.leftCalendar.month.format('YYYY-MM') || this.startDate.format('YYYY-MM') === this.rightCalendar.month.format('YYYY-MM'))
&&
(this.endDate.format('YYYY-MM') === this.leftCalendar.month.format('YYYY-MM') || this.endDate.format('YYYY-MM') === this.rightCalendar.month.format('YYYY-MM'))) {
return;
}
this.leftCalendar.month = this.startDate.clone().date(2);
if (!this.options.linkedCalendars && (this.endDate.month() !== this.startDate.month() || this.endDate.year() !== this.startDate.year())) {
this.rightCalendar.month = this.endDate.clone().date(2);
}
else {
this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month');
}
}
else {
if (this.leftCalendar.month.format('YYYY-MM') !== this.startDate.format('YYYY-MM') && this.rightCalendar.month.format('YYYY-MM') !== this.startDate.format('YYYY-MM')) {
this.leftCalendar.month = this.startDate.clone().date(2);
this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month');
}
}
if (this.options.maxDate && this.options.linkedCalendars && !this.options.singleDatePicker && this.rightCalendar.month > this.options.maxDate) {
this.rightCalendar.month = this.options.maxDate.clone().date(2);
this.leftCalendar.month = this.options.maxDate.clone().date(2).subtract(1, 'month');
}
}
updateCalendars() {
let ampm;
/*
-- Note: by jquery, we can set event listener before the target element has not been build. but we must remove event listener HERE by Vanilla-JS. --
this.container.find('.drp-calendar')
.on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this))
.on('click.daterangepicker', '.next', $.proxy(this.clickNext, this))
.on('mousedown.daterangepicker', 'td.available', $.proxy(this.clickDate, this))
.on('mouseenter.daterangepicker', 'td.available', $.proxy(this.hoverDate, this))
.on('change.daterangepicker', 'select.yearselect', $.proxy(this.monthOrYearChanged, this))
.on('change.daterangepicker', 'select.monthselect', $.proxy(this.monthOrYearChanged, this))
.on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', $.proxy(this.timeChanged, this));
--------------------------------------------------------------------------------------
*/
const drpCalendarElList = this.container.querySelectorAll('.drp-calendar');
this.jq.off(drpCalendarElList, 'click', '.prev', this.clickPrevProxy);
this.jq.off(drpCalendarElList, 'click', '.next', this.clickNextProxy);
this.jq.off(drpCalendarElList, 'mousedown', 'td.available', this.clickDateProxy);
this.jq.off(drpCalendarElList, 'mouseenter', 'td.available', this.hoverDateProxy);
this.jq.off(drpCalendarElList, 'change', 'select.yearselect', this.monthOrYearChangedProxy);
this.jq.off(drpCalendarElList, 'change', 'select.monthselect', this.monthOrYearChangedProxy);
this.jq.off(drpCalendarElList, 'change', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', this.timeChangedProxy);
if (this.options.timePicker) {
let hour;
let minute;
let second;
if (this.endDate) {
hour = parseInt(this.container.querySelector('.left .hourselect').value, 10);
minute = parseInt(this.container.querySelector('.left .minuteselect').value, 10);
if (isNaN(minute)) {
minute = parseInt(this.jq.findLast(this.container.querySelector('.left .minuteselect')).value, 10);
}
second = this.options.timePickerSeconds ? parseInt(this.container.querySelector('.left .secondselect').value, 10) : 0;
if (!this.options.timePicker24Hour) {
ampm = this.container.querySelector('.left .ampmselect').value;
if (ampm === 'PM' && hour < 12)
hour += 12;
if (ampm === 'AM' && hour === 12)
hour = 0;
}
}
else {
hour = parseInt(this.container.querySelector('.right .hourselect').value, 10);
minute = parseInt(this.container.querySelector('.right .minuteselect').value, 10);
if (isNaN(minute)) {
minute = parseInt(this.jq.findLast(this.container.querySelector('.right .minuteselect')).value, 10);
}
second = this.options.timePickerSeconds ? parseInt(this.container.querySelector('.right .secondselect').value, 10) : 0;
if (!this.options.timePicker24Hour) {
ampm = this.container.querySelector('.right .ampmselect').value;
if (ampm === 'PM' && hour < 12)
hour += 12;
if (ampm === 'AM' && hour === 12)
hour = 0;
}
}
this.leftCalendar.month.hour(hour).minute(minute).second(second);
this.rightCalendar.month.hour(hour).minute(minute).second(second);
}
this.renderCalendar('left');
this.renderCalendar('right');
// highlight any predefined range matching the current start and end dates
this.rangesLiElList = this.container.querySelectorAll('.ranges li');
for (const item of this.rangesLiElList) {
item.classList.remove('active');
}
if (this.endDate !== null) {
this.calculateChosenLabel();
}
/*
-- Note: by jquery, we can set event listener before the target element has not been build. but we must set event listener HERE by Vanilla-JS. --
this.container.find('.drp-calendar')
.on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this))
.on('click.daterangepicker', '.next', $.proxy(this.clickNext, this))
.on('mousedown.daterangepicker', 'td.available', $.proxy(this.clickDate, this))
.on('mouseenter.daterangepicker', 'td.available', $.proxy(this.hoverDate, this))
.on('change.daterangepicker', 'select.yearselect', $.proxy(this.monthOrYearChanged, this))
.on('change.daterangepicker', 'select.monthselect', $.proxy(this.monthOrYearChanged, this))
.on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', $.proxy(this.timeChanged, this));
--------------------------------------------------------------------------------------
*/
this.jq.on(drpCalendarElList, 'click', '.prev', this.clickPrevProxy);
this.jq.on(drpCalendarElList, 'click', '.next', this.clickNextProxy);
this.jq.on(drpCalendarElList, 'mousedown', 'td.available', this.clickDateProxy);
this.jq.on(drpCalendarElList, 'mouseenter', 'td.available', this.hoverDateProxy);
this.jq.on(drpCalendarElList, 'change', 'select.yearselect', this.monthOrYearChangedProxy);
this.jq.on(drpCalendarElList, 'change', 'select.monthselect', this.monthOrYearChangedProxy);
this.jq.on(drpCalendarElList, 'change', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', this.timeChangedProxy);
}
renderCalendar(side) {
// Build the matrix of dates that will populate the calendar
let i;
let calendar = side === 'left' ? this.leftCalendar : this.rightCalendar;
const month = calendar.month.month();
const year = calendar.month.year();
const hour = calendar.month.hour();
const minute = calendar.month.minute();
const second = calendar.month.second();
const daysInMonth = moment([year, month]).daysInMonth();
const firstDay = moment([year, month, 1]);
const lastDay = moment([year, month, daysInMonth]);
const lastMonth = moment(firstDay).subtract(1, 'month').month();
const lastYear = moment(firstDay).subtract(1, 'month').year();
const daysInLastMonth = moment([lastYear, lastMonth]).daysInMonth();
const dayOfWeek = firstDay.day();
// initialize 6 rows x 7 columns array for the calendar
calendar = [];
calendar.firstDay = firstDay;
calendar.lastDay = lastDay;
for (i = 0; i < 6; i++) {
calendar[i] = [];
}
// populate the calendar with date objects
let startDay = daysInLastMonth - dayOfWeek + this.options.locale.firstDay + 1;
if (startDay > daysInLastMonth) {
startDay -= 7;
}
if (dayOfWeek === this.options.locale.firstDay) {
startDay = daysInLastMonth - 6;
}
let curDate = momentTimezone.exports.tz([lastYear, lastMonth, startDay, 12, minute, second], this.options.locale.timeZone);
i = 0;
let col = 0;
let row = 0;
for (; i < 42; i++, col++, curDate = curDate.add(24, 'hour')) {
if (i > 0 && col % 7 === 0) {
col = 0;
row++;
}
calendar[row][col] = curDate.clone().hour(hour).minute(minute).second(second);
curDate.hour(12);
if (this.options.minDate && calendar[row][col].format('YYYY-MM-DD') === this.options.minDate.format('YYYY-MM-DD') && calendar[row][col].isBefore(this.options.minDate) && side === 'left') {
calendar[row][col] = this.options.minDate.clone();
}
if (this.options.maxDate && calendar[row][col].format('YYYY-MM-DD') === this.options.maxDate.format('YYYY-MM-DD') && calendar[row][col].isAfter(this.options.maxDate) && side === 'right') {
calendar[row][col] = this.options.maxDate.clone();
}
}
// make the calendar object available to hoverDate/clickDate
if (side === 'left') {
this.leftCalendar.calendar = calendar;
}
else {
this.rightCalendar.calendar = calendar;
}
//
// Display the calendar
//
const minDate = side === 'left' ? this.options.minDate : this.startDate;
let maxDate = this.options.maxDate;
/* const selected = side === 'left' ? this.startDate : this.endDate;
const arrow = this.options.locale.direction === 'ltr' ? {
left: 'chevron-left',
right: 'chevron-right',
} : { left: 'chevron-right', right: 'chevron-left' };*/
let html = '<table class="table-condensed">';
html += '<thead>';
html += '<tr>';
// add empty cell for week number
if (this.options.showWeekNumbers || this.options.showISOWeekNumbers) {
html += '<th></th>';
}
if ((!minDate || minDate.isBefore(calendar.firstDay)) && (!this.options.linkedCalendars || side === 'left')) {
html += '<th class="prev available"><span></span></th>';
}
else {
html += '<th></th>';
}
let dateHtml = this.options.locale.monthNames[calendar[1][1].month()] + calendar[1][1].format(' YYYY');
if (this.options.showDropdowns) {
const currentMonth = calendar[1][1].month();
const currentYear = calendar[1][1].year();
const maxYear = (maxDate && maxDate.year()) || parseInt(this.options.maxYear, 10);
const minYear = (minDate && minDate.year()) || parseInt(this.options.minYear, 10);
const inMinYear = currentYear === minYear;
const inMaxYear = currentYear === maxYear;
let monthHtml = '<select class="monthselect">';
for (let m = 0; m < 12; m++) {
if ((!inMinYear || (minDate && m >= minDate.month())) && (!inMaxYear || (maxDate && m <= maxDate.month()))) {
monthHtml += `<option value='${m}'${m === currentMonth ? ' selected=\'selected\'' : ''}>${this.options.locale.monthNames[m]}</option>`;
}
else {
monthHtml += `<option value='${m}'${m === currentMonth ? ' selected=\'selected\'' : ''} disabled='disabled'>${this.options.locale.monthNames[m]}</option>`;
}
}
monthHtml += '</select>';
let yearHtml = '<select class="yearselect">';
for (let y = minYear; y <= maxYear; y++) {
yearHtml += `<option value="${y}"${y === currentYear ? ' selected="selected"' : ''}>${y}</option>`;
}
yearHtml += '</select>';
dateHtml = monthHtml + yearHtml;
}
html += '<th colspan="5" class="month">' + dateHtml + '</th>';
if ((!maxDate || maxDate.isAfter(calendar.lastDay)) && (!this.options.linkedCalendars || side === 'right' || this.options.singleDatePicker)) {
html += '<th class="next available"><span></span></th>';
}
else {
html += '<th></th>';
}
html += '</tr>';
html += '<tr>';
// add week number label
if (this.options.showWeekNumbers || this.options.showISOWeekNumbers) {
html += `<th class="week">${this.options.locale.weekLabel}</th>`;
}
for (const item of this.options.locale.daysOfWeek) {
html += `<th>${item}</th>`;
}
html += '</tr>';
html += '</thead>';
html += '<tbody>';
// adjust maxDate to reflect the maxSpan setting in order to
// grey out end dates beyond the maxSpan
if (this.endDate === null && this.options.maxSpan) {
const maxLimit = this.startDate.clone().add(this.options.maxSpan).endOf('day');
if (!maxDate || maxLimit.isBefore(maxDate)) {
maxDate = maxLimit;
}
}
for (row = 0; row < 6; row++) {
html += '<tr>';
// add week number
if (this.options.showWeekNumbers) {
html += `<td class="week">${calendar[row][0].week()}</td>`;
}
else if (this.options.showISOWeekNumbers) {
html += `<td class="week">${calendar[row][0].isoWeek()}</td>`;
}
for (col = 0; col < 7; col++) {
const classes = [];
// highlight today's date
if (calendar[row][col].isSame(new Date(), 'day')) {
classes.push('today');
}
// highlight weekends
if (calendar[row][col].isoWeekday() > 5) {
classes.push('weekend');
}
// grey out the dates in other months displayed at beginning and end of this calendar
if (calendar[row][col].month() !== calendar[1][1].month()) {
classes.push('off', 'ends');
}
// don't allow selection of dates before the minimum date
if (this.options.minDate && calendar[row][col].isBefore(this.options.minDate, 'day')) {
classes.push('off', 'disabled');
}
// don't allow selection of dates after the maximum date
if (maxDate && calendar[row][col].isAfter(maxDate, 'day')) {
classes.push('off', 'disabled');
}
// don't allow selection of date if a custom function decides it's invalid
if (this.isInvalidDate(calendar[row][col])) {
classes.push('off', 'disabled');
}
// highlight the currently selected start date
if (calendar[row][col].format('YYYY-MM-DD') === this.startDate.format('YYYY-MM-DD')) {
classes.push('active', 'start-date');
}
// highlight the currently selected end date
if (this.endDate !== null && calendar[row][col].format('YYYY-MM-DD') === this.endDate.format('YYYY-MM-DD')) {
classes.push('active', 'end-date');
}
// highlight dates in-between the selected dates
if (this.endDate !== null && calendar[row][col] > this.startDate && calendar[row][col] < this.endDate) {
classes.push('in-range');
}
// apply custom classes for this date
const isCustom = this.isCustomDate(calendar[row][col]);
if (isCustom !== false) {
if (typeof isCustom === 'string') {
classes.push(isCustom);
}
else {
Array.prototype.push.apply(classes, isCustom);
}
}
let cname = '';
let disabled = false;
for (i = 0; i < classes.length; i++) {
cname += classes[i] + ' ';
if (classes[i] === 'disabled') {
disabled = true;
}
}
if (!disabled) {
cname += 'available';
}
html += `<td class="${cname.replace(/^\s+|\s+$/g, '')}" data-title="r${row}c${col}">${calendar[row][col].date()}</td>`;
}
html += '</tr>';
}
html += '</tbody>';
html += '</table>';
this.jq.html(this.container.querySelector(`.drp-calendar.${side} .calendar-table`), html);
}
renderTimePicker(side) {
let padded;
let disabled;
let time;
// Don't bother updating the time picker if it's currently disabled
let i;
// because an end date hasn't been clicked yet
if (side === 'right' && !this.endDate)
return;
let html;
let selected;
let minDate;
let maxDate = this.options.maxDate;
if (this.options.maxSpan && (!this.options.maxDate || this.startDate.clone().add(this.options.maxSpan).isBefore(this.options.maxDate))) {
maxDate = this.startDate.clone().add(this.options.maxSpan);
}
if (side === 'left') {
selected = this.startDate.clone();
minDate = this.options.minDate;
}
else if (side === 'right') {
selected = this.endDate.clone();
minDate = this.startDate;
// Preserve the time already selected
const timeSelector = this.container.querySelector('.drp-calendar.right .calendar-time');
if (timeSelector.innerHTML !== '') {
selected.hour(!isNaN(selected.hour()) ? selected.hour() : this.jq.findSelectedOption(timeSelector.querySelector('.hourselect')).value);
selected.minute(!isNaN(selected.minute()) ? selected.minute() : this.jq.findSelectedOption(timeSelector.querySelector('.minuteselect')).value);
selected.second(!isNaN(selected.second()) ? selected.second() : this.jq.findSelectedOption(timeSelector.querySelector('.secondselect')).value);
if (!this.options.timePicker24Hour) {
const ampm = this.jq.findSelectedOption(timeSelector.querySelector('.ampmselect')).value;
if (ampm === 'PM' && selected.hour() < 12)
selected.hour(selected.hour() + 12);
if (ampm === 'AM' && selected.hour() === 12)
selected.hour(0);
}
}
if (selected.isBefore(this.startDate)) {
selected = this.startDate.clone();
}
if (maxDate && selected.isAfter(maxDate)) {
selected = maxDate.clone();
}
}
//
// hours
//
html = '<select class="hourselect">';
const start = this.options.timePicker24Hour ? 0 : 1;
const end = this.options.timePicker24Hour ? 23 : 12;
for (i = start; i <= end; i++) {
let i_in_24 = i;
if (!this.options.timePicker24Hour) {
i_in_24 = selected.hour() >= 12 ? (i === 12 ? 12 : i + 12) : (i === 12 ? 0 : i);
}
time = selected.clone().hour(i_in_24);
disabled = !!(minDate && time.minute(59).isBefore(minDate));
if (maxDate && time.minute(0).isAfter(maxDate)) {
disabled = true;
}
padded = i < 10 ? `0${i}` : `${i}`;
if (i_in_24 === selected.hour() && !disabled) {
html += `<option value="${i}" selected="selected">${padded}</option>`;
}
else if (disabled) {
html += `<option value="${i}" disabled="disabled" class="disabled">${padded}</option>`;
}
else {
html += `<option value="${i}">${padded}</option>`;
}
}
html += '</select> ';
//
// minutes
//
html += ': <select class="minuteselect">';
for (i = 0; i < 60; i += this.options.timePickerIncrement) {
padded = i < 10 ? `0${i}` : `${i}`;
time = selected.clone().minute(i);
disabled = !!(minDate && time.second(59).isBefore(minDate));