editor.md 粘贴图片的插件开发

2020年5月31日 23:26 阅读 376 评论 0

粘贴图片上传的思路大致是,利用js粘贴面板时获取粘贴内容,判断格式,为图片时,自动调用路由利用ajax数据post图片,返回图片的路由,生成markdown格式的图片url。

试别粘贴内容并post图片

python manage.py collectstatic静态文件后,static中应该会多一个mdeditor文件夹,js/plugins为项目的插件包,添加image-handle-paste文件夹并在其中添加image-handle-paste.js文件。

image-handle-paste.js

/*!
 * editormd图片粘贴上传插件
 *
 * @file   image-handle-paste.js
 * @author zhangkaixing
 * @modify stray_came
 * @date   2020年5月29日
 * @link   https://www.codehui.net, https://boywithacoin.cn/
 */

(function() {

    var factory = function (exports) {
        var $            = jQuery;           // if using module loader(Require.js/Sea.js).
        var pluginName   = "image-handle-paste";  // 定义插件名称

        //图片粘贴上传方法
        exports.fn.imagePaste = function() {
            var _this       = this;
            var cm          = _this.cm;
            var settings    = _this.settings;
            var editor      = _this.editor;
            var classPrefix = _this.classPrefix;
            var id       = _this.id;

            if(!settings.imageUpload || !settings.imageUploadURL){
                console.log('你还未开启图片上传或者没有配置上传地址');
                return false;
            }

            //监听粘贴板事件
            $('#' + id).on('paste', function (e) {
                var items = (e.clipboardData || e.originalEvent.clipboardData).items;
                console.log(items[0], items[1])

                //判断图片类型
                if (items && (items[0].type.indexOf('image') > -1 || items[1].type.indexOf('image') > -1)) {
                    if (items[0].type.indexOf('image') > -1 ) {
                        var file = items[0].getAsFile();
                    } else {
                        var file = items[1].getAsFile();
                    }

                    /*生成blob
                    var blobImg = URL.createObjectURL(file);
                    */

                    /*base64
                    var reader = new FileReader();
                    reader.readAsDataURL(file);
                    reader.onload = function (e) {
                        var base64Img = e.target.result //图片的base64
                    }
                    */

                    // 创建FormData对象进行ajax上传
                    var forms = new FormData(document.forms[0]); //Filename
                    forms.append(classPrefix + "image-file", file, "file_"+Date.parse(new Date())+".png"); // 文件
                    console.log(classPrefix + "image-file", file, "file_"+Date.parse(new Date())+".png")
                    //调用imageDialog插件弹出对话框
                    _this.executePlugin("imageDialog", "image-dialog/image-dialog");

                    _ajax(settings.imageUploadURL, forms, function(ret){
                        if(ret.success == 1){
                        //数据格式可以自定义但需要把图片地址写入到该节点里面
                            $("." + classPrefix + "image-dialog").find("input[data-url]").val(ret.url);
                            // cm.replaceSelection("![](" + ret.url  + ")");
                        }
                        console.log(ret.message);
                    })
                }
            })
        };
        // ajax上传图片 可自行处理
        var _ajax = function(url, data, callback) {
            $.ajax({
                "type": 'post',
                "cache": false,
                "url": url,
                "data": data,
                "processData": false,
                "contentType": false,
                "mimeType": "multipart/form-data",
                success: function(ret){
                    callback(JSON.parse(ret));
                },
                error: function (err){
                    console.log('请求失败')
                }
            })
        }
    };

    // CommonJS/Node.js
    if (typeof require === "function" && typeof exports === "object" && typeof module === "object")
    {
        module.exports = factory;
    }
    else if (typeof define === "function")  // AMD/CMD/Sea.js
    {
        if (define.amd) { // for Require.js

            define(["editormd"], function(editormd) {
                factory(editormd);
            });

        } else { // for Sea.js
            define(function(require) {
                var editormd = require("../../editormd");
                factory(editormd);
            });
        }
    }
    else
    {
        factory(window.editormd);
    }

})();

添加插件文件成功,访问之前我们创建的前端markdown编辑界面,我们就可以粘贴图片了

重构django-mdeditor

前端的粘贴功能实现了,但是后台admin界面的编辑时还无法实现粘贴功能,原因是我们的django-mdeditor使用的html文件是不一样的,复制~\env\Lib\site-packages\mdeditor\templates下的markdown.html文件到我们django项目的templates中,添加代码: 源代码:

// image upload
            imageUpload: true,
            imageFormats: {{ config.upload_image_formats|safe }},
            ............

更改后的代码代码:

// image upload
            imageUpload: true,
            imageFormats: {{ config.upload_image_formats|safe }},
            imageUploadURL: "/tool/admin_upload/",
            toolbarIcons: function () {
                return {{ config.toolbar|safe }}
            },
            onload: function () {
                // 引入插件 执行监听方法
                editormd.loadPlugin("{% static 'mdeditor/js/plugins/image-handle-paste/image-handle-paste' %}", function(){
                    MarkDownEditor.imagePaste();
                });
                // console.log('onload', this);
                //this.fullscreen();
                //this.unwatch();
                //this.watch().fullscreen();

                //this.setMarkdown("#PHP");
                //this.width("100%");
                //this.height(480);
                //this.resize("100%", 640);
            }

可以看到我们django-mdeditor中的html代码调用传输图片的路由为/tool/admin_upload/,这里我们将前端所有人可以使用的编辑界面的图片传输路由和后端admin界面的图片传输路由分开配置。 研究一下~\env\Lib\site-packages\mdeditor\views.py代码,和其他文件,可以发现其构建了UploadView对象,并将其他的比如上传图片文件夹、上传图片支持的格式等等配置放在了其他文件。

重构UploadView对象,修改tool/views.py文件:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#!/usr/bin/python
# -*- coding: utf-8 -*-
# __author__ : stray_camel
# __date__: 2020/05/26 17:20:42

from django.views import generic
from mdeditor.configs import DEFAULT_CONFIG, MDConfig
from django.http import HttpResponse
from django.conf import settings
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from django.shortcuts import render
from django.views.decorators.http import require_POST
from django.http import JsonResponse
from django.utils.html import mark_safe
from .apis.bd_push import push_urls, get_urls
from .apis.links_test import Check
from .apis.useragent import get_user_agent
import os
import re
import markdown
import datetime
import json
from mdeditor.views import UploadView


........其他代码.........

# TODO 此处获取default配置,当用户设置了其他配置时,此处无效,需要进一步完善
MDEDITOR_CONFIGS = MDConfig('default')

class admin_upload(UploadView):
    """ upload image file """

    @method_decorator(csrf_exempt)
    def dispatch(self, *args, **kwargs):
        return super(admin_upload, self).dispatch(*args, **kwargs)

    def post(self, request, *args, **kwargs):
        upload_image = request.FILES.get("editormd-image-file", None)
        media_root = settings.MEDIA_ROOT
        # image none check
        if not upload_image:
            return HttpResponse(json.dumps({
                'success': 0,
                'message': "未获取到要上传的图片",
                'url': ""
            }))

        # image format check
        file_name_list = upload_image.name.split('.')
        file_extension = file_name_list.pop(-1)
        # 替换上传图片名中非数字和字母的字符为'_'字符
        file_name_list = ["".join(filter(str.isalnum, _))
                          for _ in file_name_list]
        file_name = '.'.join(file_name_list)

        if file_extension not in MDEDITOR_CONFIGS['upload_image_formats']:
            return HttpResponse(json.dumps({
                'success': 0,
                'message': "上传图片格式错误,允许上传图片格式为:%s" % ','.join(
                    MDEDITOR_CONFIGS['upload_image_formats']),
                'url': ""
            }))

        # image floder check
        file_path = os.path.join(media_root, MDEDITOR_CONFIGS['image_floder'], '{0:%Y%m%d}'.format(
            datetime.datetime.now()))
        if not os.path.exists(file_path):
            try:
                os.makedirs(file_path)
            except Exception as err:
                return HttpResponse(json.dumps({
                    'success': 0,
                    'message': "上传失败:%s" % str(err),
                    'url': ""
                }))

        # save image
        file_full_name = '%s_%s.%s' % (file_name,
                                       '{0:%Y%m%d%H%M}'.format(
                                           datetime.datetime.now()),
                                       file_extension)
        if not os.path.exists(os.path.join(file_path, file_full_name)):
            with open(os.path.join(file_path, file_full_name), 'wb+') as file:
                for chunk in upload_image.chunks():
                    file.write(chunk)
        res = HttpResponse(json.dumps({'success': 1,
                                       'message': "上传成功!",
                                       'url': '{0}{1}{2}/{3}/{4}'.format(settings.DOMAIN_NAME, settings.MEDIA_URL,
                                                                         MDEDITOR_CONFIGS['image_floder'], '{0:%Y%m%d}'.format(
                                           datetime.datetime.now()),
                                           file_full_name)}))
        return res



class default_upload(UploadView):
    """ upload image file """
    @method_decorator(csrf_exempt)
    def dispatch(self, *args, **kwargs):
        return super(default_upload, self).dispatch(*args, **kwargs)

    def post(self, request, *args, **kwargs):
        upload_image = request.FILES.get("editormd-image-file", None)
        media_root = settings.MEDIA_ROOT
        # image none check
        if not upload_image:
            return HttpResponse(json.dumps({
                'success': 0,
                'message': "未获取到要上传的图片",
                'url': ""
            }))

        # image format check
        file_name_list = upload_image.name.split('.')
        file_extension = file_name_list.pop(-1)
        # 替换上传图片名中非数字和字母的字符为'_'字符
        file_name_list = ["".join(filter(str.isalnum, _))
                          for _ in file_name_list]
        file_name = '.'.join(file_name_list)

        if file_extension not in MDEDITOR_CONFIGS['upload_image_formats']:
            return HttpResponse(json.dumps({
                'success': 0,
                'message': "上传图片格式错误,允许上传图片格式为:%s" % ','.join(
                    MDEDITOR_CONFIGS['upload_image_formats']),
                'url': ""
            }))

        # image floder check
        file_path = os.path.join(media_root, 'mdeditor/uploads', '{0:%Y%m%d}'.format(
            datetime.datetime.now()))
        if not os.path.exists(file_path):
            try:
                os.makedirs(file_path)
            except Exception as err:
                return HttpResponse(json.dumps({
                    'success': 0,
                    'message': "上传失败:%s" % str(err),
                    'url': ""
                }))

        # save image
        file_full_name = '%s_%s.%s' % (file_name,
                                       '{0:%Y%m%d%H%M}'.format(
                                           datetime.datetime.now()),
                                       file_extension)
        if not os.path.exists(os.path.join(file_path, file_full_name)):
            with open(os.path.join(file_path, file_full_name), 'wb+') as file:
                for chunk in upload_image.chunks():
                    file.write(chunk)
        res = HttpResponse(json.dumps({'success': 1,
                                       'message': "上传成功!",
                                       'url': '{0}{1}{2}/{3}/{4}'.format(settings.DOMAIN_NAME, settings.MEDIA_URL,
                                                                         'mdeditor/uploads', '{0:%Y%m%d}'.format(
                                           datetime.datetime.now()),
                                           file_full_name)}))
        return res

为此我们设置好两个不同的路由,分别用于md编辑界面传输图片到os.path.join(media_root, 'mdeditor/uploads', '{0:%Y%m%d}'.format(datetime.datetime.now()))路径,而admin界面的图片传输到os.path.join(media_root, MDEDITOR_CONFIGS['image_floder'], '{0:%Y%m%d}'.format(datetime.datetime.now()))文件夹。

原创文章,转载请注明出处:https://boywithacoin.cn/article/editor-md-nian-tie-tu-pian-de-cha-jian-kai-fa/


您尚未登录,请 登录注册 后评论
    0 人参与 | 0 条评论
    暂时没有评论,欢迎来尬聊!