À propos: contacts flexibles, liens sidebar éditables, grille contacts admin, et bouton supprimer

- Contacts: on peut laisser vide le nom OU le rôle (plus besoin des deux)
- Sidebar: les liens « site de l'erg » et « code source » sont éditables depuis /admin/contenus-edit.php?slug=about
- Admin: les champs Nom/Email/Lien des contacts s'affichent en grille 3 colonnes
- Admin: icône corbeille (admin-icon-btn--delete) pour supprimer un contact, avec réindexation automatique
- Database::getAproposContent() gère maintenant les valeurs string (URLs) en plus des arrays
- Database::saveAproposContent() accepte array|string
This commit is contained in:
Pontoporeia
2026-06-08 12:47:19 +02:00
parent a1a9a316ca
commit 312d9eab0e
10 changed files with 214 additions and 62 deletions

View File

@@ -21,24 +21,34 @@
<?php $entries = is_array($group['entries'] ?? null) ? $group['entries'] : []; ?>
<?php foreach ($entries as $ei => $entry): ?>
<div class="apropos-entry">
<label for="entry_f_<?= $aproposKey ?>_<?= $gi ?>_<?= $ei ?>_text">Nom :</label>
<input type="text" id="entry_f_<?= $aproposKey ?>_<?= $gi ?>_<?= $ei ?>_text"
name="groups[<?= $gi ?>][entries][<?= $ei ?>][text]"
value="<?= htmlspecialchars($entry['text'] ?? '') ?>">
<label for="entry_f_<?= $aproposKey ?>_<?= $gi ?>_<?= $ei ?>_email">Email :</label>
<input type="email" id="entry_f_<?= $aproposKey ?>_<?= $gi ?>_<?= $ei ?>_email"
name="groups[<?= $gi ?>][entries][<?= $ei ?>][email]"
value="<?= htmlspecialchars($entry['email'] ?? '') ?>">
<label for="entry_f_<?= $aproposKey ?>_<?= $gi ?>_<?= $ei ?>_url">Lien (optionnel) :</label>
<input type="url" id="entry_f_<?= $aproposKey ?>_<?= $gi ?>_<?= $ei ?>_url"
name="groups[<?= $gi ?>][entries][<?= $ei ?>][url]"
value="<?= htmlspecialchars($entry['url'] ?? '') ?>">
<div>
<label for="entry_f_<?= $aproposKey ?>_<?= $gi ?>_<?= $ei ?>_text">Nom :</label>
<input type="text" id="entry_f_<?= $aproposKey ?>_<?= $gi ?>_<?= $ei ?>_text"
name="groups[<?= $gi ?>][entries][<?= $ei ?>][text]"
value="<?= htmlspecialchars($entry['text'] ?? '') ?>">
</div>
<div>
<label for="entry_f_<?= $aproposKey ?>_<?= $gi ?>_<?= $ei ?>_email">Email :</label>
<input type="email" id="entry_f_<?= $aproposKey ?>_<?= $gi ?>_<?= $ei ?>_email"
name="groups[<?= $gi ?>][entries][<?= $ei ?>][email]"
value="<?= htmlspecialchars($entry['email'] ?? '') ?>">
</div>
<div>
<label for="entry_f_<?= $aproposKey ?>_<?= $gi ?>_<?= $ei ?>_url">Lien (optionnel) :</label>
<input type="url" id="entry_f_<?= $aproposKey ?>_<?= $gi ?>_<?= $ei ?>_url"
name="groups[<?= $gi ?>][entries][<?= $ei ?>][url]"
value="<?= htmlspecialchars($entry['url'] ?? '') ?>">
</div>
</div>
<?php endforeach; ?>
<button type="button" class="btn btn--primary btn--sm add-entry-btn-f"
data-group="<?= $gi ?>"
data-key="<?= $aproposKey ?>">+ Ajouter une entrée</button>
<button type="button" class="admin-icon-btn admin-icon-btn--delete delete-group-btn-f"
data-key="<?= $aproposKey ?>" title="Supprimer ce contact">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 256 256"><path d="M216,48H176V40a24,24,0,0,0-24-24H104A24,24,0,0,0,80,40v8H40a8,8,0,0,0,0,16h8V208a16,16,0,0,0,16,16H192a16,16,0,0,0,16-16V64h8a8,8,0,0,0,0-16ZM112,168V104a8,8,0,0,1,16,0v64a8,8,0,0,1-16,0Zm48,0V104a8,8,0,0,1,16,0v64a8,8,0,0,1-16,0Z"></path></svg>
</button>
</fieldset>
<?php endforeach; ?>
@@ -52,12 +62,18 @@
<template id="entry-template-f-<?= $aproposKey ?>">
<div class="apropos-entry">
<label>Entrée :</label>
<input type="text" name="groups[{{gi}}][entries][{{ei}}][text]">
<label>Email :</label>
<input type="email" name="groups[{{gi}}][entries][{{ei}}][email]">
<label>Lien (optionnel) :</label>
<input type="url" name="groups[{{gi}}][entries][{{ei}}][url]">
<div>
<label>Nom :</label>
<input type="text" name="groups[{{gi}}][entries][{{ei}}][text]">
</div>
<div>
<label>Email :</label>
<input type="email" name="groups[{{gi}}][entries][{{ei}}][email]">
</div>
<div>
<label>Lien (optionnel) :</label>
<input type="url" name="groups[{{gi}}][entries][{{ei}}][url]">
</div>
</div>
</template>
@@ -69,6 +85,10 @@
<button type="button" class="btn btn--primary btn--sm add-entry-btn-f"
data-group="{{gi}}"
data-key="<?= $aproposKey ?>">+ Ajouter une entrée</button>
<button type="button" class="admin-icon-btn admin-icon-btn--delete delete-group-btn-f"
data-key="<?= $aproposKey ?>" title="Supprimer ce contact">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 256 256"><path d="M216,48H176V40a24,24,0,0,0-24-24H104A24,24,0,0,0,80,40v8H40a8,8,0,0,0,0,16h8V208a16,16,0,0,0,16,16H192a16,16,0,0,0,16-16V64h8a8,8,0,0,0,0-16ZM112,168V104a8,8,0,0,1,16,0v64a8,8,0,0,1-16,0Zm48,0V104a8,8,0,0,1,16,0v64a8,8,0,0,1-16,0Z"></path></svg>
</button>
</fieldset>
</template>
</form>
@@ -81,7 +101,36 @@
var entryTpl = document.getElementById('entry-template-f-' + key).innerHTML;
var groupTpl = document.getElementById('group-template-f-' + key).innerHTML;
form.querySelectorAll('.add-entry-btn-f').forEach(function(btn) {
function reindexGroups() {
var fieldsets = form.querySelectorAll('fieldset.apropos-group');
groupCount = fieldsets.length;
fieldsets.forEach(function(fs, i) {
var newIdx = i;
var legend = fs.querySelector('legend');
if (legend) legend.textContent = 'Contact ' + (newIdx + 1);
// Update name attributes on all inputs
fs.querySelectorAll('input').forEach(function(inp) {
if (inp.name) {
inp.name = inp.name.replace(/groups\[\d+\]/, 'groups[' + newIdx + ']');
}
if (inp.id) {
inp.id = inp.id.replace(/(group_f_contacts_|entry_f_contacts_)\d+/, '$1' + newIdx);
}
});
// Update for attributes on labels
fs.querySelectorAll('label[for]').forEach(function(lbl) {
lbl.setAttribute('for', lbl.getAttribute('for').replace(/(group_f_contacts_|entry_f_contacts_)\d+/, '$1' + newIdx));
});
// Update data-group on add-entry button
var addBtn = fs.querySelector('.add-entry-btn-f');
if (addBtn) addBtn.dataset.group = newIdx;
});
}
function bindAddEntry(btn) {
btn.addEventListener('click', function() {
var gi = parseInt(this.dataset.group);
var fieldset = this.closest('fieldset');
@@ -89,7 +138,21 @@
var html = entryTpl.replaceAll('{{gi}}', gi).replaceAll('{{ei}}', entryCount);
this.insertAdjacentHTML('beforebegin', html);
});
});
}
function bindDeleteGroup(btn) {
btn.addEventListener('click', function() {
var fieldset = this.closest('fieldset');
if (fieldset) {
fieldset.remove();
reindexGroups();
}
});
}
// Bind existing buttons
form.querySelectorAll('.add-entry-btn-f').forEach(bindAddEntry);
form.querySelectorAll('.delete-group-btn-f').forEach(bindDeleteGroup);
form.querySelector('.add-group-btn-f').addEventListener('click', function() {
groupCount++;
@@ -98,17 +161,13 @@
var newGroup = this.previousElementSibling;
if (newGroup && newGroup.classList.contains('apropos-group')) {
var btn = newGroup.querySelector('.add-entry-btn-f');
if (btn) {
btn.dataset.group = groupCount;
btn.addEventListener('click', function() {
var gi = parseInt(this.dataset.group);
var fieldset = this.closest('fieldset');
var entryCount = fieldset.querySelectorAll('.apropos-entry').length;
var html = entryTpl.replaceAll('{{gi}}', gi).replaceAll('{{ei}}', entryCount);
this.insertAdjacentHTML('beforebegin', html);
});
var addBtn = newGroup.querySelector('.add-entry-btn-f');
if (addBtn) {
addBtn.dataset.group = groupCount;
bindAddEntry(addBtn);
}
var delBtn = newGroup.querySelector('.delete-group-btn-f');
if (delBtn) bindDeleteGroup(delBtn);
}
});
})();