美文网首页Golang程序员Golang语言社区
70.富文本编辑器tinyMCE提交数据到go服务端

70.富文本编辑器tinyMCE提交数据到go服务端

作者: 厚土火焱 | 来源:发表于2018-09-20 15:17 被阅读74次

    在后台管理中,当有图文混排等各种文章(比如新闻、小说类)需要使用富文本编辑器。这次我使用了一下tinyMCE编辑器。这款编辑器是免费开源的。


    提交成功效果

    Download everything you need for production usage (including a jQuery integration plugin) for free. TinyMCE is open source and licensed under LGPL 2.1.

    LGPL2.1可以让我们放心的使用了。
    首先在https://www.tiny.cloud/download/self-hosted/ 下载tinyMCE

    下载哪个都可以
    安装很简单,只要在页面里引用就可以了。
        <script language="JavaScript" type="text/javascript" src="../RichText/tinymce/tinymce.js"></script>
        <script language="JavaScript" type="text/javascript" src="../RichText/tinymce/jquery.tinymce.min.js"></script>
    

    当然,还需要init,这里给出一个设置的代码例子

    <script language="JavaScript" type="text/javascript">
    
            var tinymceEditor;
            tinymce.init({
                selector: '#NContent',
                auto_focus: "Content",
                height: 220,
                language: "zh_CN",
                theme: "modern",
                add_unload_trigger: false,
                image_advtab: true,
                automatic_uploads: false,
                plugins: [
                    "advlist autolink lists link image imagetools charmap preview",
                    "searchreplace visualblocks fullscreen",
                    "insertdatetime media table contextmenu paste",
                    "emoticons textcolor"
                ],
                toolbar1: "undo redo | styleselect | fontselect | fontsizeselect | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent",
                toolbar2: "forecolor backcolor table emoticons link image imagetools media | fullscreen preview |  ",
    
                //TinyMCE 会将所有的 font 元素转换成 span 元素
                convert_fonts_to_spans: true,
                //换行符会被转换成 br 元素
                convert_newlines_to_brs: false,
                //在换行处 TinyMCE 会用 BR 元素而不是插入段落
                force_br_newlines: false,
                //当返回或进入 Mozilla/Firefox 时,这个选项可以打开/关闭段落的建立
                force_p_newlines: false,
                //这个选项控制是否将换行符从输出的 HTML 中去除。选项默认打开,因为许多服务端系统将换行转换成 <br />,因为文本是在无格式的 textarea 中输入的。使用这个选项可以让所有内容在同一行。
                remove_linebreaks: false,
                //不能把这个设置去掉,不然图片路径会出错
                relative_urls: false,
                //不允许拖动大小
                resize: true,
    
                font_formats: "宋体=宋体;黑体=黑体;仿宋=仿宋;楷体=楷体;隶书=隶书;幼圆=幼圆;Arial=arial,helvetica,sans-serif;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Tahoma=tahoma,arial,helvetica,sans-serif;Times New Roman=times new roman,times;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats",
                fontsize_formats: "8pt 10pt 12pt 14pt 18pt 24pt 36pt",
    
                 //////////////自己控制图片上传begin/////////////////////////////////////////
                images_upload_handler: function(blobInfo, success, failure){
                    var xhr, formData;
                    // var stuId = ${user.userId};
                    // var maxLogId = ${maxLogId};
                    var myId = "joel"
                    xhr = new XMLHttpRequest();
                    xhr.withCredentials = false;
                    xhr.open("POST", "../upload2/?myid="+myId);
                    formData = new FormData();
                    formData.append("uploadfile", blobInfo.blob());
                    xhr.onload = function(e){
                        var json;
    
                        if (xhr.status != 200) {
                            failure('HTTP Error: ' + xhr.status);
                            return;
                        }
                        json = JSON.parse(this.responseText);
    
                        if (!json || typeof json.location != 'string') {
                            failure('Invalid JSON: ' + xhr.responseText);
                            return;
                        }
    
                        success(json.location);
                    };
                    xhr.send(formData);
                }
                //////////////自己控制图片上传end/////////////////////////////////////////
    
            });
            tinymce.mceImage
    
        </script>
    

    这个上传的前端代码,实现了一个文件的上传,同时还上传了一个字符串参数myid。(项目中你可以用这个参数做一些上传用户的判断之类的。)
    代码中需要注意的部分

    tinymce.init({
    selector: '#NContent',
    auto_focus: "NContent",

    这里的NContent是对应界面模板中的 textarea 组件id

    xhr.open("POST", "../upload2/?myid="+myId);
    formData = new FormData();
    formData.append("uploadfile", blobInfo.blob());

    这里面的 upload2 是接收数据的路径,uploadfile是传递文件的组件名称name,都是需要在服务端对应的。

    if (!json || typeof json.location != 'string') {
    failure('Invalid JSON: ' + xhr.responseText);
    return;
    }

    这段代码中 json.location 中的 location 是服务端接收到文件后,返回给客户端的json串中的一个键。
    html模板完整代码

    {{define "news"}}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Joel News</title>
        <script language="JavaScript" type="text/javascript" src="../RichText/tinymce/tinymce.js"></script>
        <script language="JavaScript" type="text/javascript" src="../RichText/tinymce/jquery.tinymce.min.js"></script>
    
        <script language="JavaScript" type="text/javascript">
    
            var tinymceEditor;
            tinymce.init({
                selector: '#NContent',
                auto_focus: "NContent",
                height: 220,
                language: "zh_CN",
                theme: "modern",
                add_unload_trigger: false,
                image_advtab: true,
                automatic_uploads: false,
                plugins: [
                    "advlist autolink lists link image imagetools charmap preview",
                    "searchreplace visualblocks fullscreen",
                    "insertdatetime media table contextmenu paste",
                    "emoticons textcolor"
                ],
                toolbar1: "undo redo | styleselect | fontselect | fontsizeselect | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent",
                toolbar2: "forecolor backcolor table emoticons link image imagetools media | fullscreen preview |  ",
    
                //TinyMCE 会将所有的 font 元素转换成 span 元素
                convert_fonts_to_spans: true,
                //换行符会被转换成 br 元素
                convert_newlines_to_brs: false,
                //在换行处 TinyMCE 会用 BR 元素而不是插入段落
                force_br_newlines: false,
                //当返回或进入 Mozilla/Firefox 时,这个选项可以打开/关闭段落的建立
                force_p_newlines: false,
                //这个选项控制是否将换行符从输出的 HTML 中去除。选项默认打开,因为许多服务端系统将换行转换成 <br />,因为文本是在无格式的 textarea 中输入的。使用这个选项可以让所有内容在同一行。
                remove_linebreaks: false,
                //不能把这个设置去掉,不然图片路径会出错
                relative_urls: false,
                //不允许拖动大小
                resize: true,
    
                font_formats: "宋体=宋体;黑体=黑体;仿宋=仿宋;楷体=楷体;隶书=隶书;幼圆=幼圆;Arial=arial,helvetica,sans-serif;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Tahoma=tahoma,arial,helvetica,sans-serif;Times New Roman=times new roman,times;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats",
                fontsize_formats: "8pt 10pt 12pt 14pt 18pt 24pt 36pt",
    
                 //////////////自己控制图片上传begin/////////////////////////////////////////
                images_upload_handler: function(blobInfo, success, failure){
                    var xhr, formData;
                    // var stuId = ${user.userId};
                    // var maxLogId = ${maxLogId};
                    var myId = "joel"
                    xhr = new XMLHttpRequest();
                    xhr.withCredentials = false;
                    xhr.open("POST", "../upload2/?myid="+myId);
                    formData = new FormData();
                    formData.append("uploadfile", blobInfo.blob());
                    xhr.onload = function(e){
                        var json;
    
                        if (xhr.status != 200) {
                            failure('HTTP Error: ' + xhr.status);
                            return;
                        }
                        json = JSON.parse(this.responseText);
    
                        if (!json || typeof json.location != 'string') {
                            failure('Invalid JSON: ' + xhr.responseText);
                            return;
                        }
    
                        success(json.location);
                    };
                    xhr.send(formData);
                }
                //////////////自己控制图片上传end/////////////////////////////////////////
    
            });
            tinymce.mceImage
    
        </script>
    
    
    </head>
    <body>
    
    News
    <hr style="border: 1px;height: 1px;" color="#e8e8e8">
    标题:{{.NTitle}}
    作者:{{.NAuthor}}
    发布时间:{{.NPublish}}<br>
    内容:{{.NContent }}<br>
    附件:{{.NAttachment}}
    关键字:{{.NKeyword}}
    标签:{{.NTab}}
    分类:{{.NClass}}
    <hr style="border: 1px;height: 1px;" color="#e3e3e3">
    <form method="post" action="" enctype="multipart/form-data">
        <table>
    
            <tr>
                <td>标题:</td>
                <td><input id="NTitle" name="NTitle" value={{.NTitle}}></td>
    
                <td>作者:</td>
                <td><input id="NAuthor" name="NAuthor" value={{.NAuthor}}></td>
    
                <td>发布时间:</td>
                <td><input id="NPublish" name="NPublish" value=""></td>
            </tr>
            <tr>
                <td>内容:</td>
                <td colspan="5"><textarea id="NContent" name="NContent" rows="5" cols="80"
                                          class="editor">{{.NContent }}</textarea></td>
            </tr>
            <tr>
                <td>附件:</td>
                <td><input id="NAttachment" name="NAttachment" value=""></td>
    
                <td>关键字:</td>
                <td><input id="NKeyword" name="NKeyword" value=""></td>
    
                <td>标签:</td>
                <td><input id="NTab" name="NTab" value=""></td>
    
                <td>分类:</td>
                <td><input id="NClass" name="NClass" value=""></td>
            </tr>
            <tr>
                <td></td>
                <td colspan="5"><input id="NSubmit" type="submit" value="提交"/></td>
            </tr>
    
        </table>
    
    
    </form>
    
    </body>
    </html>
    {{end}}
    

    这个模板命名为 news
    下面来看golang代码。
    此代码借用前面章节使用过的代码示例,稍作修改。
    代码大体分两个部分,一个新闻的模板绑定,一个文件的服务端接收。
    新闻代码

    
    type News struct {
        NTitle  string      //标题
        NAuthor string  //作者
        NPublish    string  //发布时间
        NContent    template.HTML   //内容
        NAttachment string  //附件
        NKeyword    string  //关键字
        NTab        string  //标签
        NClass      string  //分类
    }
    func processNewsHandler(writer http.ResponseWriter, request *http.Request) {
        var RNTitle = request.FormValue("NTitle")
        var RNAuthor = request.FormValue("NAuthor")
        var RNPublish = request.FormValue("NPublish")
        var RNContent = request.FormValue("NContent")
        var RNAttachment = request.FormValue("NAttachment")
        var RNKeyword = request.FormValue("NKeyword")
        var RNTab = request.FormValue("NTab")
        var RNClass = request.FormValue("NClass")
    
        myNews := News{}
        myNews.NTitle = RNTitle
        myNews.NAuthor = RNAuthor
        myNews.NPublish = RNPublish
        myNews.NContent = template.HTML(RNContent)
        myNews.NAttachment = RNAttachment
        myNews.NKeyword = RNKeyword
        myNews.NTab = RNTab
        myNews.NClass = RNClass
    
        t, _ := template.ParseFiles("./JoelTempWeb/tmplNews2.html")
        t.ExecuteTemplate(writer, "news", myNews)
    }
    

    文件接收代码

    
    //单页上传,无模板文件,只有模板代码
    func index(writer http.ResponseWriter, request *http.Request) {
        writer.Write([]byte(tpl))
    }
    const tpl = `<html>
    <head>
    <title>上传文件</title>
    </head>
    <body>
    <form enctype="multipart/form-data" action="/upload2/" method="post">
    <input type="file" name="uploadfile">
    <input type="hidden" name="token" value="{...{.}...}">
    <input type="submit" value="upload">
    </form>
    </body>
    </html>
    `
    func upload(writer http.ResponseWriter, request *http.Request) {
        request.ParseMultipartForm(32<<20)
        //接收客户端传来的文件 uploadfile 与客户端保持一致
        file, handler, err := request.FormFile("uploadfile")
        myid := request.FormValue("myid")
        fmt.Println(myid)
        if err != nil{
            fmt.Println(err)
            return
        }
        defer file.Close()
        //上传的文件保存在ppp路径下
        ext := path.Ext(handler.Filename)       //获取文件后缀
        fileNewName := string(time.Now().Format("20060102150405"))+strconv.Itoa(time.Now().Nanosecond())+ext
    
        f, err := os.OpenFile("./ppp/"+fileNewName, os.O_WRONLY|os.O_CREATE, 0666)
        if err != nil{
            fmt.Println(err)
            return
        }
        defer f.Close()
    
        io.Copy(f, file)
    
        back := "{\"error\":false,\"location\":\"../cdn/image/"+fileNewName+"\"}"
        fmt.Fprintln(writer, string(back))
    
        //location33 := "../cdn/image/"+fileNewName
        //back := make(map[string]interface{})
        //back["error"] = false
        //back["location"] = location33
        //result, _:= json.Marshal(back)
        //fmt.Fprintln(writer, string(result))
    }
    

    接收代码里,包含了一段内嵌的页面提交代码。用来测试上传功能。就是这部分

    //单页上传,无模板文件,只有模板代码
    func index(writer http.ResponseWriter, request *http.Request) {
        writer.Write([]byte(tpl))
    }
    const tpl = `<html>
    <head>
    <title>上传文件</title>
    </head>
    <body>
    <form enctype="multipart/form-data" action="/upload2/" method="post">
    <input type="file" name="uploadfile">
    <input type="hidden" name="token" value="{...{.}...}">
    <input type="submit" value="upload">
    </form>
    </body>
    </html>
    `
    

    如果不必要,可是删除。
    main里的代码部分

        http.HandleFunc("/news/", processNewsHandler)
        http.HandleFunc("/upload2/", upload)
        http.HandleFunc("/index/", index)
    
        http.Handle("/cdn/image/", http.StripPrefix("/cdn/image/", http.FileServer(http.Dir("ppp"))))
        http.Handle("/RichText/", http.StripPrefix("/RichText/", http.FileServer(http.Dir("JoelTempWeb/JoelRichText"))))        //富文本编辑器
    
    server := http.Server{
            Addr: ":8090",
        }
        server.ListenAndServe()
    

    在接收文件的代码中,返回给客户端值给出了2种写法

        back := "{\"error\":false,\"location\":\"../cdn/image/"+fileNewName+"\"}"
        fmt.Fprintln(writer, string(back))
    
        //location33 := "../cdn/image/"+fileNewName
        //back := make(map[string]interface{})
        //back["error"] = false
        //back["location"] = location33
        //result, _:= json.Marshal(back)
        //fmt.Fprintln(writer, string(result))
    

    看你喜欢那种。


    准备上传图片
    选择图片
    自动插入图片服务器路径
    插入编辑器
    提交成功

    相关文章

      网友评论

        本文标题:70.富文本编辑器tinyMCE提交数据到go服务端

        本文链接:https://www.haomeiwen.com/subject/jqjmnftx.html