From 15cbf5d56b4644151d59fee512f5f8fbe496caa3 Mon Sep 17 00:00:00 2001 From: polo Date: Thu, 9 Oct 2025 01:35:52 +0200 Subject: pagination partie 2, nouvelles fonctions + renommage dans Director, ArticleController::fetch, et en JS: fetchArticles, insertLocalDates, modifs dans changePaginationLimit, dans les vues --- public/js/main.js | 57 ++++++++++++++++++++++++++++++++---- public/js/modif_page.js | 78 ++++++++++++++++++++++++++++++++++++++++++------- public/js/tinymce.js | 28 +++++++++--------- 3 files changed, 132 insertions(+), 31 deletions(-) (limited to 'public/js') diff --git a/public/js/main.js b/public/js/main.js index d2f8876..59a9331 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -36,15 +36,10 @@ function toastNotify(message){ setTimeout(function(){ toast.className = toast.className.replace('show', ''); }, 5000); } - // exécuté à la fin du chargement de la page document.addEventListener('DOMContentLoaded', () => { - // détection des dates et conversion à l'heure locale - document.querySelectorAll('.local_date').forEach(function(element){ - const utc_date = element.getAttribute('date-utc'); // forme: 2025-10-10T12:17:00+00:00 - element.innerText = toFormatedLocalDate(utc_date); - }); + insertLocalDates(); // ouvrir/fermer les sous-menus avec écran tactile document.querySelectorAll('.sub-menu-toggle').forEach(button => { @@ -85,6 +80,48 @@ document.addEventListener('DOMContentLoaded', () => { }); +function fetchArticles(bloc_id){ + const parent = document.getElementById(bloc_id); + + const block_type = parent.getAttribute('block-type'); + let last_article = ''; + if(block_type === 'post_block'){ + // pas parfait, suppose que les positions sont correctes + last_article = parent.querySelectorAll('article').length - 1; + } + else if(block_type === 'news_block'){ + // date_time du dernier article affiché (heure UTC), date vide si bloc vide + const news_elements = parent.querySelector('.section_child').querySelectorAll('article'); + last_article = news_elements.length !== 0 ? news_elements[news_elements.length - 1].querySelector('.local_date').getAttribute('date-utc') : ''; + } + else{ + console.log("Erreur, le type de bloc n'est pas reconnu"); + return; + } + + fetch('index.php?fetch=next_articles&id=' + bloc_id + '&last_article=' + last_article) // méthode GET par défaut + .then(response => response.json()) + .then(data => { + if(data.success){ + // insérer les articles + parent.querySelector('.section_child').innerHTML += data.html; + insertLocalDates(); + + // cacher le bouton + parent.querySelector('.fetch_articles').querySelector('button').className = data.truncated ? '' : 'hidden'; + + console.log("Articles insérés dans le bloc"); + } + else{ + console.log("Erreur côté serveur à la récupération d'articles"); + } + }) + .catch(error => { + console.error('Erreur:', error); + }); +} + + // complète les fonctions dans tinymce.js function switchPositions(article_id, direction) { @@ -239,6 +276,14 @@ function submitDate(id_date) } } +function insertLocalDates(){ + // détection des dates et conversion à l'heure locale + document.querySelectorAll('.local_date').forEach(function(element){ + const utc_date = element.getAttribute('date-utc'); // forme: 2025-10-10T12:17:00+00:00 + element.innerText = toFormatedLocalDate(utc_date); + }); +} + function toFormatedLocalDate(utc_string_date){ // forme: 2025-07-17T13:54:00.000Z ou 2025-02-04T00:24 const date = new Date(utc_string_date); diff --git a/public/js/modif_page.js b/public/js/modif_page.js index bf269ee..15f3598 100644 --- a/public/js/modif_page.js +++ b/public/js/modif_page.js @@ -1,5 +1,8 @@ /* -- mode modification d'une page -- */ +// beaucoup de fonctions similaires +// à factoriser avec le pattern stratégie? + // même fonction que dans new_page.js function makePageNamePath(){ document.getElementById("page_name_path").value = document.getElementById("page_name").value @@ -92,7 +95,7 @@ function changeDescription(node_data_id){ toastNotify("la nouvelle description de la page est: " + data.description); } else{ - console.error('Erreur à la modification de la description de la page.'); + console.error('Erreur côté serveur à la modification de la description de la page.'); } }) .catch(error => { @@ -119,7 +122,7 @@ function renamePageBloc(bloc_id){ toastNotify('Le bloc a été renommé: ' + data.title); } else{ - console.error('Erreur au renommage du titre.'); + console.error('Erreur côté serveur au renommage du titre.'); } }) .catch(error => { @@ -168,7 +171,7 @@ function switchBlocsPositions(bloc_id, direction) { } else { - console.error('Échec de l\'inversion'); + console.error("Échec de l'inversion côté serveur"); } }) .catch(error => { @@ -187,17 +190,21 @@ function articlesOrderSelect(bloc_id){ .then(response => response.json()) .then(data => { if(data.success){ - // inverser l'ordre des articles!! - const parent = document.getElementById(bloc_id).querySelector(".section_child"); + // inversion des articles + /*const parent = document.getElementById(bloc_id).querySelector(".section_child"); const articles = Array.from(parent.querySelectorAll("article")); articles.reverse().forEach(article => { parent.appendChild(article); // déplace dans le DOM, ne copie pas - }); + });*/ + + // à cause de la pagination, au lieu d'inverser, on remplace les articles par les 1er dans le nouveau sens + document.getElementById(bloc_id).querySelector('.section_child').innerHTML = ''; + fetchArticles(bloc_id); console.log('ordre ' + articles_order_select); } else{ - console.log("Erreur au changement de l'ordre d'affichage côté serveur"); + console.log("Erreur côté serveur au changement de l'ordre d'affichage"); } }) .catch(error => { @@ -219,10 +226,10 @@ function changePresentation(bloc_id){ document.getElementById(bloc_id).className = presentation; document.getElementById(bloc_id).querySelector(".section_child").style.gridTemplateColumns = presentation === 'grid' ? 'repeat(auto-fit, minmax(' + data.cols_min_width + 'px, 1fr))' : ''; document.getElementById('cols_min_width_edit_' + bloc_id).className = presentation === 'grid' ? '' : 'hidden'; - console.log('changement de présentation'); + console.log('Changement de présentation'); } else{ - console.log('Erreur au changement de présentation côté serveur'); + console.log('Erreur côté serveur au changement de présentation'); } }) .catch(error => { @@ -230,6 +237,7 @@ function changePresentation(bloc_id){ }); } +// ressemble à changePaginationLimit function changeColsMinWidth(bloc_id){ const cols_min_width_input = document.getElementById('cols_min_width_select_' + bloc_id); @@ -250,10 +258,58 @@ function changeColsMinWidth(bloc_id){ if(data.success){ document.getElementById(bloc_id).className = 'grid'; document.getElementById(bloc_id).querySelector(".section_child").style.gridTemplateColumns = 'repeat(auto-fit, minmax(' + data.cols_min_width + 'px, 1fr))'; - console.log('changement de la largeur minimum en mode grille'); + console.log('Changement de la largeur minimum en mode grille'); + } + else{ + console.log('Erreur côté serveur au changement du nb de colonnes en mode grille'); + } + }) + .catch(error => { + console.error('Erreur:', error); + }); +} + +// ressemble à changeColsMinWidth +function changePaginationLimit(bloc_id){ + const pagination_limit_input = document.getElementById('pagination_limit_' + bloc_id); + + if(pagination_limit_input.value > 30){ + pagination_limit_input.value = 30; + } + else if(pagination_limit_input.value < 0){ + pagination_limit_input.value = 0; // fait joli dans la BDD, les valeurs négatives ont le même effet que 0 + } + + fetch('index.php?bloc_edit=change_pagination_limit', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ id: bloc_id, pagination_limit: pagination_limit_input.value }) + }) + .then(response => response.json()) + .then(data => { + if(data.success){ + const parent = document.getElementById(bloc_id).querySelector('.section_child'); + const articles_list = parent.querySelectorAll('article'); + + if(data.new_limit > data.old_limit || data.new_limit <= 0){ // si 0, fetchArticles va TOUT chercher! + parent.innerHTML = ''; // pas opti, mais améliorer ça serait très compliqué + fetchArticles(bloc_id); + } + else if(data.new_limit < articles_list.length){ + // retirer les articles + const articles_array = Array.from(articles_list).slice(0, data.new_limit); + parent.innerHTML = ''; + for(let i = 0; i < articles_array.length; i++){ + parent.appendChild(articles_array[i]); + } + // remettre le bouton "Articles suivants" + document.getElementById(bloc_id).querySelector('.fetch_articles').querySelector('button').className = ''; + } + + console.log("Changement du nombre d'articles affichés simultanément dans ce bloc"); } else{ - console.log('Erreur au changement du nb de colonnes en mode grille côté serveur'); + console.log("Erreur côté serveur au changement du nb d'éléments affichés par la pagination"); } }) .catch(error => { diff --git a/public/js/tinymce.js b/public/js/tinymce.js index 97ecad8..d2f9c46 100644 --- a/public/js/tinymce.js +++ b/public/js/tinymce.js @@ -1,5 +1,5 @@ // code à réorganiser -// seule certaines fonctions ont leur place dans Editor, d'autres servent à manipuler les articles d'une autre manière (déplacer, supprimer...) +// seules certaines fonctions ont leur place dans Editor, d'autres servent à manipuler les articles d'une autre manière (déplacer, supprimer...) // => encapsuler Editor dans une classe Article (comme la balise) qui existe même quand l'éditeur est fermé @@ -292,7 +292,7 @@ class Editor } submit(clone = null){ - var content; + let content; const params = new URL(document.location).searchParams; // "search" = ? et paramètres, searchParams = objet avec des getters // à comparer avec: new URLSearchParams(window.location.search); // c'est pareil ou pas? @@ -302,7 +302,7 @@ class Editor const prefixes = ['t', 'p', 'i', 'd']; const allElemsWithId = document.querySelectorAll('.data'); content = {}; - var id_from_builder; + let id_from_builder; allElemsWithId.forEach(element => { const first_letter = element.id.charAt(0).toLowerCase(); @@ -394,14 +394,14 @@ class Editor // restera ici jusqu'à ce que la gestion des balises soient faite ailleurs function makeNewArticleButtons(id, article_id, clone, placement = 'last') { - var share_btn = document.querySelector(`.share.hidden`); // combinaison de deux classes - var new_btn = document.getElementById(`new-${id}`); - var edit_btn = document.getElementById(`edit-${id}`); - var pos_up_btn = document.getElementById(`position_up-${id}`); - var pos_down_btn = document.getElementById(`position_down-${id}`); - var delete_btn = document.getElementById(`delete-${id}`); - var cancel_btn = document.getElementById(`cancel-${id}`); - var submit_btn = document.getElementById(`submit-${id}`); + let share_btn = document.querySelector(`.share.hidden`); // combinaison de deux classes + let new_btn = document.getElementById(`new-${id}`); + let edit_btn = document.getElementById(`edit-${id}`); + let pos_up_btn = document.getElementById(`position_up-${id}`); + let pos_down_btn = document.getElementById(`position_down-${id}`); + let delete_btn = document.getElementById(`delete-${id}`); + let cancel_btn = document.getElementById(`cancel-${id}`); + let submit_btn = document.getElementById(`submit-${id}`); share_btn.classList.remove('hidden'); new_btn.classList.add('hidden'); @@ -412,8 +412,8 @@ function makeNewArticleButtons(id, article_id, clone, placement = 'last') //cancel_btn.classList.add('hidden'); //submit_btn.classList.add('hidden'); - var article = document.getElementById(id); - var article_elem_parent = findParentByTagName(article, 'article'); + let article = document.getElementById(id); + let article_elem_parent = findParentByTagName(article, 'article'); share_btn.setAttribute('onclick', "copyInClipBoard('" + window.location.href + article_id + "')"); // # de l'ancre ajouté au clic sur le lien ouvrant l'éditeur article.id = article_id; @@ -430,7 +430,7 @@ function makeNewArticleButtons(id, article_id, clone, placement = 'last') submit_btn.id = 'submit-' + article_id; submit_btn.querySelector('button').setAttribute('onclick', "submitArticle('" + article_id + "')"); - var section_child = article_elem_parent.parentNode.querySelector('.section_child'); // renommer section_child + let section_child = article_elem_parent.parentNode.querySelector('.section_child'); // renommer section_child // parentNode vise la balise section article_elem_parent.parentNode.replaceChild(clone.cloneNode(true), article_elem_parent); // clone du squelette pour le garder intact -- cgit v1.2.3