/**
* @param {HTMLElement} element DOM element for component instantiation and scope
* @param {Object} options
* @param {String} options.format dateAdapter object with functions
*/
export class Datepicker {
/**
* @static
* Shorthand for instance creation and initialisation.
*
* @param {HTMLElement} root DOM element for component instantiation and scope
*
* @return {Datepicker} An instance of Datepicker.
*/
static autoInit(root, { DATEPICKER: defaultOptions = {} } = {}) {
const datepicker = new Datepicker(root, defaultOptions);
datepicker.init();
root.ECLDatepicker = datepicker;
return datepicker;
}
constructor(element, { format = '', localization = {} } = {}) {
// Check element
if (!element || element.nodeType !== Node.ELEMENT_NODE) {
throw new TypeError(
'DOM element should be given to initialize this widget.',
);
}
this.element = element;
// Options
this.picker = null;
this.format = format;
this.localization = {
...Datepicker.defaults.localization,
...localization,
};
// Bind `this` for use in callbacks
this.normalizeDate = this.normalizeDate.bind(this);
this.handleOpen = this.handleOpen.bind(this);
}
/**
* Initialise component.
*/
init() {
if (!customElements.get('duet-date-picker')) {
throw new TypeError(
'Duet datepicker is not available. Make sure to include the duet datepicker js in your project if you want to use the ECL datepicker',
);
}
if (!ECL) {
throw new TypeError('Called init but ECL is not present');
}
ECL.components = ECL.components || new Map();
Datepicker.applyCustomizations = () => {
this.picker = this.element.querySelector('duet-date-picker');
// Convert ISO 8601 format YYYY-MM-DD into EU format DD-MM-YYYY
const DEFAULT_DATE_ADAPTER = {
parse(value = '', createDate) {
const DATE_FORMAT_EU = /^(\d{2})-(\d{2})-(\d{4})$/;
const matches = value.match(DATE_FORMAT_EU);
if (matches) {
return createDate(matches[3], matches[2], matches[1]);
}
},
format(date) {
const pad = (n) => String(n).padStart(2, '0');
return `${pad(date.getDate())}-${pad(date.getMonth() + 1)}-${date.getFullYear()}`;
},
};
if (!this.picker) return;
if (!this.picker.identifier) {
this.picker.identifier = `ecl-datepicker-${Math.random().toString(36).substr(2, length)}`;
}
if (this.element.dataset.value) {
this.picker.value = this.normalizeDate(this.element.dataset.value);
}
this.updateConfiguration();
this.picker.addEventListener('duetOpen', this.handleOpen);
this.picker.localization = this.localization;
if (this.element.dataset.placeholder) {
this.picker.localization.placeholder = this.element.dataset.placeholder;
}
// Prevent errors if a simple string is used in this option
this.picker.dateAdapter =
this.format && typeof this.format === 'object'
? this.format
: DEFAULT_DATE_ADAPTER;
};
setTimeout(Datepicker.applyCustomizations, 50);
// Set ecl initialized attribute
this.element.setAttribute('data-ecl-auto-initialized', 'true');
ECL.components.set(this.element, this);
return this.picker;
}
/**
* Normalize the default value when it contains extra info.
*/
normalizeDate(value) {
if (typeof value !== 'string') return value;
const match = value.match(/(\d{4})-(\d{2})-(\d{2})/);
if (!match) return '';
// return YYYY-MM-DD
return `${match[1]}-${match[2]}-${match[3]}`;
}
/**
* Update picker configuration based on current state.
*/
updateConfiguration() {
if (!this.picker) return;
this.direction = getComputedStyle(this.element).direction;
this.picker.direction = this.direction === 'ltr' ? 'right' : 'left';
}
/**
* Handle datepicker open event.
*/
handleOpen() {
this.updateConfiguration();
}
/**
* Destroy component.
*/
destroy() {
if (this.picker) {
this.picker.removeEventListener('duetOpen', this.handleOpen);
}
if (this.element) {
this.element.removeAttribute('data-ecl-auto-initialized');
ECL.components.delete(this.element);
}
}
}
Datepicker.defaults = {
localization: {
previousMonth: 'Previous Month',
nextMonth: 'Next Month',
dayNames: [
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
],
months: [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
],
weekdays: [
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
],
weekdaysShort: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
monthNames: [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
],
monthNamesShort: [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
],
placeholder: 'DD-MM-YYYY',
prevMonthLabel: 'Previous month',
nextMonthLabel: 'Next month',
monthSelectLabel: 'Month',
yearSelectLabel: 'Year',
closeLabel: 'Close window',
calendarHeading: 'Choose a date',
selectedDateMessage: 'Selected date is',
buttonLabel: 'Choose date',
},
};
export default Datepicker;