Ajoute les listes à puces et numérotées dans la bibliothèque de contenu

Retour utilisateur du 24/09/2026 : "dans la section contenu il manque
la possibilité d'utiliser une liste à puce ou ordonnée".

- Deux nouveaux kinds "liste_puces"/"liste_numerotee" dans
  CONTENT_KINDS, chacun sélectionnable directement dans la bibliothèque
  (comme titre/paragraphe/image/bouton) — partagent la même structure
  d'attributs (`items`, une liste de chaînes), c'est le kind lui-même
  qui décide <ul> ou <ol> au rendu (_render_list), pas un attribut
  "ordered" redondant à tenir synchronisé.
- Rendu : un <li> par item, échappé (html.escape) comme tout le
  contenu texte du document — une liste vide rend <ul>/<ol> sans
  enfant plutôt qu'un placeholder (état normal, pas une image sans
  fichier).
- Panneau Propriétés : même patron répéteur que l'Association/Memory
  (ajouter/renommer/supprimer une ligne, rechargé après chaque
  modification).
- Icônes de bibliothèque (☰/①) + style .docList (puces/numéros
  visibles, espacement entre items).

6 nouveaux tests Python (attributs par défaut, rendu <ul>/<ol>,
échappement, liste vide, route d'ajout) + vérifié par un test jsdom
dédié contre un vrai support (bibliothèque, panneau Propriétés :
ajout/modification/suppression d'item réellement fonctionnels).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
william
2026-09-24 07:19:01 +02:00
co-authored by Claude Sonnet 5
parent eac45f1c9d
commit e7c6ed7159
8 changed files with 169 additions and 4 deletions
+52
View File
@@ -1669,6 +1669,57 @@ function forgeDocRenderButtonProps(panel, el) {
document.getElementById('docButtonTarget').addEventListener('change', (e) => patch({ target: e.target.value.trim() }));
}
function forgeDocRenderListItemHtml(item, index) {
return `
<div class="docAssocPairRow" data-item-index="${index}">
<input type="text" class="docAssocPairInput docListItemInput" data-item-index="${index}" value="${forgeDocEscapeHtml(item)}">
<button type="button" class="docQuizRemoveBtn" data-item-index="${index}" aria-label="Supprimer cet élément" title="Supprimer cet élément">✕</button>
</div>
`;
}
function forgeDocRenderListProps(panel, el) {
// Même patron répéteur que l'Association/Memory (ajouter/supprimer/
// modifier une ligne, panneau entièrement rechargé après chaque
// modification via patch()) — ici une simple liste de chaînes, pas de
// structure à 2 champs comme une paire.
const a = el.attributes;
const items = a.items || [];
const kindLabel = el.kind === 'liste_numerotee' ? 'liste numérotée' : 'liste à puces';
function patch(partial) {
forgeDocUpdateAttributes(el.id, { ...el.attributes, ...partial }).then(() => {
forgeDocRenderProps(window.forgeDocState.elementsById[el.id]);
});
}
panel.innerHTML = `
${forgeDocPropsHeader(kindLabel)}
<div class="docSectionLabel docQuizQuestionsLabel">Éléments de la liste</div>
<div id="docListItemsList">${items.length ? items.map(forgeDocRenderListItemHtml).join('') : '<div class="docEmptyState">Aucun élément — ajoute le premier ci-dessous.</div>'}</div>
<button type="button" class="docBtnSecondary docQuizAddBtn" id="docListAddItem">+ Ajouter un élément</button>
${forgeDocDeleteButtonHtml()}
`;
document.getElementById('docListAddItem').addEventListener('click', () => {
patch({ items: [...items, 'Nouvel élément'] });
});
panel.querySelectorAll('#docListItemsList .docQuizRemoveBtn').forEach((btn) => {
btn.addEventListener('click', () => {
const index = Number(btn.dataset.itemIndex);
patch({ items: items.filter((_, i) => i !== index) });
});
});
panel.querySelectorAll('.docListItemInput').forEach((input) => {
input.addEventListener('change', (e) => {
const index = Number(input.dataset.itemIndex);
patch({ items: items.map((it, i) => (i === index ? e.target.value : it)) });
});
});
}
function forgeDocRenderRowProps(panel, el) {
const a = el.attributes;
panel.innerHTML = `
@@ -2725,6 +2776,7 @@ function forgeDocRenderProps(el) {
if (el.kind === 'titre' || el.kind === 'paragraphe') forgeDocRenderTextProps(panel, el);
else if (el.kind === 'image') forgeDocRenderImageProps(panel, el);
else if (el.kind === 'bouton') forgeDocRenderButtonProps(panel, el);
else if (el.kind === 'liste_puces' || el.kind === 'liste_numerotee') forgeDocRenderListProps(panel, el);
else if (el.kind === 'row') forgeDocRenderRowProps(panel, el);
else if (el.kind === 'quiz') forgeDocRenderQuizProps(panel, el);
else if (el.kind === 'association') forgeDocRenderAssociationProps(panel, el);