ueditor编辑器优化以及自定义

2020年09月22日 未雨晴空 0评论 575阅读 3喜欢

多图上传

图片在线管理页面不显示

djangoueditor在线管理
其中的在线管理页面图片无法显示,控制台报错500,后台报错内容如下:

Python NameError: name 'unicode' is not defined `

出错的位置位于DjangoUeditor/views.py,之所以报错是因为Python2 的unicode 函数在 Python3 中被命名为 str。在 Python3 中使用我们需要使用str 来代替 Python2中的 unicode如此页面可以正常显示图片了

在这里插入图片描述

在线管理给图片增加删除按钮

  1. 修改/DjangoUeditor/static/ueditor/dialogs/image/image.js

     ...
     item.appendChild(icon);
    
     /*增加删除功能开始*/
     span= document.createElement('span');
     span.setAttribute("url",list[i].url);
     span.innerText="X";
     domUtils.addClass(span, 'delbtn');
     domUtils.on(span, 'click', (function(span){
         return function(){
             try{
                 window.event.cancelBubble = true; //停止冒泡
                 window.event.returnValue = false; //阻止事件的默认行为
                 window.event.preventDefault();    //取消事件的默认行为
                 window.event.stopPropagation();   //阻止事件的传播
             } finally {
                 if(!confirm("确定要删除吗?")) return;
                 $.post(editor.getOpt("serverUrl") + "&action=delete_site_file", { "path": span.getAttribute("url") }, function(result) {
                     if (result == "ok") domUtils.remove(span.parentNode,false);
                     else alert(result);
                 });
             }
         }
     })(span));
     item.appendChild(span);
     /*增加删除功能结束*/
    
     this.list.insertBefore(item, this.clearFloat);
    
  2. 在/DjangoUeditor/static/ueditor/dialogs/image/image.css增加以下内容:

     /* 在线管理删除按钮样式 */
     #online li span.delbtn {
         position: absolute;
         top: 0;
         right: 0;
         border: 0;
         z-index: 3;
         color: #ffffff;
         display: inline;
         font-size: 12px;
         line-height: 10.5px;
         padding:3px 5px;
         text-align: center;
         background-color: #d9534f;
     }
    
  3. 增加图片删除后台逻辑
    由于DjangoUeditor并没有提供文件删除的action,需要自己添加,可在/DjangoUeditor/views.py下修改部分内容:

    ...
    
    @csrf_exempt
    def get_ueditor_controller(request):
        """获取ueditor的后端URL地址    """
    
        action = request.GET.get("action", "")
        reponseAction = {
            "config": get_ueditor_settings,
            "uploadimage": UploadFile,
            "uploadscrawl": UploadFile,
            "uploadvideo": UploadFile,
            "uploadfile": UploadFile,
            "catchimage": catcher_remote_image,
            "listimage": list_files,
            "listfile": list_files,
            "delete_site_file":delete_site_file,#添加action
        }
        return reponseAction[action](request)
    
    ....
    
    #ueditor新增在线管理文件删除功能
    @csrf_exempt
    def delete_site_file(request):
        path=request.POST.get("path")
        file=USettings.BASE_DIR+path
        if os.path.isfile(file):
            os.remove(file)
        return HttpResponse("ok",content_type="text/html")
    
  4. 修改后效果
    图片增加删除按钮

视频上传

视频大小可读性

在这里插入图片描述
上面的图是上传5G的视频显示的视频大小,显然可读性太差。可以修改/ueditor/dialogs/video/video.js里面的updateStatus函数的

WebUploader.formatSize(fileSize)

改为如下:

WebUploader.formatSize(fileSize,['M'])

具体效果如下:

在这里插入图片描述

添加视频封面

ueditor并没有实现视频上传封面的功能,但是经过博主测试,研究出下面操作是可以实现视频上传添加封面,但是视频上传封面并不是在视频上传的时候指定的,而是在视频上传完成后再实现的,具体实现操作如下:
首先修改ueditor.all.js里面的上传视频插件内容为如下:

UE.plugins['video'] = function (){
    var me =this;
    /**
     * 创建插入视频字符窜
     * @param url 视频地址
     * @param width 视频宽度
     * @param height 视频高度
     * @param align 视频对齐
     * @param classname 标签class值
     * @param type 类型(video、image、audio、embed)
     * @param poster 视频封面
     */
    function creatInsertStr(url,width,height,id,align,classname,type,poster){
        var str;
        switch (type){
            case 'image':
                str = ''
                break;
            case 'video':
                str = '' +
                        '';
                break;
        }
        return str;
    }

    /**
     *
     * @param root 根节点
     * @param img2video 为true表示image转video,为false表示video转image
     */
    function switchImgAndVideo(root,img2video){
        console.log(img2video);
        utils.each(root.getNodesByTagName(img2video ? 'img' : 'video'),function(node){
             var className = node.getAttr('class');
              console.log("align:"+node.getStyle('float'));
            if(className && className.indexOf('fake-video') != -1){
                console.log(node);
                console.log(node.getAttr("_src"));
                var html = creatInsertStr( node.getAttr('_url'),node.getAttr('width'),
                    node.getAttr('height'),null,node.getStyle('float') || '',className,
                    img2video ? 'video':"image",node.getAttr("_src"));
                console.log(html);
                node.parentNode.replaceChild(UE.uNode.createElement(html),node);
            }
            if(className && className.indexOf('upload-video') != -1){
                var html = creatInsertStr( node.getAttr('_url'),node.getAttr('width'),
                    node.getAttr('height'),null,node.getStyle('float') || '',className,
                    img2video ? 'video':"image",node.getAttr("_src"));
                console.log(html);
                node.parentNode.replaceChild(UE.uNode.createElement(html),node);
            }
        })
    }

    me.addOutputRule(function(root){
        switchImgAndVideo(root,true)
    });
    me.addInputRule(function(root){
        switchImgAndVideo(root)
    });

    me.commands["insertvideo"] = {
        execCommand: function (cmd, videoObjs, type){
            videoObjs = utils.isArray(videoObjs)?videoObjs:[videoObjs];
            var html = [],id = 'tmpVedio',cl;//
            for(var i=0,vi,len = videoObjs.length;i

修改video.js里面的内容为如下

function initVideo(){
    createAlignButton( ["videoFloat", "upload_alignment"] );
    addUrlChangeListener($G("videoUrl"), $G("videoPoster"));
    addOkListener();

    //编辑视频时初始化相关信息
    (function(){
        var node = editor.selection.getRange().getClosedNode(),url;
        if(node && node.className){
            var hasInsertClass = node.className.indexOf("fake-video")!=-1,
                hasUploadClass = node.className.indexOf("upload-video")!=-1,
                poster=node.getAttribute("_src");
            if(hasInsertClass || hasUploadClass) {
                $G("videoUrl").value = url = node.getAttribute("_url");
                $G("videoWidth").value = node.width;
                $G("videoHeight").value = node.height;
                $G("videoPoster").value =poster ;
                var align = domUtils.getComputedStyle(node,"float"),
                    parentAlign = domUtils.getComputedStyle(node.parentNode,"text-align");
                updateAlignButton(parentAlign==="center"?"center":align);
            }
            if(hasUploadClass) {
                isModifyUploadVideo = true;
            }
        }
        createPreviewVideo(url,poster);
    })();
}



function createPreviewVideo(url,poster){
    if ( !url )return;

    var conUrl = convert_url(url);

    $G("preview").innerHTML = '
'+lang.urlError+'
'+ ''; }

选中内容区刚上传的视频如下:

然后在弹出的图片上传对话框下选择插入图片还是本地上传都可以
在这里插入图片描述

点击确认之后显示如下:
在这里插入图片描述
在这里插入图片描述
以上也支持再次更改视频封面。

音频上传

由于ueditor并没有提供音频上传功能,所以这里需要自己模仿视频上传来实现音频上传的功能。

  1. 修改ueditor.config.js文件,增加插入音频功能入口

    //这个地方的toolbars其实是默认的full类型也就是全部的编辑器操作项
    toolbars=[[...,'insertvideo','insertaudio', 'music',...]]
    //当鼠标放在工具栏上时显示的tooltip提示,留空支持自动多语言配置,否则以配置值为准
    labelMap: {
        'insertaudio' : '音频',
    }
    
  2. 修改ueditor.all.js文件,增加插入音频页面和命令入口

    //对话框路径,如果在ueditor.config.js配置了iframeUrlMap会被其覆盖
    var iframeUrlMap = {
        ...,
        'insertvideo':'~/dialogs/video/video.html',
        'insertaudio':'~/dialogs/audio/audio.html', 
        ....
    }
    //对话框按钮
    var dialogBtns = {
        noOk:['searchreplace', 'help', 'spechars', 'webapp','preview'],
        ok:[...,'insertvideo','insertaudio',...]
    };
    
  3. 修改/DjangoUeditor/static/ueditor/lang/zh-cn/zh-cn.js文件,模仿insertvideo增加insertaudio的相关配置

    'insertaudio':{
        'static':{
            'lang_tab_insertV':"插入音频",
            'lang_tab_searchV':"搜索音频",
            'lang_tab_uploadV':"上传音频",
            'lang_audio_url':"音频网址",
            'lang_audio_size':"音频尺寸",
            'lang_audioW':"宽度",
            'lang_audioH':"高度",
            'lang_alignment':"对齐方式",
            'audioSearchTxt':{'value':"请输入搜索关键字!"},
            'audioType':{'options':["全部", "热门", "娱乐", "搞笑", "体育", "科技", "综艺"]},
            'audioSearchBtn':{'value':"百度一下"},
            'audioSearchReset':{'value':"清空结果"},
    
            'lang_input_fileStatus':' 当前未上传文件',
            'startUpload':{'style':"background:url(upload.png) no-repeat;"},
    
            'lang_upload_size':"音频尺寸",
            'lang_upload_width':"宽度",
            'lang_upload_height':"高度",
            'lang_upload_alignment':"对齐方式",
            'lang_format_advice':"建议使用mp3格式."
    
        },
        'numError':"请输入正确的数值,如123,400",
        'floatLeft':"左浮动",
        'floatRight':"右浮动",
        '"default"':"默认",
        'block':"独占一行",
        'urlError':"输入的音频地址有误,请检查后再试!",
        'loading':"  音频加载中,请等待……",
        'clickToSelect':"点击选中",
        'goToSource':'访问源音频',
        'noAduio':"    抱歉,找不到对应的音频,请重试!",
        'browseFiles':'浏览文件',
        'uploadSuccess':'上传成功!',
        'delSuccessFile':'从成功队列中移除',
        'delFailSaveFile':'移除保存失败文件',
        'statusPrompt':' 个文件已上传! ',
        'flashVersionError':'当前Flash版本过低,请更新FlashPlayer后重试!',
        'flashLoadingError':'Flash加载失败!请检查路径或网络状态',
        'fileUploadReady':'等待上传……',
        'delUploadQueue':'从上传队列中移除',
        'limitPrompt1':'单次不能选择超过',
        'limitPrompt2':'个文件!请重新选择!',
        'delFailFile':'移除失败文件',
        'fileSizeLimit':'文件大小超出限制!',
        'emptyFile':'空文件无法上传!',
        'fileTypeError':'文件类型不允许!',
        'unknownError':'未知错误!',
        'fileUploading':'上传中,请等待……',
        'cancelUpload':'取消上传',
        'netError':'网络错误',
        'failUpload':'上传失败!',
        'serverIOError':'服务器IO错误!',
        'noAuthority':'无权限!',
        'fileNumLimit':'上传个数限制',
        'failCheck':'验证失败,本次上传被跳过!',
        'fileCanceling':'取消中,请等待……',
        'stopUploading':'上传已停止……',
    
        'uploadSelectFile':'点击选择文件',
        'uploadAddFile':'继续添加',
        'uploadStart':'开始上传',
        'uploadPause':'暂停上传',
        'uploadContinue':'继续上传',
        'uploadRetry':'重试上传',
        'uploadDelete':'删除',
        'uploadTurnLeft':'向左旋转',
        'uploadTurnRight':'向右旋转',
        'uploadPreview':'预览中',
        'updateStatusReady': '选中_个文件,共_KB。',
        'updateStatusConfirm': '成功上传_个,_个失败',
        'updateStatusFinish': '共_个(_KB),_个成功上传',
        'updateStatusError': ',_张上传失败。',
        'errorNotSupport': 'WebUploader 不支持您的浏览器!如果你使用的是IE浏览器,请尝试升级 flash 播放器。',
        'errorLoadConfig': '后端配置项没有正常加载,上传插件不能正常使用!',
        'errorExceedSize':'文件大小超出',
        'errorFileType':'文件格式不允许',
        'errorInterrupt':'文件传输中断',
        'errorUploadRetry':'上传失败,请重试',
        'errorHttp':'http请求错误',
        'errorServerUpload':'服务器返回出错'
    },
    
  4. 修改/DjangoUeditor/settings.py文件,模仿insertvideo配置来增加insertaudio配置

    # 上传音频配置
    "audioActionName": "uploadaudio",  # 执行上传视频的action名称
    "audioPathFormat": "",#文件存储路径格式
    "audioFieldName": "upfile",  # 提交的视频表单名称
    "audioMaxSize": 102400000,  # 上传大小限制,单位B,默认100MB
    "audioUrlPrefix": "",#上传url前缀
    "audioAllowFiles": [".mp3"],  # 上传视频格式显示
    
  5. 修改/DjangoUeditor/static/ueditor/themes/default/css/ueditor.css,增加以下内容,我这里图标用的是ueditor自带的图标也就是音乐搜索的图标

    /*音频上传*/
    .edui-default .edui-for-insertaudio .edui-dialog-content {
        width: 590px;
        height: 390px;
    }
    .edui-default  .edui-for-insertaudio .edui-icon {
        background-position: -18px -40px;
    }
    
  6. 修改/DjangoUeditor/static/ueditor/dialogs/audio/audio.css

    其实就是复制一份video.css将video字眼替换成audio即可,下面只给出涉及到audio的相关css

    
    #audioUrl {
        width: 490px;
        height: 21px;
        line-height: 21px;
        margin: 8px 5px;
        background: #FFF;
        border: 1px solid #d7d7d7;
    }
    #audioSearchTxt{margin-left:15px;background: #FFF;width:200px;height:21px;line-height:21px;border: 1px solid #d7d7d7;}
    #audioType{
        width: 65px;
        height: 23px;
        line-height: 22px;
        border: 1px solid #d7d7d7;
    }
    #audioSearchBtn,#audioSearchReset{
        /*width: 80px;*/
        height: 25px;
        line-height: 25px;
        background: #eee;
        border: 1px solid #d7d7d7;
        cursor: pointer;
        padding: 0 5px;
    }
    #preview .previewAudio {position:absolute;top:0;margin:0;padding:0;height:280px;width:100%;}
    #audioInfo {width: 120px;float: left;margin-left: 10px;_margin-left:7px;}
    #audioFloat div{cursor:pointer;opacity: 0.5;filter: alpha(opacity = 50);margin:9px;_margin:5px;width:38px;height:36px;float:left;}
    #audioFloat .focus{opacity: 1;filter: alpha(opacity = 100)}
    #uploadAudioInfo{margin-top:10px;float:right;padding-right:8px;}
    
  7. 增加/DjangoUeditor/static/ueditor/dialogs/audio/audio.html(按照video.html来改就行)

    
    
    
        
        
        
        
    
    
    
    0%
  1. 增加/DjangoUeditor/static/ueditor/dialogs/audio/audio.js,也是按照video.js来改就行
    由于内容过长不方便贴出代码,具体代码可移步前往 我的博客下载完整源代码
  1. 在/DjangoUeditor/static/ueditor/ueditor.all.js增加音频上传插件

    //plugins/audio.js
    UE.plugins['insertaudio'] = function (){
        var me =this;
    
        /**
         *
         *
         * @param url 视频地址
         * @param width 视频宽度
         * @param height 视频高度
         * @param align 视频对齐
         * @param id    id
         * @param align 音频对齐
         * @param classname class
         * @param type  类型(image还是video)
         */
        function creatInsertStr(url,width,height,id,align,classname,type){
            var str="";
            switch(type){
                case 'image':
                    str=''
                    break;
                case 'audio':
                    str='';
                    break
    
                return str;
            }
            return str;
        }
    
        /**
         *
         * @param root
         * @param img2audio 为true表示image转audio,为false表示audio转image
         */
        function switchImgAndVideo(root,img2audio){
            utils.each(root.getNodesByTagName(img2audio ? 'img' : 'audio'),function(node){
                var className = node.getAttr('class');
                if(className && className.indexOf('fake-audio') != -1){
                    var html = creatInsertStr(node.getAttr("_url"),node.getAttr('width'), node.getAttr('height'),null, node.getStyle("float"),className,img2audio?'audio':'image');
                    node.parentNode.replaceChild(UE.uNode.createElement(html),node);
                }
                if(className && className.indexOf('upload-audio') != -1){
                    var html = creatInsertStr(node.getAttr("_url"), node.getAttr('width'), node.getAttr('height'),null, node.getStyle("float"),className,img2audio?'audio':'image');
                    node.parentNode.replaceChild(UE.uNode.createElement(html),node);
                }
            })
        }
    
        me.addOutputRule(function(root){
            switchImgAndVideo(root,true)
        });
        me.addInputRule(function(root){
            switchImgAndVideo(root)
        });
    
        me.commands["insertaudio"] = {
    
                    /**
                     * 插入视频
                     * @command insertaudio
                     * @method execCommand
                     * @param { String } cmd 命令字符串
                     * @param { Array } videoArr 需要插入的视频的数组, 其中的每一个元素都是一个键值对对象, 描述了一个视频的所有属性
                     */
                    execCommand:function (cmd, audioObjs,type) {
                        var me = this,
                        audioObjs = utils.isArray(audioObjs)?audioObjs:[audioObjs];
                        var html = [],id = 'tmpAudio', cl;
                        for(var i=0,vi,len = audioObjs.length;i@command insertvideo
                     * @method queryCommandState
                     * @param { String } cmd 需要查询的命令字符串
                     * @return { int } 如果当前光标所在处的元素是一个视频对象, 则返回1,否则返回0
                     */
                    queryCommandState:function () {
                        var me = this,
                            img = me.selection.getRange().getClosedNode(),
                            flag = img && (img.className == "faked-audio" || img.className.indexOf("upload-audio")!=-1);
                        return flag ? 1 : 0;
                    }
        };
    };
    

    具体效果如下,其实实现起来也不复杂,毕竟都是按照视频上传的代码来改下就行。

代码块

ueditor通过syntaxhighlighter高亮生成的代码html文件是这样的一个结构底部出现水平滚动条

1
2
       < p  class = "rollBlock" >这是一段长度很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长的文字</ p >
```

PC端页面显示效果如下:
PC端页面显示效果
移动端页面显示效果如下:
移动端页面显示效果

可以看出代码并没有自动出现横向滚动条,导致代码语句超过了该内容所在区域,一开始我通过审查元素给对应class加上"overflow: auto,发现并不行,后来就百度了下看看能不能找到解决的办法,后来在该ueditor解决syntaxhighlighter美化代码没有出现横向滚动条)找到了解决办法,我们可以通过修改shCore.js里面源码,位置在该js文件大概2266行,也就是该js生成上面代码的地方,给上面的代码再强行在table前加上,


原代码内容如下:
html =
     '
' + (this.getParam('toolbar') ? sh.toolbar.getHtml(this) : '') + '' + this.getTitleHtml(this.getParam('title')) + '' + '' + (gutter ? '' : '') + '' + '' + '' + '
' + this.getLineNumbersHtml(code) + '' + '
' + html + '
' + '
' + '
' ;

修改后的代码如下:

html =
    '
' + (this.getParam('toolbar') ? sh.toolbar.getHtml(this) : '') +'
' + '' + this.getTitleHtml(this.getParam('title')) + '' + '' + (gutter ? '' : '') + '' + '' + '' + '
' + this.getLineNumbersHtml(code) + '' + '
' + html + '
' + '
' + '
' + '
' ;

最后让我们可以看下页面修改效果
ueditor代码美化修改后PC页面端显示效果
ueditor代码美化修改后移动端页面端显示效果

发表评论 取消回复

电子邮件地址不会被公开。

请输入以http或https开头的URL,格式如:https://oneisall.top