Implanter Easy Markdown Editor

Le problème exposé dans ce sujet a été résolu.

Salut !

Pour un projet, je souhaite utiliser Easy Markdown Editor. J’ai réussi à intégrer en version « par défaut », mais je n’arrive pas à configurer pour qu’il permette l’upload. Je ne comprends pas bien la documentation, et je suis une bille en JS :/

Voici actuellement mon code :

var editor = new EasyMDE({
element: document.getElementById('textarea')
});

Merci de votre aide.

+0 -0

Je n’ai pas essayé mais apparemment, ça se configure avec l’option uploadImage à true.
En utilisant imageUploadFunction ou imageUploadEndpoint en plus de uploadImage en fonction de comment tu comptes faire ça, c’est soit l’un, soit l’autre.

Donc, c’est pas super triviale.

Dans tous les cas, tu auras besoin d’un peu de code pour stocker l’image. Tu veux la stocker où cette image ? Tu as une idée de comment la stocker ?
Si c’est sur le serveur même, coté back, c’est quel langage ?

Basiquement, l’idée c’est :

var editor = new EasyMDE({
  element: document.getElementById('textarea'),
  uploadImage: true,
  imageUploadEndpoint: "/upload/image" // Où, upload/image est un va servir à stocker une image.
});

C’est le plus simple, mais cette solution dépends de beaucoup de choses. Ton application, elle est disponible sur internet ou pas ?

+1 -0

Côté back, c’est du PHP, je pense adapter un code d’un upload via formulaire (déjà présent dans l’application).

Oui, mon application est dispo sur Internet, le code source est ici. (Je ferais bientôt une présentation officielle sur le site ^^).

+0 -0

Alors tu peux déjà commencer par créer ta page /upload_image.php par exemple.

Cette page réagira aux requêtes POST en enregistrant les données sur le serveur. Le retour doit être du json. Pas d’inquiétude sur la génération du JSON, on est sur quelque chose de très simple, pas besoin d’une bibliothèque pour gérer ça.

imageUploadEndpoint: The endpoint where the images data will be sent, via an asynchronous POST request. The server is supposed to save this image, and return a json response.

  • if the request was successfully processed (HTTP 200-OK): {"data": {"filePath": "<filePath>"}} where filePath is the relative path of the image;
  • otherwise: {"error": "<errorCode>"}, where errorCode can be noFileGiven (HTTP 400), typeNotAllowed (HTTP 415), fileTooLarge (HTTP 413) or importError (see errorMessages below). If errorCode is not one of the errorMessages, it is alerted unchanged to the user. This allows for server side error messages. No default value.

Ça fait trop longtemps que je n’ai pas fait de PHP pour te décrire précisément comment tu dois procéder mais commencer par la documentation me semble le meilleur moyen.

Après, il va falloir penser sécurité. C’est-à-dire, que comme ça, tout le monde pourra déposer une image sur ton site, sans avoir besoin de s’inscrire à priori ? Bref, la gestion des ressources est une question que tu va devoir résoudre assez rapidement.

PS: « note: never trust client, always check * at server-side »

+0 -0
<?php
if(isset($_FILES['userfile'])) {
    $uploaddir = './';
    $uploadfile = $uploaddir . basename($_FILES['userfile']['name']);
    $blacklist_mimetype = array('text/html', 'text/javascript', 'text/x-javascript', 'application/x-shellscript', 'application/x-php', 'text/x-php', 'text/x-python', 'text/x-perl', 'text/x-bash', 'text/x-sh', 'text/x-csh', 'text/scriptlet', 'application/x-msdownload', 'application/x-msmetafile');
    if(in_array($_FILES['userfile']['type'],$blacklist_mimetype)) {
        echo json_encode(array('error'=>'typeNotAllowed'));
    }
    if(!is_uploaded_file($_FILES['userfile']['tmp_name'])) {
        echo json_encode(array('error'=>'importError'));
    }
    if(move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
        echo json_encode(array('data'=>array('filePath'=>$uploadfile)));
    }
}

Bon je peaufinerais en vérifiant si le gars est bien connecté, etc… mais ça donne une bonne base de travail pour la suite. Reste à savoir comment interfacer avec EMDE, et c’est ça que j’ai pas bien compris.

+0 -0

Mon code final. pas merci la doc pas commenté. Merci bien :-)

error_reporting(0);
if(isset($_FILES['image'])) {
    $uploaddir = './';
    $uploadfile = $uploaddir . basename($_FILES['image']['name']);
    $blacklist_mimetype = array('text/html', 'text/javascript', 'text/x-javascript', 'application/x-shellscript', 'application/x-php', 'text/x-php', 'text/x-python', 'text/x-perl', 'text/x-bash', 'text/x-sh', 'text/x-csh', 'text/scriptlet', 'application/x-msdownload', 'application/x-msmetafile');
    if(in_array($_FILES['image']['type'],$blacklist_mimetype)) {
        echo json_encode(array('error'=>'typeNotAllowed'));
    }
    if(!is_uploaded_file($_FILES['image']['tmp_name'])) {
        echo json_encode(array('error'=>'importError'));
        echo "can't upload";
    }
    if (move_uploaded_file($_FILES['image']['tmp_name'], $uploadfile)) {
        echo json_encode(array('data'=> array('filePath'=>$uploaddir.$uploadfile)));
    }
}
var editor = new EasyMDE({
  element: document.getElementById('textarea'),
  uploadImage: true,
  imageUploadEndpoint: "upload/"
});
+0 -0

Bonjour,

Je remonte ce topic. J’essaye de personnaliser mon upload (je renomme côté serveur les fichiers), mais je sais pas ce qui cloche dans mon code. Je pense que c’est ma fonction :

var editor = new EasyMDE ({
    element: document.getElementById('textarea'),
    promptURLs: true,
    uploadImage: true,
    //imageUploadEndpoint: 'api.php?do=upload',
    imageUploadFunction: UploadPicture,
    imageMaxSize: 1024*1024*20,
    imageUploadAbsoluteURL:false
});

var UploadPicture = function(file, onSuccess, onError) {
    var form_data = new FormData();
    var imageUrl;
    form_data.append('image', file);
    var xhr = new XMLHttpRequest();
    xhr.open('POST', 'api.php?do=upload');
    xhr.send(form_data);
     if (xhr.readyState === DONE) {
        if (xhr.status === OK) {
          console.log(xhr.responseText); // 'This is the returned text.'
            imageUrl = JSON.parse(xhr.image_url)
        } else {
          console.log('Error: ' + xhr.status); // An error occurred during the request.
        }
     }
}

Si vous avez une idée…

+0 -0
     if (xhr.readyState === DONE) {
        if (xhr.status === OK) {
          console.log(xhr.responseText); // 'This is the returned text.'
            imageUrl = JSON.parse(xhr.image_url)
        } else {
          console.log('Error: ' + xhr.status); // An error occurred during the request.
        }
     }

Ce bout de code là n’a rien à faire ici. Il doit se trouver dans un callback. Ceci à plus de change de marcher.

var UploadPicture = function(file, onSuccess, onError) {
    var form_data = new FormData();
    var imageUrl;
    form_data.append('image', file);
    var xhr = new XMLHttpRequest();

    xhr.onreadystatechange = () => {
      if (xhr.readyState === XMLHttpRequest.DONE) {
        if (xhr.status >= 200 && xhr.status < 300) {
          console.log(xhr.responseText); // 'This is the returned text.'
            imageUrl = JSON.parse(xhr.image_url)
        } else {
          console.log('Error: ' + xhr.status); // An error occurred during the request.
        }
      }
    };
    xhr.open('POST', 'api.php?do=upload');
    xhr.send(form_data);
}

En espérant que ça marche mieux !

xhr fonctionne de manière asynchrone. Il ne va pas bloquer ton code. Il va simplement demander au navigateur de faire la requête. Ensuite le navigateur appellera ta callback quand il aura progresser dans la requête.
C’est pour ça que l’on doit absolument utiliser une callback et que ton code ne pouvait pas fonctionner.

Edit: J’ai trouvé ça qui explique bien.

+0 -0

Bon, ça déconne toujours autant, je ne vois pas pourquoi… La doc n’est pas claire. Je sais que @A-312 a bossé sur la question pour ZDS (je me suis inspiré d’ailleurs de son code).

Dans la console, j’ai cette erreur : EasyMDE: The server did not return a valid json. easymde.min.js:14:303503 onload easymde.min.js:14

Étrange…

+0 -0

La config de zeste de savoir (sans la personnalisation des boutons) est :

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Example / Preview</title>
    <link rel="stylesheet" href="../dist/easymde.min.css">
    <script src="../dist/easymde.min.js"></script>
</head>

<body>
    <textarea id="myText"></textarea>
    <script>
        var easyMDE = new EasyMDE({
            element: document.getElementById('myText'),
            spellChecker: false,
            inputStyle: 'contenteditable',
            autosave: {
                enabled: true,
                uniqueId: 12,
                submit_delay: 10000,
                delay: 1000
            },
            indentWithTabs: false,
            minHeight: 200,
            placeholder: 'Votre message au format Markdown',
            promptURLs: true,
            promptTexts: {
            image: 'Url de votre image',
            link: 'Url de votre lien'
            },
            uploadImage: true,
            imageUploadFunction: () => {},
            imageTexts: {
            sbInit: 'Joindre des images par glisser-déposer ou coller depuis le presse-papiers.',
            sbOnDragEnter: 'Déposer l"image pour l"envoyer dans votre galérie',
            sbOnDrop: 'Téléchargement d"images #images_names#',
            sbProgress: 'Téléchargement #file_name#: #progress#%',
            sbOnUploaded: 'Image téléchargée #image_name#'
            },
            nativeSpellcheck: true,
            promptAbbrv: true,
            theme: 'idea',
            previewRender: () => {},
            syncSideBySidePreviewScroll: false
        });
    </script>
</body>

</html> 

Le code qui concerne l’upload :

  var uploadImage = function(file, onSuccess, onError) {
    var galleryUrl = '/api/galeries/' + document.body.getAttribute('data-gallery') + '/images/'

    var formData = new FormData()
    formData.append('physical', file)
    formData.append('title', file.name)
    // WARN: if you test zds with sqlite, you can"t upload multiple files at a time
    $.ajax({
      url: galleryUrl,
      data: formData,
      type: 'POST',
      processData: false,
      contentType: false,
      headers: {
        'X-CSRFToken': csrf
      },
      dataType: 'json'
    }).done(function(result) {
      onSuccess(result.url)
    }).fail(function(resp) {
      var error = 'Erreur inconnue'
      if (resp.responseText !== undefined && resp.responseText.indexOf('RequestDataTooBig') !== -1) {
        error = 'L"image est trop lourde.'
      } else if (resp.responseJSON !== undefined) {
        error = resp.responseJSON[0]
      } else if (resp.responseText !== undefined) {
        error = 'Erreur ' + resp.status + ' ' + resp.statusText + ' : ' + "'" + resp.responseText.split('\n')[0] + "'"
      } else if (resp.readyState === 0 && resp.statusText === 'error') {
        error = 'Oups ! Impossible de se connecter au serveur.'
      }
      onError(error)
    })
  }

Dans ton cas :

function UploadPicture(file, onSuccess, onError) {
    var form_data = new FormData();
    var imageUrl;
    form_data.append('image', file);
    var xhr = new XMLHttpRequest();

    xhr.onreadystatechange = () => {
      if (xhr.readyState === XMLHttpRequest.DONE) {
        if (xhr.status >= 200 && xhr.status < 300) {
          console.log(xhr.responseText); // 'This is the returned text.'
          imageUrl = JSON.parse(xhr.image_url)
          onSuccess(imageUrl)
        } else {
          console.log('Error: ' + xhr.status); // An error occurred during the request.
          onError(xhr.status) // je ne suis pas sûr d'ici
        }
      }
    };
    xhr.open('POST', 'api.php?do=upload');
    xhr.send(form_data);
}

Ensuite : function UploadPicture( et var UploadPicture = function( ne font pas la même chose. Je te laisse essayer :

console.log(typeof variable)

var variable = function() {}

et

console.log(typeof maFonction)

function maFonction() {}

C’est une très mauvaise habitude que tu as là de remplacer var variable = function() {} par function maFonction() {} (quand tu es dans la scope globale).

Merci de l’info. Je m’étais pourtant inspiré de ton code sur le github de ZDS… J’ai remplacé par function MaFonction() {}. Ça marche toujours pas, mais l’erreur change dans la console :

{"data":{"filePath":"data\/files\/STAY AT HOME-FR.jpg"}} easymde.js:20:19
SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON dataeasymde.js:21:27
    onreadystatechange easymde.js:21

J’ai cette ligne donc : imageUrl = JSON.parse(xhr.image_url) qui déconne… Je présume que je parle mal xhr.responseText

ÉDIT : En trafiquant bien, j’ai réussi à avoir ce résultat qui fonctionne :

var editor = new EasyMDE ({
    element: document.getElementById('textarea'),
    promptURLs: true,
    uploadImage: true,
    //imageUploadEndpoint: 'api.php?do=upload',
    imageUploadFunction: UploadPicture,
    imageMaxSize: 1024*1024*20,
    imageUploadAbsoluteURL:false
});

function UploadPicture(file, onSuccess, onError) {
    var form_data = new FormData();
    var imageUrl;
    form_data.append('image', file);
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = () => {
      if (xhr.readyState === XMLHttpRequest.DONE) {
        if (xhr.status >= 200 && xhr.status < 300) {
          //console.log(xhr.responseText); // 'This is the returned text.'
          var reponse = xhr.responseText
          console.log(reponse)
          imageUrl = JSON.parse(reponse)
          console.log(imageUrl.data.filePath)
          onSuccess(imageUrl.data.filePath)
        } else {
          console.log('Error: ' + xhr.status); // An error occurred during the request.
          onError(xhr.status) // je ne suis pas sûr d'ici
        }
      }
    };
    xhr.open('POST', 'api.php?do=upload');
    xhr.send(form_data);
}

Manque plus qu’à trouver comment mettre un texte alternatif à l’image et on sera bon :-)

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte