diff options
| author | polo <ordipolo@gmx.fr> | 2025-06-19 03:00:57 +0200 |
|---|---|---|
| committer | polo <ordipolo@gmx.fr> | 2025-06-19 03:00:57 +0200 |
| commit | 2521ba44fed09eaf8ba8569e783e1c7468e3f31d (patch) | |
| tree | 87fc8c03fd76d27d6cee70a129e40e35f5488d08 | |
| parent | 04f4440a77be75f8d270fe1fed69e8e4b1a32483 (diff) | |
| download | fullcalendar-2521ba44fed09eaf8ba8569e783e1c7468e3f31d.tar.gz fullcalendar-2521ba44fed09eaf8ba8569e783e1c7468e3f31d.tar.bz2 fullcalendar-2521ba44fed09eaf8ba8569e783e1c7468e3f31d.zip | |
mode admin et non admin
| -rw-r--r-- | public/css/calendar.css | 4 | ||||
| -rw-r--r-- | public/index.php (renamed from public/index.html) | 8 | ||||
| -rw-r--r-- | public/js/calendar.js | 277 | ||||
| -rw-r--r-- | public/js/calendar_admin.js | 331 | ||||
| -rw-r--r-- | src/post-ajax.php | 4 |
5 files changed, 355 insertions, 269 deletions
diff --git a/public/css/calendar.css b/public/css/calendar.css index 035118a..b762a89 100644 --- a/public/css/calendar.css +++ b/public/css/calendar.css | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | .event{ | ||
| 2 | border: 2px double; | ||
| 3 | border-radius: 5px; | ||
| 4 | } | ||
| 1 | #calendar_zone{ | 5 | #calendar_zone{ |
| 2 | display: flex; | 6 | display: flex; |
| 3 | max-width: 1000px; | 7 | max-width: 1000px; |
diff --git a/public/index.html b/public/index.php index bdd7f67..abcef90 100644 --- a/public/index.html +++ b/public/index.php | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | <?php | ||
| 2 | session_start(); | ||
| 3 | $_SESSION['admin'] = false; | ||
| 4 | ?> | ||
| 1 | <!DOCTYPE html> | 5 | <!DOCTYPE html> |
| 2 | <html lang="fr"> | 6 | <html lang="fr"> |
| 3 | <head> | 7 | <head> |
| @@ -11,7 +15,9 @@ | |||
| 11 | <script src='js/fullcalendar/packages/list/index.global.min.js'></script> | 15 | <script src='js/fullcalendar/packages/list/index.global.min.js'></script> |
| 12 | <script src='js/fullcalendar/packages/interaction/index.global.min.js'></script> | 16 | <script src='js/fullcalendar/packages/interaction/index.global.min.js'></script> |
| 13 | <script src='js/fullcalendar/packages/core/locales/fr.global.min.js'></script> | 17 | <script src='js/fullcalendar/packages/core/locales/fr.global.min.js'></script> |
| 14 | <script src="js/calendar.js"></script> | 18 | <?php |
| 19 | echo (isset($_SESSION['admin']) && $_SESSION['admin'] === true) ? '<script src="js/calendar_admin.js"></script>' . "\n" : '<script src="js/calendar.js"></script>' . "\n"; | ||
| 20 | ?> | ||
| 15 | </head> | 21 | </head> |
| 16 | 22 | ||
| 17 | <body> | 23 | <body> |
diff --git a/public/js/calendar.js b/public/js/calendar.js index 154cdfd..fb26e80 100644 --- a/public/js/calendar.js +++ b/public/js/calendar.js | |||
| @@ -1,19 +1,3 @@ | |||
| 1 | /* // à utiliser plus tard? | ||
| 2 | const current_view = calendar.view; | ||
| 3 | switch(current_view.type){ | ||
| 4 | case 'dayGridMonth': | ||
| 5 | console.log('mois'); | ||
| 6 | break; | ||
| 7 | case 'timeGridWeek': | ||
| 8 | console.log('semaine'); | ||
| 9 | break; | ||
| 10 | case 'timeGridDay': | ||
| 11 | console.log('jour'); | ||
| 12 | break; | ||
| 13 | default: | ||
| 14 | console.log('erreur'); | ||
| 15 | }*/ | ||
| 16 | |||
| 17 | document.addEventListener('DOMContentLoaded', function(){ | 1 | document.addEventListener('DOMContentLoaded', function(){ |
| 18 | const calendarEl = document.getElementById('calendar'); | 2 | const calendarEl = document.getElementById('calendar'); |
| 19 | let selected_start_string = null; | 3 | let selected_start_string = null; |
| @@ -50,90 +34,13 @@ document.addEventListener('DOMContentLoaded', function(){ | |||
| 50 | nowIndicator: true, // barre rouge pour maintenant | 34 | nowIndicator: true, // barre rouge pour maintenant |
| 51 | 35 | ||
| 52 | select: function(info){ | 36 | select: function(info){ |
| 53 | const aside = document.querySelector('aside'); | 37 | selected_start_string = info.startStr; // variable "globale" |
| 54 | let checked = ''; | ||
| 55 | let input = 'datetime-local'; | ||
| 56 | |||
| 57 | // on veut des chaines de la forme 2025-05-20T07:05 | ||
| 58 | // il faut retirer les secondes et le fuseau horaire du format ISO, c'est chiant | ||
| 59 | // on enverra par contre une chaine ISO au serveur pour avoir un enregistrement correct | ||
| 60 | |||
| 61 | let start_value; | ||
| 62 | let end_value; | ||
| 63 | const end = new Date(info.endStr); | ||
| 64 | |||
| 65 | console.log(info.startStr); | ||
| 66 | console.log(info.endStr); | ||
| 67 | |||
| 68 | if(calendar.view.type == 'dayGridMonth'){ | ||
| 69 | start_value = info.startStr + 'T10:00'; | ||
| 70 | end.setDate(end.getDate() - 1); // jour de fin modifié pour ne pas faire bizarre pour l'utilisateur | ||
| 71 | end.setHours(11); | ||
| 72 | end_value = end.toISOString().split('T')[0] + 'T11:00'; | ||
| 73 | } | ||
| 74 | else if(calendar.view.type == 'timeGridWeek' || calendar.view.type == 'timeGridDay'){ | ||
| 75 | const start_array = info.startStr.split("T"); | ||
| 76 | const end_array = info.endStr.split("T"); | ||
| 77 | |||
| 78 | // clic sur la ligne "Journée", = 'dayGridMonth' | ||
| 79 | if(start_array.length == 1){ | ||
| 80 | checked = 'checked'; | ||
| 81 | input = 'date'; | ||
| 82 | start_value = info.startStr; | ||
| 83 | end.setDate(end.getDate() - 1); | ||
| 84 | end_value = end.toISOString().split('T')[0]; | ||
| 85 | } | ||
| 86 | else if(start_array.length == 2){ | ||
| 87 | start_value = start_array[0] + "T" + start_array[1].substr(0,5); // format 2025-06-12T10:00 | ||
| 88 | end_value = end_array[0] + "T" + end_array[1].substr(0,5); | ||
| 89 | } | ||
| 90 | else{ | ||
| 91 | console.log('pas censé se produire'); | ||
| 92 | return; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | selected_start_string = start_value; // variable "globale" | ||
| 97 | |||
| 98 | const aside_content = `<div class="form_event"> | ||
| 99 | <div class="event_title_box"> | ||
| 100 | <h2>Nouvel évènement</h2> | ||
| 101 | </div> | ||
| 102 | <div class=""> | ||
| 103 | <label for="event_title">Nom</label> | ||
| 104 | <input type="text" id="event_title"> | ||
| 105 | </div> | ||
| 106 | <div class=""> | ||
| 107 | <label for="event_description">Description</label> | ||
| 108 | <textarea id="event_description" cols="27"></textarea> | ||
| 109 | </div> | ||
| 110 | <div class=""> | ||
| 111 | <input type="checkbox" id="event_all_day" class="event_all_day" ` + checked + `> | ||
| 112 | <label for="event_all_day">Journée entière</label> | ||
| 113 | </div> | ||
| 114 | <div class=""> | ||
| 115 | <label for="event_start">Début</label> | ||
| 116 | <input type="` + input + `" id="event_start" value="` + start_value + `"> | ||
| 117 | </div> | ||
| 118 | <div class=""> | ||
| 119 | <label for="event_end">Fin</label> | ||
| 120 | <input type="` + input + `" id="event_end" value="` + end_value + `"> | ||
| 121 | </div> | ||
| 122 | <div class=""> | ||
| 123 | <label for="event_color">Couleur</label> | ||
| 124 | <input type="color" id="event_color" value="#3788D8"> | ||
| 125 | </div> | ||
| 126 | <button class="submit_new_event">Enregistrer</button> | ||
| 127 | <button class="event_close_button">Annuler</button> | ||
| 128 | </div>`; | ||
| 129 | aside.innerHTML = aside_content; | ||
| 130 | calendar.updateSize(); | ||
| 131 | }, | 38 | }, |
| 132 | //unselect: function(event, view){}, | 39 | //unselect: function(event, view){}, |
| 40 | |||
| 133 | eventClick: function(info){ | 41 | eventClick: function(info){ |
| 134 | const aside = document.querySelector('aside'); | 42 | const aside = document.querySelector('aside'); |
| 135 | const checked = info.event.allDay ? 'checked' : ''; | 43 | const checked = info.event.allDay ? 'checked' : ''; |
| 136 | const input = info.event.allDay ? 'date' : 'datetime-local'; | ||
| 137 | 44 | ||
| 138 | // change des objets Date en chaînes compatibles avec les input | 45 | // change des objets Date en chaînes compatibles avec les input |
| 139 | function formatDate(date){ | 46 | function formatDate(date){ |
| @@ -148,38 +55,14 @@ document.addEventListener('DOMContentLoaded', function(){ | |||
| 148 | const formated_start = formatDate(info.event.start); | 55 | const formated_start = formatDate(info.event.start); |
| 149 | const formated_end = formatDate(info.event.allDay ? getEndMinusOneDay(info.event.end) : info.event.end, info.event.allDay); | 56 | const formated_end = formatDate(info.event.allDay ? getEndMinusOneDay(info.event.end) : info.event.end, info.event.allDay); |
| 150 | 57 | ||
| 151 | const aside_content = `<div class="form_event"> | 58 | const aside_content = `<div class="event" style="border-color: ` + info.event.backgroundColor +`;"> |
| 152 | <div class="event_title_box"> | 59 | <h3>` + info.event.title + `</h3> |
| 153 | <h2>Modifier un évènement</h2> | 60 | <p><i>` + info.event.extendedProps.description + `</i></p> |
| 154 | </div> | 61 | <p>Journée entière: ` + (checked ? 'oui' : 'non') + `</p> |
| 155 | <div class=""> | 62 | <p>Début: ` + formated_start + `</p> |
| 156 | <label for="event_title">Nom</label> | 63 | <p>Fin: ` + formated_end + `</p> |
| 157 | <input type="text" id="event_title" value="` + info.event.title + `"> | 64 | </div>`; |
| 158 | <input type="hidden" id="event_id" value="` + info.event.id + `"> | 65 | |
| 159 | </div> | ||
| 160 | <div class=""> | ||
| 161 | <label for="event_description">Description</label> | ||
| 162 | <textarea id="event_description" cols="27">` + info.event.extendedProps.description + `</textarea> | ||
| 163 | </div> | ||
| 164 | <div class=""> | ||
| 165 | <input type="checkbox" id="event_all_day" class="event_all_day" ` + checked + `> | ||
| 166 | <label for="event_all_day">Journée entière</label> | ||
| 167 | </div> | ||
| 168 | <div class=""> | ||
| 169 | <label for="event_start">Début</label> | ||
| 170 | <input type="` + input + `" id="event_start" value="` + formated_start + `"> | ||
| 171 | </div> | ||
| 172 | <div class=""> | ||
| 173 | <label for="event_end">Fin</label> | ||
| 174 | <input type="` + input + `" id="event_end" value="` + formated_end + `"> | ||
| 175 | </div> | ||
| 176 | <div class=""> | ||
| 177 | <label for="event_color">Couleur</label> | ||
| 178 | <input type="color" id="event_color" value="` + info.event.backgroundColor + `"> | ||
| 179 | </div> | ||
| 180 | <button class="submit_update_event">Modifier</button> | ||
| 181 | <button class="event_close_button">Annuler</button> | ||
| 182 | </div>`; | ||
| 183 | aside.innerHTML = aside_content; | 66 | aside.innerHTML = aside_content; |
| 184 | calendar.updateSize(); | 67 | calendar.updateSize(); |
| 185 | }, | 68 | }, |
| @@ -198,137 +81,6 @@ document.addEventListener('DOMContentLoaded', function(){ | |||
| 198 | calendar.updateSize(); | 81 | calendar.updateSize(); |
| 199 | } | 82 | } |
| 200 | 83 | ||
| 201 | function submitEvent(new_event){ | ||
| 202 | const event_title = document.getElementById('event_title').value; | ||
| 203 | const event_description = document.getElementById('event_description').value; | ||
| 204 | const event_all_day = document.getElementById('event_all_day').checked; | ||
| 205 | let event_start = document.getElementById('event_start').value; | ||
| 206 | let event_end = document.getElementById('event_end').value; | ||
| 207 | const event_color = document.getElementById('event_color').value; // #3788d8 par défaut | ||
| 208 | const event_id = new_event ? '' : document.getElementById('event_id').value; | ||
| 209 | |||
| 210 | if(event_title.length !== 0 && event_start.length !== 0 && event_end.length !== 0 && event_color.length !== 0 | ||
| 211 | && (new_event || event_id.length !== 0)) | ||
| 212 | { | ||
| 213 | if(event_all_day){ | ||
| 214 | // on remet le jour de fin exclu | ||
| 215 | const tmp_object = new Date(event_end); | ||
| 216 | tmp_object.setDate(tmp_object.getDate() + 1); | ||
| 217 | event_end = tmp_object.toISOString().split('T')[0]; | ||
| 218 | } | ||
| 219 | else{ | ||
| 220 | event_start = new Date(event_start).toISOString(); | ||
| 221 | event_end = new Date(event_end).toISOString(); | ||
| 222 | } | ||
| 223 | console.log(event_end); | ||
| 224 | |||
| 225 | if(event_start > event_end || (!event_all_day && event_start == event_end)){ | ||
| 226 | return; | ||
| 227 | } | ||
| 228 | |||
| 229 | // création | ||
| 230 | if(new_event){ | ||
| 231 | const event = { | ||
| 232 | title: event_title, | ||
| 233 | description: event_description, | ||
| 234 | allDay: event_all_day, | ||
| 235 | start: event_start, | ||
| 236 | end: event_end, | ||
| 237 | color: event_color | ||
| 238 | }; | ||
| 239 | |||
| 240 | fetch('../src/post-ajax.php', { | ||
| 241 | method: 'POST', | ||
| 242 | headers: { | ||
| 243 | 'Content-Type': 'application/json', | ||
| 244 | }, | ||
| 245 | body: JSON.stringify(event), | ||
| 246 | }) | ||
| 247 | .then(response => response.json()) | ||
| 248 | .then(data => { | ||
| 249 | if(data.success){ | ||
| 250 | event.id = data.id; | ||
| 251 | calendar.addEvent(event); | ||
| 252 | hideModal(); | ||
| 253 | } | ||
| 254 | }) | ||
| 255 | .catch((error) => { | ||
| 256 | console.error('Error:', error); | ||
| 257 | }); | ||
| 258 | |||
| 259 | } | ||
| 260 | // modification | ||
| 261 | else{ | ||
| 262 | const event = calendar.getEventById(event_id); | ||
| 263 | |||
| 264 | if(event){ | ||
| 265 | const event_copy = { | ||
| 266 | id: parseInt(event.id), | ||
| 267 | description: event_description, | ||
| 268 | title: event_title, | ||
| 269 | allDay: event_all_day, | ||
| 270 | start: event_start, | ||
| 271 | end: event_end, | ||
| 272 | color: event_color | ||
| 273 | }; | ||
| 274 | |||
| 275 | fetch('../src/post-ajax.php', { | ||
| 276 | method: 'POST', | ||
| 277 | headers: { | ||
| 278 | 'Content-Type': 'application/json', | ||
| 279 | }, | ||
| 280 | body: JSON.stringify(event_copy), | ||
| 281 | }) | ||
| 282 | .then(response => response.json()) | ||
| 283 | .then(data => { | ||
| 284 | if(data.success){ | ||
| 285 | event.setProp('title', event_title); | ||
| 286 | event.setExtendedProp('description', event_description); | ||
| 287 | event.setAllDay(event_all_day); | ||
| 288 | event.setStart(event_start); | ||
| 289 | event.setEnd(event_end); | ||
| 290 | event.setProp('color', event_color); | ||
| 291 | hideModal(); | ||
| 292 | } | ||
| 293 | }) | ||
| 294 | .catch((error) => { | ||
| 295 | console.error('Error:', error); | ||
| 296 | }); | ||
| 297 | } | ||
| 298 | else{ | ||
| 299 | console.log("Événement non trouvé !"); | ||
| 300 | } | ||
| 301 | } | ||
| 302 | } | ||
| 303 | else{ | ||
| 304 | // notif input vide | ||
| 305 | console.log('erreur: input vide'); | ||
| 306 | } | ||
| 307 | } | ||
| 308 | |||
| 309 | function checkAllDay(){ | ||
| 310 | const event_start_input = document.getElementById('event_start'); | ||
| 311 | const event_end_input = document.getElementById('event_end'); | ||
| 312 | |||
| 313 | const start = event_start_input.value; | ||
| 314 | const end = event_end_input.value; | ||
| 315 | |||
| 316 | if(document.getElementById('event_all_day').checked){ | ||
| 317 | event_start_input.type = 'date'; | ||
| 318 | event_end_input.type = 'date'; | ||
| 319 | |||
| 320 | event_start_input.value = start.split('T')[0]; | ||
| 321 | event_end_input.value = end.split('T')[0]; | ||
| 322 | } | ||
| 323 | else{ | ||
| 324 | event_start_input.type = 'datetime-local'; | ||
| 325 | event_end_input.type = 'datetime-local'; | ||
| 326 | |||
| 327 | event_start_input.value = start + 'T10:00'; | ||
| 328 | event_end_input.value = end + 'T11:00'; | ||
| 329 | } | ||
| 330 | } | ||
| 331 | |||
| 332 | document.addEventListener('keydown', function(event){ | 84 | document.addEventListener('keydown', function(event){ |
| 333 | if(event.key === 'Escape') { | 85 | if(event.key === 'Escape') { |
| 334 | hideModal(); | 86 | hideModal(); |
| @@ -340,15 +92,6 @@ document.addEventListener('DOMContentLoaded', function(){ | |||
| 340 | if(event.target.classList.contains('event_close_button')){ | 92 | if(event.target.classList.contains('event_close_button')){ |
| 341 | hideModal(); | 93 | hideModal(); |
| 342 | } | 94 | } |
| 343 | else if(event.target.classList.contains('event_all_day')){ | ||
| 344 | checkAllDay(); | ||
| 345 | } | ||
| 346 | else if(event.target.classList.contains('submit_new_event')){ | ||
| 347 | submitEvent(true); | ||
| 348 | } | ||
| 349 | else if(event.target.classList.contains('submit_update_event')){ | ||
| 350 | submitEvent(false); | ||
| 351 | } | ||
| 352 | }); | 95 | }); |
| 353 | 96 | ||
| 354 | calendar.render(); | 97 | calendar.render(); |
diff --git a/public/js/calendar_admin.js b/public/js/calendar_admin.js new file mode 100644 index 0000000..253d127 --- /dev/null +++ b/public/js/calendar_admin.js | |||
| @@ -0,0 +1,331 @@ | |||
| 1 | document.addEventListener('DOMContentLoaded', function(){ | ||
| 2 | const calendarEl = document.getElementById('calendar'); | ||
| 3 | let selected_start_string = null; | ||
| 4 | |||
| 5 | const calendar = new FullCalendar.Calendar(calendarEl,{ | ||
| 6 | editable: true, | ||
| 7 | locale: 'fr', | ||
| 8 | initialView: 'dayGridMonth', | ||
| 9 | headerToolbar:{ | ||
| 10 | left: 'prev,next today', | ||
| 11 | center: 'title', | ||
| 12 | right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek' | ||
| 13 | //right: 'dayGridMonth,timeGridWeek' | ||
| 14 | }, | ||
| 15 | slotMinWidth: 70, | ||
| 16 | defaultAllDay: false, | ||
| 17 | |||
| 18 | // numéros de semaine | ||
| 19 | //weekNumbers: true, | ||
| 20 | //weekText: 's', | ||
| 21 | |||
| 22 | // vue mois | ||
| 23 | contentHeight: 600, // après initialisation: calendar.setOption('contentHeight', 650); | ||
| 24 | //aspectRatio: 1.5, // après initialisation: calendar.setOption('aspectRatio', 1.8); | ||
| 25 | // pour recalculer la taille au redimensionnement du parent, exécuter: calendar.updateSize() | ||
| 26 | stickyHeaderDates: true, // garder les en-tête de colonnes lors du scroll | ||
| 27 | fixedWeekCount: false, // avec false, affiche 4, 5 ou 6 semaines selon le mois | ||
| 28 | selectable: true, // sélection de jours multiples | ||
| 29 | navLinks: true, // numéros de jour et de semaines clicables | ||
| 30 | |||
| 31 | // vue semaine | ||
| 32 | slotEventOverlap: true, // superposition (limitée) de deux évènements simultanés | ||
| 33 | allDayContent: 'Journée', // texte dans la case "toute la journée" | ||
| 34 | nowIndicator: true, // barre rouge pour maintenant | ||
| 35 | |||
| 36 | select: function(info){ | ||
| 37 | selected_start_string = info.startStr; // variable "globale" | ||
| 38 | const aside = document.querySelector('aside'); | ||
| 39 | let checked = ''; | ||
| 40 | let input = 'datetime-local'; | ||
| 41 | |||
| 42 | // on veut des chaines de la forme 2025-05-20T07:05 | ||
| 43 | // il faut retirer les secondes et le fuseau horaire du format ISO, c'est chiant | ||
| 44 | // on enverra par contre une chaine ISO au serveur pour avoir un enregistrement correct | ||
| 45 | |||
| 46 | let start_value; | ||
| 47 | let end_value; | ||
| 48 | const end = new Date(info.endStr); | ||
| 49 | |||
| 50 | if(calendar.view.type == 'dayGridMonth'){ | ||
| 51 | start_value = info.startStr + 'T10:00'; | ||
| 52 | end.setDate(end.getDate() - 1); // jour de fin modifié pour ne pas faire bizarre pour l'utilisateur | ||
| 53 | end.setHours(11); | ||
| 54 | end_value = end.toISOString().split('T')[0] + 'T11:00'; | ||
| 55 | } | ||
| 56 | else if(calendar.view.type == 'timeGridWeek' || calendar.view.type == 'timeGridDay'){ | ||
| 57 | const start_array = info.startStr.split("T"); | ||
| 58 | const end_array = info.endStr.split("T"); | ||
| 59 | |||
| 60 | // clic sur la ligne "Journée", = 'dayGridMonth' | ||
| 61 | if(start_array.length == 1){ | ||
| 62 | checked = 'checked'; | ||
| 63 | input = 'date'; | ||
| 64 | start_value = info.startStr; | ||
| 65 | end.setDate(end.getDate() - 1); | ||
| 66 | end_value = end.toISOString().split('T')[0]; | ||
| 67 | } | ||
| 68 | else if(start_array.length == 2){ | ||
| 69 | start_value = start_array[0] + "T" + start_array[1].substr(0,5); // format 2025-06-12T10:00 | ||
| 70 | end_value = end_array[0] + "T" + end_array[1].substr(0,5); | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | const aside_content = `<div class="form_event"> | ||
| 75 | <div class="event_title_box"> | ||
| 76 | <h2>Nouvel évènement</h2> | ||
| 77 | </div> | ||
| 78 | <div class=""> | ||
| 79 | <label for="event_title">Nom</label> | ||
| 80 | <input type="text" id="event_title"> | ||
| 81 | </div> | ||
| 82 | <div class=""> | ||
| 83 | <label for="event_description">Description</label> | ||
| 84 | <textarea id="event_description" cols="27"></textarea> | ||
| 85 | </div> | ||
| 86 | <div class=""> | ||
| 87 | <input type="checkbox" id="event_all_day" class="event_all_day" ` + checked + `> | ||
| 88 | <label for="event_all_day">Journée entière</label> | ||
| 89 | </div> | ||
| 90 | <div class=""> | ||
| 91 | <label for="event_start">Début</label> | ||
| 92 | <input type="` + input + `" id="event_start" value="` + start_value + `"> | ||
| 93 | </div> | ||
| 94 | <div class=""> | ||
| 95 | <label for="event_end">Fin</label> | ||
| 96 | <input type="` + input + `" id="event_end" value="` + end_value + `"> | ||
| 97 | </div> | ||
| 98 | <div class=""> | ||
| 99 | <label for="event_color">Couleur</label> | ||
| 100 | <input type="color" id="event_color" value="#3788D8"> | ||
| 101 | </div> | ||
| 102 | <button class="submit_new_event">Enregistrer</button> | ||
| 103 | <button class="event_close_button">Annuler</button> | ||
| 104 | </div>`; | ||
| 105 | aside.innerHTML = aside_content; | ||
| 106 | calendar.updateSize(); | ||
| 107 | }, | ||
| 108 | //unselect: function(event, view){}, | ||
| 109 | eventClick: function(info){ | ||
| 110 | const aside = document.querySelector('aside'); | ||
| 111 | const checked = info.event.allDay ? 'checked' : ''; | ||
| 112 | const input = info.event.allDay ? 'date' : 'datetime-local'; | ||
| 113 | |||
| 114 | // change des objets Date en chaînes compatibles avec les input | ||
| 115 | function formatDate(date){ | ||
| 116 | return date.getFullYear() + '-' + (date.getMonth() + 1).toString().padStart(2, '0') + '-' + date.getDate().toString().padStart(2, '0') | ||
| 117 | + (info.event.allDay ? '' : 'T' + date.getHours().toString().padStart(2, '0') + ':' + date.getMinutes().toString().padStart(2, '0')); | ||
| 118 | } | ||
| 119 | function getEndMinusOneDay(date){ | ||
| 120 | date.setDate(date.getDate() - 1); // jour de fin modifié pour ne pas faire bizarre pour l'utilisateur | ||
| 121 | return date; | ||
| 122 | } | ||
| 123 | |||
| 124 | const formated_start = formatDate(info.event.start); | ||
| 125 | const formated_end = formatDate(info.event.allDay ? getEndMinusOneDay(info.event.end) : info.event.end, info.event.allDay); | ||
| 126 | |||
| 127 | const aside_content = `<div class="form_event"> | ||
| 128 | <div class="event_title_box"> | ||
| 129 | <h2>Modifier un évènement</h2> | ||
| 130 | </div> | ||
| 131 | <div class=""> | ||
| 132 | <label for="event_title">Nom</label> | ||
| 133 | <input type="text" id="event_title" value="` + info.event.title + `"> | ||
| 134 | <input type="hidden" id="event_id" value="` + info.event.id + `"> | ||
| 135 | </div> | ||
| 136 | <div class=""> | ||
| 137 | <label for="event_description">Description</label> | ||
| 138 | <textarea id="event_description" cols="27">` + info.event.extendedProps.description + `</textarea> | ||
| 139 | </div> | ||
| 140 | <div class=""> | ||
| 141 | <input type="checkbox" id="event_all_day" class="event_all_day" ` + checked + `> | ||
| 142 | <label for="event_all_day">Journée entière</label> | ||
| 143 | </div> | ||
| 144 | <div class=""> | ||
| 145 | <label for="event_start">Début</label> | ||
| 146 | <input type="` + input + `" id="event_start" value="` + formated_start + `"> | ||
| 147 | </div> | ||
| 148 | <div class=""> | ||
| 149 | <label for="event_end">Fin</label> | ||
| 150 | <input type="` + input + `" id="event_end" value="` + formated_end + `"> | ||
| 151 | </div> | ||
| 152 | <div class=""> | ||
| 153 | <label for="event_color">Couleur</label> | ||
| 154 | <input type="color" id="event_color" value="` + info.event.backgroundColor + `"> | ||
| 155 | </div> | ||
| 156 | <button class="submit_update_event">Modifier</button> | ||
| 157 | <button class="event_close_button">Annuler</button> | ||
| 158 | </div>`; | ||
| 159 | aside.innerHTML = aside_content; | ||
| 160 | calendar.updateSize(); | ||
| 161 | }, | ||
| 162 | viewDidMount: function(info){ // déclenché lorsque qu'une nouvelle vue est chargée (mois, semaine...) | ||
| 163 | if(selected_start_string){ | ||
| 164 | calendar.gotoDate(new Date(selected_start_string)); | ||
| 165 | } | ||
| 166 | }, | ||
| 167 | //datesSet: function(info){}, // déclenché lorsque des dates affichées sont chargées (= comme viewDidMount + changement de date) | ||
| 168 | events: '../src/load-events.php' // fichier PHP qui retourne les événements | ||
| 169 | }); | ||
| 170 | |||
| 171 | function hideModal(){ | ||
| 172 | const aside = document.querySelector('aside'); | ||
| 173 | aside.innerHTML = ''; | ||
| 174 | calendar.updateSize(); | ||
| 175 | } | ||
| 176 | |||
| 177 | function submitEvent(new_event){ | ||
| 178 | const event_title = document.getElementById('event_title').value; | ||
| 179 | const event_description = document.getElementById('event_description').value; | ||
| 180 | const event_all_day = document.getElementById('event_all_day').checked; | ||
| 181 | let event_start = document.getElementById('event_start').value; | ||
| 182 | let event_end = document.getElementById('event_end').value; | ||
| 183 | const event_color = document.getElementById('event_color').value; // #3788d8 par défaut | ||
| 184 | const event_id = new_event ? '' : document.getElementById('event_id').value; | ||
| 185 | |||
| 186 | if(event_title.length !== 0 && event_start.length !== 0 && event_end.length !== 0 && event_color.length !== 0 | ||
| 187 | && (new_event || event_id.length !== 0)) | ||
| 188 | { | ||
| 189 | if(event_all_day){ | ||
| 190 | // on remet le jour de fin exclu | ||
| 191 | const tmp_object = new Date(event_end); | ||
| 192 | tmp_object.setDate(tmp_object.getDate() + 1); | ||
| 193 | event_end = tmp_object.toISOString().split('T')[0]; | ||
| 194 | } | ||
| 195 | else{ | ||
| 196 | event_start = new Date(event_start).toISOString(); | ||
| 197 | event_end = new Date(event_end).toISOString(); | ||
| 198 | } | ||
| 199 | console.log(event_end); | ||
| 200 | |||
| 201 | if(event_start > event_end || (!event_all_day && event_start == event_end)){ | ||
| 202 | return; | ||
| 203 | } | ||
| 204 | |||
| 205 | // création | ||
| 206 | if(new_event){ | ||
| 207 | const event = { | ||
| 208 | title: event_title, | ||
| 209 | description: event_description, | ||
| 210 | allDay: event_all_day, | ||
| 211 | start: event_start, | ||
| 212 | end: event_end, | ||
| 213 | color: event_color | ||
| 214 | }; | ||
| 215 | |||
| 216 | fetch('../src/post-ajax.php', { | ||
| 217 | method: 'POST', | ||
| 218 | headers: { | ||
| 219 | 'Content-Type': 'application/json', | ||
| 220 | }, | ||
| 221 | body: JSON.stringify(event), | ||
| 222 | }) | ||
| 223 | .then(response => response.json()) | ||
| 224 | .then(data => { | ||
| 225 | if(data.success){ | ||
| 226 | event.id = data.id; | ||
| 227 | calendar.addEvent(event); | ||
| 228 | hideModal(); | ||
| 229 | } | ||
| 230 | }) | ||
| 231 | .catch((error) => { | ||
| 232 | console.error('Error:', error); | ||
| 233 | }); | ||
| 234 | |||
| 235 | } | ||
| 236 | // modification | ||
| 237 | else{ | ||
| 238 | const event = calendar.getEventById(event_id); | ||
| 239 | |||
| 240 | if(event){ | ||
| 241 | const event_copy = { | ||
| 242 | id: parseInt(event.id), | ||
| 243 | description: event_description, | ||
| 244 | title: event_title, | ||
| 245 | allDay: event_all_day, | ||
| 246 | start: event_start, | ||
| 247 | end: event_end, | ||
| 248 | color: event_color | ||
| 249 | }; | ||
| 250 | |||
| 251 | fetch('../src/post-ajax.php', { | ||
| 252 | method: 'POST', | ||
| 253 | headers: { | ||
| 254 | 'Content-Type': 'application/json', | ||
| 255 | }, | ||
| 256 | body: JSON.stringify(event_copy), | ||
| 257 | }) | ||
| 258 | .then(response => response.json()) | ||
| 259 | .then(data => { | ||
| 260 | if(data.success){ | ||
| 261 | event.setProp('title', event_title); | ||
| 262 | event.setExtendedProp('description', event_description); | ||
| 263 | event.setAllDay(event_all_day); | ||
| 264 | event.setStart(event_start); | ||
| 265 | event.setEnd(event_end); | ||
| 266 | event.setProp('color', event_color); | ||
| 267 | hideModal(); | ||
| 268 | } | ||
| 269 | }) | ||
| 270 | .catch((error) => { | ||
| 271 | console.error('Error:', error); | ||
| 272 | }); | ||
| 273 | } | ||
| 274 | else{ | ||
| 275 | console.log("Événement non trouvé !"); | ||
| 276 | } | ||
| 277 | } | ||
| 278 | } | ||
| 279 | else{ | ||
| 280 | // notif input vide | ||
| 281 | console.log('erreur: input vide'); | ||
| 282 | } | ||
| 283 | } | ||
| 284 | |||
| 285 | function checkAllDay(){ | ||
| 286 | const event_start_input = document.getElementById('event_start'); | ||
| 287 | const event_end_input = document.getElementById('event_end'); | ||
| 288 | |||
| 289 | const start = event_start_input.value; | ||
| 290 | const end = event_end_input.value; | ||
| 291 | |||
| 292 | if(document.getElementById('event_all_day').checked){ | ||
| 293 | event_start_input.type = 'date'; | ||
| 294 | event_end_input.type = 'date'; | ||
| 295 | |||
| 296 | event_start_input.value = start.split('T')[0]; | ||
| 297 | event_end_input.value = end.split('T')[0]; | ||
| 298 | } | ||
| 299 | else{ | ||
| 300 | event_start_input.type = 'datetime-local'; | ||
| 301 | event_end_input.type = 'datetime-local'; | ||
| 302 | |||
| 303 | event_start_input.value = start + 'T10:00'; | ||
| 304 | event_end_input.value = end + 'T11:00'; | ||
| 305 | } | ||
| 306 | } | ||
| 307 | |||
| 308 | document.addEventListener('keydown', function(event){ | ||
| 309 | if(event.key === 'Escape') { | ||
| 310 | hideModal(); | ||
| 311 | } | ||
| 312 | }); | ||
| 313 | |||
| 314 | // technique de la délégation d'événements pour utiliser un bouton ajouté dynamiquement | ||
| 315 | document.addEventListener('click', function(event){ | ||
| 316 | if(event.target.classList.contains('event_close_button')){ | ||
| 317 | hideModal(); | ||
| 318 | } | ||
| 319 | else if(event.target.classList.contains('event_all_day')){ | ||
| 320 | checkAllDay(); | ||
| 321 | } | ||
| 322 | else if(event.target.classList.contains('submit_new_event')){ | ||
| 323 | submitEvent(true); | ||
| 324 | } | ||
| 325 | else if(event.target.classList.contains('submit_update_event')){ | ||
| 326 | submitEvent(false); | ||
| 327 | } | ||
| 328 | }); | ||
| 329 | |||
| 330 | calendar.render(); | ||
| 331 | }); \ No newline at end of file | ||
diff --git a/src/post-ajax.php b/src/post-ajax.php index df5a01a..bedfed5 100644 --- a/src/post-ajax.php +++ b/src/post-ajax.php | |||
| @@ -1,5 +1,7 @@ | |||
| 1 | <?php | 1 | <?php |
| 2 | if($_SERVER['REQUEST_METHOD'] === 'POST'){ // && $_SESSION['admin'] === true | 2 | session_start(); |
| 3 | |||
| 4 | if(isset($_SESSION['admin']) && $_SESSION['admin'] === true && $_SERVER['REQUEST_METHOD'] === 'POST'){ // && $_SESSION['admin'] === true | ||
| 3 | if($_SERVER['CONTENT_TYPE'] === 'application/json'){ | 5 | if($_SERVER['CONTENT_TYPE'] === 'application/json'){ |
| 4 | $data = file_get_contents('php://input'); | 6 | $data = file_get_contents('php://input'); |
| 5 | $json = json_decode($data, true); | 7 | $json = json_decode($data, true); |
