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.js | |
| parent | f007bac3b9172711dc0fcca1306270ab99dbd8a4 (diff) | |
| download | fullcalendar-e3a42c8342bba0db15e2ca9a78911121e5d539da.tar.gz fullcalendar-e3a42c8342bba0db15e2ca9a78911121e5d539da.tar.bz2 fullcalendar-e3a42c8342bba0db15e2ca9a78911121e5d539da.zip | |
Diffstat (limited to 'public/js/calendar.js')
| -rw-r--r-- | public/js/calendar.js | 110 |
1 files changed, 46 insertions, 64 deletions
diff --git a/public/js/calendar.js b/public/js/calendar.js index a092632..ff1a401 100644 --- a/public/js/calendar.js +++ b/public/js/calendar.js | |||
| @@ -1,115 +1,97 @@ | |||
| 1 | // js/calendar.js | 1 | // js/calendar.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 | 7 | const calendar = new FullCalendar.Calendar(calendarEl, { | |
| 7 | const calendar = new FullCalendar.Calendar(calendarEl,{ | ||
| 8 | editable: true, | 8 | editable: true, |
| 9 | locale: 'fr', | 9 | locale: 'fr', |
| 10 | //timeZone: 'local', // à modifier pour être à l'heure d'un autre pays | 10 | //timeZone: 'local', // à modifier pour être à l'heure d'un autre pays |
| 11 | initialView: 'dayGridMonth', | 11 | initialView: 'dayGridMonth', |
| 12 | headerToolbar:{ | 12 | headerToolbar: { |
| 13 | left: 'prev,next today', | 13 | left: 'prev,next today', |
| 14 | center: 'title', | 14 | center: 'title', |
| 15 | right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek' | 15 | //right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek' |
| 16 | //right: 'dayGridMonth,timeGridWeek' | 16 | right: 'dayGridMonth,timeGridWeek,listWeek' |
| 17 | }, | 17 | }, |
| 18 | slotMinWidth: 70, | 18 | slotMinWidth: 70, |
| 19 | defaultAllDay: false, | 19 | defaultAllDay: false, |
| 20 | |||
| 21 | // numéros de semaine | 20 | // numéros de semaine |
| 22 | //weekNumbers: true, | 21 | //weekNumbers: true, |
| 23 | //weekText: 's', | 22 | //weekText: 's', |
| 24 | |||
| 25 | // vue mois | 23 | // vue mois |
| 26 | contentHeight: 600, // après initialisation: calendar.setOption('contentHeight', 650); | 24 | contentHeight: 600, // après initialisation: calendar.setOption('contentHeight', 650); |
| 27 | //aspectRatio: 1.5, // après initialisation: calendar.setOption('aspectRatio', 1.8); | 25 | //aspectRatio: 1.5, // après initialisation: calendar.setOption('aspectRatio', 1.8); |
| 28 | // pour recalculer la taille au redimensionnement du parent, exécuter: calendar.updateSize() | 26 | // pour recalculer la taille au redimensionnement du parent, exécuter: calendar.updateSize() |
| 29 | stickyHeaderDates: true, // garder les en-tête de colonnes lors du scroll | 27 | stickyHeaderDates: true, // garder les en-tête de colonnes lors du scroll |
| 30 | fixedWeekCount: false, // avec false, affiche 4, 5 ou 6 semaines selon le mois | 28 | fixedWeekCount: false, // avec false, affiche 4, 5 ou 6 semaines selon le mois |
| 31 | selectable: true, // sélection de jours multiples | 29 | selectable: true, // sélection de jours en cliquant dessus |
| 30 | longPressDelay: 300, // 1000ms par défaut | ||
| 32 | navLinks: true, // numéros de jour et de semaines clicables | 31 | navLinks: true, // numéros de jour et de semaines clicables |
| 33 | |||
| 34 | // vue semaine | 32 | // vue semaine |
| 35 | slotEventOverlap: true, // superposition (limitée) de deux évènements simultanés | 33 | slotEventOverlap: true, // superposition (limitée) de deux évènements simultanés |
| 36 | allDayContent: 'Journée', // texte dans la case "toute la journée" | 34 | allDayContent: 'Journée', // texte dans la case "toute la journée" |
| 37 | nowIndicator: true, // barre rouge pour maintenant | 35 | nowIndicator: true, // barre rouge pour maintenant |
| 38 | |||
| 39 | // params en plus: https://fullcalendar.io/docs/events-json-feed | 36 | // params en plus: https://fullcalendar.io/docs/events-json-feed |
| 40 | events: 'index.php?action=get_events', // fichier PHP qui retourne les événements | 37 | events: 'index.php?action=get_events', // fichier PHP qui retourne les événements |
| 41 | 38 | select: function (info) { | |
| 42 | select: function(info){ | ||
| 43 | selected_start_string = info.startStr; // variable "globale" | 39 | selected_start_string = info.startStr; // variable "globale" |
| 44 | hideModal(); | 40 | hideModal(); |
| 45 | }, | 41 | }, |
| 46 | //unselect: function(event, view){}, | 42 | // sélection d'une date simple sur mobile, évite des problèmes de conflit avec eventClick |
| 47 | 43 | dateClick: function (info) { | |
| 48 | eventClick: function(info){ | 44 | if (window.matchMedia('(pointer: coarse)').matches) { |
| 49 | const aside = document.querySelector('aside'); | 45 | const end = new Date(info.date.getTime()); |
| 50 | const checked = info.event.allDay ? 'checked' : ''; | 46 | calendar.view.type === 'dayGridMonth' ? end.setDate(end.getDate() + 1) : end.setMinutes(end.getMinutes() + 30); |
| 51 | 47 | // vue date: la fin est une date exclue | |
| 52 | // change des objets Date en chaînes compatibles avec les input | 48 | // vue semaine: durée de 30min par défaut |
| 53 | function formatDate(date){ | 49 | calendar.select(info.date, end); // appeler select() avec un seul paramètre ne marche pas avec la vue "mois" |
| 54 | return date.getFullYear() + '-' + (date.getMonth() + 1).toString().padStart(2, '0') + '-' + date.getDate().toString().padStart(2, '0') | ||
| 55 | + (info.event.allDay ? '' : 'T' + date.getHours().toString().padStart(2, '0') + ':' + date.getMinutes().toString().padStart(2, '0')); | ||
| 56 | } | ||
| 57 | function minusOneDay(date){ | ||
| 58 | date.setDate(date.getDate() - 1); // jour de fin modifié pour ne pas faire bizarre pour l'utilisateur | ||
| 59 | return date; | ||
| 60 | } | ||
| 61 | |||
| 62 | const start = formatDate(info.event.start); | ||
| 63 | const start_date = start.split('T')[0]; | ||
| 64 | const start_hour = (info.event.allDay ? '' : '<br>à ' + start.split('T')[1]).replace(":", "h"); | ||
| 65 | const formated_start = start_date.split('-')[2] + '/' + start_date.split('-')[1] + '/' + start_date.split('-')[0] + start_hour; | ||
| 66 | const end = formatDate(info.event.allDay ? minusOneDay(info.event.end) : info.event.end, info.event.allDay); | ||
| 67 | const end_date = end.split('T')[0]; | ||
| 68 | const end_hour = (info.event.allDay ? '' : '<br>à ' + end.split('T')[1]).replace(":", "h"); | ||
| 69 | const formated_end = end_date.split('-')[2] + '/' + end_date.split('-')[1] + '/' + end_date.split('-')[0] + end_hour; | ||
| 70 | |||
| 71 | let aside_content = `<div class="event" style="border-color: ` + info.event.backgroundColor +`;"> | ||
| 72 | <h3>` + info.event.title + `</h3> | ||
| 73 | <p><i>` + info.event.extendedProps.description + `</i></p>`; | ||
| 74 | if(checked && (formated_start === formated_end)){ // affichage simplifié évènement d'un jour | ||
| 75 | aside_content = aside_content + `<p>le ` + formated_start + `</p> | ||
| 76 | </div>`; | ||
| 77 | } | 50 | } |
| 78 | else{ | 51 | }, |
| 79 | aside_content = aside_content + `<p>du ` + formated_start + `</p> | 52 | //unselect: function(event, view){}, |
| 80 | <p>au ` + formated_end + `</p> | 53 | eventClick: function (info) { |
| 81 | </div>`; | 54 | if (!info.event.start || !info.event.end) { |
| 55 | throw new Error('modale non conforme'); | ||
| 82 | } | 56 | } |
| 83 | 57 | const modal_view = new CalendarModalView({ | |
| 84 | aside.innerHTML = aside_content; | 58 | mode: 'show', |
| 59 | title: info.event.title, | ||
| 60 | description: info.event.extendedProps.description, | ||
| 61 | color: info.event.backgroundColor, | ||
| 62 | all_day: info.event.allDay, | ||
| 63 | start: info.event.start, | ||
| 64 | end: info.event.end | ||
| 65 | }); | ||
| 66 | modal.innerHTML = modal_view.getView(); | ||
| 85 | calendar.updateSize(); | 67 | calendar.updateSize(); |
| 86 | }, | 68 | }, |
| 87 | viewDidMount: function(info){ // déclenché lorsque qu'une nouvelle vue est chargée (mois, semaine...) | 69 | viewDidMount: function (_info) { |
| 88 | if(selected_start_string){ | 70 | hideModal(); |
| 71 | if (selected_start_string) { | ||
| 89 | calendar.gotoDate(new Date(selected_start_string)); | 72 | calendar.gotoDate(new Date(selected_start_string)); |
| 90 | } | 73 | } |
| 91 | }, | 74 | }, |
| 92 | //datesSet: function(info){}, // déclenché lorsque des dates affichées sont chargées (= comme viewDidMount + changement de date) | 75 | //datesSet: function(info){}, // déclenché lorsque des dates affichées sont chargées (= comme viewDidMount + changement de date) |
| 93 | }); | 76 | }); |
| 94 | 77 | function hideModal() { | |
| 95 | function hideModal(){ | 78 | modal.innerHTML = ''; |
| 96 | const aside = document.querySelector('aside'); | ||
| 97 | aside.innerHTML = ''; | ||
| 98 | calendar.updateSize(); | 79 | calendar.updateSize(); |
| 99 | } | 80 | } |
| 100 | 81 | document.addEventListener('keydown', function (event) { | |
| 101 | document.addEventListener('keydown', function(event){ | 82 | if (event.key === 'Escape') { |
| 102 | if(event.key === 'Escape') { | ||
| 103 | hideModal(); | 83 | hideModal(); |
| 104 | } | 84 | } |
| 105 | }); | 85 | }); |
| 106 | |||
| 107 | // technique de la délégation d'événements pour utiliser un bouton ajouté dynamiquement | 86 | // technique de la délégation d'événements pour utiliser un bouton ajouté dynamiquement |
| 108 | document.addEventListener('click', function(event){ | 87 | document.addEventListener('click', function (event) { |
| 109 | if(event.target.classList.contains('event_close_button')){ | 88 | if (!event.target) { |
| 89 | throw new Error('évènement click non conforme'); | ||
| 90 | } | ||
| 91 | assertElementType(event.target, HTMLElement); | ||
| 92 | if (event.target.classList.contains('event_close_button')) { | ||
| 110 | hideModal(); | 93 | hideModal(); |
| 111 | } | 94 | } |
| 112 | }); | 95 | }); |
| 113 | |||
| 114 | calendar.render(); | 96 | calendar.render(); |
| 115 | }); \ No newline at end of file | 97 | }); \ No newline at end of file |
