import datetime from 'tail.datetime'; import dateFormat from 'dateformat'; import { Utility } from '../../core/utility'; const FORM_DATE_FORMAT = 'yyyy-mm-dd"T"HH:MM:ss'; /* TODO: - DONE define a map of form id to instance lists - DONE define a function that formats all dates of a form with a specified id - WIP call this function where formdata appears in mass-input.js, async-form.js and async-table.js */ const DATEPICKER_UTIL_SELECTOR = 'input[type="date"], input[type="time"], input[type="datetime-local"]'; const DATEPICKER_INITIALIZED_CLASS = 'datepicker--initialized'; const DATEPICKER_CONFIG = { 'global': { locale: 'de', // TODO: hardcoded weekStart: 1, // TODO: hardcoded stayOpen: true, // to prevent the instance from closing when selecting a date before selecting a time closeButton: false, dateFormat: 'dd.mm.YYYY', // TODO: hardcoded, get from setting }, 'datetime-local': {}, 'date': { timeFormat: false, }, 'time': { dateFormat: false, }, }; @Utility({ selector: DATEPICKER_UTIL_SELECTOR, }) export class Datepicker { // singleton Map that maps a formID to a Map of Datepicker objects static datepickerCollections; datepickerInstance; _element; constructor(element) { if (!element) { throw new Error('Datepicker utility needs to be passed an element!'); } if (element.classList.contains(DATEPICKER_INITIALIZED_CLASS)) { return false; } // initialize datepickerCollections singleton if not already done if (!Datepicker.datepickerCollections) { Datepicker.datepickerCollections = new Map(); } this._element = element; // get all relevant config options for this datepicker type const datepickerGlobalConfig = DATEPICKER_CONFIG['global']; const datepickerConfig = DATEPICKER_CONFIG[this._element.getAttribute('type')]; if (!datepickerConfig) { throw new Error('Datepicker utility called on unsupported element!'); } // initialize tail.datetime (datepicker) instance this.datepickerInstance = datetime(this._element, { ...datepickerGlobalConfig, ...datepickerConfig }); // register this datepicker instance with the formID of the given element in the datepicker collection const formID = this._element.form.id; const elemID = this._element.id; if (!Datepicker.datepickerCollections.has(formID)) { // insert a new key value pair if the formID key is not there already Datepicker.datepickerCollections.set(formID, new Map([[elemID, this]])); } else { // otherwise, insert this instance into the Map Datepicker.datepickerCollections.get(formID).set(elemID, this); } // mark the form input element as initialized this._element.classList.add(DATEPICKER_INITIALIZED_CLASS); // close the instance if something other than the instance was clicked (i.e. if the target is not within the datepicker instance and if any previously clicked calendar view was replaced (is not in the window anymore) because it was clicked). YES, I KNOW window.addEventListener('click', event => { if (!this.datepickerInstance.dt.contains(event.target) && window.document.contains(event.target)) { this.datepickerInstance.close(); } }); // close the datepicker on escape keydown events this._element.addEventListener('keydown', event => { if (event.keyCode === 27) { this.datepickerInstance.close(); } }); // format the date value of the form input element of this datepicker before form submission this._element.form.addEventListener('submit', () => this.formatElementValue()); } destroy() { this.datepickerInstance.destroy(); } /** * Formats the value of this input element from datepicker format (i.e. DATEPICKER_CONFIG.dateFormat + " " + datetime.defaults.timeFormat) to Uni2work internal date format (i.e. FORM_DATE_FORMAT) required for form submission */ formatElementValue() { if (!this.datepickerInstance.select || !this._element.value) return; this._element.value = dateFormat(this.datepickerInstance.select, FORM_DATE_FORMAT); } }