let editors = {}; function openEditor(id, page = '') { var creation_mode; var real_id; var article; // 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é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, plugins: 'lists link autolink table image media autoresize help', toolbar: 'undo redo newdocument print selectall styles bold italic underline strikethrough fontsizeinput forecolor backcolor fontfamily align numlist bullist outdent indent table link image media help', menubar: false, toolbar_mode: 'wrap', statusbar: false, setup: function (editor) { editor.on('init', function (){ editors[id] = editor; // boutons "Modifier", "Supprimer", "déplacer vers le haut", "déplacer vers le bas", "Annuler" et "Soumettre" document.querySelector(`#cancel-${id}`).classList.remove('hidden'); document.querySelector(`#submit-${id}`).classList.remove('hidden'); if(creation_mode === false){ document.querySelector(`#edit-${id}`).classList.add('hidden'); if(page != 'article'){ document.querySelector(`#position_up-${id}`).classList.add('hidden'); document.querySelector(`#position_down-${id}`).classList.add('hidden'); document.querySelector(`#delete-${real_id}`).classList.add('hidden'); } } else{ document.querySelector(`#new-${id}`).classList.add('hidden'); // id = new-new-id_node } }); let skipPastePreProcess = false; editor.on('Paste', function (e){ // déclenchement AVANT PastePreProcess et quelque que soit le contenu collé const clipboardData = (e.clipboardData || e.originalEvent.clipboardData); if(!clipboardData){ return; } const items = clipboardData.items; let foundImage = false; for(let i = 0; i < items.length; i++){ let item = items[i]; if(item.type.indexOf('image') !== -1){ // test type MIME contenant image foundImage = true; const file = item.getAsFile(); // presse-papier => fichier lisible const reader = new FileReader(); reader.onload = function (event){ // fonction exécutée lorsque reader.readAsDataURL(file) est terminée const base64Data = event.target.result; // données de l'image fetch('index.php?action=upload_image_base64', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ image_base64: base64Data }) }) .then(response => response.json()) .then(data => { if(data.location){ editor.insertContent(''); } }) .catch(error => { console.error('Erreur lors de l’upload de l’image base64 :', error); }); }; reader.readAsDataURL(file); // lecture asynchrone du fichier } } if(foundImage){ e.preventDefault(); // supprime le collage automatiue skipPastePreProcess = true; // désactiver le PastePreProcess pour ce collage } }); editor.on('PastePreProcess', function (e){ // déclenchement au collage AVANT insertion dans l'éditeur const parser = new DOMParser(); const doc = parser.parseFromString(e.content, 'text/html'); const images = doc.querySelectorAll('img'); let downloads_in_progress = []; images.forEach(img => { if(img.src.startsWith('file://')){ // détection d'images non insérables console.warn('Image locale non insérable dans tinymce :', img.src); img.outerHTML = `
"Image locale non insérée (vient-elle d'un document LibreOffice ?). Effacez ce message rouge et copiez-collez l'image seule.
`; } else if(img.src.startsWith('http')){ // détection d'images web const promise = fetch('index.php?action=upload_image_url', { // promesse d'un fichier téléchargeable sur le serveur method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ image_url: img.src }) }) .then(response => response.json()) .then(data => { if(data.location){ img.src = data.location; // remplacer l'image par celle du serveur } }) .catch(error => { console.error('Erreur lors de l’upload de l’image distante:', error); }); downloads_in_progress.push(promise); } }); // une image web ou plus: différer l'insertion dans l'éditeur le temps que le serveur télécharge les images if(downloads_in_progress.length > 0){ e.preventDefault(); Promise.all(downloads_in_progress).then(() => { e.content = doc.body.innerHTML; // remplacement du HTML dans l'éditeur par la copie modifiée (doc) editor.insertContent(e.content); }); } else{ e.content = doc.body.innerHTML; // remplacement du HTML dans l'éditeur par la copie modifiée (doc) } }); // fin editor.on('PastePreProcess'... }, // upload d'image natif de tinymce avec le bouton "Insérer une image" images_upload_handler: (blobInfo, progress) => new Promise((resolve, reject) => { const formData = new FormData(); formData.append("file", blobInfo.blob()); fetch("index.php?action=upload_image", { method: "POST", body: formData }) .then(response => response.json()) .then(data => { if(data.location) { resolve(data.location); } else { reject("Erreur: Chemin d'image invalide"); } }) .catch(error => { reject("Erreur lors de l'upload"); }); }), image_caption: true }); // Remplacer le contenu de l'article par l'éditeur if(creation_mode === false){ document.getElementById(id).innerHTML = article.innerHTML; } } function deleteArticle(id, page = '') { if (confirm('Voulez-vous vraiment supprimer cet article ?')) { // Envoyer une requête au serveur pour supprimer l'article fetch('index.php?action=delete_article', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ id: id }) }) .then(response => response.json()) .then(data => { if(data.success) { if(page === 'article'){ // redirection vers la page d'accueil window.setTimeout(function(){ location.href = "index.php?page=accueil"; }, 0); } else{ // Supprimer l'article du DOM const articleElement = document.getElementById(id); articleElement.parentElement.parentElement.remove(); //
est deux niveau au dessus } } else { alert('Erreur lors de la suppression de l\'article.'); } }) .catch(error => { console.error('Erreur:', error); }); } } function closeEditor(id, page = '', restore_old = true) { 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(restore_old){ const originalContent = document.getElementById(id).getAttribute('data-original-content'); document.getElementById(id).innerHTML = originalContent; } // 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'); 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'); } } } function submitArticle(id, page = '', clone = null) { var editor; var content; const params = new URL(document.location).searchParams; // "search" = ? et paramètres, searchParams = objet avec des getters // clic sur "tout enregistrer" if(id[0] === 'n' && page === 'article'){ const prefixes = ['t', 'p', 'i', 'd']; const allElemsWithId = document.querySelectorAll('.data'); content = {}; var id_from_builder; allElemsWithId.forEach(element => { const first_letter = element.id.charAt(0).toLowerCase(); if(prefixes.includes(first_letter)){ content[first_letter] = element.innerHTML; if(first_letter === 'i'){ id_from_builder = element.id; } } }) content['d'] = dateToISO(content['d']); } // champs à remplir des nouvelles "news" else if(page === 'article' && params != null && params.get("id")[0] === 'n'){ closeEditor(id, page, false); //makeNewArticleButtons(id, id, clone); return; } // dans les autres cas, on doit pouvoir récupérer l'éditeur else{ // l'éditeur correspond à l'article OU page "article" à un élément: titre, aperçu, article editor = editors[id]; if(!editor) { console.error('Éditeur non trouvé pour l\'article:', id); return; } content = editor.getContent(); } // Envoi AJAX au serveur fetch('index.php?action=editor_submit', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({id: id, content: content}) }) .then(response => response.json()) .then(data => { if (data.success) { //console.log(data.article_id); if(id[0] === 'n' && page === 'article'){ console.log('données envoyées au serveur avec succès.'); // redirection page de l'article window.setTimeout(function(){ location.href = "index.php?page=article&id=" + data.article_id; }, 0); } else{ // Fermer l'éditeur et mettre à jour le contenu de l'article closeEditor(id, page, false); if(id[0] === 'n'){ makeNewArticleButtons(id, data.article_id, clone); } } } else { alert('Erreur lors de la sauvegarde de l\'article.'); } }) .catch(error => { console.error('Erreur:', error); }); } function makeNewArticleButtons(id, article_id, clone) { 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('onclick', "copyInClipBoard('" + window.location.href + article_id + "')"); // # de l'ancre ajouté au clic sur le lien ouvrant l'éditeur article.id = article_id; edit_btn.id = 'edit-' + article_id; edit_btn.querySelector('.action_icon').setAttribute('onclick', "openEditor('" + article_id + "')"); pos_up_btn.id = 'position_up-' + article_id; pos_up_btn.querySelector('.action_icon').setAttribute('onclick', "switchPositions('" + article_id + "', 'up')"); pos_down_btn.id = 'position_down-' + article_id; pos_down_btn.querySelector('.action_icon').setAttribute('onclick', "switchPositions('" + article_id + "', 'down')"); delete_btn.id = 'delete-' + article_id; delete_btn.querySelector('.action_icon').setAttribute('onclick', "deleteArticle('" + article_id + "')"); cancel_btn.id = 'cancel-' + article_id; cancel_btn.querySelector('button').setAttribute('onclick', "closeEditor('" + article_id + "')"); submit_btn.id = 'submit-' + article_id; submit_btn.querySelector('button').setAttribute('onclick', "submitArticle('" + article_id + "')"); var next_div = parent.nextElementSibling.nextElementSibling; parent.parentNode.replaceChild(clone.cloneNode(true), parent); // clone du squelette pour le garder intact next_div.appendChild(parent); }