summaryrefslogtreecommitdiff
path: root/public/js/calendar.js
diff options
context:
space:
mode:
Diffstat (limited to 'public/js/calendar.js')
-rw-r--r--public/js/calendar.js269
1 files changed, 269 insertions, 0 deletions
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 @@
1document.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 const aside = document.querySelector('aside');
38 let start_value;
39
40 // on veut des chaines de la forme 2025-05-20T07:05
41 // il faut retirer les secondes et le fuseau horaire du format ISO, c'est chiant
42 // enverra par contre une chaine ISO au serveur pour avoir un enregistrement correct
43 //selected_start = document.getElementById('event_start');
44
45 const end = new Date(info.endStr);
46 if(calendar.view.type == 'dayGridMonth'){
47 start_value = info.startStr + 'T10:00';
48 end.setDate(end.getDate() - 1);
49 end.setHours(11);
50 }
51 else if(calendar.view.type == 'timeGridWeek' || calendar.view.type == 'timeGridDay'){
52 const start_array = info.startStr.split("T");
53 start_value = start_array[0] + "T" + start_array[1].substr(0,5); // format 2025-06-12T10:00
54 }
55
56 const end_value = end.toISOString().split('T')[0] + "T" + String(end.getHours()).padStart(2, '0') + ":" + String(end.getMinutes()).padStart(2, '0');
57 selected_start_string = start_value;
58
59 //console.log(info.endStr);
60 //console.log(end_value.value);
61
62 const aside_content = `<div class="form_event">
63 <div class="event_title_box">
64 <h2>Nouvel évènement</h2>
65 </div>
66 <div class="">
67 <label for="event_title">Nom</label>
68 <input type="text" id="event_title">
69 </div>
70 <div class="">
71 <input type="checkbox" id="event_all_day">
72 <label for="event_all_day">Journée entière</label>
73 </div>
74 <div class="">
75 <label for="event_start">Début</label>
76 <input type="datetime-local" id="event_start" value="` + start_value + `">
77 </div>
78 <div class="">
79 <label for="event_end">Fin</label>
80 <input type="datetime-local" id="event_end" value="` + end_value + `">
81 </div>
82 <div class="">
83 <label for="event_color">Couleur</label>
84 <input type="color" id="event_color" value="#3788D8">
85 </div>
86 <button class="submit_new_event">Enregistrer</button>
87 <button class="event_close_button">Annuler</button>
88 </div>`;
89 aside.innerHTML = aside_content;
90 calendar.updateSize();
91 },
92 //~ unselect: function(event, view) {
93 //~ const aside = document.querySelector('aside');
94 //~ aside.innerHTML = '';
95 //~ //calendar.updateSize();
96 //~ },
97 eventClick: function(info){
98 const aside = document.querySelector('aside');
99 const checked = info.event.allDay ? 'checked' : '';
100 const input = info.event.allDay ? 'date' : 'datetime-local';
101
102 // change des objets Date en chaînes compatibles avec des input type datetime-local, ex: 2025-05-20T07:05
103 function formatDate(date, all_day){
104 return date.getFullYear() + '-' + (date.getMonth() + 1).toString().padStart(2, '0') + '-' + date.getDate().toString().padStart(2, '0')
105 + (all_day ? '' : 'T' + date.getHours().toString().padStart(2, '0') + ':' + date.getMinutes().toString().padStart(2, '0'));
106 }
107 const formated_start = formatDate(info.event.start, info.event.allDay);
108 const formated_end = formatDate(info.event.end, info.event.allDay);
109
110 const aside_content = `<div class="form_event">
111 <div class="event_title_box">
112 <h2>Modifier un évènement</h2>
113 </div>
114 <div class="">
115 <label for="event_title">Nom</label>
116 <input type="text" id="event_title" value="` + info.event.title + `">
117 <input type="hidden" id="event_id" value="` + info.event.id +`">
118 </div>
119 <div class="">
120 <input type="checkbox" id="event_all_day" class="event_all_day" ` + checked + `>
121 <label for="event_all_day">Journée entière</label>
122 </div>
123 <div class="">
124 <label for="event_start">Début</label>
125 <input type="` + input + `" id="event_start" value="` + formated_start + `">
126 </div>
127 <div class="">
128 <label for="event_end">Fin</label>
129 <input type="` + input + `" id="event_end" value="` + formated_end + `">
130 </div>
131 <div class="">
132 <label for="event_color">Couleur</label>
133 <input type="color" id="event_color" value="` + info.event.backgroundColor + `">
134 </div>
135 <button class="submit_update_event">Modifier</button>
136 <button class="event_close_button">Annuler</button>
137 </div>`;
138 aside.innerHTML = aside_content;
139 calendar.updateSize();
140 },
141 viewDidMount: function(info){ // déclenché lorsque qu'une nouvelle vue est chargée (mois, semaine...)
142 if(selected_start_string){
143 calendar.gotoDate(new Date(selected_start_string));
144 }
145 },
146 //datesSet: function(info){}, // déclenché lorsque des dates affichées sont chargées (= comme viewDidMount + changement de date)
147 events: '../src/load-events.php' // fichier PHP qui retourne les événements
148 });
149
150 function hideModal(){
151 const aside = document.querySelector('aside');
152 aside.innerHTML = '';
153 calendar.updateSize();
154 }
155
156 function submitEvent(new_event){
157 const event_title = document.getElementById('event_title').value;
158 const event_all_day = document.getElementById('event_all_day').checked;
159 const event_start = document.getElementById('event_start').value;
160 const event_end = document.getElementById('event_end').value;
161 const event_color = document.getElementById('event_color').value; // #3788d8 par défaut
162 const event_id = new_event ? '' : document.getElementById('event_id').value;
163
164 if(event_title.length !== 0 && event_start.length !== 0 && event_end.length !== 0 && event_color.length !== 0
165 && (new_event || event_id.length !== 0))
166 {
167 const event_start_utc = new Date(event_start).toISOString(); // heure UTC pour fullcalendar (et pour le serveur)
168 const event_end_utc = new Date(event_end).toISOString();
169
170 if(event_start_utc >= event_end_utc){
171 return;
172 }
173
174 // création
175 if(new_event){
176 /*const current_view = calendar.view;
177 switch(current_view.type){
178 case 'dayGridMonth':
179 console.log('mois');
180 break;
181 case 'timeGridWeek':
182 console.log('semaine');
183 break;
184 case 'timeGridDay':
185 console.log('jour');
186 break;
187 default:
188 console.log('erreur');
189 }*/
190 calendar.addEvent({
191 // pas d'id, c'est au serveur de le créer
192 title: event_title,
193 allDay: event_all_day,
194 start: event_start_utc,
195 end: event_end_utc,
196 color: event_color
197 });
198 }
199 // modification
200 else{
201 const event = calendar.getEventById(event_id);
202
203 if(event){
204 event.setProp('title', event_title);
205 event.setAllDay(event_all_day);
206 event.setStart(event_start_utc);
207 event.setEnd(event_end_utc);
208 event.setProp('color', event_color);
209 }
210 else{
211 console.log("Événement non trouvé !");
212 }
213 }
214
215 hideModal();
216 }
217 else{
218 // notif input vide
219 console.log('erreur: input vide');
220 }
221 }
222
223 function checkAllDay(){
224 const event_start_input = document.getElementById('event_start');
225 const event_end_input = document.getElementById('event_end');
226
227 const start = event_start_input.value;
228 const end = event_end_input.value;
229
230 if(document.getElementById('event_all_day').checked){
231 event_start_input.type = 'date';
232 event_end_input.type = 'date';
233
234 event_start_input.value = start.split('T')[0];
235 event_end_input.value = end.split('T')[0];
236 }
237 else{
238 event_start_input.type = 'datetime-local';
239 event_end_input.type = 'datetime-local';
240
241 event_start_input.value = start + 'T10:00';
242 event_end_input.value = end + 'T11:00';
243 }
244 }
245
246 document.addEventListener('keydown', function(event){
247 if(event.key === 'Escape') {
248 hideModal();
249 }
250 });
251
252 // technique de la délégation d'événements pour utiliser un bouton ajouté dynamiquement
253 document.addEventListener('click', function(event){
254 if(event.target.classList.contains('event_close_button')){
255 hideModal();
256 }
257 else if(event.target.classList.contains('event_all_day')){
258 checkAllDay();
259 }
260 else if(event.target.classList.contains('submit_new_event')){
261 submitEvent(true);
262 }
263 else if(event.target.classList.contains('submit_update_event')){
264 submitEvent(false);
265 }
266 });
267
268 calendar.render();
269}); \ No newline at end of file