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

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

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

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

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

@model String

@using Nop.Web.Framework.UI;

@{
Html.AddCssFileParts("~/Content/kindeditor/themes/default/default.css");
Html.AddScriptParts("~/Content/kindeditor/kindeditor-all-min.js");
} <script>
KindEditor.ready(function (K) {
window.editor = K.create('#@ViewData.TemplateInfo.GetFullHtmlFieldId(string.Empty)', {
width: 1050,
height: 650,
uploadJson: '@Url.Action("ProcessRequest", "KindEditor", new{ a= "UPLOAD" })',
fileManagerJson: '@Url.Action("ProcessRequest", "KindEditor", new { a = "MANAGE" })',
allowFileManager: true
});
});
</script> @Html.TextArea(string.Empty, /* Name suffix */
ViewData.TemplateInfo.FormattedModelValue /* Initial value */
)

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

using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.IO.Compression;
using System.Text.RegularExpressions;
using System.Web;
using Nop.Core;
using Nop.Services.Security;
using Nop.Web.Framework.Security;
using System.Globalization;
//Copyright@Tony Han
//http://qbit.cnblogs.com/
//2016-12-3 23:33:19
//http://www.cnblogs.com/Qbit/p/NopCommerce_KindEditor.html namespace Nop.Admin.Controllers
{
//Controller for Roxy fileman (http://www.roxyfileman.com/) for TinyMCE editor
//the original file was \RoxyFileman-1.4.3-net\fileman\asp_net\main.ashx
//some custom changes by wooncherk contribution //do not validate request token (XSRF)
[AdminAntiForgery(true)]
public class KindEditorController : BaseAdminController
{
#region Fields //custom code by nopCommerce team
private readonly IPermissionService _permissionService;
private readonly HttpContextBase context;
private readonly HttpResponseBase response; #endregion #region Ctor //custom code by nopCommerce team
public KindEditorController(IPermissionService permissionService, HttpContextBase context)
{
this._permissionService = permissionService;
this.context = context;
this.response = this.context.Response;
} #endregion #region Methods public void ProcessRequest()
{
string action = "UPLOAD"; //custom code by nopCommerce team
if (!_permissionService.Authorize(StandardPermissionProvider.HtmlEditorManagePictures))
showError("You don't have required permission"); try
{
if (context.Request["a"] != null)
action = (string)context.Request["a"]; switch (action.ToUpper())
{
case "UPLOAD":
Upload(context);
break;
case "MANAGE":
Manage(context);
break;
default:
break;
} }
catch (Exception ex)
{
showError(ex.ToString());
} }
private void Manage(HttpContextBase context)
{
String aspxUrl = context.Request.Path.Substring(, context.Request.Path.LastIndexOf("/") + ); //根目录路径,相对路径
String rootPath = "/Content/attached/";
//根目录URL,可以指定绝对路径,比如 http://www.yoursite.com/attached/
String rootUrl = "/Content/attached/";
//图片扩展名
String fileTypes = "gif,jpg,jpeg,png,bmp"; String currentPath = "";
String currentUrl = "";
String currentDirPath = "";
String moveupDirPath = ""; String dirPath = context.Server.MapPath(rootPath);
String dirName = context.Request.QueryString["dir"];
if (!String.IsNullOrEmpty(dirName))
{
if (Array.IndexOf("image,flash,media,file".Split(','), dirName) == -)
{
context.Response.Write("Invalid Directory name.");
context.Response.End();
}
dirPath += dirName + "/";
rootUrl += dirName + "/";
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
}
} //根据path参数,设置各路径和URL
String path = context.Request.QueryString["path"];
path = String.IsNullOrEmpty(path) ? "" : path;
if (path == "")
{
currentPath = dirPath;
currentUrl = rootUrl;
currentDirPath = "";
moveupDirPath = "";
}
else
{
currentPath = dirPath + path;
currentUrl = rootUrl + path;
currentDirPath = path;
moveupDirPath = Regex.Replace(currentDirPath, @"(.*?)[^\/]+\/$", "$1");
} //排序形式,name or size or type
String order = context.Request.QueryString["order"];
order = String.IsNullOrEmpty(order) ? "" : order.ToLower(); //不允许使用..移动到上一级目录
if (Regex.IsMatch(path, @"\.\."))
{
context.Response.Write("Access is not allowed.");
context.Response.End();
}
//最后一个字符不是/
if (path != "" && !path.EndsWith("/"))
{
context.Response.Write("Parameter is not valid.");
context.Response.End();
}
//目录不存在或不是目录
if (!Directory.Exists(currentPath))
{
context.Response.Write("Directory does not exist.");
context.Response.End();
} //遍历目录取得文件信息
string[] dirList = Directory.GetDirectories(currentPath);
string[] fileList = Directory.GetFiles(currentPath); switch (order)
{
case "size":
Array.Sort(dirList, new NameSorter());
Array.Sort(fileList, new SizeSorter());
break;
case "type":
Array.Sort(dirList, new NameSorter());
Array.Sort(fileList, new TypeSorter());
break;
case "name":
default:
Array.Sort(dirList, new NameSorter());
Array.Sort(fileList, new NameSorter());
break;
} Hashtable result = new Hashtable();
result["moveup_dir_path"] = moveupDirPath;
result["current_dir_path"] = currentDirPath;
result["current_url"] = currentUrl;
result["total_count"] = dirList.Length + fileList.Length;
List<Hashtable> dirFileList = new List<Hashtable>();
result["file_list"] = dirFileList;
for (int i = ; i < dirList.Length; i++)
{
DirectoryInfo dir = new DirectoryInfo(dirList[i]);
Hashtable hash = new Hashtable();
hash["is_dir"] = true;
hash["has_file"] = (dir.GetFileSystemInfos().Length > );
hash["filesize"] = ;
hash["is_photo"] = false;
hash["filetype"] = "";
hash["filename"] = dir.Name;
hash["datetime"] = dir.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss");
dirFileList.Add(hash);
}
for (int i = ; i < fileList.Length; i++)
{
FileInfo file = new FileInfo(fileList[i]);
Hashtable hash = new Hashtable();
hash["is_dir"] = false;
hash["has_file"] = false;
hash["filesize"] = file.Length;
hash["is_photo"] = (Array.IndexOf(fileTypes.Split(','), file.Extension.Substring().ToLower()) >= );
hash["filetype"] = file.Extension.Substring();
hash["filename"] = file.Name;
hash["datetime"] = file.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss");
dirFileList.Add(hash);
}
context.Response.Write(Newtonsoft.Json.JsonConvert.SerializeObject(result));
context.Response.End();
} public void Upload(HttpContextBase context)
{
String aspxUrl = context.Request.Path.Substring(, context.Request.Path.LastIndexOf("/") + ); //文件保存目录路径
String savePath = "/Content/attached/"; //文件保存目录URL
String saveUrl = "/Content/attached/"; //定义允许上传的文件扩展名
Hashtable extTable = new Hashtable();
extTable.Add("image", "gif,jpg,jpeg,png,bmp");
extTable.Add("flash", "swf,flv");
extTable.Add("media", "swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb");
extTable.Add("file", "doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2"); //最大文件大小
int maxSize = ; var imgFile = context.Request.Files["imgFile"];
if (imgFile == null)
{
showError("请选择文件。");
} String dirPath = context.Server.MapPath(savePath);
if (!Directory.Exists(dirPath))
{
showError("上传目录不存在。");
} String dirName = context.Request.QueryString["dir"];
if (String.IsNullOrEmpty(dirName))
{
dirName = "image";
}
if (!extTable.ContainsKey(dirName))
{
showError("目录名不正确。");
} String fileName = imgFile.FileName;
String fileExt = Path.GetExtension(fileName).ToLower(); if (imgFile.InputStream == null || imgFile.InputStream.Length > maxSize)
{
showError("上传文件大小超过限制。");
} if (String.IsNullOrEmpty(fileExt) || Array.IndexOf(((String)extTable[dirName]).Split(','), fileExt.Substring().ToLower()) == -)
{
showError("上传文件扩展名是不允许的扩展名。\n只允许" + ((String)extTable[dirName]) + "格式。");
} //创建文件夹
dirPath += dirName + "/";
saveUrl += dirName + "/";
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
}
String ymd = DateTime.Now.ToString("yyyyMMdd", DateTimeFormatInfo.InvariantInfo);
dirPath += ymd + "/";
saveUrl += ymd + "/";
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
} String newFileName = DateTime.Now.ToString("yyyyMMddHHmmss_ffff", DateTimeFormatInfo.InvariantInfo) + fileExt;
String filePath = dirPath + newFileName; imgFile.SaveAs(filePath); String fileUrl = saveUrl + newFileName; Hashtable hash = new Hashtable();
hash["error"] = ;
hash["url"] = fileUrl;
context.Response.Write(Newtonsoft.Json.JsonConvert.SerializeObject(hash));
context.Response.End();
} #endregion #region Utitlies
private void showError(string message)
{
Hashtable hash = new Hashtable();
hash["error"] = ;
hash["message"] = message;
context.Response.Write(Newtonsoft.Json.JsonConvert.SerializeObject(hash));
context.Response.End();
} #region KindEditorClass
public class NameSorter : IComparer
{
public int Compare(object x, object y)
{
if (x == null && y == null)
{
return ;
}
if (x == null)
{
return -;
}
if (y == null)
{
return ;
}
FileInfo xInfo = new FileInfo(x.ToString());
FileInfo yInfo = new FileInfo(y.ToString()); return xInfo.FullName.CompareTo(yInfo.FullName);
}
} public class SizeSorter : IComparer
{
public int Compare(object x, object y)
{
if (x == null && y == null)
{
return ;
}
if (x == null)
{
return -;
}
if (y == null)
{
return ;
}
FileInfo xInfo = new FileInfo(x.ToString());
FileInfo yInfo = new FileInfo(y.ToString()); return xInfo.Length.CompareTo(yInfo.Length);
}
} public class TypeSorter : IComparer
{
public int Compare(object x, object y)
{
if (x == null && y == null)
{
return ;
}
if (x == null)
{
return -;
}
if (y == null)
{
return ;
}
FileInfo xInfo = new FileInfo(x.ToString());
FileInfo yInfo = new FileInfo(y.ToString()); return xInfo.Extension.CompareTo(yInfo.Extension);
}
}
#endregion
#endregion }
}

测试效果:

原文地址: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. 将一个mapList转换为beanList

    public static <T> List<T> copyMapToBean(   List<Map<String, Object>> resultM ...

  2. surging+EFCore 服务实现入门

    准备工作 本篇文章基于上篇基础上进行的,请先了解此篇  surging+CentOS7+docker+rancher2.0 菜鸟部署运行笔记 开发环境  Visual Studio 2017 15.5 ...

  3. Flask从入门到做出一个博客的大型教程(一)

    本项目全部在虚拟环境中运行,因此请参照前面的文章,链接为https://blog.csdn.net/u014793102/article/details/80302975 建立虚拟环境后,再接着完成本 ...

  4. Boost Python学习笔记(二)

    你将学到什么 如何在Python中调用C++代码 如何在C++中调用Python代码 在Python中调用C++代码 首先定义一个动物类(include/animal.h) #pragma once ...

  5. Codeforces - 1181B - Split a Number - 贪心

    https://codeforces.com/contest/1181/problem/B 从中间拆开然后用大数搞一波. 当时没想清楚奇偶是怎么弄,其实都可以,奇数长度字符串的中心就在len/2,偶数 ...

  6. C#之数据类型转换

    前言    在C#中学习中,像在VB学习的时候一样,我们会接触到很多种数据类型,但是VB中在用数据类型的时候,我们会考虑这个数据要求多大的内存,或者说有时候为了满足很少的大内存事件,而狠心分配给它较大 ...

  7. 清北刷题冲刺 10-30 p.m

    少女 #include<iostream> #include<cstdio> #include<queue> #include<cstdlib> #de ...

  8. Macbook sublime 安装markdown插件

    Sublime Text为3 版本 安装sublime text 插件,需要“***”,不会弄的,就可以移步了. 首先按 command + shift + p 调出安装插件的界面,输入“instal ...

  9. JavaScript和jquery中的宽度

    Javascript: 网页可见区域宽: document.body.clientWidth 网页可见区域高: document.body.clientHeight 网页可见区域宽: document ...

  10. 使用navicat把一个数据库的表导入到另外一个数据库

    第一步:右击数据库名,选择数据传输 第二步:全选要导的数据库表 第三步:选择目标中的数据库,然后开始就可以了