Admin livres : slug auto + sélecteur d'articles par mot entier #3

Closed
opened 2026-05-16 08:31:52 +00:00 by cedricAbonnel · 0 comments
Owner

Problèmes actuels

1. Création d'un livre — slug à saisir manuellement

Dans ?new=1, l'utilisateur doit taper lui-même le slug. C'est redondant : BookManager::sanitizeSlug() existe déjà et produit un slug valide à partir du titre.

2. Édition — sélecteur de pages trop limité

Dans ?edit=<slug>, l'ajout de pages utilise un <select> listant tous les articles non encore inclus. Avec beaucoup d'articles, trouver le bon est difficile. Il n'y a aucun filtrage.


Correction 1 — Slug auto-généré à la création

UX

  • Supprimer le champ slug du formulaire ?new=1
  • Afficher à la place un aperçu du slug calculé depuis le titre (champ readonly, mis à jour en JS au fil de la saisie du titre)
  • Exemple : saisir Mon livre ESP8266 → affiche mon-livre-esp8266

Backend (public/index.php, case 'book_save')

  • Si $_POST['slug'] est vide, dériver le slug du titre :
    $bSlug = trim($_POST['slug'] ?? );
    if ($bSlug === ) {
        $bSlug = $books->sanitizeSlug($bTitle);
    }
    
  • Rendre sanitizeSlug() public dans BookManager
  • Gérer la collision : si le slug existe déjà, ajouter un suffixe (-2, -3…)

Template (templates/admin.php, bloc ?new=1)

  • Supprimer <input name="slug"> affiché
  • Ajouter <input type="hidden" name="slug" value=""> (vide → dérivé côté serveur)
  • Ajouter un affichage readonly du slug prévisuel :
    <div class="form-text font-monospace" id="slug-preview"></div>
    
  • Script JS minimal inline :
    document.querySelector("[name=title]").addEventListener("input", e => {
      document.getElementById("slug-preview").textContent =
        e.target.value.toLowerCase()
          .normalize("NFD").replace(/[\u0300-\u036f]/g, "")
          .replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "—";
    });
    
    (Approximation côté JS ; le slug canonique final est produit par sanitizeSlug() PHP)

Correction 2 — Sélecteur d'articles filtrable par mot entier

UX attendue

  • Remplacer le <select> par :
    1. Un champ texte de recherche
    2. Une liste d'articles filtrés en temps réel (JS côté client)
  • Le filtrage porte sur le titre et le contenu (plain) de l'article
  • Le filtre est par mot entier, insensible à la casse :
    • esp → matche les articles contenant le mot ESP (ou esp, Esp)
    • esp → ne matche pas les articles où espérance est le seul occurrence
    • Implémentation : new RegExp("\\b" + mot.replace(/[.*+?^${}()|[\]\\]/g, "\\\\$&") + "\\b", "i")
  • Cliquer sur un article l'ajoute en bas du textarea des slugs

Données disponibles

$adminData['all_articles'] contient déjà title, slug, published, plain — tout est disponible côté template sans requête supplémentaire.

Implémentation suggérée

  • Encoder all_articles (non encore dans le livre) en data-* JSON ou <script> inline
  • Champ de recherche <input type="text" id="book-article-filter">
  • Liste <ul id="book-article-results"> peuplée par JS
  • Clic sur un item → ajoute le slug dans #book-articles-ta + retire l'item de la liste

Critères d'acceptation

  • Formulaire ?new=1 : pas de champ slug saisi manuellement
  • Aperçu slug calculé en temps réel sous le champ titre
  • Backend : slug dérivé du titre si $_POST['slug'] est vide
  • Collision de slug gérée (-2, -3)
  • Champ de recherche sur les articles avec filtre mot entier
  • Filtre porte sur titre ET contenu (plain)
  • esp ne matche pas espérance
  • Clic sur un résultat l'ajoute dans la liste des pages
  • Testé sur http://abonnel-wiki.acegrp.lan
## Problèmes actuels ### 1. Création d'un livre — slug à saisir manuellement Dans `?new=1`, l'utilisateur doit taper lui-même le slug. C'est redondant : `BookManager::sanitizeSlug()` existe déjà et produit un slug valide à partir du titre. ### 2. Édition — sélecteur de pages trop limité Dans `?edit=<slug>`, l'ajout de pages utilise un `<select>` listant tous les articles non encore inclus. Avec beaucoup d'articles, trouver le bon est difficile. Il n'y a aucun filtrage. --- ## Correction 1 — Slug auto-généré à la création ### UX - Supprimer le champ slug du formulaire `?new=1` - Afficher à la place un aperçu du slug calculé depuis le titre (champ `readonly`, mis à jour en JS au fil de la saisie du titre) - Exemple : saisir `Mon livre ESP8266` → affiche `mon-livre-esp8266` ### Backend (`public/index.php`, `case 'book_save'`) - Si `$_POST['slug']` est vide, dériver le slug du titre : ```php $bSlug = trim($_POST['slug'] ?? ); if ($bSlug === ) { $bSlug = $books->sanitizeSlug($bTitle); } ``` - Rendre `sanitizeSlug()` public dans `BookManager` - Gérer la collision : si le slug existe déjà, ajouter un suffixe (`-2`, `-3`…) ### Template (`templates/admin.php`, bloc `?new=1`) - Supprimer `<input name="slug">` affiché - Ajouter `<input type="hidden" name="slug" value="">` (vide → dérivé côté serveur) - Ajouter un affichage readonly du slug prévisuel : ```html <div class="form-text font-monospace" id="slug-preview">—</div> ``` - Script JS minimal inline : ```js document.querySelector("[name=title]").addEventListener("input", e => { document.getElementById("slug-preview").textContent = e.target.value.toLowerCase() .normalize("NFD").replace(/[\u0300-\u036f]/g, "") .replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "—"; }); ``` *(Approximation côté JS ; le slug canonique final est produit par `sanitizeSlug()` PHP)* --- ## Correction 2 — Sélecteur d'articles filtrable par mot entier ### UX attendue - Remplacer le `<select>` par : 1. Un champ texte de recherche 2. Une liste d'articles filtrés en temps réel (JS côté client) - Le filtrage porte sur le **titre** et le **contenu** (`plain`) de l'article - Le filtre est par **mot entier, insensible à la casse** : - `esp` → matche les articles contenant le mot `ESP` (ou `esp`, `Esp`) - `esp` → ne matche **pas** les articles où `espérance` est le seul occurrence - Implémentation : `new RegExp("\\b" + mot.replace(/[.*+?^${}()|[\]\\]/g, "\\\\$&") + "\\b", "i")` - Cliquer sur un article l'ajoute en bas du textarea des slugs ### Données disponibles `$adminData['all_articles']` contient déjà `title`, `slug`, `published`, `plain` — tout est disponible côté template sans requête supplémentaire. ### Implémentation suggérée - Encoder `all_articles` (non encore dans le livre) en `data-*` JSON ou `<script>` inline - Champ de recherche `<input type="text" id="book-article-filter">` - Liste `<ul id="book-article-results">` peuplée par JS - Clic sur un item → ajoute le slug dans `#book-articles-ta` + retire l'item de la liste --- ## Critères d'acceptation - [ ] Formulaire `?new=1` : pas de champ slug saisi manuellement - [ ] Aperçu slug calculé en temps réel sous le champ titre - [ ] Backend : slug dérivé du titre si `$_POST['slug']` est vide - [ ] Collision de slug gérée (`-2`, `-3`) - [ ] Champ de recherche sur les articles avec filtre mot entier - [ ] Filtre porte sur titre ET contenu (`plain`) - [ ] `esp` ne matche pas `espérance` - [ ] Clic sur un résultat l'ajoute dans la liste des pages - [ ] Testé sur http://abonnel-wiki.acegrp.lan
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: cedricAbonnel/abonnel-www#3