diff options
| author | polo <ordipolo@gmx.fr> | 2026-01-29 22:51:19 +0100 |
|---|---|---|
| committer | polo <ordipolo@gmx.fr> | 2026-01-29 22:51:19 +0100 |
| commit | e3a42c8342bba0db15e2ca9a78911121e5d539da (patch) | |
| tree | df2b669452ba82774d741a4b9e48948b8dc45a0a /public/js/calendar_admin.js | |
| parent | f007bac3b9172711dc0fcca1306270ab99dbd8a4 (diff) | |
| download | fullcalendar-e3a42c8342bba0db15e2ca9a78911121e5d539da.tar.gz fullcalendar-e3a42c8342bba0db15e2ca9a78911121e5d539da.tar.bz2 fullcalendar-e3a42c8342bba0db15e2ca9a78911121e5d539da.zip | |
Diffstat (limited to 'public/js/calendar_admin.js')
| -rw-r--r-- | public/js/calendar_admin.js | 410 |
1 files changed, 176 insertions, 234 deletions
diff --git a/public/js/calendar_admin.js b/public/js/calendar_admin.js index a99b069..df8e19d 100644 --- a/public/js/calendar_admin.js +++ b/public/js/calendar_admin.js | |||
| @@ -1,220 +1,164 @@ | |||
| 1 | // js/calendar_admin.js | 1 | // js/calendar_admin.js |
| 2 | 2 | ||
| 3 | document.addEventListener('DOMContentLoaded', function(){ | 3 | document.addEventListener('DOMContentLoaded', function () { |
| 4 | const calendarEl = document.getElementById('calendar'); | 4 | const calendarEl = getElementOrThrow('calendar'); |
| 5 | const modal = getElementOrThrow('event_modal'); | ||
| 5 | let selected_start_string = null; | 6 | let selected_start_string = null; |
| 6 | let event_selected = false; // pour event.remove() | 7 | let event_selected = false; // pour event.remove() |
| 7 | 8 | const calendar = new FullCalendar.Calendar(calendarEl, { | |
| 8 | const calendar = new FullCalendar.Calendar(calendarEl,{ | ||
| 9 | editable: true, | 9 | editable: true, |
| 10 | locale: 'fr', | 10 | locale: 'fr', |
| 11 | //timeZone: 'local', // à modifier pour être à l'heure d'un autre pays | 11 | //timeZone: 'local', // à modifier pour être à l'heure d'un autre pays |
| 12 | initialView: 'dayGridMonth', | 12 | initialView: 'dayGridMonth', |
| 13 | headerToolbar:{ | 13 | headerToolbar: { |
| 14 | left: 'prev,next today', | 14 | left: 'prev,next today', |
| 15 | center: 'title', | 15 | center: 'title', |
| 16 | right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek' | 16 | //right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek' |
| 17 | //right: 'dayGridMonth,timeGridWeek' | 17 | right: 'dayGridMonth,timeGridWeek,listWeek' |
| 18 | }, | 18 | }, |
| 19 | slotMinWidth: 70, | 19 | slotMinWidth: 70, |
| 20 | defaultAllDay: false, | 20 | defaultAllDay: false, |
| 21 | |||
| 22 | // numéros de semaine | 21 | // numéros de semaine |
| 23 | //weekNumbers: true, | 22 | //weekNumbers: true, |
| 24 | //weekText: 's', | 23 | //weekText: 's', |
| 25 | |||
| 26 | // vue mois | 24 | // vue mois |
| 27 | contentHeight: 600, // après initialisation: calendar.setOption('contentHeight', 650); | 25 | contentHeight: 600, // après initialisation: calendar.setOption('contentHeight', 650); |
| 28 | //aspectRatio: 1.5, // après initialisation: calendar.setOption('aspectRatio', 1.8); | 26 | //aspectRatio: 1.5, // après initialisation: calendar.setOption('aspectRatio', 1.8); |
| 29 | // pour recalculer la taille au redimensionnement du parent, exécuter: calendar.updateSize() | 27 | // pour recalculer la taille au redimensionnement du parent, exécuter: calendar.updateSize() |
| 30 | stickyHeaderDates: true, // garder les en-tête de colonnes lors du scroll | 28 | stickyHeaderDates: true, // garder les en-tête de colonnes lors du scroll |
| 31 | fixedWeekCount: false, // avec false, affiche 4, 5 ou 6 semaines selon le mois | 29 | fixedWeekCount: false, // avec false, affiche 4, 5 ou 6 semaines selon le mois |
| 32 | selectable: true, // sélection de jours multiples | 30 | selectable: true, // sélection de jours en cliquant dessus |
| 31 | longPressDelay: 300, // 1000ms par défaut | ||
| 33 | navLinks: true, // numéros de jour et de semaines clicables | 32 | navLinks: true, // numéros de jour et de semaines clicables |
| 34 | |||
| 35 | // vue semaine | 33 | // vue semaine |
| 36 | slotEventOverlap: true, // superposition (limitée) de deux évènements simultanés | 34 | slotEventOverlap: true, // superposition (limitée) de deux évènements simultanés |
| 37 | allDayContent: 'Journée', // texte dans la case "toute la journée" | 35 | allDayContent: 'Journée', // texte dans la case "toute la journée" |
| 38 | nowIndicator: true, // barre rouge pour maintenant | 36 | nowIndicator: true, // barre rouge pour maintenant |
| 39 | |||
| 40 | // params en plus: https://fullcalendar.io/docs/events-json-feed | 37 | // params en plus: https://fullcalendar.io/docs/events-json-feed |
| 41 | events: 'index.php?action=get_events', // fichier PHP qui retourne les événements | 38 | events: 'index.php?action=get_events', // fichier PHP qui retourne les événements |
| 42 | 39 | select: function (info) { | |
| 43 | select: function(info){ | ||
| 44 | selected_start_string = info.startStr; // variable "globale" | 40 | selected_start_string = info.startStr; // variable "globale" |
| 45 | event_selected = false; | 41 | event_selected = false; |
| 46 | const aside = document.querySelector('aside'); | 42 | let all_day = false; |
| 47 | let checked = ''; | 43 | let input_type = 'datetime-local'; // input datetime-local = date + heure |
| 48 | let input = 'datetime-local'; | 44 | const start = new Date(info.startStr); |
| 49 | |||
| 50 | // on veut des chaines de la forme 2025-05-20T07:05 | ||
| 51 | // il faut retirer les secondes et le fuseau horaire du format ISO, c'est chiant | ||
| 52 | // on enverra par contre une chaine ISO au serveur pour avoir un enregistrement correct | ||
| 53 | |||
| 54 | let start_value; | ||
| 55 | let end_value; | ||
| 56 | const end = new Date(info.endStr); | 45 | const end = new Date(info.endStr); |
| 57 | 46 | if (calendar.view.type == 'dayGridMonth') { | |
| 58 | if(calendar.view.type == 'dayGridMonth'){ | ||
| 59 | start_value = info.startStr + 'T10:00'; | ||
| 60 | end.setDate(end.getDate() - 1); // jour de fin modifié pour ne pas faire bizarre pour l'utilisateur | 47 | end.setDate(end.getDate() - 1); // jour de fin modifié pour ne pas faire bizarre pour l'utilisateur |
| 61 | end.setHours(11); | 48 | end.setHours(start.getTime() === end.getTime() ? 11 : 10); |
| 62 | end_value = end.toISOString().split('T')[0] + 'T11:00'; | 49 | start.setHours(10); |
| 63 | } | 50 | } |
| 64 | else if(calendar.view.type == 'timeGridWeek' || calendar.view.type == 'timeGridDay'){ | 51 | else if (calendar.view.type == 'timeGridWeek' && info.startStr.split("T").length === 1) { // clic sur la ligne "Journée" => évènement allDay |
| 65 | const start_array = info.startStr.split("T"); | 52 | all_day = true; |
| 66 | const end_array = info.endStr.split("T"); | 53 | input_type = 'date'; |
| 67 | |||
| 68 | // clic sur la ligne "Journée", = 'dayGridMonth' | ||
| 69 | if(start_array.length == 1){ | ||
| 70 | checked = 'checked'; | ||
| 71 | input = 'date'; | ||
| 72 | start_value = info.startStr; | ||
| 73 | end.setDate(end.getDate() - 1); | ||
| 74 | end_value = end.toISOString().split('T')[0]; | ||
| 75 | } | ||
| 76 | else if(start_array.length == 2){ | ||
| 77 | start_value = start_array[0] + "T" + start_array[1].substr(0,5); // format 2025-06-12T10:00 | ||
| 78 | end_value = end_array[0] + "T" + end_array[1].substr(0,5); | ||
| 79 | } | ||
| 80 | } | 54 | } |
| 81 | 55 | //else if(calendar.view.type == 'timeGridDay'){} | |
| 82 | const aside_content = `<div class="form_event"> | 56 | const modal_view = new CalendarModalView({ |
| 83 | <div class="event_title_box"> | 57 | mode: 'new', |
| 84 | <h2>Nouvel évènement</h2> | 58 | all_day: all_day, |
| 85 | </div> | 59 | input_type: input_type, |
| 86 | <div class=""> | 60 | start: start, |
| 87 | <label for="event_title">Nom</label> | 61 | end: end |
| 88 | <input type="text" id="event_title"> | 62 | }); |
| 89 | </div> | 63 | modal.innerHTML = modal_view.getView(); |
| 90 | <div class=""> | ||
| 91 | <label for="event_description">Description</label> | ||
| 92 | <textarea id="event_description" cols="27"></textarea> | ||
| 93 | </div> | ||
| 94 | <div class=""> | ||
| 95 | <input type="checkbox" id="event_all_day" class="event_all_day" ` + checked + `> | ||
| 96 | <label for="event_all_day">Journée entière</label> | ||
| 97 | </div> | ||
| 98 | <div class=""> | ||
| 99 | <label for="event_start">Début</label> | ||
| 100 | <input type="` + input + `" id="event_start" value="` + start_value + `"> | ||
| 101 | </div> | ||
| 102 | <div class=""> | ||
| 103 | <label for="event_end">Fin</label> | ||
| 104 | <input type="` + input + `" id="event_end" value="` + end_value + `"> | ||
| 105 | </div> | ||
| 106 | <div class=""> | ||
| 107 | <label for="event_color">Couleur</label> | ||
| 108 | <input type="color" id="event_color" value="#3788D8"> | ||
| 109 | </div> | ||
| 110 | <button class="submit_new_event">Enregistrer</button> | ||
| 111 | <button class="event_close_button">Annuler</button> | ||
| 112 | </div>`; | ||
| 113 | aside.innerHTML = aside_content; | ||
| 114 | calendar.updateSize(); | 64 | calendar.updateSize(); |
| 115 | }, | 65 | }, |
| 66 | // sélection d'une date simple sur mobile, évite des problèmes de conflit avec eventClick | ||
| 67 | dateClick: function (info) { | ||
| 68 | if (window.matchMedia('(pointer: coarse)').matches) { | ||
| 69 | const end = new Date(info.date); | ||
| 70 | calendar.view.type === 'dayGridMonth' ? end.setDate(end.getDate() + 1) : end.setMinutes(end.getMinutes() + 30); | ||
| 71 | // vue date: la fin est une date exclue | ||
| 72 | // vue semaine: durée de 30min par défaut | ||
| 73 | const local_end_date_array = end.toLocaleDateString().split('/'); | ||
| 74 | let local_end_str = local_end_date_array[2] + '-' + local_end_date_array[1] + '-' + local_end_date_array[0]; | ||
| 75 | if (calendar.view.type != 'dayGridMonth') { | ||
| 76 | local_end_str += 'T' + end.toLocaleTimeString(); | ||
| 77 | } | ||
| 78 | // on a besoin de deux chaînes représentant l'heure locale pour obtenir le même objet "info" qu'avec l'évènement select | ||
| 79 | // la vue "dayGridMonth" nécessite deux paramètres, par sécurité on en enverra toujours deux | ||
| 80 | calendar.select(info.dateStr, local_end_str); | ||
| 81 | } | ||
| 82 | }, | ||
| 116 | //unselect: function(event, view){}, | 83 | //unselect: function(event, view){}, |
| 117 | eventClick: function(info){ | 84 | eventClick: function (info) { |
| 118 | event_selected = true; // variable "globale" | 85 | event_selected = true; // variable "globale" |
| 119 | const aside = document.querySelector('aside'); | 86 | if (!info.event.start || !info.event.end) { |
| 120 | const checked = info.event.allDay ? 'checked' : ''; | 87 | throw new Error("info.event.start ou info.event.end est null"); |
| 121 | const input = info.event.allDay ? 'date' : 'datetime-local'; | ||
| 122 | |||
| 123 | // change des objets Date en chaînes compatibles avec les input | ||
| 124 | function formatDate(date){ | ||
| 125 | return date.getFullYear() + '-' + (date.getMonth() + 1).toString().padStart(2, '0') + '-' + date.getDate().toString().padStart(2, '0') | ||
| 126 | + (info.event.allDay ? '' : 'T' + date.getHours().toString().padStart(2, '0') + ':' + date.getMinutes().toString().padStart(2, '0')); | ||
| 127 | } | ||
| 128 | function minusOneDay(date){ | ||
| 129 | date.setDate(date.getDate() - 1); // jour de fin modifié pour ne pas faire bizarre pour l'utilisateur | ||
| 130 | return date; | ||
| 131 | } | 88 | } |
| 132 | 89 | const modal_view = new CalendarModalView({ | |
| 133 | const formated_start = formatDate(info.event.start); | 90 | mode: 'edit', |
| 134 | const formated_end = formatDate(info.event.allDay ? minusOneDay(info.event.end) : info.event.end, info.event.allDay); | 91 | input_type: info.event.allDay ? 'date' : 'datetime-local', |
| 135 | 92 | id: info.event.id, | |
| 136 | const aside_content = `<div class="form_event"> | 93 | title: info.event.title, |
| 137 | <div class="event_title_box"> | 94 | description: info.event.extendedProps.description, |
| 138 | <h2>Modifier un évènement</h2> | 95 | color: info.event.backgroundColor, |
| 139 | </div> | 96 | all_day: info.event.allDay, |
| 140 | <div class=""> | 97 | start: info.event.start, |
| 141 | <label for="event_title">Nom</label> | 98 | end: info.event.end |
| 142 | <input type="text" id="event_title" value="` + info.event.title + `"> | 99 | }); |
| 143 | <input type="hidden" id="event_id" value="` + info.event.id + `"> | 100 | modal.innerHTML = modal_view.getView(); |
| 144 | </div> | ||
| 145 | <div class=""> | ||
| 146 | <label for="event_description">Description</label> | ||
| 147 | <textarea id="event_description" cols="27">` + info.event.extendedProps.description + `</textarea> | ||
| 148 | </div> | ||
| 149 | <div class=""> | ||
| 150 | <input type="checkbox" id="event_all_day" class="event_all_day" ` + checked + `> | ||
| 151 | <label for="event_all_day">Journée entière</label> | ||
| 152 | </div> | ||
| 153 | <div class=""> | ||
| 154 | <label for="event_start">Début</label> | ||
| 155 | <input type="` + input + `" id="event_start" value="` + formated_start + `"> | ||
| 156 | </div> | ||
| 157 | <div class=""> | ||
| 158 | <label for="event_end">Fin</label> | ||
| 159 | <input type="` + input + `" id="event_end" value="` + formated_end + `"> | ||
| 160 | </div> | ||
| 161 | <div class=""> | ||
| 162 | <label for="event_color">Couleur</label> | ||
| 163 | <input type="color" id="event_color" value="` + info.event.backgroundColor + `"> | ||
| 164 | </div> | ||
| 165 | <button class="submit_update_event">Modifier</button> | ||
| 166 | <button class="event_close_button">Annuler</button> | ||
| 167 | <button class="delete_event">Supprimer</button> | ||
| 168 | </div>`; | ||
| 169 | aside.innerHTML = aside_content; | ||
| 170 | calendar.updateSize(); | 101 | calendar.updateSize(); |
| 171 | }, | 102 | }, |
| 172 | viewDidMount: function(info){ // déclenché lorsque qu'une nouvelle vue est chargée (mois, semaine...) | 103 | viewDidMount: function (_info) { |
| 173 | if(selected_start_string){ | 104 | hideModal(); |
| 105 | if (selected_start_string) { | ||
| 174 | calendar.gotoDate(new Date(selected_start_string)); | 106 | calendar.gotoDate(new Date(selected_start_string)); |
| 175 | } | 107 | } |
| 176 | }, | 108 | }, |
| 177 | //datesSet: function(info){}, // déclenché lorsque des dates affichées sont chargées (= comme viewDidMount + changement de date) | 109 | //datesSet: function(info){}, // déclenché lorsque des dates affichées sont chargées (= comme viewDidMount + changement de date) |
| 178 | }); | 110 | }); |
| 179 | 111 | function hideModal() { | |
| 180 | function hideModal(){ | ||
| 181 | const aside = document.querySelector('aside'); | ||
| 182 | event_selected = false; | 112 | event_selected = false; |
| 183 | aside.innerHTML = ''; | 113 | modal.innerHTML = ''; |
| 184 | calendar.updateSize(); | 114 | calendar.updateSize(); |
| 185 | } | 115 | } |
| 186 | 116 | function submitEvent(new_event) { | |
| 187 | function submitEvent(new_event){ | 117 | const event_title_input = getElementOrThrow('event_title'); |
| 188 | const event_title = document.getElementById('event_title').value; | 118 | const event_description_input = getElementOrThrow('event_description'); |
| 189 | const event_description = document.getElementById('event_description').value; | 119 | const event_all_day_input = getElementOrThrow('event_all_day'); |
| 190 | const event_all_day = document.getElementById('event_all_day').checked; | 120 | const event_start_input = getElementOrThrow('event_start'); |
| 191 | let event_start = document.getElementById('event_start').value; | 121 | const event_end_input = getElementOrThrow('event_end'); |
| 192 | let event_end = document.getElementById('event_end').value; | 122 | const event_color_input = getElementOrThrow('event_color'); |
| 193 | const event_color = document.getElementById('event_color').value; // #3788d8 par défaut | 123 | assertElementType(event_title_input, HTMLInputElement); |
| 194 | const event_id = new_event ? '' : document.getElementById('event_id').value; | 124 | assertElementType(event_description_input, HTMLTextAreaElement); |
| 195 | 125 | assertElementType(event_all_day_input, HTMLInputElement); | |
| 196 | if(event_title.length !== 0 && event_start.length !== 0 && event_end.length !== 0 && event_color.length !== 0 | 126 | assertElementType(event_start_input, HTMLInputElement); |
| 197 | && (new_event || event_id.length !== 0)) | 127 | assertElementType(event_end_input, HTMLInputElement); |
| 198 | { | 128 | assertElementType(event_color_input, HTMLInputElement); |
| 199 | if(event_all_day){ | 129 | const event_title = event_title_input.value; |
| 130 | const event_description = event_description_input.value; | ||
| 131 | const event_all_day = event_all_day_input.checked; | ||
| 132 | let event_start = new Date(event_start_input.value); | ||
| 133 | let event_end = new Date(event_end_input.value); | ||
| 134 | const event_color = event_color_input.value; // #3788d8 par défaut | ||
| 135 | let event_id = ''; | ||
| 136 | if (!new_event) { | ||
| 137 | //const event_id_input: HTMLElement|null = document.getElementById('event_id'); | ||
| 138 | const event_id_input = getElementOrThrow('event_id'); | ||
| 139 | assertElementType(event_id_input, HTMLInputElement); | ||
| 140 | event_id = event_id_input.value; | ||
| 141 | } | ||
| 142 | // contrôle de saisie | ||
| 143 | if (event_title.length !== 0 && event_start_input.value.length !== 0 && event_end_input.value.length !== 0 && event_color.length !== 0 | ||
| 144 | && (new_event || event_id.length !== 0)) { | ||
| 145 | if (event_all_day) { | ||
| 200 | // on remet le jour de fin exclu | 146 | // on remet le jour de fin exclu |
| 201 | const tmp_object = new Date(event_end); | 147 | event_end.setDate(event_end.getDate() + 1); |
| 202 | tmp_object.setDate(tmp_object.getDate() + 1); | ||
| 203 | event_end = tmp_object.toISOString().split('T')[0]; | ||
| 204 | } | 148 | } |
| 205 | else{ | 149 | else { |
| 206 | event_start = new Date(event_start).toISOString(); | 150 | event_start = new Date(event_start); |
| 207 | event_end = new Date(event_end).toISOString(); | 151 | event_end = new Date(event_end); |
| 208 | } | 152 | } |
| 209 | console.log(event_end); | 153 | // contrôle date/heure de fin après le début |
| 210 | 154 | if (event_start > event_end || (!event_all_day && event_start == event_end)) { | |
| 211 | if(event_start > event_end || (!event_all_day && event_start == event_end)){ | 155 | console.log("Erreur: la fin de l'évènement doit se situer après son début."); |
| 212 | return; | 156 | return; |
| 213 | } | 157 | } |
| 214 | |||
| 215 | // création | 158 | // création |
| 216 | if(new_event){ | 159 | if (new_event) { |
| 217 | const event = { | 160 | const event = { |
| 161 | id: '', | ||
| 218 | title: event_title, | 162 | title: event_title, |
| 219 | description: event_description, | 163 | description: event_description, |
| 220 | allDay: event_all_day, | 164 | allDay: event_all_day, |
| @@ -222,7 +166,6 @@ document.addEventListener('DOMContentLoaded', function(){ | |||
| 222 | end: event_end, | 166 | end: event_end, |
| 223 | color: event_color | 167 | color: event_color |
| 224 | }; | 168 | }; |
| 225 | |||
| 226 | fetch('index.php?action=new_event', { | 169 | fetch('index.php?action=new_event', { |
| 227 | method: 'POST', | 170 | method: 'POST', |
| 228 | headers: { | 171 | headers: { |
| @@ -230,146 +173,145 @@ document.addEventListener('DOMContentLoaded', function(){ | |||
| 230 | }, | 173 | }, |
| 231 | body: JSON.stringify(event), | 174 | body: JSON.stringify(event), |
| 232 | }) | 175 | }) |
| 233 | .then(response => response.json()) | 176 | .then(response => response.json()) |
| 234 | .then(data => { | 177 | .then(data => { |
| 235 | if(data.success){ | 178 | if (data.success) { |
| 236 | event.id = data.id; | 179 | event.id = data.id; |
| 237 | calendar.addEvent(event); | 180 | calendar.addEvent(event); |
| 238 | hideModal(); | 181 | hideModal(); |
| 239 | } | 182 | } |
| 240 | }) | 183 | }) |
| 241 | .catch((error) => { | 184 | .catch((error) => { |
| 242 | console.error('Error:', error); | 185 | console.error('Error:', error); |
| 243 | }); | 186 | }); |
| 244 | |||
| 245 | } | 187 | } |
| 246 | // modification | 188 | // modification |
| 247 | else{ | 189 | else { |
| 248 | const event = calendar.getEventById(event_id); | 190 | const event = calendar.getEventById(event_id); |
| 249 | 191 | if (!event) { | |
| 250 | if(event){ | 192 | throw new Error("Événement non trouvé !"); |
| 251 | const event_copy = { | 193 | } |
| 252 | id: parseInt(event.id), | 194 | const event_copy = { |
| 253 | description: event_description, | 195 | id: parseInt(event.id), |
| 254 | title: event_title, | 196 | description: event_description, |
| 255 | allDay: event_all_day, | 197 | title: event_title, |
| 256 | start: event_start, | 198 | allDay: event_all_day, |
| 257 | end: event_end, | 199 | start: event_start, |
| 258 | color: event_color | 200 | end: event_end, |
| 259 | }; | 201 | color: event_color |
| 260 | 202 | }; | |
| 261 | fetch('index.php?action=update_event', { | 203 | fetch('index.php?action=update_event', { |
| 262 | method: 'POST', | 204 | method: 'POST', |
| 263 | headers: { | 205 | headers: { |
| 264 | 'Content-Type': 'application/json', | 206 | 'Content-Type': 'application/json', |
| 265 | }, | 207 | }, |
| 266 | body: JSON.stringify(event_copy), | 208 | body: JSON.stringify(event_copy), |
| 267 | }) | 209 | }) |
| 268 | .then(response => response.json()) | 210 | .then(response => response.json()) |
| 269 | .then(data => { | 211 | .then(data => { |
| 270 | if(data.success){ | 212 | if (data.success) { |
| 271 | event.setProp('title', event_title); | 213 | event.setProp('title', event_title); |
| 272 | event.setExtendedProp('description', event_description); | 214 | event.setExtendedProp('description', event_description); |
| 273 | event.setAllDay(event_all_day); | 215 | event.setAllDay(event_all_day); |
| 274 | event.setStart(event_start); | 216 | event.setStart(event_start); |
| 275 | event.setEnd(event_end); | 217 | event.setEnd(event_end); |
| 276 | event.setProp('color', event_color); | 218 | event.setProp('color', event_color); |
| 277 | hideModal(); | 219 | hideModal(); |
| 278 | } | 220 | } |
| 279 | }) | 221 | }) |
| 280 | .catch((error) => { | 222 | .catch((error) => { |
| 281 | console.error('Error:', error); | 223 | console.error('Error:', error); |
| 282 | }); | 224 | }); |
| 283 | } | ||
| 284 | else{ | ||
| 285 | console.log("Événement non trouvé !"); | ||
| 286 | } | ||
| 287 | } | 225 | } |
| 288 | } | 226 | } |
| 289 | else{ | 227 | else { |
| 290 | // notif input vide | 228 | // notif input vide |
| 291 | console.log('erreur: input vide'); | 229 | console.log('erreur: input vide'); |
| 292 | } | 230 | } |
| 293 | } | 231 | } |
| 294 | 232 | function checkAllDay() { | |
| 295 | function checkAllDay(){ | 233 | const event_start_input = getElementOrThrow('event_start'); |
| 296 | const event_start_input = document.getElementById('event_start'); | 234 | const event_end_input = getElementOrThrow('event_end'); |
| 297 | const event_end_input = document.getElementById('event_end'); | 235 | const event_all_day = getElementOrThrow('event_all_day'); |
| 298 | 236 | assertElementType(event_start_input, HTMLInputElement); | |
| 237 | assertElementType(event_end_input, HTMLInputElement); | ||
| 238 | assertElementType(event_all_day, HTMLInputElement); | ||
| 299 | const start = event_start_input.value; | 239 | const start = event_start_input.value; |
| 300 | const end = event_end_input.value; | 240 | const end = event_end_input.value; |
| 301 | 241 | if (event_all_day.checked) { | |
| 302 | if(document.getElementById('event_all_day').checked){ | ||
| 303 | event_start_input.type = 'date'; | 242 | event_start_input.type = 'date'; |
| 304 | event_end_input.type = 'date'; | 243 | event_end_input.type = 'date'; |
| 305 | |||
| 306 | event_start_input.value = start.split('T')[0]; | 244 | event_start_input.value = start.split('T')[0]; |
| 307 | event_end_input.value = end.split('T')[0]; | 245 | event_end_input.value = end.split('T')[0]; |
| 308 | } | 246 | } |
| 309 | else{ | 247 | else { |
| 310 | event_start_input.type = 'datetime-local'; | 248 | event_start_input.type = 'datetime-local'; |
| 311 | event_end_input.type = 'datetime-local'; | 249 | event_end_input.type = 'datetime-local'; |
| 312 | |||
| 313 | event_start_input.value = start + 'T10:00'; | 250 | event_start_input.value = start + 'T10:00'; |
| 314 | event_end_input.value = end + 'T11:00'; | 251 | event_end_input.value = end + 'T11:00'; |
| 315 | } | 252 | } |
| 316 | } | 253 | } |
| 317 | function removeEvent(){ | 254 | function removeEvent() { |
| 318 | if(!confirm("Voulez-vous vraiment supprimer cet évènement du calendrier?")){ | 255 | if (!confirm("Voulez-vous vraiment supprimer cet évènement du calendrier?")) { |
| 319 | return; | 256 | return; |
| 320 | } | 257 | } |
| 321 | const event_id = document.getElementById('event_id').value; | 258 | const event_tag = getElementOrThrow('event_id'); // cible input hidden |
| 259 | assertElementType(event_tag, HTMLInputElement); | ||
| 260 | const event_id = event_tag.value; | ||
| 322 | const event = calendar.getEventById(event_id); | 261 | const event = calendar.getEventById(event_id); |
| 323 | 262 | if (!event) { | |
| 263 | throw new Error("Événement non trouvé !"); | ||
| 264 | } | ||
| 324 | fetch('index.php?action=remove_event', { | 265 | fetch('index.php?action=remove_event', { |
| 325 | method: 'POST', | 266 | method: 'POST', |
| 326 | headers: { | 267 | headers: { |
| 327 | 'Content-Type': 'application/json', | 268 | 'Content-Type': 'application/json', |
| 328 | }, | 269 | }, |
| 329 | body: JSON.stringify({'id': event_id}), | 270 | body: JSON.stringify({ 'id': event_id }), |
| 330 | }) | 271 | }) |
| 331 | .then(response => response.json()) | 272 | .then(response => response.json()) |
| 332 | .then(data => { | 273 | .then(data => { |
| 333 | if(data.success){ | 274 | if (data.success) { |
| 334 | event.remove(); | 275 | event.remove(); |
| 335 | hideModal(); | 276 | hideModal(); |
| 336 | } | 277 | } |
| 337 | }) | 278 | }) |
| 338 | .catch((error) => { | 279 | .catch((error) => { |
| 339 | console.error('Error:', error); | 280 | console.error('Error:', error); |
| 340 | }); | 281 | }); |
| 341 | event_selected = false; | 282 | event_selected = false; |
| 342 | } | 283 | } |
| 343 | |||
| 344 | // touches de clavier | 284 | // touches de clavier |
| 345 | document.addEventListener('keydown', function(event){ | 285 | document.addEventListener('keydown', function (event) { |
| 346 | if(event.key === 'Escape'){ | 286 | if (event.key === 'Escape') { |
| 347 | hideModal(); | 287 | hideModal(); |
| 348 | } | 288 | } |
| 349 | else if(event.key === 'Delete' && event_selected === true){ | 289 | else if (event.key === 'Delete' && event_selected === true) { |
| 350 | removeEvent(); | 290 | removeEvent(); |
| 351 | } | 291 | } |
| 352 | }); | 292 | }); |
| 353 | |||
| 354 | // boutons dans la "modale" | 293 | // boutons dans la "modale" |
| 355 | // technique de la délégation d'événements pour utiliser un bouton ajouté dynamiquement | 294 | // technique de la délégation d'événements pour utiliser un bouton ajouté dynamiquement |
| 356 | document.addEventListener('click', function(event){ | 295 | document.addEventListener('click', function (event) { |
| 357 | if(event.target.classList.contains('event_close_button')){ | 296 | if (!event.target) { |
| 297 | throw new Error('évènement click non conforme'); | ||
| 298 | } | ||
| 299 | assertElementType(event.target, HTMLElement); | ||
| 300 | if (event.target.classList.contains('event_close_button')) { | ||
| 358 | hideModal(); | 301 | hideModal(); |
| 359 | } | 302 | } |
| 360 | else if(event.target.classList.contains('event_all_day')){ | 303 | else if (event.target.classList.contains('event_all_day')) { |
| 361 | checkAllDay(); | 304 | checkAllDay(); |
| 362 | } | 305 | } |
| 363 | else if(event.target.classList.contains('submit_new_event')){ | 306 | else if (event.target.classList.contains('submit_new_event')) { |
| 364 | submitEvent(true); | 307 | submitEvent(true); |
| 365 | } | 308 | } |
| 366 | else if(event.target.classList.contains('submit_update_event')){ | 309 | else if (event.target.classList.contains('submit_update_event')) { |
| 367 | submitEvent(false); | 310 | submitEvent(false); |
| 368 | } | 311 | } |
| 369 | else if(event.target.classList.contains('delete_event')){ | 312 | else if (event.target.classList.contains('delete_event')) { |
| 370 | removeEvent(); | 313 | removeEvent(); |
| 371 | } | 314 | } |
| 372 | }); | 315 | }); |
| 373 | |||
| 374 | calendar.render(); | 316 | calendar.render(); |
| 375 | }); \ No newline at end of file | 317 | }); \ No newline at end of file |
