From ba4c1d898fbcaa118ab6ff81317ef32839293d66 Mon Sep 17 00:00:00 2001 From: polo Date: Wed, 11 Jun 2025 12:17:17 +0200 Subject: =?UTF-8?q?front-end=20bien=20avanc=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/js/calendar.js | 269 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 269 insertions(+) create mode 100644 public/js/calendar.js (limited to 'public/js/calendar.js') diff --git a/public/js/calendar.js b/public/js/calendar.js new file mode 100644 index 0000000..3046ef0 --- /dev/null +++ b/public/js/calendar.js @@ -0,0 +1,269 @@ +document.addEventListener('DOMContentLoaded', function(){ + const calendarEl = document.getElementById('calendar'); + let selected_start_string = null; + + const calendar = new FullCalendar.Calendar(calendarEl,{ + editable: true, + locale: 'fr', + initialView: 'dayGridMonth', + headerToolbar:{ + left: 'prev,next today', + center: 'title', + right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek' + //right: 'dayGridMonth,timeGridWeek' + }, + slotMinWidth: 70, + defaultAllDay: false, + + // numéros de semaine + //weekNumbers: true, + //weekText: 's', + + // vue mois + contentHeight: 600, // après initialisation: calendar.setOption('contentHeight', 650); + //aspectRatio: 1.5, // après initialisation: calendar.setOption('aspectRatio', 1.8); + // pour recalculer la taille au redimensionnement du parent, exécuter: calendar.updateSize() + stickyHeaderDates: true, // garder les en-tête de colonnes lors du scroll + fixedWeekCount: false, // avec false, affiche 4, 5 ou 6 semaines selon le mois + selectable: true, // sélection de jours multiples + navLinks: true, // numéros de jour et de semaines clicables + + // vue semaine + slotEventOverlap: true, // superposition (limitée) de deux évènements simultanés + allDayContent: 'Journée', // texte dans la case "toute la journée" + nowIndicator: true, // barre rouge pour maintenant + + select: function(info){ + const aside = document.querySelector('aside'); + let start_value; + + // on veut des chaines de la forme 2025-05-20T07:05 + // il faut retirer les secondes et le fuseau horaire du format ISO, c'est chiant + // enverra par contre une chaine ISO au serveur pour avoir un enregistrement correct + //selected_start = document.getElementById('event_start'); + + const end = new Date(info.endStr); + if(calendar.view.type == 'dayGridMonth'){ + start_value = info.startStr + 'T10:00'; + end.setDate(end.getDate() - 1); + end.setHours(11); + } + else if(calendar.view.type == 'timeGridWeek' || calendar.view.type == 'timeGridDay'){ + const start_array = info.startStr.split("T"); + start_value = start_array[0] + "T" + start_array[1].substr(0,5); // format 2025-06-12T10:00 + } + + const end_value = end.toISOString().split('T')[0] + "T" + String(end.getHours()).padStart(2, '0') + ":" + String(end.getMinutes()).padStart(2, '0'); + selected_start_string = start_value; + + //console.log(info.endStr); + //console.log(end_value.value); + + const aside_content = `
+
+

Nouvel évènement

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + +
`; + aside.innerHTML = aside_content; + calendar.updateSize(); + }, + //~ unselect: function(event, view) { + //~ const aside = document.querySelector('aside'); + //~ aside.innerHTML = ''; + //~ //calendar.updateSize(); + //~ }, + eventClick: function(info){ + const aside = document.querySelector('aside'); + const checked = info.event.allDay ? 'checked' : ''; + const input = info.event.allDay ? 'date' : 'datetime-local'; + + // change des objets Date en chaînes compatibles avec des input type datetime-local, ex: 2025-05-20T07:05 + function formatDate(date, all_day){ + return date.getFullYear() + '-' + (date.getMonth() + 1).toString().padStart(2, '0') + '-' + date.getDate().toString().padStart(2, '0') + + (all_day ? '' : 'T' + date.getHours().toString().padStart(2, '0') + ':' + date.getMinutes().toString().padStart(2, '0')); + } + const formated_start = formatDate(info.event.start, info.event.allDay); + const formated_end = formatDate(info.event.end, info.event.allDay); + + const aside_content = `
+
+

Modifier un évènement

+
+
+ + + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + +
`; + aside.innerHTML = aside_content; + calendar.updateSize(); + }, + viewDidMount: function(info){ // déclenché lorsque qu'une nouvelle vue est chargée (mois, semaine...) + if(selected_start_string){ + calendar.gotoDate(new Date(selected_start_string)); + } + }, + //datesSet: function(info){}, // déclenché lorsque des dates affichées sont chargées (= comme viewDidMount + changement de date) + events: '../src/load-events.php' // fichier PHP qui retourne les événements + }); + + function hideModal(){ + const aside = document.querySelector('aside'); + aside.innerHTML = ''; + calendar.updateSize(); + } + + function submitEvent(new_event){ + const event_title = document.getElementById('event_title').value; + const event_all_day = document.getElementById('event_all_day').checked; + const event_start = document.getElementById('event_start').value; + const event_end = document.getElementById('event_end').value; + const event_color = document.getElementById('event_color').value; // #3788d8 par défaut + const event_id = new_event ? '' : document.getElementById('event_id').value; + + if(event_title.length !== 0 && event_start.length !== 0 && event_end.length !== 0 && event_color.length !== 0 + && (new_event || event_id.length !== 0)) + { + const event_start_utc = new Date(event_start).toISOString(); // heure UTC pour fullcalendar (et pour le serveur) + const event_end_utc = new Date(event_end).toISOString(); + + if(event_start_utc >= event_end_utc){ + return; + } + + // création + if(new_event){ + /*const current_view = calendar.view; + switch(current_view.type){ + case 'dayGridMonth': + console.log('mois'); + break; + case 'timeGridWeek': + console.log('semaine'); + break; + case 'timeGridDay': + console.log('jour'); + break; + default: + console.log('erreur'); + }*/ + calendar.addEvent({ + // pas d'id, c'est au serveur de le créer + title: event_title, + allDay: event_all_day, + start: event_start_utc, + end: event_end_utc, + color: event_color + }); + } + // modification + else{ + const event = calendar.getEventById(event_id); + + if(event){ + event.setProp('title', event_title); + event.setAllDay(event_all_day); + event.setStart(event_start_utc); + event.setEnd(event_end_utc); + event.setProp('color', event_color); + } + else{ + console.log("Événement non trouvé !"); + } + } + + hideModal(); + } + else{ + // notif input vide + console.log('erreur: input vide'); + } + } + + function checkAllDay(){ + const event_start_input = document.getElementById('event_start'); + const event_end_input = document.getElementById('event_end'); + + const start = event_start_input.value; + const end = event_end_input.value; + + if(document.getElementById('event_all_day').checked){ + event_start_input.type = 'date'; + event_end_input.type = 'date'; + + event_start_input.value = start.split('T')[0]; + event_end_input.value = end.split('T')[0]; + } + else{ + event_start_input.type = 'datetime-local'; + event_end_input.type = 'datetime-local'; + + event_start_input.value = start + 'T10:00'; + event_end_input.value = end + 'T11:00'; + } + } + + document.addEventListener('keydown', function(event){ + if(event.key === 'Escape') { + hideModal(); + } + }); + + // technique de la délégation d'événements pour utiliser un bouton ajouté dynamiquement + document.addEventListener('click', function(event){ + if(event.target.classList.contains('event_close_button')){ + hideModal(); + } + else if(event.target.classList.contains('event_all_day')){ + checkAllDay(); + } + else if(event.target.classList.contains('submit_new_event')){ + submitEvent(true); + } + else if(event.target.classList.contains('submit_update_event')){ + submitEvent(false); + } + }); + + calendar.render(); +}); \ No newline at end of file -- cgit v1.2.3