diff options
-rw-r--r-- | public/index.php | 97 |
1 files changed, 93 insertions, 4 deletions
diff --git a/public/index.php b/public/index.php index 5f5d904..54ddb31 100644 --- a/public/index.php +++ b/public/index.php | |||
@@ -164,6 +164,45 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_url'){ | |||
164 | } | 164 | } |
165 | die; | 165 | die; |
166 | } | 166 | } |
167 | elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_base64'){ | ||
168 | $json = json_decode(file_get_contents('php://input'), true); | ||
169 | $dest = 'images/'; | ||
170 | |||
171 | if(!is_dir('images')){ | ||
172 | mkdir('images', 0777, true); | ||
173 | } | ||
174 | |||
175 | // détection de data:image/ et de ;base64, et capture du format dans $type | ||
176 | if(!isset($json['image_base64']) || !preg_match('/^data:image\/(\w+);base64,/', $json['image_base64'], $type)){ | ||
177 | http_response_code(400); | ||
178 | echo json_encode(['message' => 'Données image base64 manquantes ou invalides']); | ||
179 | die; | ||
180 | } | ||
181 | |||
182 | $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif']; | ||
183 | $extension = strtolower($type[1]); | ||
184 | if(!in_array($extension, $allowed_extensions) || $extension === 'jpg'){ | ||
185 | $extension = 'jpeg'; | ||
186 | } | ||
187 | |||
188 | $image_data = base64_decode(substr($json['image_base64'], strpos($json['image_base64'], ',') + 1)); // découpe la chaine à la virgule puis convertit en binaire | ||
189 | if($image_data === false){ | ||
190 | http_response_code(400); | ||
191 | echo json_encode(['message' => 'Décodage base64 invalide']); | ||
192 | die; | ||
193 | } | ||
194 | |||
195 | $local_path = $dest . 'pasted_image_' . uniqid() . '.' . $extension; | ||
196 | |||
197 | if(imagickCleanImage($image_data, $local_path)){ | ||
198 | echo json_encode(['location' => $local_path]); | ||
199 | } | ||
200 | else{ | ||
201 | http_response_code(500); | ||
202 | echo json_encode(['message' => 'Erreur image non valide']); | ||
203 | } | ||
204 | die; | ||
205 | } | ||
167 | ?> | 206 | ?> |
168 | <!DOCTYPE html> | 207 | <!DOCTYPE html> |
169 | <html lang="fr"> | 208 | <html lang="fr"> |
@@ -188,6 +227,7 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_url'){ | |||
188 | // Récupérer et sauvegarder le contenu d'origine de l'article | 227 | // Récupérer et sauvegarder le contenu d'origine de l'article |
189 | const articleContent = document.getElementById(articleId).innerHTML; | 228 | const articleContent = document.getElementById(articleId).innerHTML; |
190 | document.getElementById(articleId).setAttribute('data-original-content', articleContent); | 229 | document.getElementById(articleId).setAttribute('data-original-content', articleContent); |
230 | let skipPastePreProcess = false; | ||
191 | 231 | ||
192 | tinymce.init({ | 232 | tinymce.init({ |
193 | selector: `#${articleId}`, | 233 | selector: `#${articleId}`, |
@@ -211,7 +251,57 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_url'){ | |||
211 | document.querySelector(`#cancel-${articleId}`).classList.remove('hidden'); | 251 | document.querySelector(`#cancel-${articleId}`).classList.remove('hidden'); |
212 | document.querySelector(`#submit-${articleId}`).classList.remove('hidden'); | 252 | document.querySelector(`#submit-${articleId}`).classList.remove('hidden'); |
213 | }); | 253 | }); |
214 | editor.on('PastePreProcess', function (e){ // déclenchement au collage AVANT insertion dans l'éditeur | 254 | editor.on('Paste', function (e){ // déclenchement AVANT PastePreProcess et quelque que soit le contenu collé |
255 | const clipboardData = (e.clipboardData || e.originalEvent.clipboardData); | ||
256 | if(!clipboardData){ | ||
257 | return; | ||
258 | } | ||
259 | const items = clipboardData.items; | ||
260 | let foundImage = false; | ||
261 | |||
262 | for(let i = 0; i < items.length; i++){ | ||
263 | let item = items[i]; | ||
264 | |||
265 | if(item.type.indexOf('image') !== -1){ // test type MIME contenant image | ||
266 | foundImage = true; | ||
267 | |||
268 | const file = item.getAsFile(); // presse-papier => fichier lisible | ||
269 | const reader = new FileReader(); | ||
270 | |||
271 | reader.onload = function (event){ // fonction exécutée lorsque reader.readAsDataURL(file) est terminée | ||
272 | const base64Data = event.target.result; // données de l'image | ||
273 | |||
274 | fetch('index.php?action=upload_image_base64', { | ||
275 | method: 'POST', | ||
276 | headers: { 'Content-Type': 'application/json' }, | ||
277 | body: JSON.stringify({ image_base64: base64Data }) | ||
278 | }) | ||
279 | .then(response => response.json()) | ||
280 | .then(data => { | ||
281 | if(data.location){ | ||
282 | editor.insertContent('<img src="' + data.location + '">'); | ||
283 | } | ||
284 | }) | ||
285 | .catch(error => { | ||
286 | console.error('Erreur lors de l’upload de l’image base64 :', error); | ||
287 | }); | ||
288 | }; | ||
289 | reader.readAsDataURL(file); // lecture asynchrone du fichier | ||
290 | } | ||
291 | } | ||
292 | |||
293 | if(foundImage){ | ||
294 | e.preventDefault(); // supprime le collage automatiue | ||
295 | skipPastePreProcess = true; // désactiver le PastePreProcess pour ce collage | ||
296 | } | ||
297 | }); | ||
298 | editor.on('PastePreProcess', function (e){ // déclenchement au collage AVANT insertion dans l'éditeur SI le contenu est du HTML | ||
299 | if(skipPastePreProcess){ | ||
300 | skipPastePreProcess = false; // réinitialiser pour la prochaine fois | ||
301 | return; // ignorer ce traitement | ||
302 | } | ||
303 | |||
304 | console.log('PastePreProcess'); | ||
215 | const parser = new DOMParser(); | 305 | const parser = new DOMParser(); |
216 | const doc = parser.parseFromString(e.content, 'text/html'); | 306 | const doc = parser.parseFromString(e.content, 'text/html'); |
217 | const images = doc.querySelectorAll('img'); | 307 | const images = doc.querySelectorAll('img'); |
@@ -221,9 +311,8 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_url'){ | |||
221 | images.forEach(img => { | 311 | images.forEach(img => { |
222 | if(img.src.startsWith('file://')){ // détection d'images non insérables | 312 | if(img.src.startsWith('file://')){ // détection d'images non insérables |
223 | console.warn('Image locale non insérable dans tinymce :', img.src); | 313 | console.warn('Image locale non insérable dans tinymce :', img.src); |
224 | img.outerHTML = '<div style="border:1px solid red; padding:10px; margin:5px 0; background-color:#ffe6e6; color:#a94442; font-size:14px;">' + | 314 | img.outerHTML = `<div style="border:1px solid red; padding:10px; margin:5px 0; background-color:#ffe6e6; color:#a94442; font-size:14px;"> |
225 | "Image locale non insérée (vient-elle de LibreOffice ?). Effacez cet encadré et copiez-collez l'image seule. Ensuite cliquez sur le bouton Insérer une image puis dans la nouvelle fenêtre sur Enregistrer." + | 315 | "Image locale non insérée (vient-elle d'un document LibreOffice ?). Effacez ce message rouge et copiez-collez l'image seule.</div>`; |
226 | '</div>'; | ||
227 | } | 316 | } |
228 | else if(img.src.startsWith('http')){ // détection d'images web | 317 | else if(img.src.startsWith('http')){ // détection d'images web |
229 | const promise = fetch('index.php?action=upload_image_url', { // promesse d'un fichier téléchargeable sur le serveur | 318 | const promise = fetch('index.php?action=upload_image_url', { // promesse d'un fichier téléchargeable sur le serveur |