替百度文本编辑器UEditor添加附件管理功能

为百度文本编辑器UEditor添加附件管理功能

最近朋友的一个项目需要一个文本编辑器,让我突然想起那个百度编辑器UEditor,功能比较齐全而且开源,但也有很多bug和不足。

http://ueditor.baidu.com/website/onlinedemo.html

一年前我就就曾经关注过,让我感到最不能容忍的不足就是,添加的附件的地方,文件和服务器端重名这样的错误如果能够容忍,但如果上传错了,我想删除怎么办呢,居然没有附件管理,如下图所示,字体也太小:

替百度文本编辑器UEditor添加附件管理功能

为此我优化了上传,主要是增加增了附件管理,可以删除不需要的附件,效果如下:

上传文件增加了文件类型,和重名判断

替百度文本编辑器UEditor添加附件管理功能

附件管理部分,不仅可以显示服务器端的不同附件,而且双击附件可以删除附件。
替百度文本编辑器UEditor添加附件管理功能

 

首先在ueditor\server\submit\net目录下,这里以.net为例,添加一个服务器端文件fileManager.ashx,用来显示服务器端的附件内容,以及删除附件操作代码,前端页面通过AJAX来调用这个文件。

<%@ WebHandler Language="C#" Class="imageManager" %>
/**
 * User: xuhk
 * Date: 13-3-15
 * 对已经上传的附件进行管理,显示附件,删除附件
 */
using System;
using System.Web;
using System.IO;

public class imageManager : IHttpHandler {
    
    public void ProcessRequest (HttpContext context) {
        context.Response.ContentType = "text/plain";

        string path = context.Server.MapPath("../../upload/uploadfiles");                  
        string[] filetype = { ".rar", ".doc", ".docx", ".zip", ".pdf", ".txt", ".swf", ".wmv" };    //文件允许格式
        
        string action = context.Server.HtmlEncode(context.Request["action"]);
       
        if(action == "get")
        {
            String str=String.Empty;
            DirectoryInfo info = new DirectoryInfo(path);
            
            //目录验证
            if (info.Exists)
            {
                foreach (FileInfo fi in info.GetFiles())
                {
                    if (Array.IndexOf(filetype, fi.Extension) != -1)
                    {
                        str += "uploadfiles/" + fi.Name + "ue_separate_ue";
                    }
                }
            }
            context.Response.Write(str);
        }

        //删除选中的文件
        string fileName = context.Server.HtmlEncode(context.Request["fileName"]);
        if (action == "del")
        {
            try
            {
                String fullPath = String.Empty;
                fullPath = path + "/" + fileName;
                File.Delete(fullPath);
                context.Response.Write("success");
            }
            catch
            {
                context.Response.Write("error");
            }
        }
    }
 
    public bool IsReusable {
        get {
            return false;
        }
    }
}

目录ueditor\dialogs\attachment下的文件attachment.html改为如下形式: 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <title>附件上传</title>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
    <link rel="stylesheet" type="text/css" href="attachment.css" />
</head>
<body>
    <div class="wrapper">
        <div id="fileTab">
            <div id="tabHeads">
                <span tabsrc="file" class="focus">附件上传</span> <span tabsrc="fileManager">文件管理</span>
            </div>
            <div id="tabBodys">
                <div id="file" class="panel">
                    <div class="controller">
                        <span id="divStatus">本次共成功上传 0 个文件</span> <span id="spanButtonPlaceHolder"></span>
                    </div>
                    <div class="fieldset flash" id="fsUploadProgress">
                    </div>
                    <span id="startUpload" style="display: none;"></span>
                </div>
                <div id="fileManager" style="display: none;" class="panel">
                    <div id="fileListView" style="display: none;">
                          文件加载中……</div>
                    <span id="fileListAddress" style="display: none;"></span>
                </div>
            </div>
        </div>
    </div>

    <script type="text/javascript" src="../internal.js"></script>

    <script type="text/javascript" src="../../third-party/swfupload/swfupload.js"></script>

    <script type="text/javascript" src="../../third-party/swfupload/swfupload.queue.js"></script>

    <script type="text/javascript" src="../../third-party/swfupload/fileprogress.js"></script>

    <script type="text/javascript" src="callbacks.js"></script>

    <script type="text/javascript" src="fileTypeMaps.js"></script>

    <script type="text/javascript">
        var g = $G,
            ajax = parent.baidu.editor.ajax;
        /**
        * 找到id下具有focus类的节点并返回该节点下的某个属性
        * @param id
        * @param returnProperty
        */
        function findFocus(id, returnProperty) {
            var tabs = g(id).children,
                property;
            for (var i = 0, ci; ci = tabs[i++]; ) {
                if (ci.className == "focus") {
                    property = ci.getAttribute(returnProperty);
                    break;
                }
            }
            return property;
        }
        /**
        * 绑定确认按钮
        */
        function addOKListener() {
            dialog.onok = function() {
                var currentTab = findFocus("tabHeads", "tabSrc");
                switch (currentTab) {
                    case "file":
                        return insertBatch();
                        break;
                    case "fileManager":
                        insertSearch("fileListView");
                        return;
                        break;
                    default:
                        return;
                }
            }
        }

        //插入单个文件
        function insertBatch() {
            var map = fileTypeMaps,
                str = "";
            for (var i = 0, ci; ci = filesList[i++]; ) {
                var src = editor.options.UEDITOR_HOME_URL + "dialogs/attachment/fileTypeImages/" + (map[ci.type] || "icon_default.png");
                str += "<p style='line-height: 16px;'><img src='" + src + "' data_ue_src='" + src + "' />" +
                       "<a href='" + editor.options.filePath + ci.url + "'>" + ci.title + "</a></p>";
            }
            editor.execCommand("insertHTML", str);
            swfupload.destroy();
        }

        //插入多个文件
        function insertSearch(id) {
            var fileTypeImg = $G("fileListView").getElementsByTagName("img");
            var fileAddress = $G("fileListAddress").getElementsByTagName("a");

            for (var i = 0, ci; ci = fileTypeImg[i++]; ) {

                if (ci.getAttribute("selected")) {

                    //i被加1了,所以这里减一
                    var ci2 = fileAddress[i - 1];

                    //地址
                    var url = ci2.getAttribute("src").replace(/(\s*$)/g, "");

                    //文件名
                    var arrTitle = url.split("/");
                    var strTitle = arrTitle[arrTitle.length - 1];

                    //文件类型
                    var arrType = url.split(".");
                    var strType = "." + arrType[arrType.length - 1];
                    filesList.push({ title: strTitle, url: url, type: strType });
                }
            }

            insertBatch()
        }
        /**
        * 延迟加载
        */
        function addScrollListener() {

            g("fileListView").onscroll = function() {
                var fileTypeImg = this.getElementsByTagName("img"),
                    top = Math.ceil(this.scrollTop / 100) - 1;
                top = top < 0 ? 0 : top;
                for (var i = top * 5; i < (top + 5) * 5; i++) {
                    var img = fileTypeImg[i];
                    if (img && !img.getAttribute("src")) {
                        img.src = img.getAttribute("lazy_src");
                        img.removeAttribute("lazy_src");
                    }
                }
            }
        }

        /**
        * 附件缩放
        * @param img
        * @param max
        */
        function scale(img, max, oWidth, oHeight) {
            var width = 0, height = 0, percent, ow = img.width || oWidth, oh = img.height || oHeight;
            if (ow > max || oh > max) {
                if (ow >= oh) {
                    if (width = ow - max) {
                        percent = (width / ow).toFixed(2);
                        img.height = oh - oh * percent;
                        img.width = max;
                    }
                } else {
                    if (height = oh - max) {
                        percent = (height / oh).toFixed(2);
                        img.width = ow - ow * percent;
                        img.height = max;
                    }
                }
            }
        }

        function selectTxt(node) {
            if (node.select) {
                node.select();
            } else {
                var r = node.createTextRange && node.createTextRange();
                r.select();
            }
        }

        /**
        * 改变o的选中状态
        * @param o
        */
        function changeSelected(o) {

            if (o.getAttribute("selected")) {
                o.removeAttribute("selected");
                o.childNodes[0].removeAttribute("selected");
                o.style.cssText = "filter:alpha(Opacity=100);-moz-opacity:1;opacity: 1;border: 1px solid #E8E8E8;";
                /*为选中文件下部的文件名DIV部分增加样式*/
                o.childNodes[1].style.cssText = "filter:alpha(Opacity=100);-moz-opacity:1;opacity: 1;border: 0px solid #E8E8E8;";

            } else {
                o.setAttribute("selected", "true");
                o.childNodes[0].setAttribute("selected", "true");
                o.style.cssText = "filter:alpha(Opacity=100);-moz-opacity:0.5;opacity: 0.5;border:1px solid #316ac5;background-color: #F0F5FF;";
                /*为选中文件下部的文件名DIV部分增加样式*/
                o.childNodes[1].style.cssText = "filter:alpha(Opacity=100);-moz-opacity:0.5;opacity: 0.5;border:0px solid #316ac5;background-color: #F0F5FF;";

            }
        }

        /**
        * tab切换
        * @param tabParentId
        * @param keepFocus   当此值为真时,切换按钮上会保留focus的样式
        */
        function switchTab(tabParentId, keepFocus) {
            var tabElements = $G(tabParentId).children,
                tabHeads = tabElements[0].children,
                tabBodys = tabElements[1].children;
            var map = fileTypeMaps;
            for (var i = 0, length = tabHeads.length; i < length; i++) {
                var head = tabHeads[i];
                domUtils.on(head, "click", function() {
                    //head样式更改
                    for (var k = 0, len = tabHeads.length; k < len; k++) {
                        if (!keepFocus) tabHeads[k].className = "";
                    }
                    this.className = "focus";
                    //body显隐
                    var tabSrc = this.getAttribute("tabSrc");
                    for (var j = 0, length = tabBodys.length; j < length; j++) {
                        var body = tabBodys[j],
                        id = body.getAttribute("id");

                        if (id == tabSrc) {
                            body.style.display = "";
                            if (id == "fileManager") {

                                //转换到文件管理TAB时,显示DIV里的内容
                                g("fileManager").style.display = "";
                                g("fileListView").style.display = "";


                                var list = g("fileListView");
                                //已经初始化过时不再重复提交请求
                                //2013-03-09删除这个判断,这样才能保证上传新文件后,点管理附件显示新的附件你
                                //                                if (!list.children.length) {
                                ajax.request(editor.options.fileManagerPath, {
                                    timeout: 100000,
                                    action: "get",
                                    onsuccess: function(xhr) {
                                        var tmp = xhr.responseText,
                                                imageUrls = !tmp ? [] : tmp.split("ue_separate_ue"),
                                                length = imageUrls.length;

                                        //当服务器没上传文件的时候
                                        if (0 == length) {
                                            g("fileManager").style.display = "";
                                            list.style.display = "";
                                            list.innerHTML = !length ? "  当前未上传过任何附件!" : "";
                                        } else {
                                            list.innerHTML = "";
                                        }
                                        for (var i = 0, ci; ci = imageUrls[i++]; ) {
                                            //文件真实地址
                                            var url = editor.options.UEDITOR_HOME_URL + ci;

                                            //创建一个图片标签来显示文件类型图标
                                            var img = document.createElement("img");
                                            //创建一个链接标签来存放文件真实地址
                                            var a = document.createElement("a");

                                            //显示单个文件信息的DIV快
                                            var divFileView = document.createElement("div");
                                            //存放单个文件地址
                                            var divFileAddress = document.createElement("div");

                                            //在文件类型图标上,增加个fileAddress属性,存放该文件的真实地址,目的为了双击图标删除此文件
                                            divFileView.setAttribute("fileAddress", url);
                                            divFileView.appendChild(img);

                                            // 在显示文件类型图标下显示文件名
                                            var divFileName = document.createElement("div");
                                            var arrFileName = ci.split("/");
                                            var strFileName = arrFileName[arrFileName.length - 1];

                                            //在鼠标放上面给出全文件名提示
                                            img.parentNode.title = strFileName

                                            //获得文件扩展名前点的位置,并去掉文件扩展名
                                            var indexDot = strFileName.lastIndexOf(".");
                                            strFileName = strFileName.substring(0, indexDot);

                                            //文件名太长就截取
                                            if (strFileName.length >= 6)
                                                strFileName = strFileName.substring(0, 6);

                                            //把文件名显示在图标下面
                                            divFileName.innerHTML = strFileName;
                                            divFileView.appendChild(divFileName);
                                            divFileAddress.appendChild(a);

                                            //显示文件类型
                                            g("fileListView").appendChild(divFileView);
                                            //隐藏DIV,对应显示文件的真实地址
                                            g("fileListAddress").appendChild(divFileAddress);

                                            //单击选中
                                            img.parentNode.onclick = function() {
                                                changeSelected(this);
                                            };

                                            //双击删除
                                            img.parentNode.ondblclick = function() {

                                                var me = this,
                                                    src = me.getAttribute("fileAddress");
                                                if (!confirm("删除操作不可恢复,您确认要删除本附件么?")) return;
                                                ajax.request(editor.options.fileManagerPath, {
                                                    action: "del",
                                                    fileName: src.substr(src.lastIndexOf("/") + 1),
                                                    onsuccess: function(xhr) {

                                                        if (xhr.responseText == "success") {
                                                            me.parentNode.removeChild(me);
                                                        } else {
                                                            alert("服务器删除附件失败,请重试!");
                                                        }
                                                    }
                                                });
                                            };
                                            img.onload = function() {
                                                this.parentNode.style.display = "";
                                                var w = this.width, h = this.height;
                                                scale(this, 100, 200, 80);

                                            };

                                            //文件类型图标地址
                                            var arrType = url.split(".");
                                            var strType = "." + arrType[arrType.length - 1];
                                            var imgTypeURL = editor.options.UEDITOR_HOME_URL + "dialogs/attachment/fileTypeImages/" + map[strType];

                                            img.setAttribute(i < 35 ? "src" : "lazy_src", imgTypeURL);
                                            img.setAttribute("data_ue_src", imgTypeURL);

                                            //文件存放真实地址
                                            a.setAttribute(i < 35 ? "src" : "lazy_src", ci);
                                            a.setAttribute("data_ue_src", ci);
                                            list.style.display = "";

                                        }
                                    },
                                    onerror: function() {
                                        g("fileListView").innerHTML = "糟糕,附件读取失败了!";
                                    }
                                });
                                //                                }
                            }

                            //当切换到本地附件上传时,隐藏遮罩用的iframe
                            if (id == "file") {

                                g("fileManager").style.display = "none";
                                g("fileListView").style.display = "none";
                            }

                        }
                        else {
                            body.style.display = "none";
                        }
                    }
                });
            }
        }
        var swfupload,
        filesList = [];

        window.onload = function() {

            var settings = {
                flash_url: "../../third-party/swfupload/swfupload.swf",
                flash9_url: "../../third-party/swfupload/swfupload_fp9.swf",
                upload_url: "../../server/upload/net/fileUp.ashx",           //附件上传服务器地址
                post_params: { "PHPSESSID": "<?php echo session_id(); ?>" }, //解决session丢失问题
                file_size_limit: "100 MB",                                 //文件大小限制,此处仅是前端flash选择时候的限制,具体还需要和后端结合判断
                file_types: "*.*",                                         //允许的扩展名,多个扩展名之间用分号隔开,支持*通配符
                file_types_description: "All Files",                      //扩展名描述
                file_upload_limit: 100,                                   //单次可同时上传的文件数目
                file_queue_limit: 10,                                      //队列中可同时上传的文件数目
                custom_settings: {                                         //自定义设置,用户可在此向服务器传递自定义变量
                    progressTarget: "fsUploadProgress",
                    startUploadId: "startUpload"
                },
                debug: false,

                // 按钮设置
                button_image_url: "../../themes/default/images/fileScan.png",
                button_width: "100",
                button_height: "25",
                button_placeholder_id: "spanButtonPlaceHolder",
                button_text: '<span class="theFont">文件浏览…</span>',
                button_text_style: ".theFont { font-size:14px;}",
                button_text_left_padding: 10,
                button_text_top_padding: 4,

                // 所有回调函数 in handlers.js
                swfupload_preload_handler: preLoad,
                swfupload_load_failed_handler: loadFailed,
                file_queued_handler: fileQueued,
                file_queue_error_handler: fileQueueError,
                //选择文件完成回调
                file_dialog_complete_handler: function(numFilesSelected, numFilesQueued) {
                    var me = this;        //此处的this是swfupload对象
                    if (numFilesQueued > 0) {
                        dialog.buttons[0].setDisabled(true);
                        var start = $G(this.customSettings.startUploadId);
                        start.style.display = "";
                        start.onclick = function() {
                            me.startUpload();
                            start.style.display = "none";
                        }
                    }
                },
                upload_start_handler: uploadStart,
                upload_progress_handler: uploadProgress,
                upload_error_handler: uploadError,
                upload_success_handler: function(file, serverData) {
                    try {
                        var info = eval("(" + serverData + ")");
                    } catch (e) { }
                    var progress = new FileProgress(file, this.customSettings.progressTarget);
                    if (info.state == "SUCCESS") {
                        progress.setComplete();
                        progress.setStatus("<span style='color: #0b0;font-weight: bold'>上传成功!</span>");
                        //filesList.push({ url: info.url, type: info.fileType});
                        filesList.push({ title: info.title, url: info.url, type: info.fileType });
                        progress.toggleCancel(true, this, "从成功队列中移除");
                    } else {
                        progress.setError();
                        progress.setStatus(info.state);
                        progress.toggleCancel(true, this, "移除保存失败文件");
                    }

                },
                //上传完成回调
                upload_complete_handler: uploadComplete,
                //队列完成回调
                queue_complete_handler: function(numFilesUploaded) {
                    dialog.buttons[0].setDisabled(false);
                    var status = $G("divStatus");
                    var num = status.innerHTML.match(/\d+/g);
                    status.innerHTML = "本次共成功上传 " + ((num && num[0] ? parseInt(num[0]) : 0) + numFilesUploaded) + " 个文件";
                }
            };
            swfupload = new SWFUpload(settings);

            dialog.oncancel = function() {
                swfupload.destroy();
            }

            switchTab("fileTab");

            addOKListener();
            addScrollListener();

        };
    </script>

</body>
</html>