From 68b6058e2a27fc251c117c4efeb141392a0c9736 Mon Sep 17 00:00:00 2001 From: polo Date: Sun, 6 Apr 2025 12:18:49 +0200 Subject: =?UTF-8?q?nouvel=20article,=20boutons=20dans=20les=20builders,=20?= =?UTF-8?q?makeArticleNode,=20JS=20MAJ=20page,=20tri=20quand=20d=C3=A9plac?= =?UTF-8?q?ement=20ou=20suppression?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/css/main.css | 14 +++- public/css/trombinoscope.css | 6 ++ public/images/SAR_Constructions.jpg | Bin 0 -> 571935 bytes public/images/Ysoline Rabin.jpg | Bin 0 -> 4993 bytes public/images/beatrice_carre.jpg | Bin 0 -> 4475 bytes public/images/eaulibre.jpg | Bin 0 -> 53251 bytes public/images/frank_pouliquen.jpg | Bin 0 -> 27842 bytes public/images/leclerc_bigouden.png | Bin 0 -> 82228 bytes public/images/silhouette nageur.jpg | Bin 0 -> 11805 bytes public/images/silhouette nageuse.jpg | Bin 0 -> 18499 bytes public/images/yves_pouliquen.jpg | Bin 0 -> 37276 bytes public/index.php | 4 +- public/js/main.js | 30 +++++-- public/js/tinymce.js | 151 +++++++++++++++++++++++++++++------ src/controller/Director.php | 93 ++++++++++++++------- src/controller/Security.php | 2 +- src/controller/ajax.php | 88 +++++++++++++++----- src/model/entities/Article.php | 8 +- src/model/entities/Node.php | 71 ++++++++++------ src/view/AbstractBuilder.php | 6 ++ src/view/ArticleBuilder.php | 14 ++-- src/view/BlogBuilder.php | 41 +++++++--- src/view/GaleryBuilder.php | 41 +++++++--- src/view/GridBuilder.php | 47 +++++++---- src/view/templates/article.php | 1 - src/view/templates/blog.php | 8 +- src/view/templates/galery.php | 7 +- src/view/templates/grid.php | 6 +- 28 files changed, 479 insertions(+), 159 deletions(-) create mode 100644 public/images/SAR_Constructions.jpg create mode 100644 public/images/Ysoline Rabin.jpg create mode 100644 public/images/beatrice_carre.jpg create mode 100644 public/images/eaulibre.jpg create mode 100644 public/images/frank_pouliquen.jpg create mode 100644 public/images/leclerc_bigouden.png create mode 100644 public/images/silhouette nageur.jpg create mode 100644 public/images/silhouette nageuse.jpg create mode 100644 public/images/yves_pouliquen.jpg diff --git a/public/css/main.css b/public/css/main.css index 50c2173..cb44e16 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -28,8 +28,8 @@ section > p /* boutons spéciaux mode admin */ } .galery_photos .html_from_editor img { - max-width: 400px; - max-height: 250px; + max-width: 300px; + max-height: 200px; } article { @@ -50,6 +50,11 @@ article .logo2 { width: 100%; } +article img +{ + max-width: 100%; + height: auto; +} .new_content_text { max-height: 250px; @@ -120,4 +125,9 @@ main button:hover cursor: pointer; /* curseur qui pointe du doigt */ background-color: #ffff00; border-radius: 4px; +} + +article a:hover +{ + cursor: pointer; } \ No newline at end of file diff --git a/public/css/trombinoscope.css b/public/css/trombinoscope.css index f42dad8..357e6b0 100644 --- a/public/css/trombinoscope.css +++ b/public/css/trombinoscope.css @@ -1,4 +1,10 @@ article img { border-radius: 50%; +} + +.grid_columns +{ + /* écrase les 3 colonnes par défaut */ + grid-template-columns: repeat(4, 1fr); } \ No newline at end of file diff --git a/public/images/SAR_Constructions.jpg b/public/images/SAR_Constructions.jpg new file mode 100644 index 0000000..1b9cb81 Binary files /dev/null and b/public/images/SAR_Constructions.jpg differ diff --git a/public/images/Ysoline Rabin.jpg b/public/images/Ysoline Rabin.jpg new file mode 100644 index 0000000..2ecfcc4 Binary files /dev/null and b/public/images/Ysoline Rabin.jpg differ diff --git a/public/images/beatrice_carre.jpg b/public/images/beatrice_carre.jpg new file mode 100644 index 0000000..8db4036 Binary files /dev/null and b/public/images/beatrice_carre.jpg differ diff --git a/public/images/eaulibre.jpg b/public/images/eaulibre.jpg new file mode 100644 index 0000000..02b1917 Binary files /dev/null and b/public/images/eaulibre.jpg differ diff --git a/public/images/frank_pouliquen.jpg b/public/images/frank_pouliquen.jpg new file mode 100644 index 0000000..7bb3ead Binary files /dev/null and b/public/images/frank_pouliquen.jpg differ diff --git a/public/images/leclerc_bigouden.png b/public/images/leclerc_bigouden.png new file mode 100644 index 0000000..596ead7 Binary files /dev/null and b/public/images/leclerc_bigouden.png differ diff --git a/public/images/silhouette nageur.jpg b/public/images/silhouette nageur.jpg new file mode 100644 index 0000000..526cc0f Binary files /dev/null and b/public/images/silhouette nageur.jpg differ diff --git a/public/images/silhouette nageuse.jpg b/public/images/silhouette nageuse.jpg new file mode 100644 index 0000000..e4f7307 Binary files /dev/null and b/public/images/silhouette nageuse.jpg differ diff --git a/public/images/yves_pouliquen.jpg b/public/images/yves_pouliquen.jpg new file mode 100644 index 0000000..435c69e Binary files /dev/null and b/public/images/yves_pouliquen.jpg differ diff --git a/public/index.php b/public/index.php index 3c6f261..2512d6d 100644 --- a/public/index.php +++ b/public/index.php @@ -69,9 +69,9 @@ elseif(isset($_GET['action']) && $_GET['action'] === 'modif_mdp') } // -- contrôleurs -- -$director = new Director($entityManager); +$director = new Director($entityManager, true); $director->makeRootNode($id); -$node = $director->getRootNode(); +$node = $director->getNode(); // -- vues -- $view_builder = new ViewBuilder($node); diff --git a/public/js/main.js b/public/js/main.js index 1351fea..c05eb2f 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -30,10 +30,10 @@ function copyInClipBoard(link){ } // complète les fonctions dans tinymce.js -function switchPositions(articleId, direction) +function switchPositions(article_id, direction) { - const current_article = document.getElementById(articleId).parentElement.parentElement; - var other_article = current_article; + const current_article = findParent(document.getElementById(article_id), 'article'); + var other_article; if(direction == 'down'){ other_article = current_article.nextElementSibling; @@ -41,14 +41,23 @@ function switchPositions(articleId, direction) else if(direction == 'up'){ other_article = current_article.previousElementSibling; } - const other_article_id = other_article.querySelector('div[id]').id; + + var other_article_id; + try{ + other_article_id = other_article.querySelector('div[id]').id; + other_article_id = 'i' + other_article_id.slice(1); // peut mieux faire + } + catch(error){ + console.log('Inversion impossible'); + return; + } fetch('index.php?action=switch_positions', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ id1: articleId, id2: other_article_id }) + body: JSON.stringify({ id1: article_id, id2: other_article_id }) }) .then(response => response.json()) .then(data => { @@ -155,4 +164,15 @@ function submitDate(id_date) .catch(error => { console.error('Erreur:', error); }); +} + +function findParent(element, tag_name) { + while (element !== null) { + if (element.tagName === tag_name.toUpperCase()) // tagName est en majuscules + { + return element; + } + element = element.parentElement; + } + return null; } \ No newline at end of file diff --git a/public/js/tinymce.js b/public/js/tinymce.js index d3c9739..cb1938a 100644 --- a/public/js/tinymce.js +++ b/public/js/tinymce.js @@ -1,15 +1,26 @@ let editors = {}; function openEditor(id, page = '') { - const real_id = 'i' + id.slice(1); + var creation_mode; + var real_id; + var article; - // Récupérer et sauvegarder le contenu d'origine de l'article - const articleContent = document.getElementById(id).innerHTML; - document.getElementById(id).setAttribute('data-original-content', articleContent); + // création ou modification d'un article? + if(id[0] === 'n'){ + creation_mode = true; + article = document.getElementById(id); + } + else{ + creation_mode = false; + // Récupérer et sauvegarder le contenu d'origine de l'article + real_id = 'i' + id.slice(1); + article = document.getElementById(id); + document.getElementById(id).setAttribute('data-original-content', article.innerHTML); + } tinymce.init({ selector: `#${id}`, - language: 'fr_FR', // télécharger des paquets de langue ici: https://www.tiny.cloud/get-tiny/language-packages/ + language: 'fr_FR', // téléchargement ici: https://www.tiny.cloud/get-tiny/language-packages/ language_url: 'js/tinymce-langs/fr_FR.js', // ou installer tweeb/tinymce-i18n avec composer license_key: 'gpl', branding: false, @@ -23,14 +34,18 @@ function openEditor(id, page = '') { editors[id] = editor; // boutons "Modifier", "Supprimer", "déplacer vers le haut", "déplacer vers le bas", "Annuler" et "Soumettre" - document.querySelector(`#edit-${id}`).classList.add('hidden'); document.querySelector(`#cancel-${id}`).classList.remove('hidden'); document.querySelector(`#submit-${id}`).classList.remove('hidden'); - document.querySelector(`#delete-${real_id}`).classList.add('hidden'); - // boutons absents page article - if(page != 'article'){ - document.querySelector(`#position_up-${id}`).classList.add('hidden'); - document.querySelector(`#position_down-${id}`).classList.add('hidden'); + if(creation_mode === false){ + document.querySelector(`#edit-${id}`).classList.add('hidden'); + document.querySelector(`#delete-${real_id}`).classList.add('hidden'); + if(page != 'article'){ + document.querySelector(`#position_up-${id}`).classList.add('hidden'); + document.querySelector(`#position_down-${id}`).classList.add('hidden'); + } + } + else{ + document.querySelector(`#new-${id}`).classList.add('hidden'); // id = new-new-id_node } }); }, @@ -60,7 +75,9 @@ function openEditor(id, page = '') { }); // Remplacer le contenu de l'article par l'éditeur - document.getElementById(id).innerHTML = articleContent; + if(creation_mode === false){ + document.getElementById(id).innerHTML = article.innerHTML; + } } function deleteArticle(id, page = '') { @@ -100,33 +117,78 @@ function deleteArticle(id, page = '') { } } -function closeEditor(id, page = '', display_old = true) +function closeEditor(id, page = '', restore_old = true) { - const real_id = 'i' + id.slice(1); + var creation_mode; + var real_id; + var article; + var parent; + + // création ou modification d'un article? + if(id[0] === 'n'){ + creation_mode = true; + } + else{ + creation_mode = false; + } // Fermer l'éditeur tinymce.remove(`#${id}`); delete editors[id]; + if(creation_mode){ + article = document.getElementById(id); + parent = findParent(article, 'section'); + } + else{ + real_id = 'i' + id.slice(1); + } + // Restaurer le contenu d'origine de l'article - if(display_old){ + if(restore_old){ const originalContent = document.getElementById(id).getAttribute('data-original-content'); document.getElementById(id).innerHTML = originalContent; } - // boutons "Modifier", "Supprimer", "déplacer vers le haut", "déplacer vers le bas", "Annuler" et "Soumettre" - document.querySelector(`#edit-${id}`).classList.remove('hidden'); + // boutons: "Nouvel article", Modifier", "Supprimer", "déplacer vers le haut", "déplacer vers le bas", "Annuler" et "Valider" document.querySelector(`#cancel-${id}`).classList.add('hidden'); document.querySelector(`#submit-${id}`).classList.add('hidden'); - document.querySelector(`#delete-${real_id}`).classList.remove('hidden'); - // boutons absents page article + if(creation_mode){ + document.querySelector(`#new-${id}`).classList.remove('hidden'); // id = new-new-id_node + } + else{ + document.querySelector(`#edit-${id}`).classList.remove('hidden'); + if(page != 'article'){ + document.querySelector(`#position_up-${id}`).classList.remove('hidden'); + document.querySelector(`#position_down-${id}`).classList.remove('hidden'); + document.querySelector(`#delete-${id}`).classList.remove('hidden'); + } + } if(page != 'article'){ - document.querySelector(`#position_up-${id}`).classList.remove('hidden'); + /*document.querySelector(`#position_up-${id}`).classList.remove('hidden'); document.querySelector(`#position_down-${id}`).classList.remove('hidden'); - } + document.querySelector(`#delete-${id}`).classList.remove('hidden');*/ + } + else{ + //document.querySelector(`#delete-${real_id}`).classList.remove('hidden'); + } + } -function submitArticle(id, page = '') { +function submitArticle(id, page = '', clone = null) { + //var creation_mode; + if(id[0] === 'n'){ + //creation_mode = true; + + // sécurité + if(clone == null){ + return; + } + } + else{ + //creation_mode = false; + } + // Récupérer l'éditeur correspondant à l'article const editor = editors[id]; if(!editor) { @@ -150,7 +212,50 @@ function submitArticle(id, page = '') { if (data.success) { // Fermer l'éditeur et mettre à jour le contenu de l'article closeEditor(id, page, false); - document.getElementById(id).innerHTML = html; + if(id[0] === 'n'){ + var share_btn = document.querySelector(`.share.hidden`); // combinaison de deux classes + var new_btn = document.querySelector(`#new-${id}`); + var edit_btn = document.querySelector(`#edit-${id}`); + var pos_up_btn = document.querySelector(`#position_up-${id}`); + var pos_down_btn = document.querySelector(`#position_down-${id}`); + var delete_btn = document.querySelector(`#delete-${id}`); + var cancel_btn = document.querySelector(`#cancel-${id}`); + var submit_btn = document.querySelector(`#submit-${id}`); + + share_btn.classList.remove('hidden') + new_btn.classList.add('hidden'); + edit_btn.classList.remove('hidden'); + pos_up_btn.classList.remove('hidden'); + pos_down_btn.classList.remove('hidden'); + delete_btn.classList.remove('hidden'); + //cancel_btn.classList.add('hidden'); + //submit_btn.classList.add('hidden'); + + var article = document.getElementById(id); + var parent = findParent(article, 'article'); + //share_btn.setAttribute('href', '#' + data.article_id); + share_btn.setAttribute('onclick', "copyInClipBoard('" + window.location.href + data.article_id + "')"); // # de l'ancre ajouté au clic sur le lien ouvrant l'éditeur + article.id = data.article_id; + edit_btn.id = 'edit-' + data.article_id; + edit_btn.querySelector('.action_icon').setAttribute('onclick', "openEditor('" + data.article_id + "')"); + pos_up_btn.id = 'position_up-' + data.article_id; + pos_up_btn.querySelector('.action_icon').setAttribute('onclick', "switchPositions('" + data.article_id + "', 'up')"); + pos_down_btn.id = 'position_down-' + data.article_id; + pos_down_btn.querySelector('.action_icon').setAttribute('onclick', "switchPositions('" + data.article_id + "', 'down')"); + delete_btn.id = 'delete-' + data.article_id; + delete_btn.querySelector('.action_icon').setAttribute('onclick', "deleteArticle('" + data.article_id + "')"); + cancel_btn.id = 'cancel-' + data.article_id; + cancel_btn.querySelector('button').setAttribute('onclick', "closeEditor('" + data.article_id + "')"); + submit_btn.id = 'submit-' + data.article_id; + submit_btn.querySelector('button').setAttribute('onclick', "submitArticle('" + data.article_id + "')"); + + var next_div = parent.nextElementSibling.nextElementSibling; + parent.parentNode.replaceChild(clone, parent); + next_div.appendChild(parent); + } + else{ + //document.getElementById(id).innerHTML = html; + } } else { alert('Erreur lors de la sauvegarde de l\'article.'); diff --git a/src/controller/Director.php b/src/controller/Director.php index 5ff8f47..db84661 100644 --- a/src/controller/Director.php +++ b/src/controller/Director.php @@ -13,17 +13,29 @@ class Director static public Menu $menu_data; // pour NavBuilder static public Path $page_path; // pour BreadcrumbBuilder private Page $page; - private Node $root_node; + private Node $node; + private Node $article; - public function __construct(EntityManager $entityManager) + public function __construct(EntityManager $entityManager, bool $for_display = false) { $this->entityManager = $entityManager; - self::$menu_data = new Menu($entityManager); // Menu est un modèle mais pas une entité - self::$page_path = new Path(); - $this->page = self::$page_path->getLast(); - $this->root_node = new Node; // instance mère "vide" ne possédant rien d'autre que des enfants + if($for_display){ + self::$menu_data = new Menu($entityManager); // Menu est un modèle mais pas une entité + self::$page_path = new Path(); + $this->page = self::$page_path->getLast(); + } + $this->node = new Node; // instance mère "vide" ne possédant rien d'autre que des enfants } + public function getNode(): Node + { + return $this->node; + } + public function getArticleNode(): Node + { + return $this->article; + } + public function makeRootNode(string $id = ''): void { // on récupère toutes les entrées @@ -44,25 +56,10 @@ class Director ->setParameter('id', $id) ->getResult(); } - $this->feedObjects($bulk_data); - } - - public function makeArticleNode(string $id = ''): bool - { - $bulk_data = $this->entityManager - ->createQuery('SELECT n FROM App\Entity\Node n WHERE n.article_timestamp = :id') - ->setParameter('id', $id) - ->getResult(); - - if(count($bulk_data) === 0){ - return false; - } - - $this->root_node = $bulk_data[0]; - return true; + $this->feedRootNodeObjects($bulk_data); } - private function feedObjects(array $bulk_data): void // $bulk_data = tableau de Node + private function feedRootNodeObjects(array $bulk_data): void // $bulk_data = tableau de Node { // puis on les range // (attention, risque de disfonctionnement si les noeuds de 1er niveau ne sont pas récupérés en 1er dans la BDD) @@ -71,7 +68,7 @@ class Director // premier niveau if($node->getParent() == null) { - $this->root_node->addChild($node); + $this->node->addChild($node); // spécifique page article if($node->getName() === 'main' && $this->page->getEndOfPath() == 'article'){ @@ -94,8 +91,50 @@ class Director } } - public function getRootNode(): Node - { - return $this->root_node; + // récupération d'un article pour modification + public function makeArticleNode(string $id = '', bool $get_section = false): bool + { + if($get_section){ + $dql = 'SELECT n, p FROM App\Entity\Node n LEFT JOIN n.parent p WHERE n.article_timestamp = :id'; + } + else{ + $dql = 'SELECT n FROM App\Entity\Node n WHERE n.article_timestamp = :id'; + } + // n est l'article et p son $parent + $bulk_data = $this->entityManager + ->createQuery($dql) + ->setParameter('id', $id) + ->getResult(); + + if(count($bulk_data) === 0){ + return false; + } + + if($get_section){ + $this->article = $bulk_data[0]; + $this->makeSectionNode($bulk_data[0]->getParent()->getId()); + } + else{ + $this->article = $bulk_data[0]; + } + + return true; + } + + // récupération des articles d'un bloc
à la création d'un article + public function makeSectionNode(int $section_id): bool + { + $section = $this->entityManager->find('App\Entity\Node', (string)$section_id); + + $bulk_data = $this->entityManager + ->createQuery('SELECT n FROM App\Entity\Node n WHERE n.parent = :parent') + ->setParameter('parent', $section) + ->getResult(); + + foreach($bulk_data as $article){ + $section->addChild($article); // pas de flush, on ne va pas écrire dans la BDD à chaque nouvelle page + } + $this->node = $section; + return true; } } diff --git a/src/controller/Security.php b/src/controller/Security.php index 818a2bd..f9092e2 100644 --- a/src/controller/Security.php +++ b/src/controller/Security.php @@ -9,7 +9,7 @@ class Security 'safe'=>1, // protection contre les élements et attributs dangereux // liste blanche d'éléments HTML - 'elements'=> 'h1, h2, h3, h4, h5, h6, p, s, em, span, strong, a, ul, ol, li, sup, sub, code, blockquote, div, pre, table, caption, colgroup, col, tbody, tr, th, td, figure, img, figcaption, iframe, small', + 'elements'=> 'h1, h2, h3, h4, h5, h6, p, br, s, em, span, strong, a, ul, ol, li, sup, sub, code, blockquote, div, pre, table, caption, colgroup, col, tbody, tr, th, td, figure, img, figcaption, iframe, small', // liste noire d'attributs HTML 'deny_attribute'=> 'id, class' // on garde 'style' diff --git a/src/controller/ajax.php b/src/controller/ajax.php index 86acd39..b5c2e51 100644 --- a/src/controller/ajax.php +++ b/src/controller/ajax.php @@ -3,6 +3,9 @@ declare(strict_types=1); +use App\Entity\Article; +use App\Entity\Node; + // détection des requêtes de tinymce if($_SERVER['CONTENT_TYPE'] === 'application/json' && isset($_GET['action'])) { @@ -15,13 +18,44 @@ if($_SERVER['CONTENT_TYPE'] === 'application/json' && isset($_GET['action'])) if(json_last_error() === JSON_ERROR_NONE) { $id = $json['id']; - $id[0] = 'i'; $content = Security::secureString($json['content']); - $director = new Director($entityManager); + + // nouvel article + if($id[0] === 'n') + { + if($content === ''){ + echo json_encode(['success' => false, 'message' => 'pas de données à sauvegarder']); + die; + } + $section_id = (int)substr($id, 1); // id du bloc
+ $director->makeSectionNode($section_id); + $node = $director->getNode(); // =
+ + $timestamp = time(); + $date = new \DateTime; + $date->setTimestamp($timestamp); + + $article = new Article($content, $date); // le "current" timestamp est obtenu par la BDD + $article_node = new Node('article', 'i' . (string)$timestamp, [], count($node->getChildren()) + 1, $node, $node->getPage(), $article); + + $entityManager->persist($article_node); + $entityManager->flush(); + + // id_node tout juste généré + //$article_node->getId(); + + echo json_encode(['success' => true, 'article_id' => $article_node->getArticleTimestamp()]); + die; + } + // modification article + else{ + $id[0] = 'i'; // id de l'article node + } + if($director->makeArticleNode($id)) // une entrée est trouvée { - $node = $director->getRootNode(); + $node = $director->getArticleNode(); // article switch($json['id'][0]){ case 'i': $node->getArticle()->setContent($content); @@ -42,8 +76,9 @@ if($_SERVER['CONTENT_TYPE'] === 'application/json' && isset($_GET['action'])) $entityManager->flush(); echo json_encode(['success' => true]); } - else{ - echo json_encode(['success' => false, 'message' => 'Aucune entrée trouvée en BDD']); + else + { + echo json_encode(['success' => false, 'message' => 'article non identifié']); } } else{ @@ -53,16 +88,18 @@ if($_SERVER['CONTENT_TYPE'] === 'application/json' && isset($_GET['action'])) } elseif($_GET['action'] === 'delete_article' && isset($json['id'])) { - $id = $json['id']; - $director = new Director($entityManager); - $director->makeArticleNode($id); - $node = $director->getRootNode(); - $entityManager->remove($node); + $director->makeArticleNode($json['id'], true); + $article = $director->getArticleNode(); + $section = $director->getNode(); + + $entityManager->remove($article); + $section->removeChild($article); + $section->sortChildren(true); // régénère les positions $entityManager->flush(); // test avec une nouvelle requête qui ne devrait rien trouver - if(!$director->makeArticleNode($id)) + if(!$director->makeArticleNode($json['id'])) { echo json_encode(['success' => true]); @@ -78,14 +115,25 @@ if($_SERVER['CONTENT_TYPE'] === 'application/json' && isset($_GET['action'])) elseif($_GET['action'] === 'switch_positions' && isset($json['id1']) && isset($json['id2'])) { $director = new Director($entityManager); - $director->makeArticleNode($json['id1']); - $node1 = $director->getRootNode(); - $director->makeArticleNode($json['id2']); - $node2 = $director->getRootNode(); - - $tmp = $node1->getPosition(); - $node1->setPosition($node2->getPosition()); - $node2->setPosition($tmp); + $director->makeArticleNode($json['id1'], true); + $article1 = $director->getArticleNode(); + $section = $director->getNode(); + + $section->sortChildren(true); // régénère les positions avant inversion + + $article2; + foreach($section->getChildren() as $child){ + if($child->getArticleTimestamp() === $json['id2']) // type string + { + $article2 = $child; + break; + } + } + + // inversion + $tmp = $article1->getPosition(); + $article1->setPosition($article2->getPosition()); + $article2->setPosition($tmp); $entityManager->flush(); echo json_encode(['success' => true]); @@ -99,7 +147,7 @@ if($_SERVER['CONTENT_TYPE'] === 'application/json' && isset($_GET['action'])) $director = new Director($entityManager); $director->makeArticleNode($id); - $node = $director->getRootNode(); + $node = $director->getArticleNode(); $node->getArticle()->setDateTime($date); $entityManager->flush(); diff --git a/src/model/entities/Article.php b/src/model/entities/Article.php index 601e573..dc2d78b 100644 --- a/src/model/entities/Article.php +++ b/src/model/entities/Article.php @@ -20,7 +20,7 @@ class Article // datetime_immutable permet à la base de toujours gérer cette clé primaire correctement #[ORM\Column(type: 'datetime', options: ['default' => 'CURRENT_TIMESTAMP'], unique: true)] - private \DateTime $date_time; // le type datetime de doctrine convertit en type \DateTime de PHP + private ?\DateTime $date_time; // le type datetime de doctrine convertit en type \DateTime de PHP #[ORM\Column(type: "string")] private string $title; @@ -40,8 +40,12 @@ class Article )] private Collection $images; - public function __construct() + public function __construct(string $content, \DateTime $date_time = null, string $title = '', string $preview = '') { + $this->date_time = $date_time; + $this->title = $title; + $this->preview = $preview; + $this->content = $content; $this->images = new ArrayCollection(); // initialisation nécessaire } diff --git a/src/model/entities/Node.php b/src/model/entities/Node.php index 9240413..c9b310a 100644 --- a/src/model/entities/Node.php +++ b/src/model/entities/Node.php @@ -65,32 +65,6 @@ class Node $this->article = $article; } - public function addChild(self $child): void - { - $this->children[] = $child; - $this->sortChildren(); - } - - // utiliser $position pour afficher les éléments dans l'ordre - private function sortChildren(): void - { - $iteration = count($this->children); - while($iteration > 1) - { - for($i = 0; $i < $iteration - 1; $i++) - { - //echo '
' . $this->children[$i]->getPosition() . ' - ' . $this->children[$i + 1]->getPosition(); - if($this->children[$i]->getPosition() > $this->children[$i + 1]->getPosition()) - { - $tmp = $this->children[$i]; - $this->children[$i] = $this->children[$i + 1]; - $this->children[$i + 1] = $tmp; - } - } - $iteration--; - } - } - // pfff... public function getId(): int { @@ -156,6 +130,51 @@ class Node { return $this->children; } + public function addChild(self $child): void + { + $this->children[] = $child; + $this->sortChildren(false); + } + // utiliser $position pour afficher les éléments dans l'ordre + public function sortChildren(bool $reposition = false): void + { + // ordre du tableau des enfants + // inefficace quand des noeuds ont la même position + + // tri par insertion + for($i = 1; $i < count($this->children); $i++) + { + $tmp = $this->children[$i]; + $j = $i - 1; + + // Déplacez les éléments du tableau qui sont plus grands que la clé + // à une position devant leur position actuelle + while ($j >= 0 && $this->children[$j]->getPosition() > $tmp->getPosition()) { + $this->children[$j + 1] = $this->children[$j]; + $j = $j - 1; + } + $this->children[$j + 1] = $tmp; + } + + // nouvelles positions + if($reposition){ + $i = 1; + foreach($this->children as $child){ + $child->setPosition($i); + $i++; + } + } + } + public function removeChild(self $child): void + { + foreach($this->children as $key => $object){ + if($object->getId() === $child->getId()){ + unset($this->children[$key]); + } + break; + } + $this->children = array_values($this->children); // réindexer pour supprimer la case vide + } public function getTempChild(): ?self // peut renvoyer null { diff --git a/src/view/AbstractBuilder.php b/src/view/AbstractBuilder.php index cd2b361..285ebc3 100644 --- a/src/view/AbstractBuilder.php +++ b/src/view/AbstractBuilder.php @@ -7,6 +7,12 @@ abstract class AbstractBuilder { protected const VIEWS_PATH = '../src/view/templates/'; protected string $html = ''; + protected int $id_node; + + protected function __construct(Node $node) + { + $this->id_node = $node->getId(); + } protected function useChildrenBuilder(Node $node): void { diff --git a/src/view/ArticleBuilder.php b/src/view/ArticleBuilder.php index f86f9bd..1f5dbb8 100644 --- a/src/view/ArticleBuilder.php +++ b/src/view/ArticleBuilder.php @@ -25,29 +25,29 @@ class ArticleBuilder extends AbstractBuilder // partage $share_link = new URL(['page' => CURRENT_PAGE], $id); $share_js = 'onclick="copyInClipBoard(\'' . $share_link . '\')"'; - $share_button = '' . "\n"; + $share_button = '' . "\n"; // modifier un article $admin_buttons = ''; if($_SESSION['admin']) { $modify_js = 'onclick="openEditor(\'' . $id . '\')"'; - $modify_article = '

' . "\n"; + $modify_article = '

' . "\n"; $up_js = 'onclick="switchPositions(\'' . $id . '\', \'up\')"'; - $up_button = '

' . "\n"; + $up_button = '

' . "\n"; $down_js = 'onclick="switchPositions(\'' . $id . '\', \'down\')"'; - $down_button = '

' . "\n"; + $down_button = '

' . "\n"; $delete_js = 'onclick="deleteArticle(\'' . $id . '\')"'; - $delete_article = '

' . "\n"; + $delete_article = '

' . "\n"; $close_js = 'onclick="closeEditor(\'' . $id . '\')"'; - $close_editor = ''; + $close_editor = ''; $submit_js = 'onclick="submitArticle(\'' . $id . '\')"'; - $submit_article = ''; + $submit_article = ''; $admin_buttons = $modify_article . $up_button . $down_button . $delete_article . $close_editor . $submit_article; } diff --git a/src/view/BlogBuilder.php b/src/view/BlogBuilder.php index 8c2125f..ca020b2 100644 --- a/src/view/BlogBuilder.php +++ b/src/view/BlogBuilder.php @@ -7,6 +7,7 @@ class BlogBuilder extends AbstractBuilder { public function __construct(Node $node) { + parent::__construct($node); $viewFile = self::VIEWS_PATH . $node->getName() . '.php'; if(file_exists($viewFile)) @@ -18,26 +19,44 @@ class BlogBuilder extends AbstractBuilder // ajouter un article $new_article = ''; - $new_article_admin_buttons = ''; if($_SESSION['admin']) { - $id = 'new'; - - //$link = new URL(['page' => CURRENT_PAGE, 'action' => 'open_editor']); + $id = 'n' . $this->id_node; $js = 'onclick="openEditor(\'' . $id . '\')"'; - //$new_article = ''; - $new_article = '

' . "\n" . - '

'; + + $share_button = ''; + $html = ''; + + $new_button = '

' . "\n" . + '

'; + + $modify_js = 'onclick="openEditor(\'' . $id . '\')"'; + $modify_article = '' . "\n"; + + $up_js = 'onclick="switchPositions(\'' . $id . '\', \'up\')"'; + $up_button = '' . "\n"; + + $down_js = 'onclick="switchPositions(\'' . $id . '\', \'down\')"'; + $down_button = '' . "\n"; + + $delete_js = 'onclick="deleteArticle(\'' . $id . '\')"'; + $delete_article = '' . "\n"; $close_js = 'onclick="closeEditor(\'' . $id . '\')"'; - $close_editor = '
'; + $close_editor = ''; - $submit_js = 'onclick="submitArticle(\'' . $id . '\')"'; - $submit_article = '
'; + $submit_js = 'onclick="submitArticle(\'' . $id . '\', \'\', clone' . $this->id_node . ')"'; + $submit_article = ''; - $new_article_admin_buttons = $close_editor . $submit_article; + $admin_buttons = $new_button . $modify_article . $up_button . $down_button . $delete_article . $close_editor . $submit_article; + + // squelette d'un nouvel article + ob_start(); + require self::VIEWS_PATH . 'article.php'; + $new_article = ob_get_clean(); } + // articles existants $this->useChildrenBuilder($node); $content = $this->html; diff --git a/src/view/GaleryBuilder.php b/src/view/GaleryBuilder.php index 89be2b1..a895d70 100644 --- a/src/view/GaleryBuilder.php +++ b/src/view/GaleryBuilder.php @@ -7,6 +7,7 @@ class GaleryBuilder extends AbstractBuilder { public function __construct(Node $node) { + parent::__construct($node); $viewFile = self::VIEWS_PATH . $node->getName() . '.php'; if(file_exists($viewFile)) @@ -18,26 +19,44 @@ class GaleryBuilder extends AbstractBuilder // ajouter un article $new_article = ''; - $new_article_admin_buttons = ''; if($_SESSION['admin']) { - $id = 'new'; - - //$link = new URL(['page' => CURRENT_PAGE, 'action' => 'open_editor']); + $id = 'n' . $this->id_node; $js = 'onclick="openEditor(\'' . $id . '\')"'; - //$new_article = ''; - $new_article = '

' . "\n" . - '

'; + + $share_button = ''; + $html = ''; + + $new_button = '

' . "\n" . + '

'; + + $modify_js = 'onclick="openEditor(\'' . $id . '\')"'; + $modify_article = '' . "\n"; + + $up_js = 'onclick="switchPositions(\'' . $id . '\', \'up\')"'; + $up_button = '' . "\n"; + + $down_js = 'onclick="switchPositions(\'' . $id . '\', \'down\')"'; + $down_button = '' . "\n"; + + $delete_js = 'onclick="deleteArticle(\'' . $id . '\')"'; + $delete_article = '' . "\n"; $close_js = 'onclick="closeEditor(\'' . $id . '\')"'; - $close_editor = '
'; + $close_editor = ''; - $submit_js = 'onclick="submitArticle(\'' . $id . '\')"'; - $submit_article = '
'; + $submit_js = 'onclick="submitArticle(\'' . $id . '\', \'\', clone' . $this->id_node . ')"'; + $submit_article = ''; - $new_article_admin_buttons = $close_editor . $submit_article; + $admin_buttons = $new_button . $modify_article . $up_button . $down_button . $delete_article . $close_editor . $submit_article; + + // squelette d'un nouvel article + ob_start(); + require self::VIEWS_PATH . 'article.php'; + $new_article = ob_get_clean(); } + // articles existants $this->useChildrenBuilder($node); $content = $this->html; diff --git a/src/view/GridBuilder.php b/src/view/GridBuilder.php index 6e16d46..e183e6f 100644 --- a/src/view/GridBuilder.php +++ b/src/view/GridBuilder.php @@ -7,6 +7,7 @@ class GridBuilder extends AbstractBuilder { public function __construct(Node $node) { + parent::__construct($node); $viewFile = self::VIEWS_PATH . $node->getName() . '.php'; if(file_exists($viewFile)) @@ -18,32 +19,50 @@ class GridBuilder extends AbstractBuilder // ajouter un article $new_article = ''; - $new_article_admin_buttons = ''; if($_SESSION['admin']) { - $id = 'new'; + $id = 'n' . $this->id_node; $js = 'onclick="openEditor(\'' . $id . '\')"'; - if(Director::$page_path->getLast()->getEndOfPath() === 'accueil') - { - $new_article = '

' . "\n" . - '

'; + $share_button = ''; + $html = ''; + + if(CURRENT_PAGE === 'accueil'){ + $new_button = '

+

'; } - else - { - $new_article = '

' . "\n" . - '

'; + else{ + $new_button = '

' . "\n" . + '

'; } + + $modify_js = 'onclick="openEditor(\'' . $id . '\')"'; + $modify_article = '' . "\n"; + + $up_js = 'onclick="switchPositions(\'' . $id . '\', \'up\')"'; + $up_button = '' . "\n"; + $down_js = 'onclick="switchPositions(\'' . $id . '\', \'down\')"'; + $down_button = '' . "\n"; + + $delete_js = 'onclick="deleteArticle(\'' . $id . '\')"'; + $delete_article = '' . "\n"; + $close_js = 'onclick="closeEditor(\'' . $id . '\')"'; - $close_editor = '
'; + $close_editor = ''; - $submit_js = 'onclick="submitArticle(\'' . $id . '\')"'; - $submit_article = '
'; + $submit_js = 'onclick="submitArticle(\'' . $id . '\', \'\', clone' . $this->id_node . ')"'; + $submit_article = ''; - $new_article_admin_buttons = $close_editor . $submit_article; + $admin_buttons = $new_button . $modify_article . $up_button . $down_button . $delete_article . $close_editor . $submit_article; + + // squelette d'un nouvel article + ob_start(); + require self::VIEWS_PATH . 'article.php'; + $new_article = ob_get_clean(); } + // articles existants $this->useChildrenBuilder($node); $content = $this->html; diff --git a/src/view/templates/article.php b/src/view/templates/article.php index f3ab32f..c57c1cb 100644 --- a/src/view/templates/article.php +++ b/src/view/templates/article.php @@ -10,5 +10,4 @@ -
\ No newline at end of file diff --git a/src/view/templates/blog.php b/src/view/templates/blog.php index 35cac8b..e2066c8 100644 --- a/src/view/templates/blog.php +++ b/src/view/templates/blog.php @@ -1,6 +1,10 @@ -
+

- + +
+
\ No newline at end of file diff --git a/src/view/templates/galery.php b/src/view/templates/galery.php index 306526f..246c4dd 100644 --- a/src/view/templates/galery.php +++ b/src/view/templates/galery.php @@ -1,9 +1,10 @@ -
+

- +
-

diff --git a/src/view/templates/grid.php b/src/view/templates/grid.php index a09ed40..f9e441d 100644 --- a/src/view/templates/grid.php +++ b/src/view/templates/grid.php @@ -1,7 +1,9 @@ -
+

- +
-- cgit v1.2.3