summaryrefslogtreecommitdiff
path: root/public/index.php
diff options
context:
space:
mode:
authorpolo <ordipolo@gmx.fr>2026-01-02 23:28:41 +0100
committerpolo <ordipolo@gmx.fr>2026-01-02 23:28:41 +0100
commit5d87ee20d0d34ba676b10b5f67f4251428e1f2f7 (patch)
tree5cbb4c9970ea2a0e1e4fe1d657d48e6c73109f44 /public/index.php
parente3bd9b082a3440ce678f5e01c4a8151bf9f36c93 (diff)
downloadtinymce-5d87ee20d0d34ba676b10b5f67f4251428e1f2f7.tar.gz
tinymce-5d87ee20d0d34ba676b10b5f67f4251428e1f2f7.tar.bz2
tinymce-5d87ee20d0d34ba676b10b5f67f4251428e1f2f7.zip
upload images et documents par copier-coller et glisser-déposer, format whitelist par extensions côté JS, erreur chemin traduction, ajout format RTF
Diffstat (limited to 'public/index.php')
-rw-r--r--public/index.php258
1 files changed, 166 insertions, 92 deletions
diff --git a/public/index.php b/public/index.php
index 2cd0c78..f46b384 100644
--- a/public/index.php
+++ b/public/index.php
@@ -72,7 +72,8 @@ function curlDownloadImage(string $url, int $maxRetries = 3, int $timeout = 10):
72 return false; // échec après trois tentatives 72 return false; // échec après trois tentatives
73} 73}
74 74
75function sanitizeFileName(string $filename): string { 75function sanitizeFileName(string $filename): string
76{
76 $filename = preg_replace('/[^a-zA-Z0-9_-]/', '_', $filename); // ne garder que les lettres, chiffres, tirets et underscores 77 $filename = preg_replace('/[^a-zA-Z0-9_-]/', '_', $filename); // ne garder que les lettres, chiffres, tirets et underscores
77 $filename = preg_replace('/_+/', '_', $filename); // doublons d'underscores 78 $filename = preg_replace('/_+/', '_', $filename); // doublons d'underscores
78 return trim($filename, '_'); 79 return trim($filename, '_');
@@ -80,8 +81,8 @@ function sanitizeFileName(string $filename): string {
80 81
81function checkFileDownload(array $file): bool 82function checkFileDownload(array $file): bool
82{ 83{
83 $extensions_white_list = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'odt', 'ods', 'odp']; 84 $extensions_white_list = ['pdf', 'rtf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'odt', 'ods', 'odp']; // = extensions_white_list côté javascript
84 $mime_type_white_list = ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/vnd.oasis.opendocument.text', 'application/vnd.oasis.opendocument.spreadsheet', 'application/vnd.oasis.opendocument.presentation']; 85 $mime_type_white_list = ['application/pdf', 'application/rtf', 'text/rtf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/vnd.oasis.opendocument.text', 'application/vnd.oasis.opendocument.spreadsheet', 'application/vnd.oasis.opendocument.presentation'];
85 86
86 // 1/ extension 87 // 1/ extension
87 $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); 88 $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
@@ -93,18 +94,15 @@ function checkFileDownload(array $file): bool
93 if(!is_uploaded_file($file['tmp_name'])){ 94 if(!is_uploaded_file($file['tmp_name'])){
94 return false; 95 return false;
95 } 96 }
96 97
97 $finfo = finfo_open(FILEINFO_MIME_TYPE);
98
99 // 3/ objet $finfo valide (dépend du paramètre FILEINFO_MIME_TYPE) 98 // 3/ objet $finfo valide (dépend du paramètre FILEINFO_MIME_TYPE)
99 $finfo = new finfo(FILEINFO_MIME_TYPE);
100 if($finfo === false){ 100 if($finfo === false){
101 return false; 101 return false;
102 } 102 }
103 103
104 $real_type = finfo_file($finfo, $file['tmp_name']);
105 finfo_close($finfo);
106
107 // 4/ contrôle du "vrai" type mime (finfo_file lit les 1ers octets des fichiers pour y trouver des "signatures", très fiable sauf avec les conteneurs: doc, zip...) 104 // 4/ contrôle du "vrai" type mime (finfo_file lit les 1ers octets des fichiers pour y trouver des "signatures", très fiable sauf avec les conteneurs: doc, zip...)
105 $real_type = finfo_file($finfo, $file['tmp_name']);
108 return in_array($real_type, $mime_type_white_list, true); 106 return in_array($real_type, $mime_type_white_list, true);
109} 107}
110 108
@@ -113,9 +111,9 @@ if(isset($_GET['action']) && $_GET['action'] == 'editor_submit'){
113 $data = file_get_contents('php://input'); 111 $data = file_get_contents('php://input');
114 $json = json_decode($data, true); 112 $json = json_decode($data, true);
115 113
116 if(json_last_error() === JSON_ERROR_NONE) { 114 if(json_last_error() === JSON_ERROR_NONE){
117 // Traitement côté serveur 115 // Traitement côté serveur
118 $articleId = $json['id']; 116 $article_id = $json['id'];
119 $content = $json['content']; 117 $content = $json['content'];
120 118
121 // retour au client 119 // retour au client
@@ -135,7 +133,7 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'delete_article'){
135 $success = true; 133 $success = true;
136 134
137 // retour au client 135 // retour au client
138 if($success) { 136 if($success){
139 echo json_encode(['success' => true]); 137 echo json_encode(['success' => true]);
140 } 138 }
141 else { 139 else {
@@ -145,8 +143,6 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'delete_article'){
145 } 143 }
146 die; 144 die;
147} 145}
148
149
150elseif(isset($_GET['action']) && in_array($_GET['action'], ['upload_image', 'upload_image_url', 'upload_image_base64'])){ 146elseif(isset($_GET['action']) && in_array($_GET['action'], ['upload_image', 'upload_image_url', 'upload_image_base64'])){
151 $dest = 'images/'; 147 $dest = 'images/';
152 if(!is_dir($dest)){ 148 if(!is_dir($dest)){
@@ -222,8 +218,6 @@ elseif(isset($_GET['action']) && in_array($_GET['action'], ['upload_image', 'upl
222 } 218 }
223 die; 219 die;
224} 220}
225
226
227elseif(isset($_GET['action']) && $_GET['action'] == 'upload_file'){ 221elseif(isset($_GET['action']) && $_GET['action'] == 'upload_file'){
228 if(isset($_FILES['file'])){ 222 if(isset($_FILES['file'])){
229 $dest = 'media/'; 223 $dest = 'media/';
@@ -275,15 +269,15 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_file'){
275 <script> 269 <script>
276 let editors = {}; 270 let editors = {};
277 271
278 function openEditor(articleId) { 272 function openEditor(article_id){
279 // Récupérer et sauvegarder le contenu d'origine de l'article 273 // Récupérer et sauvegarder le contenu d'origine de l'article
280 const articleContent = document.getElementById(articleId).innerHTML; 274 const articleContent = document.getElementById(article_id).innerHTML;
281 document.getElementById(articleId).setAttribute('data-original-content', articleContent); 275 document.getElementById(article_id).setAttribute('data-original-content', articleContent);
282 276
283 tinymce.init({ 277 tinymce.init({
284 selector: `#${articleId}`, 278 selector: `#${article_id}`,
285 language: 'fr_FR', // télécharger des paquets de langue ici: https://www.tiny.cloud/get-tiny/language-packages/ 279 language: 'fr_FR', // télécharger des paquets de langue ici: https://www.tiny.cloud/get-tiny/language-packages/
286 language_url: '../vendor/tweeb/tinymce-i18n/langs/fr_FR.js', // ou installer tweeb/tinymce-i18n avec composer 280 language_url: '../vendor/mklkj/tinymce-i18n/langs/fr_FR.js', // paquet mklkj/tinymce-i18n avec composer
287 license_key: 'gpl', 281 license_key: 'gpl',
288 branding: false, 282 branding: false,
289 plugins: 'lists link autolink table image media autoresize help', 283 plugins: 'lists link autolink table image media autoresize help',
@@ -298,16 +292,17 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_file'){
298 attrs.rel += 'noreferrer'; // cacher la page d'où on vient 292 attrs.rel += 'noreferrer'; // cacher la page d'où on vient
299 } 293 }
300 },*/ 294 },*/
301 //paste_data_images: true, 295 setup: function (editor){
302 setup: function (editor) { 296 const extensions_white_list = ['pdf', 'rtf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'odt', 'ods', 'odp']; // = $extensions_white_list côté PHP
303 editor.on('init', function () { 297
304 editors[articleId] = editor; 298 editor.on('init', function (){
299 editors[article_id] = editor;
305 300
306 // Masquer le bouton "Modifier" et afficher les boutons "Annuler" et "Soumettre" 301 // Masquer le bouton "Modifier" et afficher les boutons "Annuler" et "Soumettre"
307 document.querySelector(`#edit-${articleId}`).classList.add('hidden'); 302 document.querySelector(`#edit-${article_id}`).classList.add('hidden');
308 document.querySelector(`#delete-${articleId}`).classList.add('hidden'); 303 document.querySelector(`#delete-${article_id}`).classList.add('hidden');
309 document.querySelector(`#cancel-${articleId}`).classList.remove('hidden'); 304 document.querySelector(`#cancel-${article_id}`).classList.remove('hidden');
310 document.querySelector(`#submit-${articleId}`).classList.remove('hidden'); 305 document.querySelector(`#submit-${article_id}`).classList.remove('hidden');
311 }); 306 });
312 let skipPastePreProcess = false; 307 let skipPastePreProcess = false;
313 editor.on('Paste', function (e){ // déclenchement AVANT PastePreProcess et quelque que soit le contenu collé 308 editor.on('Paste', function (e){ // déclenchement AVANT PastePreProcess et quelque que soit le contenu collé
@@ -315,41 +310,39 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_file'){
315 if(!clipboardData){ 310 if(!clipboardData){
316 return; 311 return;
317 } 312 }
318 const items = clipboardData.items; 313 const items = clipboardData.items; // base64
319 let foundImage = false; 314 const files = clipboardData.files; // explorateur de fichiers
320 315 let found_file = false;
321 for(let i = 0; i < items.length; i++){ 316
322 let item = items[i]; 317 // données dans files
323 318 if(files && files.length > 0){ // noter que files peut être vide, alors que items non
324 if(item.type.indexOf('image') !== -1){ // test type MIME contenant image 319 for(let i = 0; i < files.length; i++){
325 foundImage = true; 320 let file = files[i];
326 321
327 const file = item.getAsFile(); // presse-papier => fichier lisible 322 if(extensions_white_list.includes(file.name.split('.').pop().toLowerCase())){
328 const reader = new FileReader(); 323 found_file = true;
329 324 uploadDocument(file, editor);
330 reader.onload = function (event){ // fonction exécutée lorsque reader.readAsDataURL(file) est terminée 325 }
331 const base64Data = event.target.result; // données de l'image 326 else if(file.type.indexOf('image') !== -1){
332 327 found_file = true;
333 fetch('index.php?action=upload_image_base64', { 328 uploadImageBase64(file, editor);
334 method: 'POST', 329 }
335 headers: { 'Content-Type': 'application/json' }, 330 }
336 body: JSON.stringify({ image_base64: base64Data }) 331 }
337 }) 332 // données dans items
338 .then(response => response.json()) 333 else{ // les images collées depuis l'explorateur sont aussi dans items, or elles sont déjà gérées plus haut
339 .then(data => { 334 for(let i = 0; i < items.length; i++){
340 if(data.location){ 335 let item = items[i];
341 editor.insertContent('<img src="' + data.location + '">'); 336
342 } 337 if(item.type.indexOf('image') !== -1){ // test type MIME contenant image
343 }) 338 found_file = true;
344 .catch(error => { 339 const file = item.getAsFile(); // presse-papier => fichier lisible
345 console.error('Erreur lors de l’upload de l’image base64 :', error); 340 uploadImageBase64(file, editor);
346 }); 341 }
347 };
348 reader.readAsDataURL(file); // lecture asynchrone du fichier
349 } 342 }
350 } 343 }
351 344
352 if(foundImage){ 345 if(found_file){
353 e.preventDefault(); // supprime le collage automatiue 346 e.preventDefault(); // supprime le collage automatiue
354 skipPastePreProcess = true; // désactiver le PastePreProcess pour ce collage 347 skipPastePreProcess = true; // désactiver le PastePreProcess pour ce collage
355 } 348 }
@@ -363,7 +356,6 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_file'){
363 const parser = new DOMParser(); 356 const parser = new DOMParser();
364 const doc = parser.parseFromString(e.content, 'text/html'); 357 const doc = parser.parseFromString(e.content, 'text/html');
365 const images = doc.querySelectorAll('img'); 358 const images = doc.querySelectorAll('img');
366
367 let downloads_in_progress = []; 359 let downloads_in_progress = [];
368 360
369 images.forEach(img => { 361 images.forEach(img => {
@@ -395,7 +387,6 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_file'){
395 // une image web ou plus: différer l'insertion dans l'éditeur le temps que le serveur télécharge les images 387 // une image web ou plus: différer l'insertion dans l'éditeur le temps que le serveur télécharge les images
396 if(downloads_in_progress.length > 0){ 388 if(downloads_in_progress.length > 0){
397 e.preventDefault(); 389 e.preventDefault();
398
399 Promise.all(downloads_in_progress).then(() => { 390 Promise.all(downloads_in_progress).then(() => {
400 e.content = doc.body.innerHTML; // remplacement du HTML dans l'éditeur par la copie modifiée (doc) 391 e.content = doc.body.innerHTML; // remplacement du HTML dans l'éditeur par la copie modifiée (doc)
401 editor.insertContent(e.content); 392 editor.insertContent(e.content);
@@ -405,13 +396,47 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_file'){
405 e.content = doc.body.innerHTML; // remplacement du HTML dans l'éditeur par la copie modifiée (doc) 396 e.content = doc.body.innerHTML; // remplacement du HTML dans l'éditeur par la copie modifiée (doc)
406 } 397 }
407 }); 398 });
399 // glisser-déposer de fichiers (sauf images qui sont déjà gérées nativement)
400 editor.on('drop', function(e){
401 const data = e.dataTransfer;
402 if(!data || !data.files || data.files.length === 0){
403 return; // Laisser TinyMCE gérer (texte, images déjà supportées, etc.)
404 }
405 const files = data.files;
406
407 let has_documents = false;
408 for(let i = 0; i < files.length; i++){
409 if(extensions_white_list.includes(files[i].name.split('.').pop().toLowerCase())){
410 has_documents = true;
411 break;
412 }
413 }
414
415 if(has_documents){
416 e.preventDefault();
417 e.stopPropagation();
418
419 for(let i = 0; i < files.length; i++){
420 let file = files[i];
421
422 if(extensions_white_list.includes(file.name.split('.').pop().toLowerCase())){
423 uploadDocument(file, editor);
424 }
425 else if(file.type.indexOf('image') !== -1){
426 uploadImageBase64(file, editor);
427 }
428 }
429 }
430 // autres cas: tinymce gère tout seul
431 });
408 }, 432 },
409 // upload d'image natif de tinymce avec le bouton "Insérer une image" 433 // upload d'image avec le bouton "Insérer une image"
410 images_upload_handler: images_upload_handler, // = fonction fléchée 434 images_upload_handler: images_upload_handler, // = fonction fléchée
411 // upload de documents (bouton "insérer un lien") 435 // upload de documents avec le bouton "insérer un lien"
412 files_upload_handler: files_upload_handler, // = fonction fléchée 436 files_upload_handler: files_upload_handler, // = fonction fléchée
413 documents_file_types: [ // files_upload_handler a besoin qu'on lui donne tous les types mime 437 documents_file_types: [ // files_upload_handler a besoin qu'on lui donne tous les types mime
414 { mimeType: 'application/pdf', extensions: [ 'pdf' ] }, 438 { mimeType: 'application/pdf', extensions: [ 'pdf' ] },
439 { mimeType: 'application/rtf', extensions: [ 'rtf' ] },
415 { mimeType: 'application/msword', extensions: [ 'doc' ] }, 440 { mimeType: 'application/msword', extensions: [ 'doc' ] },
416 { mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', extensions: [ 'docx' ] }, 441 { mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', extensions: [ 'docx' ] },
417 { mimeType: 'application/vnd.ms-excel', extensions: [ 'xls' ] }, 442 { mimeType: 'application/vnd.ms-excel', extensions: [ 'xls' ] },
@@ -426,7 +451,7 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_file'){
426 }); 451 });
427 452
428 // Remplacer le contenu de l'article par l'éditeur 453 // Remplacer le contenu de l'article par l'éditeur
429 document.getElementById(articleId).innerHTML = articleContent; 454 document.getElementById(article_id).innerHTML = articleContent;
430 } 455 }
431 456
432 const images_upload_handler = (blobInfo, progress) => new Promise((resolve, reject) => { 457 const images_upload_handler = (blobInfo, progress) => new Promise((resolve, reject) => {
@@ -439,10 +464,10 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_file'){
439 }) 464 })
440 .then(response => response.json()) 465 .then(response => response.json())
441 .then(data => { 466 .then(data => {
442 if(data.location) { 467 if(data.location){
443 resolve({url: data.location}); 468 resolve({url: data.location});
444 } 469 }
445 else { 470 else{
446 reject("Erreur: Chemin d'image invalide"); 471 reject("Erreur: Chemin d'image invalide");
447 } 472 }
448 }) 473 })
@@ -451,7 +476,7 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_file'){
451 }); 476 });
452 }); 477 });
453 478
454 const files_upload_handler = (blobInfo, progress) => new Promise((resolve, reject) => { 479 const files_upload_handler = (blobInfo, progress) => new Promise((resolve, reject) => { // utilisation = bouton "link" (OU drag & drop, et oui)
455 const formData = new FormData(); 480 const formData = new FormData();
456 formData.append("file", blobInfo.blob()); 481 formData.append("file", blobInfo.blob());
457 482
@@ -461,7 +486,7 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_file'){
461 }) 486 })
462 .then(response => response.json()) 487 .then(response => response.json())
463 .then(data => { 488 .then(data => {
464 if(data.location) { 489 if(data.location){
465 console.log(blobInfo.filename()); 490 console.log(blobInfo.filename());
466 console.log(data.location); 491 console.log(data.location);
467 492
@@ -471,7 +496,7 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_file'){
471 fileName: blobInfo.filename(), 496 fileName: blobInfo.filename(),
472 }); 497 });
473 } 498 }
474 else { 499 else{
475 reject("Erreur: Chemin du fichier invalide"); 500 reject("Erreur: Chemin du fichier invalide");
476 } 501 }
477 }) 502 })
@@ -480,21 +505,21 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_file'){
480 }); 505 });
481 }); 506 });
482 507
483 function deleteArticle(articleId) { 508 function deleteArticle(article_id) {
484 if (confirm('Voulez-vous vraiment supprimer cet article ?')) { 509 if(confirm('Voulez-vous vraiment supprimer cet article ?')){
485 // Envoyer une requête au serveur pour supprimer l'article 510 // Envoyer une requête au serveur pour supprimer l'article
486 fetch('index.php?action=delete_article', { 511 fetch('index.php?action=delete_article', {
487 method: 'POST', 512 method: 'POST',
488 headers: { 513 headers: {
489 'Content-Type': 'application/json' 514 'Content-Type': 'application/json'
490 }, 515 },
491 body: JSON.stringify({ id: articleId }) 516 body: JSON.stringify({ id: article_id })
492 }) 517 })
493 .then(response => response.json()) 518 .then(response => response.json())
494 .then(data => { 519 .then(data => {
495 if (data.success) { 520 if (data.success) {
496 // Supprimer l'article du DOM 521 // Supprimer l'article du DOM
497 const articleElement = document.getElementById(articleId); 522 const articleElement = document.getElementById(article_id);
498 articleElement.parentElement.remove(); 523 articleElement.parentElement.remove();
499 } 524 }
500 else { 525 else {
@@ -507,29 +532,29 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_file'){
507 } 532 }
508 } 533 }
509 534
510 function closeEditor(articleId){ 535 function closeEditor(article_id){
511 // Récupérer le contenu d'origine de l'article 536 // Récupérer le contenu d'origine de l'article
512 const originalContent = document.getElementById(articleId).getAttribute('data-original-content'); 537 const originalContent = document.getElementById(article_id).getAttribute('data-original-content');
513 538
514 // Fermer l'éditeur 539 // Fermer l'éditeur
515 tinymce.remove(`#${articleId}`); 540 tinymce.remove(`#${article_id}`);
516 delete editors[articleId]; 541 delete editors[article_id];
517 542
518 // Restaurer le contenu d'origine de l'article 543 // Restaurer le contenu d'origine de l'article
519 document.getElementById(articleId).innerHTML = originalContent; 544 document.getElementById(article_id).innerHTML = originalContent;
520 545
521 // Afficher le bouton "Modifier" et masquer les boutons "Annuler" et "Soumettre" 546 // Afficher le bouton "Modifier" et masquer les boutons "Annuler" et "Soumettre"
522 document.querySelector(`#edit-${articleId}`).classList.remove('hidden'); 547 document.querySelector(`#edit-${article_id}`).classList.remove('hidden');
523 document.querySelector(`#delete-${articleId}`).classList.remove('hidden'); 548 document.querySelector(`#delete-${article_id}`).classList.remove('hidden');
524 document.querySelector(`#cancel-${articleId}`).classList.add('hidden'); 549 document.querySelector(`#cancel-${article_id}`).classList.add('hidden');
525 document.querySelector(`#submit-${articleId}`).classList.add('hidden'); 550 document.querySelector(`#submit-${article_id}`).classList.add('hidden');
526 } 551 }
527 552
528 function submitArticle(articleId) { 553 function submitArticle(article_id) {
529 // Récupérer l'éditeur correspondant à l'article 554 // Récupérer l'éditeur correspondant à l'article
530 const editor = editors[articleId]; 555 const editor = editors[article_id];
531 if(!editor){ 556 if(!editor){
532 console.error('Éditeur non trouvé pour l\'article:', articleId); 557 console.error('Éditeur non trouvé pour l\'article:', article_id);
533 return; 558 return;
534 } 559 }
535 560
@@ -542,18 +567,18 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_file'){
542 headers: { 567 headers: {
543 'Content-Type': 'application/json' 568 'Content-Type': 'application/json'
544 }, 569 },
545 body: JSON.stringify({ id: articleId, content: newContent }) 570 body: JSON.stringify({ id: article_id, content: newContent })
546 }) 571 })
547 .then(response => response.json()) 572 .then(response => response.json())
548 .then(data => { 573 .then(data => {
549 // Fermer l'éditeur et mettre à jour le contenu de l'article 574 // Fermer l'éditeur et mettre à jour le contenu de l'article
550 closeEditor(articleId); 575 closeEditor(article_id);
551 document.getElementById(articleId).innerHTML = newContent; 576 document.getElementById(article_id).innerHTML = newContent;
552 //console.log(newContent); 577 //console.log(newContent);
553 if(data.success){ 578 if(data.success){
554 // Fermer l'éditeur et mettre à jour le contenu de l'article 579 // Fermer l'éditeur et mettre à jour le contenu de l'article
555 tinymce.remove(`#${articleId}`); 580 tinymce.remove(`#${article_id}`);
556 document.getElementById(articleId).innerHTML = newContent; 581 document.getElementById(article_id).innerHTML = newContent;
557 } 582 }
558 else{ 583 else{
559 alert('Erreur lors de la sauvegarde de l\'article.'); 584 alert('Erreur lors de la sauvegarde de l\'article.');
@@ -563,6 +588,55 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_file'){
563 console.error('Erreur:', error); 588 console.error('Erreur:', error);
564 }); 589 });
565 } 590 }
591
592 function uploadImageBase64(file, editor){
593 const reader = new FileReader();
594
595 reader.onload = function (event){ // fonction exécutée lorsque reader.readAsDataURL(file) est terminée
596 const base64 = event.target.result; // données de l'image
597
598 fetch('index.php?action=upload_image_base64', {
599 method: 'POST',
600 headers: { 'Content-Type': 'application/json' },
601 body: JSON.stringify({ image_base64: base64 })
602 })
603 .then(response => response.json())
604 .then(data => {
605 if(data.location){
606 editor.insertContent('<img src="' + data.location + '">');
607 }
608 })
609 .catch(error => {
610 console.error('Erreur lors de l’upload de l’image base64 :', error);
611 });
612 };
613 reader.readAsDataURL(file); // lecture asynchrone du fichier
614 }
615 function uploadDocument(file, editor){ // utilisation = copier-coller de l'explorateur de fichiers
616 const formData = new FormData();
617 formData.append("file", file);
618
619 fetch('index.php?action=upload_file', {
620 method: 'POST',
621 body: formData
622 })
623 .then(response => response.json())
624 .then(data => {
625 if(data.location){
626 // créer le lien <a>
627 const file_name = file.name;
628 const extension = file_name.split('.').pop().toLowerCase();
629 const target = extension === 'pdf' ? 'target="_blank"' : ''; // PDF = page
630 editor.insertContent(`<a href="${data.location}" ${target} title="${file_name}">[${extension}] ${file_name}</a>`);
631 }
632 else {
633 console.error("Erreur: Chemin du fichier invalide");
634 }
635 })
636 .catch(error => {
637 console.error("Erreur lors de l'upload du document :", error);
638 });
639 }
566 </script> 640 </script>
567</head> 641</head>
568<body> 642<body>