aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpolo <ordipolo@gmx.fr>2025-09-18 17:26:24 +0200
committerpolo <ordipolo@gmx.fr>2025-09-18 17:26:24 +0200
commitf977313ff095a10478291334109d9aae40528a34 (patch)
tree7e17b780c15c6882bdd962fb9d97ed2425847245
parentfa3c582a2bd91433399a5b275616052028a5a011 (diff)
downloadcms-f977313ff095a10478291334109d9aae40528a34.zip
gestion correcte des dates des articles: UTC côté serveur, locale côté client + date UTC dans l'attribut date-utc
-rw-r--r--public/js/main.js142
-rw-r--r--public/js/tinymce.js7
-rw-r--r--src/view/NewBuilder.php7
-rw-r--r--src/view/templates/new.php2
4 files changed, 86 insertions, 72 deletions
diff --git a/public/js/main.js b/public/js/main.js
index 2936ea0..d2f8876 100644
--- a/public/js/main.js
+++ b/public/js/main.js
@@ -29,7 +29,7 @@ function copyInClipBoard(link){
29 alert('Cette adresse a été copiée dans le presse-papier:\n\n' + link); 29 alert('Cette adresse a été copiée dans le presse-papier:\n\n' + link);
30} 30}
31 31
32function toastNotify(message) { 32function toastNotify(message){
33 var toast = document.getElementById('toast'); 33 var toast = document.getElementById('toast');
34 toast.textContent = message; 34 toast.textContent = message;
35 toast.className = 'toast show'; 35 toast.className = 'toast show';
@@ -37,7 +37,15 @@ function toastNotify(message) {
37} 37}
38 38
39 39
40document.addEventListener('DOMContentLoaded', () => { // pour pouvoir attraper les balises 40// exécuté à la fin du chargement de la page
41document.addEventListener('DOMContentLoaded', () => {
42
43 // détection des dates et conversion à l'heure locale
44 document.querySelectorAll('.local_date').forEach(function(element){
45 const utc_date = element.getAttribute('date-utc'); // forme: 2025-10-10T12:17:00+00:00
46 element.innerText = toFormatedLocalDate(utc_date);
47 });
48
41 // ouvrir/fermer les sous-menus avec écran tactile 49 // ouvrir/fermer les sous-menus avec écran tactile
42 document.querySelectorAll('.sub-menu-toggle').forEach(button => { 50 document.querySelectorAll('.sub-menu-toggle').forEach(button => {
43 button.addEventListener('click', e => { 51 button.addEventListener('click', e => {
@@ -108,8 +116,7 @@ function switchPositions(article_id, direction)
108 }) 116 })
109 .then(response => response.json()) 117 .then(response => response.json())
110 .then(data => { 118 .then(data => {
111 if(data.success) 119 if(data.success){
112 {
113 if(direction == 'down'){ 120 if(direction == 'down'){
114 current_article.parentElement.insertBefore(other_article, current_article); 121 current_article.parentElement.insertBefore(other_article, current_article);
115 console.log('Inversion réussie'); 122 console.log('Inversion réussie');
@@ -119,12 +126,11 @@ function switchPositions(article_id, direction)
119 console.log('Inversion réussie'); 126 console.log('Inversion réussie');
120 } 127 }
121 else{ 128 else{
122 console.error('Échec de l\'inversion'); 129 console.error("Échec de l'inversion");
123 } 130 }
124 } 131 }
125 else { 132 else{
126 133 console.error("Échec de l'inversion");
127 console.error('Échec de l\'inversion');
128 } 134 }
129 }) 135 })
130 .catch(error => { 136 .catch(error => {
@@ -132,14 +138,42 @@ function switchPositions(article_id, direction)
132 }); 138 });
133} 139}
134 140
135function changeDate(id_date) 141function closeInput(id)
142{
143 const date_span = document.getElementById(id);
144 const date_input = document.getElementById('input-' + id);
145 const date_label = document.getElementById('label-' + id);
146
147 date_span.classList.remove('hidden');
148 date_input.remove();
149 date_label.remove();
150 document.querySelector(`#edit-${id}`).classList.remove('hidden');
151 document.querySelector(`#cancel-${id}`).classList.add('hidden');
152 document.querySelector(`#submit-${id}`).classList.add('hidden');
153}
154
155function findParentByTagName(element, tag_name){
156 while(element !== null){
157 if(element.tagName === tag_name.toUpperCase()){ // tagName est en majuscules
158 return element;
159 }
160 element = element.parentElement;
161 }
162 return null;
163}
164
165
166/* -- fonctions spécifiques à la gestion des dates -- */
167
168function openDatetimeLocalInput(id_date)
136{ 169{
137 const real_id = 'i' + id_date.slice(1); 170 const real_id = 'i' + id_date.slice(1);
138 const date_span = document.getElementById(id_date); // = <span> 171 const date_span = document.getElementById(id_date); // = <span>
139 var old_date = date_span.innerHTML;
140
141 old_date = dateToISO(old_date);
142 172
173 /*var old_date = date_span.innerHTML;*/
174 let old_date = new Date(date_span.getAttribute('date-utc'));
175 old_date = forInputTypeDatetimeLocal(old_date); // 2025-06-03T17:24
176
143 var label = document.createElement('label'); 177 var label = document.createElement('label');
144 label.textContent = 'Choisir une date: '; 178 label.textContent = 'Choisir une date: ';
145 label.id = 'label-' + id_date; 179 label.id = 'label-' + id_date;
@@ -159,39 +193,22 @@ function changeDate(id_date)
159 document.querySelector(`#submit-${id_date}`).classList.remove('hidden'); 193 document.querySelector(`#submit-${id_date}`).classList.remove('hidden');
160} 194}
161 195
162function dateToISO(date){
163 // changer "le 28-12-2024 à 23h14" en "2024-12-28T23:14"
164 let values = date.split(" à "); // 2 parties: date et heure
165 values[1] = values[1].replace('h', ':');
166 values[0] = values[0].replace("le ", "");
167 let date_array = values[0].split("-"); // tableau jj-mm-aaaa
168 return date_array[2] + '-' + date_array[1] + "-" + date_array[0] + "T" + values[1];
169}
170
171function closeInput(id)
172{
173 const date_span = document.getElementById(id);
174 const date_input = document.getElementById('input-' + id);
175 const date_label = document.getElementById('label-' + id);
176
177 date_span.classList.remove('hidden');
178 date_input.remove();
179 date_label.remove();
180 document.querySelector(`#edit-${id}`).classList.remove('hidden');
181 document.querySelector(`#cancel-${id}`).classList.add('hidden');
182 document.querySelector(`#submit-${id}`).classList.add('hidden');
183}
184
185function submitDate(id_date) 196function submitDate(id_date)
186{ 197{
187 var date_input = document.getElementById('input-' + id_date); 198 const date_input = document.getElementById('input-' + id_date);
199 const date_span = document.getElementById(id_date);
200
201 let date = new Date(date_input.value); // forme: 2025-02-04T00:24
202 let utc_date = date.toISOString(); // forme: 2025-02-03T23:24:00.000Z
188 203
189 // cas des nouvelles "news" 204 // cas des nouvelles "news"
190 const params = new URL(document.location).searchParams; // "search" = ? et paramètres, searchParams = objet avec des getters 205 const params = new URL(document.location).searchParams; // "search" = ? et paramètres, searchParams = objet avec des getters
191 if(params != null && params.get("id")[0] === 'n') 206 if(params != null && params.get("id")[0] === 'n')
192 { 207 {
193 // modifier la date dans le <span> caché 208 // modifier la date dans le <span> caché ET l'attribut date-utc
194 date_input = updateDate(id_date, date_input); 209 date_span.setAttribute('date-utc', utc_date); // heure UTC
210 date_span.innerHTML = toFormatedLocalDate(utc_date); // heure locale
211
195 closeInput(id_date); 212 closeInput(id_date);
196 return; 213 return;
197 } 214 }
@@ -201,44 +218,41 @@ function submitDate(id_date)
201 headers: { 218 headers: {
202 'Content-Type': 'application/json' 219 'Content-Type': 'application/json'
203 }, 220 },
204 body: JSON.stringify({id: id_date, date: date_input.value}) 221 body: JSON.stringify({id: id_date, date: utc_date.slice(0, 16)}) // heure UTC
205 }) 222 })
206 .then(response => response.json()) 223 .then(response => response.json())
207 .then(data => { 224 .then(data => {
208 if (data.success) { 225 if(data.success){
209 // modifier la date dans le <span> caché 226 // modifier la date dans le <span> caché ET l'attribut date-utc
210 date_input = updateDate(id_date, date_input); 227 date_span.setAttribute('date-utc', utc_date); // heure UTC
228 date_span.innerHTML = toFormatedLocalDate(utc_date); // heure locale
229
211 closeInput(id_date); 230 closeInput(id_date);
212 } 231 }
213 else { 232 else{
214 console.error('Erreur lors de la sauvegarde de la date.'); 233 console.error('Erreur lors de la sauvegarde de la date.');
215 } 234 }
216 }) 235 })
217 .catch(error => { 236 .catch(error => {
218 console.error('Erreur:', error); 237 console.error('Erreur:', error);
219 }); 238 });
220 } 239 }
221} 240}
222 241
223function updateDate(id_date, date_input){ 242function toFormatedLocalDate(utc_string_date){ // forme: 2025-07-17T13:54:00.000Z ou 2025-02-04T00:24
224 var date_span = document.getElementById(id_date); 243 const date = new Date(utc_string_date);
225 let date = new Date(date_input.value);
226 date_span.innerHTML =
227 'le ' + String(date.getDate()).padStart(2, '0') + '-' +
228 String(date.getMonth() + 1).padStart(2, '0') + '-' +
229 String(date.getFullYear()).padStart(4, '0') + ' à ' +
230 String(date.getHours()).padStart(2, '0') + 'h' +
231 String(date.getMinutes()).padStart(2, '0');
232
233 return date_input;
234}
235 244
236function findParentByTagName(element, tag_name){ 245 // donne l'heure locale, forme: le 10-10-2025 à 14:17
237 while(element !== null){ 246 return 'le ' + String(date.getDate()).padStart(2, '0')
238 if(element.tagName === tag_name.toUpperCase()){ // tagName est en majuscules 247 + '-' + String(date.getMonth() + 1).padStart(2, '0') // mois comptés à partir de 0 !!
239 return element; 248 + '-' + date.getFullYear()
240 } 249 + ' à ' + String(date.getHours()).padStart(2, '0')
241 element = element.parentElement; 250 + 'h' + String(date.getMinutes()).padStart(2, '0');
242 } 251}
243 return null; 252function forInputTypeDatetimeLocal(date){ // forme: 2024-12-28T23:14
253 return date.getFullYear()
254 + '-' + String(date.getMonth() + 1).padStart(2, '0') // mois comptés à partir de 0 !!
255 + '-' + String(date.getDate()).padStart(2, '0')
256 + 'T' + String(date.getHours()).padStart(2, '0')
257 + ':' + String(date.getMinutes()).padStart(2, '0');
244} \ No newline at end of file 258} \ No newline at end of file
diff --git a/public/js/tinymce.js b/public/js/tinymce.js
index 81ba8ea..97ecad8 100644
--- a/public/js/tinymce.js
+++ b/public/js/tinymce.js
@@ -292,7 +292,6 @@ class Editor
292 } 292 }
293 293
294 submit(clone = null){ 294 submit(clone = null){
295 //var editor;
296 var content; 295 var content;
297 const params = new URL(document.location).searchParams; // "search" = ? et paramètres, searchParams = objet avec des getters 296 const params = new URL(document.location).searchParams; // "search" = ? et paramètres, searchParams = objet avec des getters
298 // à comparer avec: new URLSearchParams(window.location.search); 297 // à comparer avec: new URLSearchParams(window.location.search);
@@ -312,9 +311,12 @@ class Editor
312 if(first_letter === 'i'){ 311 if(first_letter === 'i'){
313 id_from_builder = element.id; 312 id_from_builder = element.id;
314 } 313 }
314 else if(first_letter === 'd'){
315 content[first_letter] = element.getAttribute('date-utc');
316 }
315 } 317 }
316 }) 318 })
317 content['d'] = dateToISO(content['d']); 319 content['d'] = new Date(content['d']).toISOString().slice(0, 16); // date UTC, format: 2025-09-18T15:21
318 } 320 }
319 // champs à remplir des nouvelles "news" 321 // champs à remplir des nouvelles "news"
320 else if(window.Config.page === 'article' && params != null && params.get("id")[0] === 'n'){ 322 else if(window.Config.page === 'article' && params != null && params.get("id")[0] === 'n'){
@@ -324,7 +326,6 @@ class Editor
324 // dans les autres cas, on doit pouvoir récupérer l'éditeur 326 // dans les autres cas, on doit pouvoir récupérer l'éditeur
325 else{ 327 else{
326 // l'éditeur correspond à l'article OU si page = "article" à un élément: titre, aperçu, article 328 // l'éditeur correspond à l'article OU si page = "article" à un élément: titre, aperçu, article
327 //editor = editors[id];
328 if(!this.tiny_instance){ 329 if(!this.tiny_instance){
329 console.error("Éditeur non trouvé pour l'article:", this.id); 330 console.error("Éditeur non trouvé pour l'article:", this.id);
330 return; 331 return;
diff --git a/src/view/NewBuilder.php b/src/view/NewBuilder.php
index cd5534b..2a082dd 100644
--- a/src/view/NewBuilder.php
+++ b/src/view/NewBuilder.php
@@ -61,9 +61,8 @@ class NewBuilder extends AbstractBuilder
61 $from_to_button = '<p><a class="link_to_article" href="' . new URL(['page' => 'article', 'id' => $id, 'from' => CURRENT_PAGE]) . '"><button><img class="action_icon" src="assets/book-open.svg">Lire la suite</button></a></p>'; 61 $from_to_button = '<p><a class="link_to_article" href="' . new URL(['page' => 'article', 'id' => $id, 'from' => CURRENT_PAGE]) . '"><button><img class="action_icon" src="assets/book-open.svg">Lire la suite</button></a></p>';
62 } 62 }
63 63
64 64 $date = $node->getArticle()->getDateTime()->format('Y-m-d\TH:i:s.v\Z'); // format: 2025-07-17T13:54:00.000Z
65 $date_object = $node->getArticle()->getDateTime(); // class DateTime 65 // format(\DateTime::ATOM) produit le format: 2025-10-10T12:17:00+00:00, c'est aussi de la norme ISO, mais à éviter pour être compatible avec date.toISOString en JS
66 $date = 'le ' . str_replace(':', 'h', $date_object->format('d-m-Y à H:i'));
67 66
68 // partage 67 // partage
69 $share_link = new URL(['page' => 'article', 'id' => $id]); 68 $share_link = new URL(['page' => 'article', 'id' => $id]);
@@ -108,7 +107,7 @@ class NewBuilder extends AbstractBuilder
108 $submit_article = '<p id="submit-' . $id_content . '" class="hidden"><button ' . $submit_js_article . '>Valider</button></p>'; 107 $submit_article = '<p id="submit-' . $id_content . '" class="hidden"><button ' . $submit_js_article . '>Valider</button></p>';
109 $article_buttons = '<div class="button_zone">' . $modify_article . $close_editor_article . $submit_article . '</div>'; 108 $article_buttons = '<div class="button_zone">' . $modify_article . $close_editor_article . $submit_article . '</div>';
110 109
111 $date_js = 'onclick="changeDate(\'' . $id_date . '\', \'article\');'; 110 $date_js = 'onclick="openDatetimeLocalInput(\'' . $id_date . '\', \'article\');';
112 $modify_date = '<p id="edit-' . $id_date . '"><button ' . $date_js . '"><img class="action_icon" src="assets/edit.svg">Date</button></p>' . "\n"; 111 $modify_date = '<p id="edit-' . $id_date . '"><button ' . $date_js . '"><img class="action_icon" src="assets/edit.svg">Date</button></p>' . "\n";
113 $close_js_date = 'onclick="closeInput(\'' . $id_date . '\')"'; 112 $close_js_date = 'onclick="closeInput(\'' . $id_date . '\')"';
114 $close_editor_date = '<p id="cancel-' . $id_date . '" class="hidden"><button ' . $close_js_date . '>Annuler</button></p>'; 113 $close_editor_date = '<p id="cancel-' . $id_date . '" class="hidden"><button ' . $close_js_date . '>Annuler</button></p>';
diff --git a/src/view/templates/new.php b/src/view/templates/new.php
index bda7daf..b1b3453 100644
--- a/src/view/templates/new.php
+++ b/src/view/templates/new.php
@@ -18,7 +18,7 @@
18 <div class="under_an_article"> 18 <div class="under_an_article">
19 <p> 19 <p>
20 <img src="assets/calendar.svg"> 20 <img src="assets/calendar.svg">
21 <span class="data" id="<?= $id_date ?>"><?= $date ?></span> 21 <span class="data local_date" id="<?= $id_date ?>" date-utc="<?= $date ?>">Chargement...</span>
22 </p> 22 </p>
23 </div> 23 </div>
24 <?= $date_buttons ?> 24 <?= $date_buttons ?>