1import {Controller} from "@hotwired/stimulus"; 2import moment from 'moment'; 3import AirDatepicker from "air-datepicker"; 4import "air-datepicker/air-datepicker.css"; 5import localeFr from "air-datepicker/locale/fr"; 6import localeEs from "air-datepicker/locale/es"; 7import localeEn from "air-datepicker/locale/en"; 8 9const locales = { 10 fr: localeFr.default, 11 es: localeEs.default, 12 en: localeEn.default 13}; 14 15const possibleView = ['days', 'month', 'year']; 16export default class extends Controller { 17 static targets = ["datepicker"]; 18 datepickers = []; 19 20 connect() { 21 this.isEdit = !!this.element.dataset.evenementId; 22 23 // Initialisation de tous les pickers marqués en target 24 this.datepickerTargets.forEach(datePicker => { 25 const config = this.getConfig(datePicker); 26 27 // Création et Stockage de l'instance dans l'élément input et dans le controller, pour la récupérer dans d'autres contrôleurs/fonctions 28 const pickerInstance = new AirDatepicker(datePicker, config); 29 this.datepickers.push(pickerInstance); 30 datePicker.datepickerInstance = pickerInstance; 31 32 // Vérification initiale de la valeur du champ input 33 this.verifyInput(datePicker, true); 34 }); 35 } 36 37 verifyInput(datePicker, firstInit = false) { 38 const datepickerInstance = datePicker.datepickerInstance; 39 const config = datepickerInstance.opts; 40 const inputValue = datePicker.value; 41 42 const parsedDate = moment(inputValue, `${config.dateFormat.toUpperCase()}${config.dateTimeSeparator}${config.timeFormat}`); 43 44 if (parsedDate.isValid()) { 45 const date = parsedDate.toDate(); 46 const minDate = config.minDate; 47 const maxDate = config.maxDate; 48 49 // En édition, lors de l'initialisation, on accepte toujours la valeur existante 50 // même si elle est en dehors de la plage min/max. 51 if (firstInit && this.isEdit) { 52 datepickerInstance.selectDate(date, {silent: true, updateTime: true}); 53 return; 54 } 55 56 let isInRange = true; 57 if (minDate && date < minDate) { 58 isInRange = false; 59 } 60 if (maxDate && date > maxDate) { 61 isInRange = false; 62 } 63 64 if (isInRange) { 65 datepickerInstance.selectDate(date, {silent: true, updateTime: true}); 66 if (!firstInit) { 67 this.dispatchSelectEvent(datePicker, date); 68 } 69 return; 70 } 71 } 72 73 if (datepickerInstance.selectedDates.length > 0) { 74 datepickerInstance.selectDate(datepickerInstance.selectedDates[0], {silent: true, updateTime: true}); 75 } else { 76 datepickerInstance.clear({silent: true}); 77 } 78 } 79 80 getConfig(datePicker) { 81 const localeKey = datePicker.getAttribute('data-datepicker-locale') || 'fr'; 82 const locale = locales[localeKey] ?? localeFr.default; 83 84 const options = { 85 locale: locale, 86 timepicker: true, 87 autoClose: false, 88 position: 'bottom left', 89 container: datePicker.closest('.modal-body') || 'body', 90 }; 91 92 const dateFormat = datePicker.getAttribute('data-datepicker-dateFormat') || 'YYYY-MM-DD'; 93 const timeFormat = datePicker.getAttribute('data-datepicker-timeFormat') || 'HH:mm'; 94 const dateTimeSeparator = datePicker.getAttribute('data-datepicker-dateTimeSeparator') || " "; 95 96 const minView = datePicker.getAttribute('data-datepicker-minView') 97 if(minView && possibleView.includes(minView)) { 98 option.minVew = minView; 99 } 100 101 const startDate = datePicker.getAttribute('data-datepicker-startDate'); 102 if (startDate) { 103 options.startDate = moment(startDate, `${dateFormat.toUpperCase()}${dateTimeSeparator}${timeFormat}`).toDate(); 104 } 105 106 const minDate = datePicker.getAttribute('data-datepicker-minDate'); 107 if (minDate) { 108 options.minDate = moment(minDate, `${dateFormat.toUpperCase()}${dateTimeSeparator}${timeFormat}`).toDate(); 109 } 110 111 const maxDate = datePicker.getAttribute('data-datepicker-max
111Date'); 112 if (maxDate) { 113 options.maxDate = moment(maxDate, `${dateFormat.toUpperCase()}${dateTimeSeparator}${timeFormat}`).toDate(); 114 } 115 116 const minuteStep = datePicker.getAttribute('data-datepicker-minutesStep'); 117 if (minuteStep) { 118 options.minutesStep = parseInt(minuteStep, 10); 119 } 120 121 const userTimezone = datePicker.getAttribute('data-datepicker-userTimezone') || 'Europe/Paris'; 122 123 if (dateFormat && timeFormat) { 124 options.dateFormat = dateFormat; 125 options.timeFormat = timeFormat; 126 options.dateTimeSeparator = dateTimeSeparator; 127 } 128 129 options.onSelect = ({date, formattedDate, datepicker}) => { 130 this.dispatchSelectEvent(datePicker, date); 131 }; 132 133 options.onHide = (isfinished) => { 134 if (!isfinished) { 135 this.verifyInput(datePicker); 136 } 137 }; 138 139 options.timepicker = datePicker.getAttribute('data-datepicker-timepicker') !== "0"; 140 141 return options; 142 } 143 144 dispatchSelectEvent(datePicker, date) { 145 const event = new CustomEvent('datepicker:select', { 146 detail: {date: date, datepicker: datePicker}, 147 bubbles: true 148 }); 149 datePicker.dispatchEvent(event); 150 } 151 152 disconnect() { 153 this.datepickers.forEach(picker => picker.destroy()); 154 } 155}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.