// code à réorganiser
// seule certaines fonctions ont leur place dans Editor, d'autres servent à manipuler les articles d'une autre manière (déplacer, supprimer...)
// => encapsuler Editor dans une classe Article (comme la balise) qui existe même quand l'éditeur est fermé
/* -- utilisé par les évènements -- */
let editors = {};
function openEditor(id){
if(!editors[id]){
editors[id] = new Editor(id); // appel de init à l'intérieur
}
//else{editors[id].reopen();}
}
// placement d'un nouvel article dans un bloc "Articles libres"
function setArticlePlacement(id){
if(editors[id]){
editors[id].setArticlePlacement(id);
}
}
function closeEditor(id, restore_old){
if(editors[id]){
editors[id].close(restore_old);
}
}
function submitArticle(id, clone = null)
{
// bouton Valider de l'éditeur
if(editors[id]){
editors[id].submit(clone);
}
// bouton Tout enregistrer
else if(window.Config.page === "article" && id[0] === 'n'){
if(Object.keys(editors).length === 0){ // vérifier qu'il n'y a pas d'éditeur ouvert
editors[id] = new Editor(id);
editors[id].submit();
}
else{
toastNotify("Un editeur est ouvert. Validez ou annulez d'abord votre saisie dans chaque éditeur.");
}
}
}
// standalone contraîrement aux autres fonctions ici
function deleteArticle(id){
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)
{
// Supprimer l'article du DOM
const articleElement = document.getElementById(id);
findParentByTagName(articleElement, 'article').remove();
toastNotify("L'article a été supprimé.");
}
else{
toastNotify('Erreur lors de la suppression de l\'article.');
}
})
.catch(error => {
console.error('Erreur:', error);
});
}
}
class Editor
{
constructor(id){
this.id = id;
this.article = document.getElementById(this.id);
this.creation_mode = this.id[0] === 'n' ? true : false;
//this.isOpen = false;
this.tiny_instance = null;
// moche, on ne devrait sortir l'envoi des données avec fetch de Editor.submit
if(!this.creation_mode || window.Config.page !== 'article'){
if(this.creation_mode && window.Config.page !== 'article'){
this.setArticlePlacement(this.id);
}
else{
// insérer le contenu de l'article dans l'éditeur
this.article.setAttribute('data-original-content', this.article.innerHTML);
}
this.init();
}
//else // bouton Tout enregistrer, pas d'éditeur
}
setArticlePlacement(id_block){
const checked_button = document.querySelector('input[name="article_placement-' + id_block + '"]:checked');
if(checked_button){ // vrai clic
this.placement = checked_button.value;
}
else{
document.getElementById('radio_last-' + id_block).checked = true; // faux clic
this.placement = 'last';
}
}
init(){
tinymce.init({
selector: `[id="${this.id}"]`, // écrire [id="246"] au lieu de #246 parce que l'id commence par un chiffre
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,
// les fonctions fléchées permettent de garder le contexte (= this)
setup: (editor) => {
editor.on('init', () => {
this.tiny_instance = editor;
// boutons "Modifier", "Supprimer", "déplacer vers le haut", "déplacer vers le bas", "Annuler" et "Soumettre"
document.getElementById(`cancel-${this.id}`).classList.remove('hidden');
document.getElementById(`submit-${this.id}`).classList.remove('hidden');
const radio = document.getElementById(`radio-${this.id}`);
if(radio){
radio.classList.remove('hidden');
}
if(this.creation_mode){
document.getElementById(`new-${this.id}`).classList.add('hidden'); // id = new-new-id_node
}
else{
document.getElementById(`edit-${this.id}`).classList.add('hidden');
if(window.Config.page !== 'article'){
document.getElementById(`position_up-${this.id}`).classList.add('hidden');
document.getElementById(`position_down-${this.id}`).classList.add('hidden');
document.getElementById(`delete-${this.id}`).classList.add('hidden');
}
}
});
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 = `