NopCommerce 自带的编辑器tinymce 功能不是很全。所以尝试将其替换为功能更强大的 KindEditor 并替实现文件上传和在线浏览功能

首先下载 并解压到如下位置

请注意这里是部署在Nop.Web站点下,前后台分离部署的情况请另作调整

部署时记得删除Kindedtor/asp.net/文件夹

修改富文本编辑器模板:Presentation/Nop.Web/Administration/Views/Shared/EditorTemplates/RichEditor.cshtml

  1. @model String
  2.  
  3. @using Nop.Web.Framework.UI;
  4.  
  5. @{
  6. Html.AddCssFileParts("~/Content/kindeditor/themes/default/default.css");
  7. Html.AddScriptParts("~/Content/kindeditor/kindeditor-all-min.js");
  8. }
  9.  
  10. <script>
  11. KindEditor.ready(function (K) {
  12. window.editor = K.create('#@ViewData.TemplateInfo.GetFullHtmlFieldId(string.Empty)', {
  13. width: 1050,
  14. height: 650,
  15. uploadJson: '@Url.Action("ProcessRequest", "KindEditor", new{ a= "UPLOAD" })',
  16. fileManagerJson: '@Url.Action("ProcessRequest", "KindEditor", new { a = "MANAGE" })',
  17. allowFileManager: true
  18. });
  19. });
  20. </script>
  21.  
  22. @Html.TextArea(string.Empty, /* Name suffix */
  23. ViewData.TemplateInfo.FormattedModelValue /* Initial value */
  24. )

添加文件上传控制器 KindEditorController.cs

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Drawing;
  5. using System.Drawing.Imaging;
  6. using System.IO;
  7. using System.IO.Compression;
  8. using System.Text.RegularExpressions;
  9. using System.Web;
  10. using Nop.Core;
  11. using Nop.Services.Security;
  12. using Nop.Web.Framework.Security;
  13. using System.Globalization;
  14. //Copyright@Tony Han
    //http://qbit.cnblogs.com/
    //2016-12-3 23:33:19
    //http://www.cnblogs.com/Qbit/p/NopCommerce_KindEditor.html
  15.  
  16. namespace Nop.Admin.Controllers
  17. {
  18. //Controller for Roxy fileman (http://www.roxyfileman.com/) for TinyMCE editor
  19. //the original file was \RoxyFileman-1.4.3-net\fileman\asp_net\main.ashx
  20. //some custom changes by wooncherk contribution
  21.  
  22. //do not validate request token (XSRF)
  23. [AdminAntiForgery(true)]
  24. public class KindEditorController : BaseAdminController
  25. {
  26. #region Fields
  27.  
  28. //custom code by nopCommerce team
  29. private readonly IPermissionService _permissionService;
  30. private readonly HttpContextBase context;
  31. private readonly HttpResponseBase response;
  32.  
  33. #endregion
  34.  
  35. #region Ctor
  36.  
  37. //custom code by nopCommerce team
  38. public KindEditorController(IPermissionService permissionService, HttpContextBase context)
  39. {
  40. this._permissionService = permissionService;
  41. this.context = context;
  42. this.response = this.context.Response;
  43. }
  44.  
  45. #endregion
  46.  
  47. #region Methods
  48.  
  49. public void ProcessRequest()
  50. {
  51. string action = "UPLOAD";
  52.  
  53. //custom code by nopCommerce team
  54. if (!_permissionService.Authorize(StandardPermissionProvider.HtmlEditorManagePictures))
  55. showError("You don't have required permission");
  56.  
  57. try
  58. {
  59. if (context.Request["a"] != null)
  60. action = (string)context.Request["a"];
  61.  
  62. switch (action.ToUpper())
  63. {
  64. case "UPLOAD":
  65. Upload(context);
  66. break;
  67. case "MANAGE":
  68. Manage(context);
  69. break;
  70. default:
  71. break;
  72. }
  73.  
  74. }
  75. catch (Exception ex)
  76. {
  77. showError(ex.ToString());
  78. }
  79.  
  80. }
  81. private void Manage(HttpContextBase context)
  82. {
  83. String aspxUrl = context.Request.Path.Substring(, context.Request.Path.LastIndexOf("/") + );
  84.  
  85. //根目录路径,相对路径
  86. String rootPath = "/Content/attached/";
  87. //根目录URL,可以指定绝对路径,比如 http://www.yoursite.com/attached/
  88. String rootUrl = "/Content/attached/";
  89. //图片扩展名
  90. String fileTypes = "gif,jpg,jpeg,png,bmp";
  91.  
  92. String currentPath = "";
  93. String currentUrl = "";
  94. String currentDirPath = "";
  95. String moveupDirPath = "";
  96.  
  97. String dirPath = context.Server.MapPath(rootPath);
  98. String dirName = context.Request.QueryString["dir"];
  99. if (!String.IsNullOrEmpty(dirName))
  100. {
  101. if (Array.IndexOf("image,flash,media,file".Split(','), dirName) == -)
  102. {
  103. context.Response.Write("Invalid Directory name.");
  104. context.Response.End();
  105. }
  106. dirPath += dirName + "/";
  107. rootUrl += dirName + "/";
  108. if (!Directory.Exists(dirPath))
  109. {
  110. Directory.CreateDirectory(dirPath);
  111. }
  112. }
  113.  
  114. //根据path参数,设置各路径和URL
  115. String path = context.Request.QueryString["path"];
  116. path = String.IsNullOrEmpty(path) ? "" : path;
  117. if (path == "")
  118. {
  119. currentPath = dirPath;
  120. currentUrl = rootUrl;
  121. currentDirPath = "";
  122. moveupDirPath = "";
  123. }
  124. else
  125. {
  126. currentPath = dirPath + path;
  127. currentUrl = rootUrl + path;
  128. currentDirPath = path;
  129. moveupDirPath = Regex.Replace(currentDirPath, @"(.*?)[^\/]+\/$", "$1");
  130. }
  131.  
  132. //排序形式,name or size or type
  133. String order = context.Request.QueryString["order"];
  134. order = String.IsNullOrEmpty(order) ? "" : order.ToLower();
  135.  
  136. //不允许使用..移动到上一级目录
  137. if (Regex.IsMatch(path, @"\.\."))
  138. {
  139. context.Response.Write("Access is not allowed.");
  140. context.Response.End();
  141. }
  142. //最后一个字符不是/
  143. if (path != "" && !path.EndsWith("/"))
  144. {
  145. context.Response.Write("Parameter is not valid.");
  146. context.Response.End();
  147. }
  148. //目录不存在或不是目录
  149. if (!Directory.Exists(currentPath))
  150. {
  151. context.Response.Write("Directory does not exist.");
  152. context.Response.End();
  153. }
  154.  
  155. //遍历目录取得文件信息
  156. string[] dirList = Directory.GetDirectories(currentPath);
  157. string[] fileList = Directory.GetFiles(currentPath);
  158.  
  159. switch (order)
  160. {
  161. case "size":
  162. Array.Sort(dirList, new NameSorter());
  163. Array.Sort(fileList, new SizeSorter());
  164. break;
  165. case "type":
  166. Array.Sort(dirList, new NameSorter());
  167. Array.Sort(fileList, new TypeSorter());
  168. break;
  169. case "name":
  170. default:
  171. Array.Sort(dirList, new NameSorter());
  172. Array.Sort(fileList, new NameSorter());
  173. break;
  174. }
  175.  
  176. Hashtable result = new Hashtable();
  177. result["moveup_dir_path"] = moveupDirPath;
  178. result["current_dir_path"] = currentDirPath;
  179. result["current_url"] = currentUrl;
  180. result["total_count"] = dirList.Length + fileList.Length;
  181. List<Hashtable> dirFileList = new List<Hashtable>();
  182. result["file_list"] = dirFileList;
  183. for (int i = ; i < dirList.Length; i++)
  184. {
  185. DirectoryInfo dir = new DirectoryInfo(dirList[i]);
  186. Hashtable hash = new Hashtable();
  187. hash["is_dir"] = true;
  188. hash["has_file"] = (dir.GetFileSystemInfos().Length > );
  189. hash["filesize"] = ;
  190. hash["is_photo"] = false;
  191. hash["filetype"] = "";
  192. hash["filename"] = dir.Name;
  193. hash["datetime"] = dir.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss");
  194. dirFileList.Add(hash);
  195. }
  196. for (int i = ; i < fileList.Length; i++)
  197. {
  198. FileInfo file = new FileInfo(fileList[i]);
  199. Hashtable hash = new Hashtable();
  200. hash["is_dir"] = false;
  201. hash["has_file"] = false;
  202. hash["filesize"] = file.Length;
  203. hash["is_photo"] = (Array.IndexOf(fileTypes.Split(','), file.Extension.Substring().ToLower()) >= );
  204. hash["filetype"] = file.Extension.Substring();
  205. hash["filename"] = file.Name;
  206. hash["datetime"] = file.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss");
  207. dirFileList.Add(hash);
  208. }
  209. context.Response.Write(Newtonsoft.Json.JsonConvert.SerializeObject(result));
  210. context.Response.End();
  211. }
  212.  
  213. public void Upload(HttpContextBase context)
  214. {
  215. String aspxUrl = context.Request.Path.Substring(, context.Request.Path.LastIndexOf("/") + );
  216.  
  217. //文件保存目录路径
  218. String savePath = "/Content/attached/";
  219.  
  220. //文件保存目录URL
  221. String saveUrl = "/Content/attached/";
  222.  
  223. //定义允许上传的文件扩展名
  224. Hashtable extTable = new Hashtable();
  225. extTable.Add("image", "gif,jpg,jpeg,png,bmp");
  226. extTable.Add("flash", "swf,flv");
  227. extTable.Add("media", "swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb");
  228. extTable.Add("file", "doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2");
  229.  
  230. //最大文件大小
  231. int maxSize = ;
  232.  
  233. var imgFile = context.Request.Files["imgFile"];
  234. if (imgFile == null)
  235. {
  236. showError("请选择文件。");
  237. }
  238.  
  239. String dirPath = context.Server.MapPath(savePath);
  240. if (!Directory.Exists(dirPath))
  241. {
  242. showError("上传目录不存在。");
  243. }
  244.  
  245. String dirName = context.Request.QueryString["dir"];
  246. if (String.IsNullOrEmpty(dirName))
  247. {
  248. dirName = "image";
  249. }
  250. if (!extTable.ContainsKey(dirName))
  251. {
  252. showError("目录名不正确。");
  253. }
  254.  
  255. String fileName = imgFile.FileName;
  256. String fileExt = Path.GetExtension(fileName).ToLower();
  257.  
  258. if (imgFile.InputStream == null || imgFile.InputStream.Length > maxSize)
  259. {
  260. showError("上传文件大小超过限制。");
  261. }
  262.  
  263. if (String.IsNullOrEmpty(fileExt) || Array.IndexOf(((String)extTable[dirName]).Split(','), fileExt.Substring().ToLower()) == -)
  264. {
  265. showError("上传文件扩展名是不允许的扩展名。\n只允许" + ((String)extTable[dirName]) + "格式。");
  266. }
  267.  
  268. //创建文件夹
  269. dirPath += dirName + "/";
  270. saveUrl += dirName + "/";
  271. if (!Directory.Exists(dirPath))
  272. {
  273. Directory.CreateDirectory(dirPath);
  274. }
  275. String ymd = DateTime.Now.ToString("yyyyMMdd", DateTimeFormatInfo.InvariantInfo);
  276. dirPath += ymd + "/";
  277. saveUrl += ymd + "/";
  278. if (!Directory.Exists(dirPath))
  279. {
  280. Directory.CreateDirectory(dirPath);
  281. }
  282.  
  283. String newFileName = DateTime.Now.ToString("yyyyMMddHHmmss_ffff", DateTimeFormatInfo.InvariantInfo) + fileExt;
  284. String filePath = dirPath + newFileName;
  285.  
  286. imgFile.SaveAs(filePath);
  287.  
  288. String fileUrl = saveUrl + newFileName;
  289.  
  290. Hashtable hash = new Hashtable();
  291. hash["error"] = ;
  292. hash["url"] = fileUrl;
  293. context.Response.Write(Newtonsoft.Json.JsonConvert.SerializeObject(hash));
  294. context.Response.End();
  295. }
  296.  
  297. #endregion
  298.  
  299. #region Utitlies
  300. private void showError(string message)
  301. {
  302. Hashtable hash = new Hashtable();
  303. hash["error"] = ;
  304. hash["message"] = message;
  305. context.Response.Write(Newtonsoft.Json.JsonConvert.SerializeObject(hash));
  306. context.Response.End();
  307. }
  308.  
  309. #region KindEditorClass
  310. public class NameSorter : IComparer
  311. {
  312. public int Compare(object x, object y)
  313. {
  314. if (x == null && y == null)
  315. {
  316. return ;
  317. }
  318. if (x == null)
  319. {
  320. return -;
  321. }
  322. if (y == null)
  323. {
  324. return ;
  325. }
  326. FileInfo xInfo = new FileInfo(x.ToString());
  327. FileInfo yInfo = new FileInfo(y.ToString());
  328.  
  329. return xInfo.FullName.CompareTo(yInfo.FullName);
  330. }
  331. }
  332.  
  333. public class SizeSorter : IComparer
  334. {
  335. public int Compare(object x, object y)
  336. {
  337. if (x == null && y == null)
  338. {
  339. return ;
  340. }
  341. if (x == null)
  342. {
  343. return -;
  344. }
  345. if (y == null)
  346. {
  347. return ;
  348. }
  349. FileInfo xInfo = new FileInfo(x.ToString());
  350. FileInfo yInfo = new FileInfo(y.ToString());
  351.  
  352. return xInfo.Length.CompareTo(yInfo.Length);
  353. }
  354. }
  355.  
  356. public class TypeSorter : IComparer
  357. {
  358. public int Compare(object x, object y)
  359. {
  360. if (x == null && y == null)
  361. {
  362. return ;
  363. }
  364. if (x == null)
  365. {
  366. return -;
  367. }
  368. if (y == null)
  369. {
  370. return ;
  371. }
  372. FileInfo xInfo = new FileInfo(x.ToString());
  373. FileInfo yInfo = new FileInfo(y.ToString());
  374.  
  375. return xInfo.Extension.CompareTo(yInfo.Extension);
  376. }
  377. }
  378. #endregion
  379. #endregion
  380.  
  381. }
  382. }

测试效果:

原文地址:http://www.cnblogs.com/Qbit/p/NopCommerce_KindEditor.html

NopCommerce 3.80框架研究(三)替换tinymce 为KindEditor的更多相关文章

  1. NopCommerce 3.80框架研究(一) 数据访问与持久化

    NopCommerce 是一个国外的开源电商系统.3.80版本使用EF6.0 和.Net Framework 4.5.1 并引入了Autofac , Autofac是一款IOC框架,比较于其他的IOC ...

  2. NopCommerce 3.80框架研究(二) MVC 表示层与数据验证

    表示层框架结构 /Views/Shared/_Root.Head.cshtml /Views/Shared/_Root.cshtml /Views/Shared/_ColumnsOne.cshtml ...

  3. Prism框架研究(三)

    这一篇主要用来介绍一下基于Prism Library中的核心服务以及如何配置Container,还有一个重要的部分是如何管理各个组件之间的依赖性,下面就这些内容来做一一的介绍. 1 Prism中的核心 ...

  4. ASP.NET Web API 框架研究 ASP.NET Web API 路由

    ASP.NET Web API 核心框架是一个独立的.抽象的消息处理管道,ASP.NET Web API有自己独立的路由系统,是消息处理管道的组成部分,其与ASP.NET路由系统有类似的设计,都能找到 ...

  5. Jquery如何序列化form表单数据为JSON对象 C# ADO.NET中设置Like模糊查询的参数 从客户端出现小于等于公式符号引发检测到有潜在危险的Request.Form 值 jquery调用iframe里面的方法 Js根据Ip地址自动判断是哪个城市 【我们一起写框架】MVVM的WPF框架(三)—数据控件 设计模式之简单工厂模式(C#语言描述)

    jquery提供的serialize方法能够实现. $("#searchForm").serialize();但是,观察输出的信息,发现serialize()方法做的是将表单中的数 ...

  6. JavaScript框架设计(三) push兼容性和选择器上下文

    JavaScript框架设计(三) push兼容性和选择器上下文 博主很久没有更博了. 在上一篇 JavaScript框架设计(二) 中实现了最基本的选择器,getId,getTag和getClass ...

  7. 【原创】NIO框架入门(三):iOS与MINA2、Netty4的跨平台UDP双向通信实战

    前言 本文将演示一个iOS客户端程序,通过UDP协议与两个典型的NIO框架服务端,实现跨平台双向通信的完整Demo.服务端将分别用MINA2和Netty4进行实现,而通信时服务端你只需选其一就行了.同 ...

  8. Flask框架(三)—— 请求扩展、中间件、蓝图、session源码分析

    Flask框架(三)—— 请求扩展.中间件.蓝图.session源码分析 目录 请求扩展.中间件.蓝图.session源码分析 一.请求扩展 1.before_request 2.after_requ ...

  9. Pytest测试框架(三):pytest fixture 用法

    xUnit style 结构的 fixture用于初始化测试函数, pytest fixture是对传统的 xUnit 架构的setup/teardown功能的改进.pytest fixture为测试 ...

随机推荐

  1. C++基础之函数和作用域

    (1)函数的定义格式如下所示.<类型><函数名>(<形参表>) {<若干条语句>}其中,<类型>包含存储类和数据类型.存储类省略为外部函数, ...

  2. cf837D(01背包)

    题目链接: http://codeforces.com/contest/837/problem/D 题意: 给出 n 个数, 从中选出 k 个数使得这 k 个数的乘积末尾 0 最多 . 思路: 先记录 ...

  3. 清北刷题冲刺 10-28 a.m

    立方数 (cubic) Time Limit:1000ms   Memory Limit:128MB 题目描述 LYK定义了一个数叫“立方数”,若一个数可以被写作是一个正整数的3次方,则这个数就是立方 ...

  4. Redis数据类型,持久化,回收策略——(Redis缓存第一章)

    缓存:第一种是内存缓存 比如Map(简单的数据结构),以及EH Cache(Java第三方库),第二种是缓存组件比如Memached,Redis:Redis(remote dictionary ser ...

  5. 我的省选 Day -9

    Day -9 不知不觉,日子已经变成一位数了,已经到了最后关头了. 早上班主任在上数学课时告诉我们,高校自招的降分政策已经没有以前那么优惠了(这我知道啊) 于是老师间接的暗示了奥赛如果没拿到省一就没什 ...

  6. css奇技淫巧—border-radius

    官方介绍: 浏览器支持:IE9+, Firefox 4+, Chrome, Safari 5+,和Opera支持border-radius属性. border-radius 属性是一个最多可指定四个 ...

  7. Migration-添加表(加外键)

    public partial class _222 : DbMigration { public override void Up() { //DropForeignKey("dbo.Ass ...

  8. Flask&&人工智能AI --1

    Flask初识,Response三剑客,jsonify以及send_file.Request,模板语言 Jinja2,用户登录例子,内置Sessio 一.Flask初识 首先,要看你学没学过Djang ...

  9. Java中常用的数据源

    几种常用的Java数据源解决方案 Java中的数据源就是javax.sql.DataSource.DataSource的创建可以有不同的实现. JNDI方式创建DataSource 以JNDI方式创建 ...

  10. jdbc取出表名 名称

    package com.dataconnect.test.util; import java.sql.Connection; import java.sql.DatabaseMetaData; imp ...