ASP.NET HTML 编辑器控件






4.91/5 (66投票s)
创建一个有用的 ASP.NET HTML 编辑器自定义控件。
引言
如今,许多 Web 应用程序,如论坛和博客,都使用 HTML 编辑器作为用户发布的主要工具。基于 Web 的 HTML 编辑器是一种控件,允许在线用户创建和编辑他们的 HTML 文档,用户可以在其中编写文本并设置字体、颜色、大小和超链接,还可以插入图像、SWF 和文件。此外,用户可以查看其文档的 HTML 代码并进行编辑,并在设计模式下查看结果,反之亦然。
本文讨论如何创建具有某些安全考虑的 HTML 编辑器服务器控件。
背景
四年前,我当时在一家对开发安全产品非常谨慎的公司工作,所以我们的技术经理要求我开发一个 HTML 文本编辑器作为我们 CMS 门户中的一个模块,供我们重要的客户使用,因为安全是他们的首要任务。因此,我开发了一个考虑了 XSS 等重要安全问题的 HTML 编辑器。通常,它不如当前新版本的文本编辑器(如 FCKEditor)安全,但对我来说,这是一个很好的机会,可以为我大脑中编程一些创意 Web 软件的必要性创造一个有用、用户友好且最重要的是独特的体验。我希望这篇文章也能帮助你。
系统要求
- ASP.NET 2+
UI
组件外观
- 顶部有三排工具栏
- 用于添加表格、按钮等元素的对话框
- 一个编辑器区域,以两种模式显示和/或编辑文档
组件构成
此自定义控件分为两部分:服务器端和客户端。服务器端负责一些任务,例如使用 AntiXSS 处理安全问题、提供 HTML 编辑器的 HTML 源代码、设置安全级别、提供设置编辑器值和从编辑器获取安全值等方法、脚本注册、存储上传的文件、提供从 HTML 编辑器发送的解码数据以及为控件提供 WebResources。
客户端确保消除 HTML 编辑器源代码中一些危险内容(XSS 方面),这些内容将发送到服务器端并进行编码,将数据发送到服务器端等。
在客户端有六个 JavaScript 源文件
- RichText.js 是主要的 javascript 源代码,所有与编辑器功能相关的事情都在这里完成。
- Encoder.js 提供所有用于编码数据的方法
- Loading.js 为编辑器提供可选的加载器。(其中一部分已被注释,如果你想要加载器,请取消注释它们)
- Slider.js 为调整编辑器文本区域大小提供一个滑块
- jscolor.js 是一个我只是使用的开源 javascript
在服务器端,包含五个类
- HtmlSourceInitializer.cs:初始化编辑器 HTML
- Registrar.cs:将脚本列表注册到我们的控件中
- Security.cs:负责使用 AntiXSS 和 HtmlSanitizationLibrary 进行安全防护
- SourceActions.cs:获取从客户端发送的数据
- RichTextBox.cs:建立 HtmlEditor 控件的可访问方法和属性
EditorStyles、RichTextBoxIcons、Colorpicker 是其他部分。
HtmlSourceInitializer.cs
该组件有一些自己的 HTML 源代码,用于创建 HTML 编辑器视图。此类别使用 StringBuilder 将已添加到 _HtmlSource
中的 HTML 编辑器视图部分与 InitializeHtmlSource
方法一起追加,然后将 _HtmlSource
放入静态 RichTextHtmlSource
属性中。
internal static class HtmlSourceInitializer
{
#region fields
private static StringBuilder _HtmlSource = null;
#endregion
#region getHtmlSource
public static StringBuilder RichTextHtmlSource
{
get
{
if (_HtmlSource != null)
{
return _HtmlSource;
}
return null;
}
}
#endregion
#region Initialize html source
/// <summary>
/// Initializes the Html source of editor
/// </summary>
/// <param name="CurrentPage"></param>
public static void InitializeHtmlSource(Page CurrentPage)
{
StringBuilder HtmlSource = new StringBuilder();
HtmlSource.Append("<center id=\"centerElement\" style=\"display:none\">");
...............
Security.cs
为了防止跨站脚本攻击,我决定使用 Microsoft AntiXSS 库。正如您可以在其概述中读到的那样
"Microsoft 反跨站脚本库 V4.2 (AntiXSS V4.2) 是一个编码库,旨在帮助开发人员保护其基于 ASP.NET 的 Web 应用程序免受 XSS 攻击。它与大多数编码库不同,因为它使用白名单技术——有时也称为包含原则——来提供针对 XSS 攻击的保护。
这种方法的工作原理是首先定义一个有效或允许的字符集,并对该集之外的任何内容(无效字符或潜在攻击)进行编码。白名单方法比其他编码方案具有多个优势。"
_SetHighLevelSecurityForHtmlTags
字段已设置为 True
,这意味着从客户端发送的 HTML 文档将分两级解码,并仅更改为文本代码。例如,"<b>hello</b>" 将变为类似 ";<b>hello</b>" 的内容。这在某些情况下很有用,您希望获得更安全的 HTML 代码,检查后可以将其解码以再次获得纯 HTML 源代码。
EncodeHtml
方法使用 AntiXSS HtmlEncode
方法对创建文档的字符串 HTML 源进行编码。
方法。此外,GetSafeHtmlFragment
方法返回标签保持不变的 HTML 片段。
public static class Security
{
/// <summary>
/// if this properties is true, in this case will set two steps security over exchanged data
/// The default value of this property is true
/// </summary>
internal static bool _SetHighLevelSecurityForHtmlTags = true;
internal static string EncodeHtml(string html)
{
return AntiXss.HtmlEncode(Sanitizer.GetSafeHtmlFragment(html));
}
}
SourceActions.cs
SourceActions
类通过 SourceProvider
提供从客户端发送的 HTML 源代码。
public class SourceActions : System.Web.UI.Page
{
#region fields
internal string _SourceCode = string.Empty;
#endregion
#region Cunstructor
public SourceActions()
{
//
// TODO: Add constructor if it is requiered
//
}
#endregion Cunstructor
#region Source provider
/// <summary>
/// provide editor html source code
/// </summary>
/// <summary>
/// Sets the Current page.
/// </summary>
/// <param name="CurrentPage">The current page.</param>
/// <returns>void</returns>
internal void SourceProvider(Page CurrentPage)
{
CurrentPage.ClientScript.GetPostBackEventReference(CurrentPage, string.Empty);
if (CurrentPage.IsPostBack)
{
string eventTarget = (CurrentPage.Request["__EVENTTARGET"] == null ?
string.Empty : CurrentPage.Request["__EVENTTARGET"]);
string eventArgument = (CurrentPage.Request["__EVENTARGUMENT"] == null ?
string.Empty : CurrentPage.Request["__EVENTARGUMENT"]);
if (eventTarget == "getHtmlData")
{
if (SigmaToolBox.TextEditor.Security._SetHighLevelSecurityForHtmlTags)
{
_SourceCode = SigmaToolBox.TextEditor.Security.EncodeHtml(eventArgument);
}
else
{
_SourceCode = eventArgument;
}
}
}
}
#endregion
}
RichTextBox.cs
SetValue 方法
此方法将为编辑器设置一些值,例如 HTML 文档。例如,如果您想使用已存储在数据库或其他资源中的某些文档,您可以使用此方法将您的文档插入编辑器进行编辑。
/// <summary>
/// This function sets a value to the text editor like some text
/// or html data from database or other resources for edition activities
/// </summary>
/// <param name="Value"></param>
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public void SetValue(string Value)
{
string script = "disableElement(document.getElementById('textToolsContainer'));" +
"document.getElementById('textEditor').style.display='none';isOnSourceMode" +
"=true;isOndesignMode=false;document.getElementById('sourceTxt')." +
"style.display='block';document.getElementById('sourceTxt').value='" + Value + "'";
Page.ClientScript.RegisterStartupScript(Page.GetType(),
"valueSetterScript", script, true);
}
GetValue 方法
此函数获取在文本编辑器中提供的数据,用于某些目的,例如:在指定页面中演示、存储在数据库中等。
public string GetValue()
{
return this.Page.Server.HtmlDecode(AntiXss.HtmlAttributeEncode(GetDecodedValue()));
}
OnPreRender
必须修改为调用 RegisterStartupScript
,如下所示
protected override void OnPreRender(EventArgs e)
{
base.OnInit(e);
Registrar.RegisterScripts(new List<string> { "SigmaToolBox.js.loading.js",
"SigmaToolBox.js.testJS.js", "SigmaToolBox.js.Encoder.js",
"SigmaToolBox.js.slider.js" }, this.Page, this.GetType());
string InitializerJS = Page.ClientScript.GetWebResourceUrl(this.GetType(),
"SigmaToolBox.js.Initializer.js");
this.Page.ClientScript.RegisterStartupScript(this.GetType(),
"RichText", "<script language="\""javascript\" src='" +
InitializerJS + "'></script>");
}
RichText.js
由于 HTML 编辑器的客户端行为相当广泛,因此客户端控件中需要相当多的 JavaScript。这大部分是典型的 designMode
客户端编程。
这包括一些重要的函数,它们承担一些任务,例如
- 在编辑器上执行命令
- 元素创建
- 所有其他设计模式活动
- 创建事件处理程序
文档是使用这些 javascript 函数创建和设计的,然后如果有人想在服务器端使用它(例如:存储/解码),则应将其发送到服务器。此操作通过 sendValue()
发生。
sendValue()
函数将创建的文档发送到服务器,同时它还清除了某些存在 XSS 攻击风险的标签,如 script
、iframe
、javascript
,并在发送到服务器之前使用 Encoder.js
(通过 htmlEncode()
函数)对文档进行编码。实际上,编码过程将分两步进行,第一步在客户端,第二步在服务器端。
//Sends all elements of textEditor to the server
function sendValue(){
var innerHtmlData= usedFrame.innerHTML;
var clearData=innerHtmlData.toLowerCase().replace(/<script[^>]*?>/g,"");
var clearData = clearData.replace(/<\/script>/g, "");
clearData = clearData.replace(/javascript/g, "");
clearData = clearData.replace(/script/g, "");
clearData = clearData.replace(/<iframe[^>]*?>/g, "");
clearData = clearData.replace(/<\/iframe>/g, "");
clearData = Encoder.htmlEncode(clearData);
__doPostBack('getHtmlData', clearData);
}
这个编辑器最关键的函数,换句话说,是它的核心,是 textEdit(x,y)
函数,它负责所有关于文本编辑的问题。其背后的基本思想是使用浏览器的一个基本函数,它允许您在当前文档、当前选择或给定范围内执行命令,例如加粗、斜体、下划线、复制、删除、重新格式化等,名为 execCommand
。
execCommand 方法生成的代码在不同浏览器中是不同的。Internet Explorer 使用 HTML 标签,Firefox、Google Chrome 和 Safari 生成内联样式,Opera 有时使用 HTML 标签,有时使用样式。
例如,如果在非粗体文本上执行“粗体”命令,
•Internet Explorer 和 Opera 会在其周围生成一个 strong 元素,
•Firefox、Google Chrome 和 Safari 会在其周围生成一个 span 元素,并将该 span 元素的 fontWeight 样式属性设置为“bold”。如果非粗体文本周围存在一个元素,则 Firefox、Google Chrome 和 Safari 会将该元素的 fontWeight 样式属性设置为“bold”。
如果在粗体文本上执行“粗体”命令,浏览器会删除指定的样式属性和/或包含文本的元素。
这导致我在识别粗体、下划线和斜体文本以粗体、斜体和下划线按钮的形式显示时遇到了问题。无论如何,我为 Firefox 和 IE 解决了这个问题,但它在其他浏览器如 Chrome、Opera 和 Firefox 中仍然存在一些问题。getActiveButtons()
方法如下所示:
function getActiveButtons(){
isColorPickerInAction=isAdvanceColorPickerInAction=false;
var isBold=false;var isItalic=false;var isUnderline=false;
try{
if(document.all){
var xmlDocument=StringtoXML(getRangeNode(window.frames["textEditor"]));
var richTextElementsnodes=xmlDocument.documentElement.getElementsByTagName("nodeName");
var NodesCount=richTextElementsnodes.length;
for(var i=0;i<NodesCount;i++){
var innerNodeValue=richTextElementsnodes[i].firstChild.nodeValue;
//alert(innerNodeValue)
switch(innerNodeValue){
case "STRONG":
isBold=true;
break;
case "EM":
isItalic=true;
break;
case "U":
isUnderline=true;
break;
}
}
}
else{
var retrivedData=getRangeNode(textEditorElement.contentWindow);
for(var i=0;i<retrivedData.length;i++){
switch(removeSpaces(retrivedData[i])){
case "font-style:italic":
isItalic=true;
break;
case "text-decoration:underline":
isUnderline=true;
break;
case "font-weight:bold":
isBold=true;
break;
}
}
}
}
catch(e){
}
setActivationStatus(isBold,isItalic,isUnderline);
}
StringtoXML()
方法将输入字符串(由 getRangeNode()
方法生成)转换为 XML:
function StringtoXML(text){
var doc;
if (window.ActiveXObject){
doc=new ActiveXObject('Microsoft.XMLDOM');
doc.async='false';
doc.loadXML(text);
}
else{
parser=new DOMParser();
doc=parser.parseFromString(text,"text/xml");
}
return doc;
} </span>
getRangeNode()
方法获取选中文本的父节点及其样式,以识别选中文本的样式:
function getRangeNode(win){
var retrivedString="";
checkCursor(usedFrame);
if (window.getSelection){
node = win.getSelection().anchorNode;
var nodeStyleAttribute=node.parentNode.getAttributeNode("style").nodeValue.toString();
var nodeStyleAttributeChildes=nodeStyleAttribute.split(";");
retrivedString=nodeStyleAttributeChildes;
}
else if (win.document.selection){
var range = win.document.selection.createRange();
if (range){
node = range.parentElement();
nodesList="";
retrivedString= "<nodesList>"+getParentNodesList(node)+
"<nodeName>"+node.nodeName+
"</nodeName>"+"</nodesList>";
}
}
return retrivedString;
}
语法是:object.execCommand(cmdID, showUI, value)
。execCommand
函数的功能和兼容性在不同浏览器中有所不同,因此在此组件中,有些功能(例如“文档保存”或“背景颜色”)在除 IE 之外的其他浏览器中无法执行。正如您在下面看到的,浏览器之间存在许多不兼容性,这使我们的工作更加困难,而且似乎它将比以前得到更多改进。
方法或属性 | IE 6/7 | Firefox 2 | Safari 3 | Opera 9 |
---|---|---|---|---|
背景色 | 是 | 是 | 是 | 是 |
Moz/Saf 要求 |
||||
粗体 | 是 | 是 | 是 | 是 |
注释 | ||||
内容只读 | 否 | 是 | ? | 否 |
IE 报错 | ||||
复制 | 是 | 受保护的 | 是 | 受保护的 |
Ctrl+C 始终有效 | ||||
创建书签 | ? | ? | ? | ? |
注释 | ||||
创建链接 | 是 | 是 | 是 | 是 |
注释 | ||||
剪切 | 是 | 受保护的 | 是 | 受保护的 |
Ctrl+X 始终有效 | ||||
方法或属性 | IE 6/7 | Firefox 2 | Safari 3 | Opera 9 |
减小字号 | 否 | 是 | ? | 不正确 |
Op 只允许一次减小;第二次会将文本恢复到原始字号。 | ||||
删除 | 是 | 是 | 是 | 是 |
注释 | ||||
字体名称 | 是 | 是 | 是 | 是 |
注释 | ||||
字号 | 否 | 糟糕 | 是 | 糟糕 |
Moz/Op 生成一个(天哪!) |
||||
前景色 | 是 | 是 | 是 | 是 |
Moz/Saf 要求 # |
||||
格式块 (将选区放入标题或段落中) |
否 | 是 | 有 bug | 不完整 |
Opera 仅将选区中的第一个块级元素更改为所需的块。 | ||||
方法或属性 | IE 6/7 | Firefox 2 | Safari 3 | Opera 9 |
heading | 否 | 是 | 否 | 否 |
注释 | ||||
高亮色 | 否 | 是 | 否 | 是 |
与 IE/Saf 中的 bgcolor 作用相同:它只给选区(而不是包含块)定义好的背景颜色。 |
||||
增大字号 | 否 | 是 | ? | 不正确 |
Op 只允许一次增大;第二次会将文本恢复到原始字号。 | ||||
缩进 | 不正确 | 是 | 有 bug | 更不正确 |
Moz 每次缩进增加 40px 的左外边距。IE/Op 每次缩进增加一个(天哪!) 当应用于 |
||||
插入水平线 | 是 | 是 | 是 | 是 |
注释 | ||||
插入HTML | 否 | 是 | ? | 否 |
注释 | ||||
方法或属性 | IE 6/7 | Firefox 2 | Safari 3 | Opera 9 |
插入图片 | 是 | 是 | 是 | 是 |
IE 允许调整图像大小 | ||||
插入有序列表 | 差不多 | 是 | 差不多 | 是 |
如果新创建的有序列表与现有列表相邻,IE 和 Safari 会将两者合并。 | ||||
插入无序列表 | 差不多 | 是 | 是 | 是 |
如果新创建的无序列表与现有列表相邻,IE 会将两者合并。 | ||||
插入段落 | 是 | 替代方案 | 是 | 是 |
Mozilla 在选定的块周围添加一个段落。其他浏览器删除选定的块并插入一个空段落,用户可以填充。 | ||||
斜体 | 是 | 是 | 是 | 是 |
注释 | ||||
居中对齐 | 是 | 是 | 是 | 是 |
注释 | ||||
方法或属性 | IE 6/7 | Firefox 2 | Safari 3 | Opera 9 |
两端对齐 | 是 | 是 | 是 | 是 |
注释 | ||||
左对齐 | 是 | 是 | 是 | 是 |
注释 | ||||
右对齐 | 是 | 是 | 是 | 是 |
注释 | ||||
多选 | ? | ? | ? | ? |
注释 | ||||
取消缩进 | 是 | 是 | 有 bug | 是 |
当应用于作为单个 不幸的是,IE 在我的测试页面中有一个额外的错误:它将 |
||||
覆盖 | ? | ? | ? | ? |
注释 | ||||
粘贴 | 是 | 受保护的 | 是 | 受保护的 |
Ctrl+V 始终有效 | ||||
? | ? | ? | ? | |
注释 | ||||
重做 | 是 | 是 | 是 | 是 |
重做在 Safari 中有效,但如果撤销/重做次数过多,它会崩溃。在 3 中已解决。 如果您在可编辑区域中进行了自己的更改,Mozilla 和 Safari 中的撤消/重做将继续工作(尽管它会忽略您的自定义更改),但在 IE 和 Opera 中它会停止工作。 |
||||
方法或属性 | IE 6/7 | Firefox 2 | Safari 3 | Opera 9 |
刷新 | ? | ? | ? | ? |
注释 | ||||
移除格式 | ? | ? | ? | ? |
注释 | ||||
另存为 | ? | ? | ? | ? |
注释 | ||||
全选 | ? | ? | ? | ? |
注释 | ||||
删除线 | 是 | 是 | 是 | 是 |
注释 | ||||
使用 CSS 样式 | 否 | 是 | ? | 否 |
提供一个通用命令,指示样式应该使用 CSS(true ;默认)还是标签(false )应用。当执行 execCommand("bold") 时,前者会生成一个 <span style="font-weight: bold";> ,后者会生成一个 <b> 标签。 |
||||
下标 | 是 | 是 | 是 | 是 |
IE/Moz/Op:再次使用相同的命令会删除下标。同时使用下标和上标会产生奇怪的效果。 | ||||
上标 | 是 | 是 | 是 | 是 |
IE/Moz/Op:再次使用相同的命令会删除上标。同时使用下标和上标会产生奇怪的效果。 | ||||
方法或属性 | IE 6/7 | Firefox 2 | Safari 3 | Opera 9 |
取消书签 | ? | ? | ? | ? |
注释 | ||||
下划线 | 是 | 是 | 是 | 是 |
注释 | ||||
撤消 | 是 | 是 | 是 | 是 |
撤销在 Safari 中有效,但如果撤销/重做次数过多,它会崩溃。在 3 中已解决。 如果您在可编辑区域中进行了自己的更改,Mozilla 和 Safari 中的撤消/重做将继续工作(尽管它会忽略您的自定义更改),但在 IE 和 Opera 中它会停止工作。 |
||||
取消链接 | 是 | 是 | 是 | 是 |
注释 | ||||
方法或属性 | IE 6/7 | Firefox 2 | Safari 3 | Opera 9 |
另一个关键问题是找到光标上一次停留的位置。这将使编辑器知道当前 execCommand
应该影响哪个文本元素。此功能主要在 IE 中使用,因为 Firefox 和其他浏览器默认具有此功能。此任务由 checkCursor()
方法负责,正如您所看到的:
//checks the cursor and return the carret Position
function checkCursor(where){
try{
Current=where;
if (!isToolBoxContainerDivDisabled)
{
where.focus();
if(document.all){
CarretPosition=document.selection.createRange();
if(CarretPosition.text==""){
where.focus();
}
}
}
}
catch(error){
alert(error.name + ": " + error.message);
}
}
CreateEventForGeneratedButton()
是另一个重要的函数,它将指定的事件处理程序分配给动态创建的按钮,例如表格创建器、链接添加器等对话框中的所有按钮。
function CreateEventForGeneratedButton(ActionType){
try{
switch(ActionType){
case "Link":
(document.all)?SetCommandButton.attachEvent ("onclick",
SetLinkCommandEventHandler):SetCommandButton.addEventListener (
"click",SetLinkCommandEventHandler,false);
break;
case "Image":
(document.all)?SetCommandImageButton.attachEvent ("onclick",
SetImageCommandEventHandler):SetCommandImageButton.addEventListener (
"click",SetImageCommandEventHandler,false);
break;
case "insertTable":
(document.all)?SetCommandInsertTableButton.attachEvent ("onclick",
SetInsertTableCommandEventHandler):SetCommandInsertTableButton.addEventListener (
"click",SetInsertTableCommandEventHandler,false);
break;
case "insertButton":
(document.all)?SetCommandInsertButton_Button.attachEvent ("onclick",
SetInsertButtonCommandEventHandler): SetCommandInsertButton_Button.addEventListener (
"click",SetInsertButtonCommandEventHandler,false);
break;
case "insertSWF":
isToolBoxContainerDivDisabled=false;
(document.all)?SetSWFCommandButton.attachEvent ("onclick",
SetInsertSWFButtonCommandEventHandler): SetSWFCommandButton.addEventListener (
"click",SetInsertSWFButtonCommandEventHandler,false);
break;
case "uploadSWF":
(document.all)?SetSWFUploaderCommandButton.attachEvent ("onclick",
SetSWFUploaderButtonCommandEventHandler):
SetSWFUploaderCommandButton.addEventListener (
"click",SetSWFUploaderButtonCommandEventHandler,false);
break;
case "CancelingInsertButtton":
(document.all)?SetCommandCancelInsertingButton_Button.attachEvent (
"onclick",SetCancelingInsertButtonCommandEventHandler):
SetCommandCancelInsertingButton_Button.addEventListener (
"click",SetCancelingInsertButtonCommandEventHandler,false);
break;
}
}
catch(error){
alert(error.name + ": " + error.message);
}
}
Setposition()
方法设置创建对象的位置。当一个对象被创建时,它需要被定位在页面上。此方法根据鼠标和页面设置对象的位置。例如,当您拖动对话框栏时,它使用此方法并将 related
参数设置为“mouse”,当创建对象生成器时,它使用此函数并将“page”作为 related
参数。
//Sets the position of object maker
function SetPosition(e,elementName,Related){
try{
var ContainerElement=document.getElementById(elementName);
switch(Related){
case "Page":
if(ContainerElement!=null){
ContainerElement.style.left=(document.body.clientWidth)/2-100 +"px";
ContainerElement.style.top=(document.body.clientHeight)/2-100 +"px";
}
break;
case "Mouse":
e=e||window.event;
document.getElementById(elementName).style.display="block";
document.getElementById(elementName).style.left=e.clientX+10+"px";
document.getElementById(elementName).style.top=e.clientY +"px";
break;
}
}
catch(error){
alert(error.name + ": " + error.message);
} }
RichText.js 不是基于面向对象编程的,但我试图使其清晰易用。
使用此代码
要使用此控件,您应该将控件的 DLL 从 RichTextBox\Control_dll 文件夹添加到您的 Visual Studio 工具箱中,然后将其拖到您的 ASPX 页面上。您将看到类似以下内容:
<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="Default.aspx.cs" Inherits="testCustom._Default" %>
<%@ Register Assembly="SigmaToolBox"
Namespace="SigmaToolBox.TextEditor" TagPrefix="sigma" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body id="body1">
<%=htmlCode %>
<form id="form1" runat="server">
<div>
<sigma:RichTextBox ID="RichTextBox1" runat="server" />
</div>
<div id="div1">
<asp:Button Style="border-style: groove"
ID="Button1" runat="server" OnClientClick="sendValue()"
Text="Get Data" OnClick="Button1_Click" />
</div>
</form>
</body>
</html>
如果您想获取创建的文档,首先您应该通过 OnClientClick="sendValue()"
将其发送到服务器,然后通过在您的事件触发器控件(如按钮)上设置 OnClick
事件来获取安全数据,并编写您的代码,如下所示:
public partial class _Default : System.Web.UI.Page
{
public string htmlCode = string.Empty;
protected void Page_Load(object sender, EventArgs e)
{
//To DO
}
protected void Button1_Click(object sender, EventArgs e)
{
RichTextBox1.SetHighLevelSecurityForHtmlTags = false;
htmlCode =RichTextBox1.GetValue();
}
}
浏览器测试
本文讨论的控件已在 Firefox 5+、IE 8、Opera、Safari 和 Chrome 上进行测试。
IE 9:IE 9 中没有错误,但外观存在一些不足
- 两个多余的滚动条
- 对话框栏在表格或文本后面消失
如何用 Visual Studio 2010 或更低版本打开此项目
上次我用 Visual Studio 2012 打开此项目检查其可靠性以来,您可能在用低于 VS2012 的版本打开此项目时遇到问题。要解决此问题,请按以下步骤操作
- 用记事本之类的文本编辑器打开项目 SLN 文件。在第二行,您会看到这行:Microsoft Visual Studio Solution File, Format Version 12.00。将版本更改为 11.00 或更低
- 保存文本并用您的 VS 打开项目。享受吧!
结论
我努力让这个控件对用户友好,总而言之,我相信使用它非常简单。它并非完全没有错误,但在我开发它的所有 6 个月里,对我来说这是一次很好的经历,我希望这个源代码能让您学到一些关于创建 ASP.NET 自定义控件和基于 Web 的 HTML 编辑器的宝贵知识。
你将学到很多小知识点,比如:从 CSS 文件中将图像地址化到自定义控件项目,以及 Assemblyinfo 和 JavaScript 源代码中的许多其他内容。希望有所帮助。
历史
2012 年 11 月 5 日
- Firefox 上关于颜色选择器操作的 onclick JavaScript 错误已修复
- Chrome 和 Opera 上创建的表格外观已改进
2012 年 10 月 26 日
- 修复 Safari 浏览器问题
2009 年 11 月 23 日
- GetValue 和 SetValue 方法已添加
2009 年 4 月 10 日
新增功能
- 支持 SWF
- 支持特殊字符
- 支持预览