将django-filebrowser整合Ueditor作为图片管理器

戈博易
2023-12-01

Ueditor是国内广泛使用的一款开源编辑器,但是其缺点是图片管理功能比较简陋,图片选择不显示图片名,无法删除图片以及 无法创建文件夹等问题导致图片很难维护。

整合思路:给ueditor加入自定义对话框调用filebrowser接口并创建适合ueditor的filebrowser回调函数。

一、 创建ueditor的customize dialog

在static/ueditor/下新建customizes文件夹(这个文件夹名是自定义的),在里面创建selectImageDialog.js. 如下,

UE.registerUI('selectimage',function(editor,uiName){

    //创建dialog
    var dialog = new UE.ui.Dialog({
        //指定弹出层中页面的路径,这里只能支持页面
        iframeUrl:'/static/ueditor/dialogs/selectimage/select.html',
        //需要指定当前的编辑器实例
        editor:editor,
        //指定dialog的名字
        name:uiName,
        //dialog的标题
        title:"插入图片",

        //指定dialog的外围样式
        cssRules:"width:650px;height:400px;",

        //如果给出了buttons就代表dialog有确定和取消
        buttons:[
            {
                className:'edui-okbutton',
                label:'确定',
                onclick:function () {
                    dialog.close(true);
                }
            },
            {
                className:'edui-cancelbutton',
                label:'取消',
                onclick:function () {
                    dialog.close(false);
                }
            }
        ]});

   
    var btn = new UE.ui.Button({
        name:'dialogbutton' + uiName,
        title:'dialogbutton' + uiName,
        //需要添加的额外样式,指定icon图标,这里默认使用一个重复的icon
        cssRules :'background-position: -380px 0;',
        onclick:function () {
            //渲染dialog
            dialog.render();
            dialog.open();
        }
    });

    return btn;
}/*index 指定添加到工具栏上的那个位置,默认时追加到最后,editorId 指定这个UI是那个编辑器实例上的,默认是页面上所有的编辑器都会添加这个按钮*/);

这样就注册了一个自定义对话框,用于作为选取图片的容器。

然后再找到ueditor/static/dialogs/文件夹,创建selectimages文件夹。这里我们是基于ueditor原生的image对话框进行二次开发,可以直接复制过来然后修改。这里我把所有的文件名都改为select以作区分,文件结构如下:

selectimage/

--imags/

--select.css

--select.html

--select.js

将select.html的body修改为以下内容:

<div class="wrapper">
        <div id="tabhead" class="tabhead">
            <span class="tab focus" data-content-id="remote"><var id="lang_tab_remote"></var></span>
        </div>
        <div class="alignBar" style="display:none">
            <label class="algnLabel"><var id="lang_input_align"></var></label>
                    <span id="alignIcon">
                        <span id="noneAlign" class="none-align focus" data-align="none"></span>
                        <span id="leftAlign" class="left-align" data-align="left"></span>
                        <span id="rightAlign" class="right-align" data-align="right"></span>
                        <span id="centerAlign" class="center-align" data-align="center"></span>
                    </span>
            <input id="align" name="align" type="hidden" value="none"/>
        </div>
        <div id="tabbody" class="tabbody">


            <!-- 远程图片 -->
            <div id="remote" class="panel focus">
                <div class="top">
                    <div class="row">
                        <label for="ueditor_url"><var id="lang_input_url"></var></var></label>
                        <span>
                            <input class="text" id="ueditor_url" type="text"/>
                        </span>
                        <!-- 将上面input的id作为参数传入下面方法 -->
                         <a id="select-button" href="javascript:FileBrowser.show('ueditor_url', '/admin/filebrowser/browse/?pop=4');"></a>
                    </div>
                </div>
                 <div class="left" style="display:none">
                    <div class="row">
                        <label><var id="lang_input_size"></var></label>
                        <span><var id="lang_input_width">&nbsp;&nbsp;</var><input class="text" type="text" id="width"/>px </span>
                        <span><var id="lang_input_height">&nbsp;&nbsp;</var><input class="text" type="text" id="height"/>px </span>
                        <span><input id="lock" type="checkbox" disabled="disabled"><span id="lockicon"></span></span>
                    </div>
                    <div class="row">
                        <label><var id="lang_input_border"></var></label>
                        <span><input class="text" type="text" id="border"/>px </span>
                    </div>
                    <div class="row">
                        <label><var id="lang_input_vhspace"></var></label>
                        <span><input class="text" type="text" id="vhSpace"/>px </span>
                    </div>
                    <div class="row">
                        <label><var id="lang_input_title"></var></label>
                        <span><input class="text" type="text" id="title"/></span>
                    </div>
                </div>
                <div class="right">
                    <div id="preview">
                        <!-- 以下三个element的id前缀必须这样设定,后面的与上面input的id保持一致 -->
                        <p id="preview_ueditor_url" style="display:none;">
                            <a href="javascript://" target="_self" id="previewlink_ueditor_url">
                                <img src="" id="previewimage_ueditor_url">
                            </a>
                        </p>
                    </div>
                </div>
            </div>
        </div>
    </div>

在image.html的基础上去掉了上传图片,在线管理,图片搜索的模块,并加上了检索图片的按钮和缩略图显示的区域。

相应的修改css,在select.css添加如下代码;

#remote #select-button{
    display: inline-block;
    background-position: 0 -1037px;
    background-color: #e1f0f5;
    background-image: url('images/icons-s846f870921.png');
    background-repeat: no-repeat;
    position: relative;
    margin: 0 0 -5px -25px;
    padding: 0;
    width: 28px;
    height: 28px;
    -moz-border-radius-topright: 3px;
    -webkit-border-top-right-radius: 3px;
    border-top-right-radius: 3px;
    -moz-border-radius-bottomright: 3px;
    -webkit-border-bottom-right-radius: 3px;
    border-bottom-right-radius: 3px;
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    cursor: pointer;
    overflow: hidden;
    vertical-align: top;
    color: #fff;
    border: 1px solid #ccc; 
}

#remote #previewimage_ueditor_url{
    max-width:100%;
}

下面要修改select.js文件。原来的image.js文件比较大,可以删除 上传图片,在线管理,图片搜索的模块。关于初始化对话框部分。

   var remoteImage,
    
    window.onload = function () {
        
        remoteImage = remoteImage || new RemoteImage();
        initButtons();
    };

    /* 初始化onok事件 */
    function initButtons() {

        dialog.onok = function () {
            var remote = false, list = [], id, tabs = $G('tabhead').children;
            for (var i = 0; i < tabs.length; i++) {
                if (domUtils.hasClass(tabs[i], 'focus')) {
                    id = tabs[i].getAttribute('data-content-id');
                    break;
                }
            }
            list = remoteImage.getInsertList();

            if(list) {
                editor.execCommand('insertimage', list);
                remote && editor.fireEvent("catchRemoteImage");
            }
        };
    }

可以看出是删除了uploadImage, onlineImage, searchImage这三个变量与initTabs()及相关方法。另外,image.js的默认imput的id是“url”,因为我们把上面select.html中把所有input的id改为“ueditor_url",所以这里也要把所有的url改为ueditor_url。

至此,dialog的二次开发基本完成。打开templates/ueditor.html,在最后添加

<script type="text/javascript" charset="utf-8" src="{{ STATIC_URL }}ueditor/customizes/selectImageDialog.js"></script>

如果在model里添加过ueditor,打开admin应该就可以看到输入框的toolbar最后有一个跟单张上传一样的按钮即我们添加的对话框,但此时打开会发现没有文字。这是因为没有注册相关语言包,需要打开static/lang/zh-cn/zh-cn.js里面找到insertimage,将整个数组复制并粘贴的下面,将insertimage,selectimage即可。

至此,ueditor部分已经设置完成。打开filebrowser下的static/filebrowser/js/,新建FB_Ueditor.js文件,输入如下:

function FileSubmit(FilePath, FileURL, ThumbURL, FileType) {
    
    // var input_id=window.name.split("___").join(".");
    var input_id=window.name.replace(/____/g,'-').split("___").join(".");
    var preview_id = 'preview_' + input_id;
    var previewlink_id = 'previewlink_' + input_id;
    var previewimage_id = 'previewimage_' + input_id;
    input = opener.document.getElementById(input_id);
    preview = opener.document.getElementById(preview_id);
    previewlink = opener.document.getElementById(previewlink_id);
    previewimage = opener.document.getElementById(previewimage_id);
    // set new value for input field
    input.value=FileURL;
        
    if (ThumbURL && FileType != "") {
        // selected file is an image and thumbnail is available:
        // display the preview-image (thumbnail)
        // link the preview-image to the original image
        previewlink.setAttribute("href", FileURL);
        previewlink.setAttribute("target", "_blank");
        previewimage.setAttribute("src", FileURL);   
        preview.setAttribute("style", "display:block");
    } else {
        // hide preview elements
        previewlink.setAttribute("href", "");
        previewlink.setAttribute("target", "");
        previewimage.setAttribute("src", "");
        preview.setAttribute("style", "display:none");
    }
    this.close();
}

在filebrowser添加对ueditor的支持,打开templates/filebrowser/index.html,在三个{% ifequal %}下面添加

{% ifequal query.pop '4' %} <!-- Ueditor -->
    <script language="javascript" type="text/javascript" src="{% static "filebrowser/js/FB_Ueditor.js" %}"></script>
    {% endifequal %}

打开 templates/filebrowser/include/filelisting.html中的<!-- FILE_ICON -->上面添加

        <!-- FILESELECT FOR UEDITOR -->
        {% if query.pop == "4" %}
            <td class="fb_icon">
                {% selectable fileobject.filetype query.type %}
                {% if selectable %}
                    <!-- select original -->
                    <button class="grp-button fb_selectlink" οnclick="FileSubmit('{{ fileobject.path }}', '{{ fileobject.url }}', '{{ thumbnail_version.url }}', '{{ fileobject.filetype }}');">{% trans "Select" %}</button>
                    <!-- select versions -->
                    {% if fileobject.filetype == "Image" and settings_var.ADMIN_VERSIONS %}
                        <div class="grp-pulldown-versions-container">
                            <a href="javascript://" class="grp-pulldown-versions-handler" title="{% trans "Versions" %}"> </a>
                            <ul class="grp-pulldown-versions">
                                {% for version in settings_var.ADMIN_VERSIONS %}
                                    {% version_setting version %}
                                    <li><a href="{% url 'filebrowser:fb_version' %}{% query_string '' 'filename, dirname' %}&dir={{ fileobject.dirname|urlencode }}&filename={{ fileobject.filename|urlencode }}&version={{ version }}" title="">{{ version_setting.verbose_name }}</a></li>
                                {% endfor %}
                            </ul>
                        </div>
                    {% endif %}
                {% else %}
                     
                {% endif %}
            </td>
        {% endif %}

至此,所有配置完成,用户可以用filebrowser在ueditor下进行图片和文件的管理。

为方便大家指正和使用,本人已经将filebowser和ueditor完全整合并开源,欢迎访问https://github.com/ZhangJingyuan/django-filebrowser-ueditor,可以下载代码或者直接在sdist文件夹内下载压缩包安装。

最近比较忙,再加上两个项目的代码风格相差太大,目前还不是十分的完善,但足够使用,详细配置请访问两个项目的github

 类似资料: