1.什么是KindEditor
KindEditor 是一套开源的在线HTML编辑器,主要用于让用户在网站上获得所见即所得编辑效果,开发人员可以用 KindEditor 把传统的多行文本输入框(textarea)替换为可视化的富文本输入框。 KindEditor 使用 JavaScript 编写,可以无缝地与 Java、.NET、PHP、ASP 等程序集成,比较适合在 CMS、商城、论坛、博客、Wiki、电子邮件等互联网应用上使用。
2.前期准备
到官网下载最新版的KindEditor 4.1.10,解压文件后可得
文件结构:
asp:与asp结合的示例代码
asp.net:与asp.net结合的示例代码
attached:上传文件的根目录,可在相关的代码中修改
examples:功能演示的示例代码
jsp:与jsp结合的示例代码
lang:语言包
php:与php结合的示例代码
plugins:控件的功能代码的实现
kindeditor.js:配置文件
kindeditor-min.js:集成文件
由于使用的是ASP.NET,所以将不需要的文件夹删掉。其中在asp.net中demo.aspx是参考代码,也可以删掉。
3.配置KindEditor
(1)新建ASP.NET空项目,添加WebForm.aspx
3.2:将attached文件夹直接放在项目根目录下
3.1:将精简后的kindeditor文件夹(删除asp/examples/jsp/php文件夹)放到项目根目录下
3.3:新建libs文件夹,将kindeditor/asp.net/bin/LitJSON.dll文件复制到libs文件夹中,并引用(在别的电脑上,这个引用路径可能不正确,直接找到项目中libs中的LitJSON.dll再次引用即可)。
(2)新建WebForm1.aspx文件,引入相关文件
1 <link href="kindeditor/plugins/code/prettify.css" rel="stylesheet" type="text/css" /> 2 <script src="kindeditor/lang/zh_CN.js" type="text/javascript"></script> 3 <script src="kindeditor/kindeditor.js" type="text/javascript"></script> 4 <script src="kindeditor/plugins/code/prettify.js" type="text/javascript"></script> 5 <script type="text/javascript"> 6 KindEditor.ready(function (K) { 7 var editor = K.create('#content', { 8 //上传管理 9 uploadJson: 'kindeditor/asp.net/upload_json.ashx', 10 //文件管理 11 fileManagerJson: 'kindeditor/asp.net/file_manager_json.ashx', 12 allowFileManager: true, 13 //设置编辑器创建后执行的回调函数 14 afterCreate: function () { 15 var self = this; 16 K.ctrl(document, 13, function () { 17 self.sync(); 18 K('form[name=example]')[0].submit(); 19 }); 20 K.ctrl(self.edit.doc, 13, function () { 21 self.sync(); 22 K('form[name=example]')[0].submit(); 23 }); 24 }, 25 //上传文件后执行的回调函数,获取上传图片的路径 26 afterUpload : function(url) { 27 alert(url); 28 }, 29 //编辑器高度 30 width: '700px', 31 //编辑器宽度 32 height: '450px;', 33 //配置编辑器的工具栏 34 items: [ 35 'source', '|', 'undo', 'redo', '|', 'preview', 'print', 'template', 'code', 'cut', 'copy', 'paste', 36 'plainpaste', 'wordpaste', '|', 'justifyleft', 'justifycenter', 'justifyright', 37 'justifyfull', 'insertorderedlist', 'insertunorderedlist', 'indent', 'outdent', 'subscript', 38 'superscript', 'clearhtml', 'quickformat', 'selectall', '|', 'fullscreen', '/', 39 'formatblock', 'fontname', 'fontsize', '|', 'forecolor', 'hilitecolor', 'bold', 40 'italic', 'underline', 'strikethrough', 'lineheight', 'removeformat', '|', 'image', 'multiimage', 41 'flash', 'media', 'insertfile', 'table', 'hr', 'emoticons', 'baidumap', 'pagebreak', 42 'anchor', 'link', 'unlink', '|', 'about' 43 ] 44 }); 45 prettyPrint(); 46 }); 47 </script>
(3)在页面中添加一个textbox控件,将id命名为content,把属性"TextMode"属性改为Multiline
<body> <form id="form1" runat="server"> <div id="main"> <asp:TextBox id="content" name="content" TextMode="MultiLine" runat="server"></asp:TextBox> </div> </form> </body>
(4)在浏览器查看
4.附件上传原理
在asp.net文件夹下有两个重要的file_manager_json.ashx,upload_json.ashx,一个负责文件管理,一个负责上传管理。你可以根据自己需求进行相关修改。
原理:通过实现接口IHttpHandler来接管HTTP请求。
file_manager_json.ashx
1 <%@ webhandler Language="C#" class="FileManager" %> 2 3 /** 4 * KindEditor ASP.NET 5 * 6 * 本ASP.NET程序是演示程序,建议不要直接在实际项目中使用。 7 * 如果您确定直接使用本程序,使用之前请仔细确认相关安全设置。 8 * 9 */ 10 11 using System; 12 using System.Collections; 13 using System.Web; 14 using System.IO; 15 using System.Text.RegularExpressions; 16 using LitJson; 17 using System.Collections.Generic; 18 19 public class FileManager : IHttpHandler 20 { 21 public void ProcessRequest(HttpContext context) 22 { 23 String aspxUrl = context.Request.Path.Substring(0, context.Request.Path.LastIndexOf("/") + 1); 24 25 //根目录路径,相对路径 26 String rootPath = "../attached/"; 27 //根目录URL,可以指定绝对路径,比如 http://www.yoursite.com/attached/ 28 String rootUrl = aspxUrl + "../attached/"; 29 //图片扩展名 30 String fileTypes = "gif,jpg,jpeg,png,bmp"; 31 32 String currentPath = ""; 33 String currentUrl = ""; 34 String currentDirPath = ""; 35 String moveupDirPath = ""; 36 37 String dirPath = context.Server.MapPath(rootPath); 38 String dirName = context.Request.QueryString["dir"]; 39 if (!String.IsNullOrEmpty(dirName)) { 40 if (Array.IndexOf("image,flash,media,file".Split(','), dirName) == -1) { 41 context.Response.Write("Invalid Directory name."); 42 context.Response.End(); 43 } 44 dirPath += dirName + "/"; 45 rootUrl += dirName + "/"; 46 if (!Directory.Exists(dirPath)) { 47 Directory.CreateDirectory(dirPath); 48 } 49 } 50 51 //根据path参数,设置各路径和URL 52 String path = context.Request.QueryString["path"]; 53 path = String.IsNullOrEmpty(path) ? "" : path; 54 if (path == "") 55 { 56 currentPath = dirPath; 57 currentUrl = rootUrl; 58 currentDirPath = ""; 59 moveupDirPath = ""; 60 } 61 else 62 { 63 currentPath = dirPath + path; 64 currentUrl = rootUrl + path; 65 currentDirPath = path; 66 moveupDirPath = Regex.Replace(currentDirPath, @"(.*?)[^\/]+\/$", "$1"); 67 } 68 69 //排序形式,name or size or type 70 String order = context.Request.QueryString["order"]; 71 order = String.IsNullOrEmpty(order) ? "" : order.ToLower(); 72 73 //不允许使用..移动到上一级目录 74 if (Regex.IsMatch(path, @"\.\.")) 75 { 76 context.Response.Write("Access is not allowed."); 77 context.Response.End(); 78 } 79 //最后一个字符不是/ 80 if (path != "" && !path.EndsWith("/")) 81 { 82 context.Response.Write("Parameter is not valid."); 83 context.Response.End(); 84 } 85 //目录不存在或不是目录 86 if (!Directory.Exists(currentPath)) 87 { 88 context.Response.Write("Directory does not exist."); 89 context.Response.End(); 90 } 91 92 //遍历目录取得文件信息 93 string[] dirList = Directory.GetDirectories(currentPath); 94 string[] fileList = Directory.GetFiles(currentPath); 95 96 switch (order) 97 { 98 case "size": 99 Array.Sort(dirList, new NameSorter()); 100 Array.Sort(fileList, new SizeSorter()); 101 break; 102 case "type": 103 Array.Sort(dirList, new NameSorter()); 104 Array.Sort(fileList, new TypeSorter()); 105 break; 106 case "name": 107 default: 108 Array.Sort(dirList, new NameSorter()); 109 Array.Sort(fileList, new NameSorter()); 110 break; 111 } 112 113 Hashtable result = new Hashtable(); 114 result["moveup_dir_path"] = moveupDirPath; 115 result["current_dir_path"] = currentDirPath; 116 result["current_url"] = currentUrl; 117 result["total_count"] = dirList.Length + fileList.Length; 118 List<Hashtable> dirFileList = new List<Hashtable>(); 119 result["file_list"] = dirFileList; 120 for (int i = 0; i < dirList.Length; i++) 121 { 122 DirectoryInfo dir = new DirectoryInfo(dirList[i]); 123 Hashtable hash = new Hashtable(); 124 hash["is_dir"] = true; 125 hash["has_file"] = (dir.GetFileSystemInfos().Length > 0); 126 hash["filesize"] = 0; 127 hash["is_photo"] = false; 128 hash["filetype"] = ""; 129 hash["filename"] = dir.Name; 130 hash["datetime"] = dir.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss"); 131 dirFileList.Add(hash); 132 } 133 for (int i = 0; i < fileList.Length; i++) 134 { 135 FileInfo file = new FileInfo(fileList[i]); 136 Hashtable hash = new Hashtable(); 137 hash["is_dir"] = false; 138 hash["has_file"] = false; 139 hash["filesize"] = file.Length; 140 hash["is_photo"] = (Array.IndexOf(fileTypes.Split(','), file.Extension.Substring(1).ToLower()) >= 0); 141 hash["filetype"] = file.Extension.Substring(1); 142 hash["filename"] = file.Name; 143 hash["datetime"] = file.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss"); 144 dirFileList.Add(hash); 145 } 146 context.Response.AddHeader("Content-Type", "application/json; charset=UTF-8"); 147 context.Response.Write(JsonMapper.ToJson(result)); 148 context.Response.End(); 149 } 150 151 public class NameSorter : IComparer 152 { 153 public int Compare(object x, object y) 154 { 155 if (x == null && y == null) 156 { 157 return 0; 158 } 159 if (x == null) 160 { 161 return -1; 162 } 163 if (y == null) 164 { 165 return 1; 166 } 167 FileInfo xInfo = new FileInfo(x.ToString()); 168 FileInfo yInfo = new FileInfo(y.ToString()); 169 170 return xInfo.FullName.CompareTo(yInfo.FullName); 171 } 172 } 173 174 public class SizeSorter : IComparer 175 { 176 public int Compare(object x, object y) 177 { 178 if (x == null && y == null) 179 { 180 return 0; 181 } 182 if (x == null) 183 { 184 return -1; 185 } 186 if (y == null) 187 { 188 return 1; 189 } 190 FileInfo xInfo = new FileInfo(x.ToString()); 191 FileInfo yInfo = new FileInfo(y.ToString()); 192 193 return xInfo.Length.CompareTo(yInfo.Length); 194 } 195 } 196 197 public class TypeSorter : IComparer 198 { 199 public int Compare(object x, object y) 200 { 201 if (x == null && y == null) 202 { 203 return 0; 204 } 205 if (x == null) 206 { 207 return -1; 208 } 209 if (y == null) 210 { 211 return 1; 212 } 213 FileInfo xInfo = new FileInfo(x.ToString()); 214 FileInfo yInfo = new FileInfo(y.ToString()); 215 216 return xInfo.Extension.CompareTo(yInfo.Extension); 217 } 218 } 219 220 public bool IsReusable 221 { 222 get 223 { 224 return true; 225 } 226 } 227 }
upload_json.ashx
1 <%@ webhandler Language="C#" class="Upload" %> 2 3 /** 4 * KindEditor ASP.NET 5 * 6 * 本ASP.NET程序是演示程序,建议不要直接在实际项目中使用。 7 * 如果您确定直接使用本程序,使用之前请仔细确认相关安全设置。 8 * 9 */ 10 11 using System; 12 using System.Collections; 13 using System.Web; 14 using System.IO; 15 using System.Globalization; 16 using LitJson; 17 18 public class Upload : IHttpHandler 19 { 20 private HttpContext context; 21 22 public void ProcessRequest(HttpContext context) 23 { 24 String aspxUrl = context.Request.Path.Substring(0, context.Request.Path.LastIndexOf("/") + 1); 25 26 //文件保存目录路径 27 String savePath = "../attached/"; 28 29 //文件保存目录URL 30 String saveUrl = aspxUrl + "../attached/"; 31 32 //定义允许上传的文件扩展名 33 Hashtable extTable = new Hashtable(); 34 extTable.Add("image", "gif,jpg,jpeg,png,bmp"); 35 extTable.Add("flash", "swf,flv"); 36 extTable.Add("media", "swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb"); 37 extTable.Add("file", "doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2"); 38 39 //最大文件大小 40 int maxSize = 1000000; 41 this.context = context; 42 43 HttpPostedFile imgFile = context.Request.Files["imgFile"]; 44 if (imgFile == null) 45 { 46 showError("请选择文件。"); 47 } 48 49 String dirPath = context.Server.MapPath(savePath); 50 if (!Directory.Exists(dirPath)) 51 { 52 showError("上传目录不存在。"); 53 } 54 55 String dirName = context.Request.QueryString["dir"]; 56 if (String.IsNullOrEmpty(dirName)) { 57 dirName = "image"; 58 } 59 if (!extTable.ContainsKey(dirName)) { 60 showError("目录名不正确。"); 61 } 62 63 String fileName = imgFile.FileName; 64 String fileExt = Path.GetExtension(fileName).ToLower(); 65 66 if (imgFile.InputStream == null || imgFile.InputStream.Length > maxSize) 67 { 68 showError("上传文件大小超过限制。"); 69 } 70 71 if (String.IsNullOrEmpty(fileExt) || Array.IndexOf(((String)extTable[dirName]).Split(','), fileExt.Substring(1).ToLower()) == -1) 72 { 73 showError("上传文件扩展名是不允许的扩展名。\n只允许" + ((String)extTable[dirName]) + "格式。"); 74 } 75 76 //创建文件夹 77 dirPath += dirName + "/"; 78 saveUrl += dirName + "/"; 79 if (!Directory.Exists(dirPath)) { 80 Directory.CreateDirectory(dirPath); 81 } 82 String ymd = DateTime.Now.ToString("yyyyMMdd", DateTimeFormatInfo.InvariantInfo); 83 dirPath += ymd + "/"; 84 saveUrl += ymd + "/"; 85 if (!Directory.Exists(dirPath)) { 86 Directory.CreateDirectory(dirPath); 87 } 88 89 String newFileName = DateTime.Now.ToString("yyyyMMddHHmmss_ffff", DateTimeFormatInfo.InvariantInfo) + fileExt; 90 String filePath = dirPath + newFileName; 91 92 imgFile.SaveAs(filePath); 93 94 String fileUrl = saveUrl + newFileName; 95 96 Hashtable hash = new Hashtable(); 97 hash["error"] = 0; 98 hash["url"] = fileUrl; 99 context.Response.AddHeader("Content-Type", "text/html; charset=UTF-8"); 100 context.Response.Write(JsonMapper.ToJson(hash)); 101 context.Response.End(); 102 } 103 104 private void showError(string message) 105 { 106 Hashtable hash = new Hashtable(); 107 hash["error"] = 1; 108 hash["message"] = message; 109 context.Response.AddHeader("Content-Type", "text/html; charset=UTF-8"); 110 context.Response.Write(JsonMapper.ToJson(hash)); 111 context.Response.End(); 112 } 113 114 public bool IsReusable 115 { 116 get 117 { 118 return true; 119 } 120 } 121 }
5.优化改进
使用KindEditor文本编辑器时,发现不能在图片空间中修改已上传图片的信息,删除图片等,也不能进行目录操作,我觉得这是比CKEditor和CKFinder结合的文本编辑器弱势的地方。
大致想了下,有两个方法可以解决:
一是:独立写一个图片管理的模块,进行可视化操作
二是:修改plugins/filemanager/filemanager.js,并结合handler进行操作。(这个方法扩展性比较好)
如上述有什么不清晰的,可以去官网参考下!KindEditor
ASP.NET WebForm总体参考代码:
1 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="_20160306_KindEditorSetting.WebForm1" %> 2 3 <!DOCTYPE html> 4 5 <html xmlns="http://www.w3.org/1999/xhtml"> 6 <head runat="server"> 7 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 8 <title></title> 9 <link href="kindeditor/plugins/code/prettify.css" rel="stylesheet" type="text/css" /> 10 <script src="kindeditor/lang/zh_CN.js" type="text/javascript"></script> 11 <script src="kindeditor/kindeditor.js" type="text/javascript"></script> 12 <script src="kindeditor/plugins/code/prettify.js" type="text/javascript"></script> 13 <script type="text/javascript"> 14 KindEditor.ready(function (K) { 15 var editor = K.create('#content', { 16 //上传管理 17 uploadJson: 'kindeditor/asp.net/upload_json.ashx', 18 //文件管理 19 fileManagerJson: 'kindeditor/asp.net/file_manager_json.ashx', 20 allowFileManager: true, 21 //设置编辑器创建后执行的回调函数 22 afterCreate: function () { 23 var self = this; 24 K.ctrl(document, 13, function () { 25 self.sync(); 26 K('form[name=example]')[0].submit(); 27 }); 28 K.ctrl(self.edit.doc, 13, function () { 29 self.sync(); 30 K('form[name=example]')[0].submit(); 31 }); 32 }, 33 //上传文件后执行的回调函数,获取上传图片的路径 34 afterUpload: function (url) { 35 alert(url); 36 }, 37 //编辑器高度 38 width: '700px', 39 //编辑器宽度 40 height: '450px;', 41 //配置编辑器的工具栏 42 items: [ 43 'source', '|', 'undo', 'redo', '|', 'preview', 'print', 'template', 'code', 'cut', 'copy', 'paste', 44 'plainpaste', 'wordpaste', '|', 'justifyleft', 'justifycenter', 'justifyright', 45 'justifyfull', 'insertorderedlist', 'insertunorderedlist', 'indent', 'outdent', 'subscript', 46 'superscript', 'clearhtml', 'quickformat', 'selectall', '|', 'fullscreen', '/', 47 'formatblock', 'fontname', 'fontsize', '|', 'forecolor', 'hilitecolor', 'bold', 48 'italic', 'underline', 'strikethrough', 'lineheight', 'removeformat', '|', 'image', 'multiimage', 49 'flash', 'media', 'insertfile', 'table', 'hr', 'emoticons', 'baidumap', 'pagebreak', 50 'anchor', 'link', 'unlink', '|', 'about' 51 ] 52 }); 53 prettyPrint(); 54 }); 55 </script> 56 </head> 57 <body> 58 <form id="form1" runat="server"> 59 <div id="main"> 60 <asp:TextBox ID="content" name="content" TextMode="MultiLine" runat="server"></asp:TextBox> 61 </div> 62 </form> 63 </body> 64 </html>
参考源代码:链接:http://pan.baidu.com/s/1o7rXGD0 密码:kkod