sparksuite / simplemde-markdown-editor

A simple, beautiful, and embeddable JavaScript Markdown editor. Delightful editing for beginners and experts alike. Features built-in autosaving and spell checking.
https://simplemde.com
MIT License
9.79k stars 1.12k forks source link

Add upload-image toolbar #728

Open ruesin opened 5 years ago

ruesin commented 5 years ago

In my project, I need to use the image upload. At first, I used the custom toolbar. Later, I thought if I could add a feature.

So here's my code, I hope it can help others.

var simplemde = new SimpleMDE({
    status: ["lines", "words"],
    spellChecker: false,
    element: document.getElementById("sin-markdown"),
    promptURLs: true,
    uploadUrl: '/index/image/upload',
    toolbar: ["upload-image"]
});

Add upload-image to toolbar, then custom uploadUrl which is the server url for uploading images.

If the upload is successful, will type like this:![response.name or file.name](response.url)

elixirgraphics commented 5 years ago

I'm interested in implementing this in SimpleMDE for a project. I'm not having much luck so far. Once the file chooser opens it allows you to select an image but the image does not get uploaded and the response obviously comes back as just this, since no file was uploaded:

![]()
ruesin commented 5 years ago

I'm interested in implementing this in SimpleMDE for a project. I'm not having much luck so far. Once the file chooser opens it allows you to select an image but the image does not get uploaded and the response obviously comes back as just this, since no file was uploaded:

![]()

what's your api response?

        xmlhttp.onreadystatechange = function() {
            if(xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                var res = JSON.parse(xmlhttp.responseText);
                if(res.url) {
                    editor.codemirror.replaceSelection("![" + (res.name || file.name) + "](" + res.url + ")");
                }
            }
        };
elixirgraphics commented 5 years ago

The xmlhttp.readyState returns as 4 and the xmlhttp.status returns as 200

xmlhttp.responseText returns:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
 <head>
  <title>Index of /test/imgtest/upload</title>
 </head>
 <body>
<h1>Index of /test/imgtest/upload</h1>
<pre>      <a href="?C=N;O=D">Name</a>                    <a href="?C=M;O=A">Last modified</a>      <a href="?C=S;O=A">Size</a>  <a href="?C=D;O=A">Description</a><hr>      <a href="/test/imgtest/">Parent Directory</a>                             -   
<hr></pre>
</body></html>
ruesin commented 5 years ago

The xmlhttp.readyState returns as 4 and the xmlhttp.status returns as 200

xmlhttp.responseText returns:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
 <head>
  <title>Index of /test/imgtest/upload</title>
 </head>
 <body>
<h1>Index of /test/imgtest/upload</h1>
<pre>      <a href="?C=N;O=D">Name</a>                    <a href="?C=M;O=A">Last modified</a>      <a href="?C=S;O=A">Size</a>  <a href="?C=D;O=A">Description</a><hr>      <a href="/test/imgtest/">Parent Directory</a>                             -   
<hr></pre>
</body></html>

xmlhttp.responseText must be a json-string like this:

{
    "url": "/images/20190223/dc4a1c262d9722537e4f0e9b69f0dad5.png",
    "name": "my_pic_0.png",
    "md5_name": "974ebc4ebc746f5d2200d7f797451d04"
}

The program will convert json-string to json-object, make result string to textarea:

xmlhttp.onreadystatechange = function() {
    if(xmlhttp.readyState == 4 && xmlhttp.status == 200) {
        try {
            var res = JSON.parse(xmlhttp.responseText);
            if(res.url) {
//The result of the textarea will be: `![res.name](res.url)`
                editor.codemirror.replaceSelection("![" + (res.name || file.name) + "](" + res.url + ")");
            }
        } catch (e) {
            editor.codemirror.replaceSelection("![]()");
        }
    }
};

This is my test:

upload-example
elixirgraphics commented 5 years ago

Strange. I am implementing your exact code and not getting a json string back from xmlhttp.responseText after the user selects an image.

ruesin commented 5 years ago

Strange. I am implementing your exact code and not getting a json string back from xmlhttp.responseText after the user selects an image.

uh, JSON is the Web-server's response.

elixirgraphics commented 5 years ago

Yes the JSON response comes from the server, which should come from the <input> you are building here:

var _html = document.createElement("input");
    _html.setAttribute("type", "file");
    _html.setAttribute("accept", "image/gif,image/jpeg,image/jpg,image/png,image/svg");
    _html.setAttribute("id", _input_id);
    _html.setAttribute("style", "display:none");

I’m using all the same code as your commit yet I’m not receiving a a JSON response and can’t seem to figure out why.

ruesin commented 5 years ago

What is the version of your browser? Chrome is ok~

elixirgraphics commented 5 years ago

Using Chrome here, too:

screen shot 2019-02-25 at 8 27 01 am

ruesin commented 5 years ago

sry, I have no idea. Try the browser warning? Here is my code:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
    <title>test</title>
</head>
<body class="page-header-fixed">

<link rel="stylesheet" href="/simplemde/simplemde.min.css">

<form action="http://local.blog.com/content.html" method="POST" id="form_sample_2"  class="form-horizontal" >

    <div class="control-group" id = "test-editormd">
        <textarea style="display:none;" id="sin-markdown" name="markdown"></textarea>
    </div>
</form>

<!-- <script src="/static/metronic/media/js/jquery-1.10.1.min.js" type="text/javascript"></script> -->

<script src="/simplemde/simplemde.min.js"></script>
<style>
.CodeMirror {
    min-height: 300px;
    height: 500px;
}
</style>
<script>
var simplemde = new SimpleMDE({
    status: ["lines", "words"],
    spellChecker: false,
    element: $("#sin-markdown")[0],
    promptURLs: true,
    uploadUrl: '/index/image/upload',
    toolbar: ["upload-image"]
});
</script>
</body>
</html>
elixirgraphics commented 5 years ago

@ruesin Are you using PHP to process your uploaded image? If so, could you share that code?

ruesin commented 5 years ago

@ruesin Are you using PHP to process your uploaded image? If so, could you share that code?

public function upload()
{
    $file = request()->file('image');
    if (!$file) {
        $this->error('no img~');
    }

    //move & save image to server
    $info = $file->move(SOURCE_PATH . SOURCE_DIR);
    $fileName = $info->getFileName();
    $url = DS.SOURCE_DIR.DS.date('Ymd').DS.$fileName;
    $this->save($fileName, $file->getInfo('name'), $url);

    echo json_encode(['url'=>$url,'name'=>$file->getInfo('name'),'md5_name'=>md5($file->getInfo('name'))]);
}