Tinymce 编辑器添加自定义图片管理插件

在使用Tinymce的过程中需要用到图片上传功能,而提供的上传插件在上传文件后是给了一个连接地址,就想用户需要什么图片,不能用最直观的方式表现出来么!

虽然官网上也有一个文件管理的插件moxiemanager,可奈何他是收费的!https://www.tiny.cloud/docs/plugins/moxiemanager/

然后就打算自己弄一个,其实实现效果起来很简单,就只是做了一个类型相册管理的功能,然后在点击图片的时候,将图片的地址信息插入到编辑器里就行了,由于后台用的是layui

的框架,所以界面也就用了layui来实现,这里我只弄了上传,删除功能,也可自己添加检索等功能,实现效果如下

1 、添加插件

我们需要在tinymce的 Plugins  目录下新建一个filemanager文件夹,并添加一个名为plugin.min.js ,其中editor传参后再图片管理页面通过

var editor = top.tinymce.activeEditor.windowManager.getParams().editor; 获取编辑器对象,进行图片插入操作

tinymce.PluginManager.add("filemanager", function (editor, url) {
    editor.addButton("filemanager", {
        title: "图片管理",
        icon: 'image',
        onclick: function () {
            editor.windowManager.open({
                title: "图片管理",
                url:  "/Administrator/Filemanager/Editor",
                width: window.innerWidth * 0.9,
                height: window.innerHeight * 0.8
            }, {
                    editor: editor // pointer to access editor from cshtml
            })
        }
    })
});

  

2. 相册功能实现

文件夹管理实体类

public class FileManagerDirectoryEntity : BaseEntity
    {
        /// <summary>
        /// 父级Id
        /// </summary>
        public int ParentId { get; set; }

        /// <summary>
        /// 文件夹名称
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 路径
        /// </summary>
        public string FullPath { get; set; }

        /// <summary>
        /// 子文件数量
        /// </summary>
        public int ChildrenCount { get; set; }
    }

  

文件管理实体类

public class FileManagerDirectoryEntity : BaseEntity
    {
        /// <summary>
        /// 父级Id
        /// </summary>
        public int ParentId { get; set; }

        /// <summary>
        /// 文件夹名称
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 路径
        /// </summary>
        public string FullPath { get; set; }

        /// <summary>
        /// 子文件数量
        /// </summary>
        public int ChildrenCount { get; set; }
    }

  

相册功能具体实现controller

public class FileManagerController : Controller
    {

        #region Core
        private readonly IRepository<FileManagerDirectoryEntity> _fileManagerDirectoryRepository;
        private readonly IRepository<FileManagerFilesEntity> _fileManagerFilesRepository;
        private const string smallImage = "_small";

        public FileManagerController(
             IRepository<FileManagerDirectoryEntity> fileManagerDirectoryRepository,
             IRepository<FileManagerFilesEntity> fileManagerFilesRepository
            )
        {
            this._fileManagerDirectoryRepository = fileManagerDirectoryRepository;
            this._fileManagerFilesRepository = fileManagerFilesRepository;
        }

        #endregion


        /// <summary>
        /// 编辑器插件
        /// 获取文件数据
        /// </summary>
        /// <param name="dirId"></param>
        /// <returns></returns>
        public ActionResult Editor(int dirId = 0) {

            List<FileManagerFileModel> modelList = new List<FileManagerFileModel>();
            
            //加载该文件夹下的文件夹
            var dirList = _fileManagerDirectoryRepository.Table
                .Where(x=>x.ParentId==dirId)
                .OrderByDescending(x=>x.CreateTime)
                .ToList();
            foreach(var item in dirList)
            {

                FileManagerFileModel model = new FileManagerFileModel();
                model.Id = item.Id;
                model.Name = item.Name;
                model.FullPath = item.FullPath;
                model.FileType = 2;
                model.ChildrenCount = item.ChildrenCount;
                modelList.Add(model);
            }

            //加载该文件夹下的图片文件
            var fileList = _fileManagerFilesRepository.Table
                .Where(x => x.DirectoryId == dirId)
                .OrderByDescending(x => x.CreateTime)
                .ToList();
            foreach (var item in fileList)
            {

                FileManagerFileModel model = new FileManagerFileModel();
                model.Id = item.Id;
                model.Name = item.Name;
                model.FullPath = item.FullPath;
                model.SmallFullPath = item.FullPath + smallImage + item.FileExt;
                model.FileType = 1;
                modelList.Add(model);
            }

            return View(modelList);
        }

        /// <summary>
        /// 创建文件夹
        /// </summary>
        /// <param name="dirId"></param>
        /// <returns></returns>
        public ActionResult _AddDirectory(int dirId) {
            return View();
        }

        /// <summary>
        /// 文件夹信息保存
        /// </summary>
        /// <param name="dirId"></param>
        /// <param name="dirName"></param>
        /// <returns></returns>
        public ActionResult _AddDirectorySave(int dirId , string dirName) {
            var parentDirEntity = _fileManagerDirectoryRepository.GetById(dirId);
            if (!string.IsNullOrEmpty(dirName))
            {
                var parentDirPath = parentDirEntity == null ? "/Content/FileManager/" : parentDirEntity.FullPath;
                if(parentDirEntity != null)
                {
                    parentDirEntity.ChildrenCount++;
                }

                FileManagerDirectoryEntity entity = new FileManagerDirectoryEntity();
                entity.ParentId = dirId;
                entity.Name = dirName;
                entity.FullPath = string.Format("{0}/{1}/", parentDirPath, Guid.NewGuid());
                if (!Directory.Exists(Server.MapPath(entity.FullPath)))
                {
                    Directory.CreateDirectory(Server.MapPath(entity.FullPath));
                }

                _fileManagerDirectoryRepository.Insert(entity);
                _fileManagerDirectoryRepository.SaveChanges();
            }
            return RedirectToAction("Editor",new { dirId = dirId});
        }

        /// <summary>
        /// 上传图片
        /// </summary>
        /// <param name="dirId"></param>
        /// <returns></returns>
        public JsonResult UploadImage(int dirId)
        {
            //路径地址
            string fileUrl = "";
            var parentDirEntity = _fileManagerDirectoryRepository.GetById(dirId);
            var parentDirPath = parentDirEntity == null ? "/Content/FileManager/" : parentDirEntity.FullPath;

            HttpFileCollectionBase postfile = HttpContext.Request.Files;
            if (postfile == null)
            {
                return Json(new { code = 1, msg = "文件不能为空" });
            }

            var file = postfile[0];
            string extName = Path.GetExtension(file.FileName);

            using (System.Drawing.Image image = System.Drawing.Image.FromStream(file.InputStream))
            {

                string fileName = Guid.NewGuid().ToString() + extName;
                string smallImgName = string.Format("{0}{1}{2}", fileName, smallImage, extName);

                string route = Server.MapPath(parentDirPath);
                fileUrl = Path.Combine(parentDirPath, fileName);
                string savePath = Path.Combine(route, fileName);
                //缩略图路径
                string smallImgPath = Path.Combine(route, smallImgName);

                //生成缩略图
                try
                {
                    ImageResizer.Fit(image, 160, 160, ImageResizeMode.Crop, ImageResizeScale.Down).Save(smallImgPath);
                }
                catch (Exception)
                {
                    return Json(new { flag = false, msg = "生成缩略图出错!" });
                }

                file.SaveAs(savePath);
            }

            #region 添加数据到素材表
            FileManagerFilesEntity entity = new FileManagerFilesEntity();
            entity.FileExt = extName;
            entity.FullPath = fileUrl;
            entity.Name = Path.GetFileNameWithoutExtension(file.FileName);
            entity.DirectoryId = dirId;
            entity.Size = file.ContentLength;

            _fileManagerFilesRepository.Insert(entity);
            _fileManagerFilesRepository.SaveChanges();
            #endregion


            if (parentDirEntity != null)
            {
                parentDirEntity.ChildrenCount++;
            }
            _fileManagerDirectoryRepository.SaveChanges();

            return Json(new { code = 0 });
        }



        public class DeleteFilesParams
        {
            public int Id { get; set; }

            public int Type { get; set; }
        }

        /// <summary>
        /// 删除选中文件夹及图片
        /// </summary>
        /// <returns></returns>
        public JsonResult CheckedFilesDelete(List<DeleteFilesParams> checkeds)
        {
            var directoryList = _fileManagerDirectoryRepository.Table.ToList();
            var fileList = _fileManagerFilesRepository.Table.ToList();


            foreach(var item in checkeds)
            {
                //删除图片
                if (item.Type == 1)
                {
                    var fileEntity = fileList.FirstOrDefault(x => x.Id == item.Id);
                    string path = Server.MapPath(fileEntity.FullPath);
                    if (System.IO.File.Exists(path))
                    {
                        System.IO.File.Delete(path);
                    }


                    var parentDir = directoryList.Find(x => x.Id == fileEntity.DirectoryId);
                    if (parentDir != null)
                    {
                        parentDir.ChildrenCount--;
                    }

                    _fileManagerFilesRepository.Delete(fileEntity);
                }
                else
                {
                    var dirEntity = directoryList.FirstOrDefault(x => x.Id == item.Id);
                    DeleteChildDirFiles(dirEntity.Id, directoryList, fileList);
                    string path = Server.MapPath(dirEntity.FullPath);
                    if (Directory.Exists(path))
                    {
                        Directory.Delete(path, true);
                    }


                    var parentDir = directoryList.Find(x => x.Id == dirEntity.ParentId);
                    if (parentDir != null)
                    {
                        parentDir.ChildrenCount--;
                    }

                    _fileManagerDirectoryRepository.Delete(dirEntity);
                }
            }
            _fileManagerFilesRepository.SaveChanges();
            _fileManagerDirectoryRepository.SaveChanges();

            return Json(new { code = 0 });
        }

        public void DeleteChildDirFiles(int pid,List<FileManagerDirectoryEntity> dirList, List<FileManagerFilesEntity> files) {
            var dirEntityList = dirList.Where(x => x.ParentId == pid);
            var fileEntityList = files.Where(x => x.DirectoryId == pid);
            foreach (var item in dirEntityList)
            {
                DeleteChildDirFiles(item.Id, dirList, files);
                _fileManagerDirectoryRepository.Delete(item);
            }

            foreach (var item in fileEntityList)
            {
                _fileManagerFilesRepository.Delete(item);
            }
            _fileManagerDirectoryRepository.SaveChanges();
            _fileManagerFilesRepository.SaveChanges();

        }
    }

 

文件管理页面 Editor.chtml

 

@using Web.Areas.Administrator.Models
@model List<FileManagerFileModel>
@{
    Layout = null;
}

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>文件管理</title>
    <link href="/Assets/iconfont/iconfont.css" rel="stylesheet" />
    <link href="/Scripts/layui/css/layui.css" rel="stylesheet" />
    <style>
        body { background: #f6f6f6; }
        .toolbar { padding: 10px; background: #fff; }
        .toolbar i.iconfont{margin-right:10px;}
        .file-list{margin:20px;}
        .file-list li { float: left; background:#fff; margin-bottom:20px; margin-right:20px; }
        .file-list li .img-wapper { width:160px;  }
        .file-list li .img-wapper img{width:100%; height:160px;}
        .file-list li .file-name { padding: 0 10px; width: 100%; overflow:hidden; line-height: 30px; height:30px; color: #666; font-size: 12px; background: #fafafa; }
        .file-list li .file-name .layui-form-checkbox{width:140px !important; overflow:hidden !important; }
        .file-list li:hover { box-shadow: 0 0 10px rgba(0,0,0,.1); }
        .file-list li:hover .file-name { background: #f5f5f5;}
    </style>
</head>
<body>
    <div class="toolbar">
        <a class="layui-btn layui-btn-small" href="javascript:;" data-toggle="modal" data-title="新建文件夹" data-url="@Url.Action("_AddDirectory",new { dirId = Request["dirId"] == null ? 0 : int.Parse(Request["dirId"])})">
            <i class="iconfont icon-directory"></i>
            新建文件夹
        </a>
        <button id="upload-img-btn" type="button" class="layui-btn"><i class="iconfont icon-photo"></i>上传图片</button>
        <button id="delete-img-btn" type="button" class="layui-btn layui-btn-danger"><i class="iconfont icon-photo"></i>删除图片</button>
    </div>
    <div class="layui-form">
        <ul class="file-list">
            @if (!string.IsNullOrWhiteSpace(Request["dirId"]))
            {
                <li class="file-item">
                    <div class="img-wapper">
                        <a href="javascript:history.back(-1);">
                            <img src="/Assets/images/default/admin_directory_back.png" alt="返回上级" title="返回上级" />
                        </a>
                    </div>
                    <div class="file-name">
                        ...
                    </div>
                </li>
            }
            @if (Model.Any())
            {
                foreach (var item in Model)
                {
                    <li class="file-item">
                        @if (item.FileType == 1)
                        {
                            <div class="img-wapper">
                                <a href="javascript:;" class="file-img" data-url="@item.FullPath" data-title="@item.Name">
                                    <img src="@item.SmallFullPath" title="@item.Name" />
                                </a>
                            </div>
                            <div class="file-name">
                                <input type="checkbox" name="file-id" lay-skin="primary" title="@item.Name" data-id="@item.Id" data-type="1">
                            </div>
                        }
                        else
                        {
                            <div class="img-wapper">
                                <a href="@Url.Action("Editor",new { dirId=item.Id})">
                                    @if (item.ChildrenCount > 0)
                                    {
                                        <img src="/Assets/images/default/admin_directory_files.png" title="@item.Name" />
                                    }
                                    else
                                    {
                                        <img src="/Assets/images/default/admin_directory.png" title="@item.Name" />
                                    }
                                </a>
                            </div>
                            <div class="file-name">
                                <input type="checkbox" name="file-id" lay-skin="primary" title="@item.Name" data-id="@item.Id" data-type="2">
                            </div>
                        }
                    </li>
                }
            }
        </ul>
    </div>
    <input id="dirId" value="@Request["dirId"]" hidden>
    <script src="~/Scripts/jquery-3.2.1.min.js"></script>
    <script src="/Scripts/layui/layui.js"></script>
    <script>
        //获取tinymce编辑器
        var editor = top.tinymce.activeEditor.windowManager.getParams().editor;

        layui.use(['upload'], function () {
            var upload = layui.upload;
            var dirId = $("#dirId").val() == "" ? 0 : $("#dirId").val();
            upload.render({ //允许上传的文件后缀
                elem: '#upload-img-btn'
                , url: 'UploadImage?dirId=' + dirId
                , accept: 'file' //普通文件
                , multiple: true
                , size: 1024 * 2 //限制文件大小,单位 KB
                , exts: 'jpg|jpeg|png|gif' //只允许上传压缩文件
                , done: function (res) {
                    if (res.code == 0) {
                        window.location.reload();
                    }
                }
            });

            //删除图片
            $("#delete-img-btn").click(function () {
                var checkeds = [];
                $("input[name='file-id']:checkbox").each(function () {
                    if (true == $(this).is(':checked')) {
                        checkeds.push({
                            id: $(this).data('id'),
                            type: $(this).data('type')
                        });
                    }
                });
                if (checkeds.length == 0) {
                    layer.alert('请先选择需要删除的文件!');
                }
                else {
                    layer.confirm('删除后将无法恢复,请确认是否要删除所选文件?', {
                        btn: ['确定删除', '我在想想'] //按钮
                    }, function () {
                        $.ajax({
                            type: 'post',
                            url: 'CheckedFilesDelete',
                            data: { checkeds : checkeds },
                            success: function (result) {
                                if (result.code == 0) {
                                    window.location.reload();
                                }
                                else {
                                    showMsg(result.msg);
                                }
                            }
                        })
                    }, function () {
                    });
                }
            })
        })

        //添加图片至编辑器
        $(".file-img").click(function () {
            var url = $(this).data("url"),
                title = $(this).data("title");

            //添加确认
            layer.confirm('是否需要添加此图片?', {
                btn: ['确认添加', '我在想想'] //按钮
            }, function () {
                editor.execCommand('mceInsertContent', false, '<img alt="' + title + '" src="' + url + '"/>');
                editor.windowManager.close();
            }, function () {});
        })
        
    </script>
    <script>
        //layui基本代码
        $(function () {
            layui.use(['element', 'form', "layer"], function () {
                var element = layui.element;

                //表单渲染
                var form = layui.form;
                form.on('submit(formDemo)', function (data) {
                    layer.msg(JSON.stringify(data.field));
                    return false;
                });
                form.render();

                //异步加载modal
                $(document).on("click", '[data-toggle="modal"]', function (e) {
                    var $this = $(this),
                        url = $(this).data('url'),
                        title = $(this).data("title")
                    if (url) {
                        $.ajax({
                            url: url,
                            data: { rnd: Math.random() },
                            //dataType: 'html',
                            success: function (data) {
                                //示范一个公告层
                                layer.open({
                                    type: 1
                                    , title: title //不显示标题栏
                                    , shade: 0.8
                                    , shadeClose: true
                                    , fixed: false
                                    , area: ["900px"]
                                    , offset: '40px'
                                    , id: 'ajax-modal-wapper' //设定一个id,防止重复弹出
                                    , move: false //禁止拖拽
                                    , content: data
                                });
                            },
                            error: function (XMLHttpRequest, textStatus, errorThrown) {
                                alert('加载出错。' + textStatus + '. ' + XMLHttpRequest.status);
                            },
                            complete: function () {
                            }
                        });
                    }
                });
            });
        })
    </script>
</body>
</html>

  

新增文件夹页面 _AddDirectory.chtml

@{
    Layout = null;
}

<div class="modal-content" style="padding-top:20px;">
    <form class="layui-form" action="_AddDirectorySave" method="post" enctype="multipart/form-data">
        <input name="dirId" value="@Request["dirId"]" hidden>
        <div class="layui-form-item">
            <label class="layui-form-label" for="dirName">文件夹名称</label>
            <div class="layui-input-block">
                <input class="layui-input" id="dirName" lay-verify="required" name="dirName" placeholder="请输入文件夹名称" type="text" value="">
            </div>
        </div>
        <div class="layui-form-item">
            <div class="layui-input-block">
                <button class="layui-btn" lay-submit lay-filter="account-form" type="submit">保存信息</button>
            </div>
        </div>
    </form>
</div>

  

 

3. 将选中图片插入编辑器

在图片列表的页面中,我们只需要在点击图片的事件中调用Tinymce编辑器的插入方法即可,以下为插入图片的代码

<script>
        //获取tinymce编辑器
        var editor = top.tinymce.activeEditor.windowManager.getParams().editor;

        layui.use(['upload'], function () {
            var upload = layui.upload;
            var dirId = $("#dirId").val() == "" ? 0 : $("#dirId").val();
            upload.render({ //允许上传的文件后缀
                elem: '#upload-img-btn'
                , url: 'UploadImage?dirId=' + dirId
                , accept: 'file' //普通文件
                , multiple: true
                , size: 1024 * 2 //限制文件大小,单位 KB
                , exts: 'jpg|jpeg|png|gif' //只允许上传压缩文件
                , done: function (res) {
                    if (res.code == 0) {
                        window.location.reload();
                    }
                }
            });

            //删除图片
            $("#delete-img-btn").click(function () {
                var checkeds = [];
                $("input[name='file-id']:checkbox").each(function () {
                    if (true == $(this).is(':checked')) {
                        checkeds.push({
                            id: $(this).data('id'),
                            type: $(this).data('type')
                        });
                    }
                });
                if (checkeds.length == 0) {
                    layer.alert('请先选择需要删除的文件!');
                }
                else {
                    layer.confirm('删除后将无法恢复,请确认是否要删除所选文件?', {
                        btn: ['确定删除', '我在想想'] //按钮
                    }, function () {
                        $.ajax({
                            type: 'post',
                            url: 'CheckedFilesDelete',
                            data: { checkeds : checkeds },
                            success: function (result) {
                                if (result.code == 0) {
                                    window.location.reload();
                                }
                                else {
                                    showMsg(result.msg);
                                }
                            }
                        })
                    }, function () {
                    });
                }
            })
        })

        //添加图片至编辑器
        $(".file-img").click(function () {
            var url = $(this).data("url"),
                title = $(this).data("title");

            //添加确认
            layer.confirm('是否需要添加此图片?', {
                btn: ['确认添加', '我在想想'] //按钮
            }, function () {
                editor.execCommand('mceInsertContent', false, '<img alt="' + title + '" src="' + url + '"/>');
                editor.windowManager.close();
            }, function () {});
        })
        
    </script>
 

 Ps: 还有很多的不足之处,希望能一起成长, 我的博客地址 jiojun.com 

posted @ 2018-09-30 11:00  夏天的小枕头  阅读(7147)  评论(2编辑  收藏  举报