import {module} from '../module'; import Component from '../lib/component'; import Flatpickr from 'vendor/src/flatpickr'; import './style.scss'; // equivalences to format date between flatpicker and angularjs export const formatEquivalence = { d: 'dd', // Day of the month, 2 digits with leading zeros (01 to 31) j: 'd', // Day of the month without leading zeros (1 to 31) m: 'MM', // Month in year, padded (01-12) n: 'M', // Month in year (1-12) y: 'yy', // A two digit representation of a year (00-99) Y: 'yyyy', // A full numeric representation of a year, 4 digits (1999 or 2003) H: 'HH', // Hour in AM/PM, padded (01-12) h: 'H', // Hour in AM/PM, (1-12) i: 'mm', // Minutes (00 to 59) s: 'ss' // Seconds (00 to 59) }; class DatePicker extends Component { constructor($element, $translate, $filter, $timeout, $attrs) { super($element); this.input = $element[0].querySelector('input'); this.$translate = $translate; this.$filter = $filter; this.$timeout = $timeout; this.$attrs = $attrs; this.enabled = true; this._modelView = null; this._model = undefined; this._optionsChecked = false; this._waitingInit = 0; this.hasFocus = false; this.hasMouseIn = false; componentHandler.upgradeElement($element[0].firstChild); } get model() { return this._model; } set model(value) { if (this._optionsChecked) { this._waitingInit = 0; this._model = value; if (value && !this.modelView) { let initialDateFormat = this.$translate.use() === 'es' ? 'd-m-Y' : 'Y-m-d'; if (this.iniOptions.enableTime) { initialDateFormat += ' H:i:s'; } let format = this._formatFlat2Angular(initialDateFormat); this._modelView = this.$filter('date')(new Date(value), format); this.mdlUpdate(); } } else if (this._waitingInit < 4) { this._waitingInit++; this.$timeout(() => { this.model = value; }, 250); } else { this.model = null; this.modelView = ''; this._waitingInit = 0; } } get modelView() { return this._modelView; } set modelView(value) { this._modelView = value; this.input.value = value; this._setModel(value); this.mdlUpdate(); } onClear() { this.modelView = null; } onClick() { if (this.vp) { this.vp.open(); } } mdlUpdate() { this.$timeout(() => { let mdlField = this.element.firstChild.MaterialTextfield; if (mdlField) mdlField.updateClasses_(); }, 500); } _formatFlat2Angular(string) { // change string Flatpickr format to angular format (d-m-Y -> dd-MM-yyyy) let aux = string.split(/[ZT.,/ :-]/); let parts = []; aux.forEach( val => { parts.push(formatEquivalence[val]); } ); if (string.indexOf(' ') !== -1 || string.indexOf('T') !== -1) { // datetime format let dates = parts.slice(0, 3).join('-'); let hours = parts.slice(3, parts.length).join(':'); return `${dates} ${hours}`.trim(); } else if (string.indexOf(':') !== -1) { // only time format return parts.join(':'); } // only date format return parts.join('-'); } _setModel(value) { let model; if (!value) { model = undefined; } else if (!this.iniOptions || (this.iniOptions.dateFormat && this.iniOptions.dateFormat.startsWith('Y-m-d'))) { model = value; } else { let formats = this.iniOptions.dateFormat.split(/[ZT.,/ :-]/); let aux = value.split(/[ZT.,/ :-]/); let date = {}; formats.forEach( (k, i) => { if (k.toLowerCase() === 'y') { date.year = aux[i]; } else if (k === 'm' || k === 'n') { date.month = aux[i]; } else if (k === 'd' || k === 'j') { date.day = aux[i]; } else if (k.toLowerCase() === 'h') { date.hour = aux[i]; } else if (k === 'i') { date.minutes = aux[i]; } else if (k === 's') { date.seccons = aux[i]; } } ); let dateStr = ''; let hourStr = ''; if (date.year && date.month && date.day) { dateStr = `${date.year}-${date.month}-${date.day}`; } if (date.hour) { hourStr = date.hour; if (date.minutes) { hourStr += ':' + date.minutes; } else { hourStr += ':00'; } if (date.seccons) { hourStr += ':' + date.seccons; } else { hourStr += ':00'; } } model = `${dateStr} ${hourStr}`.trim(); } if (this.model !== model) { this.model = model; } } _getOptions() { if (this.iniOptions && this._optionsChecked) { return this.iniOptions; } else if (!this.iniOptions) { this.iniOptions = {}; } if (!this.iniOptions.locale) this.iniOptions.locale = this.$translate.use(); if (!this.iniOptions.dateFormat) this.iniOptions.dateFormat = this.iniOptions.locale === 'es' ? 'd-m-Y' : 'm-d-Y'; else if (this.iniOptions.dateFormat) { let format = this.iniOptions.dateFormat.split(/[ZT.,/ :-]/); if (format.length <= 1) { throw new Error(`Error: Invalid string format ${format}`); } format.forEach( val => { if (!formatEquivalence[val]) { throw new Error(`Error in dateFormat ${this.iniOptions.dateFormat}: is not like Flatpickr Formatting Token https://chmln.github.io/flatpickr/formatting/`); } } ); } if (this.$attrs.hasOwnProperty('today')) { this.iniOptions.defaultDate = new Date(); } this._optionsChecked = true; return this.iniOptions; } initPicker() { this.iniOptions = this._getOptions(); this.isTimePicker = (this.iniOptions && this.iniOptions.enableTime && this.iniOptions.noCalendar); this.vp = new Flatpickr(this.input, this.iniOptions); if (this.iniOptions.defaultDate) { this.modelView = this.vp.formatDate(this.iniOptions.defaultDate, this.iniOptions.dateFormat); } } destroyPicker() { if (this.vp) this.vp.destroy(); this.vp = undefined; } $onChanges(objChange) { if (objChange.iniOptions && objChange.iniOptions.currentValue) { this.iniOptions = Object.assign(this.iniOptions, objChange.iniOptions.currentValue); } } $onInit() { this.initPicker(); } $onDestroy() { this.destroyPicker(); } } DatePicker.$inject = ['$element', '$translate', '$filter', '$timeout', '$attrs']; module.component('vnDatePicker', { template: require('./datePicker.html'), bindings: { model: '=', label: '@?', name: '@?', enabled: '