How to Create an HTML Editor for ASP.NET AJAX
Prize winner in Competition "Best ASP.NET article of May 2008"
- Download source for Visual Studio 2008 and ASP.NET 3.5 - 157.51 KB
- Download source for Visual Studio 2005 and ASP.NET 2.0 - 157.24 KB
Introduction
Most blog, forum, and Wiki applications use an HTML editor as the primary authoring tool for site content. With this type of a control, an online user can create and edit an HTML document. The user is able to modify the text — including its format, fonts, and colors — as well as add links and images. Often, the user can also view and/or edit the HTML source.
Microsoft AJAX (ASP.NET AJAX Extensions) introduces a new implementation model for server controls with related scripts. This article discusses how to create an HTML editor server control specifically for the Microsoft AJAX environment. The reader can also download the source code, including a sample web page, and view an online demo.
Background
DesignMode
Most modern browsers now support the "editing" of displayed HTML content by the user. When the document designMode property is set to true, the rendered HTML on the page can be edited by the user. While in designMode, the document's execCommand method supports additional commands that enable "programmatic" modification of document content. For example, passing the command string bold as the first parameter to execCommand causes the selected text to appear bold by adding appropriate HTML tags and/or attributes.
The resources listed at the end of this article discuss designMode and execCommand in more detail, and describe how to implement a basic HTML editor. Also, the source code available with this article can be examined for implementation examples.
Microsoft AJAX Model for Server Controls with Related Scripts
As part of ASP.NET AJAX, Microsoft introduced a new "model" for extending the capabilities of a server control with client-side script. That model is described in an ASP.NET AJAX tutorial that should be read along with this article. In general, we create two related controls:
- A server control that implements the
IScriptControlinterface - A related client control derived from
Sys.UI.Control(part of the client-side AJAX library)
In order for ScriptManager to know how to create and initialize the related client control, we implement the new IScriptControl interface, adding two callback methods. Then, we add a few lines of code to OnPreRender and Render to trigger those callbacks at appropriate times in the page life cycle. The specifics are described in the tutorial, and again in the discussion of HtmlEditor.cs below.
We also encapsulate our client-side behavior in a JavaScript class, implemented as a Microsoft AJAX client control. This permits the client control object to be created and initialized in a standard way by the client-side AJAX code. The specifics are described in the tutorial, and again in the discussion of HtmlEditor.js below.
Source Code
Click the appropriate link to download the source code, including a sample web page.
System Requirements
- ASP.NET 2.0 or higher
- ASP.NET AJAX
Component Parts
- HtmlEditor.cs (the C# file for our server control)
- HtmlEditor.js (the JavaScript file for our client control)
- Images/*.gif (image files for our toolbar images)
UI Elements
Component appearance:
- Two toolbar rows across the top
- Two tabs along the bottom
- An editor area that displays and/or edits the document in either mode

Click here for an online demo.
Overview
HTML Schema
-
Divcontainer for the control-
Divcontainer for eachToolbar-
Selectelements for dropdown lists -
Imgelements for buttons
-
-
Divcontainer for the Design editor-
IFrameelement for the Design mode document
-
-
Divcontainer for the HTML editor-
IFrameelement for the HTML mode document-
Textareafor HTML mode editing
-
-
-
Divcontainer for theTabbar-
Divelement for each tab-
Imgelement for the tab icon -
Spanelement for the tab text
-
-
-
Server Control
- Creates child controls for each HTML element required
- Provides
publicproperty methods for configuration properties (colors, etc.) - Implements property methods for properties passed to the client control on initialization
- Implements default property values
- Implements
IScriptControlmethods
Client Control
- Provides
getandsetproperty methods for properties passed from the server control on initialization - Dynamically creates the
IFramedocuments - Sets
designModetotruefor the Design mode document - Provides appropriate handlers for
ToolbarandTabbarmouse events - Converts to and from XHTML when appropriate
- Converts deprecated syntax inserted by the
designModebrowser to a standards-based equivalent - Filters tags and attributes to those allowed
- Removes/restores extraneous default tags inserted by
designModebrowsers
HtmlEditor.cs
The component itself contains many different HTML elements, so the server control class is derived from CompositeControl. In addition, the class must implement the IScriptControl methods:
public class HtmlEditor : CompositeControl, IScriptControl
In CompositeControl, child controls are added in the CreateChildControls method:
protected override void CreateChildControls()
{
...
CreateToolbars(...);
this.Controls.Add(CreateHtmlArea());
this.Controls.Add(CreateDesignArea());
this.Controls.Add(CreateTabbar());
this.Controls.Add(CreateUpdateArea());
base.CreateChildControls();
}
To implement the IScriptControl interface, two callback methods are required. The first, GetScriptReferences, tells ScriptManager what related script file(s) to load and from where. For this server control, we have chosen to embed the HtmlEditor.js file in our assembly resources. We tell ScriptManager the full resource path and assembly name so that it can load it from there, simplifying deployment:
protected virtual IEnumerable<ScriptReference>
GetScriptReferences()
{
ScriptReference htmlEditorReference =
new ScriptReference(
"Winthusiasm.HtmlEditor.Scripts.HtmlEditor.js",
"Winthusiasm.HtmlEditor");
...
return new ScriptReference[] { htmlEditorReference, ... };
}
The second callback method, GetScriptDescriptors, "maps" properties in the client control(s) to properties in the server control. ScriptManager uses this information to set the appropriate values in the client control as part of its client-side creation:
protected virtual IEnumerable<ScriptDescriptor>
GetScriptDescriptors()
{
ScriptControlDescriptor descriptor =
new ScriptControlDescriptor("Winthusiasm.HtmlEditor",
this.ClientID);
descriptor.AddProperty("htmlencodedTextID",
this.HtmlEncodedTextID);
...
return new ScriptDescriptor[] { descriptor };
}
Although we have now implemented the IScriptControl methods, there are two remaining modifications to make so that the IScriptControl callbacks get called. First, OnPreRender must be modified to call RegisterScriptControl, as follows:
protected override void OnPreRender(EventArgs e)
{
...
if (!this.DesignMode)
{
// Test for ScriptManager and register if it exists.
sm = ScriptManager.GetCurrent(Page);
if (sm == null)
throw new HttpException(
"A ScriptManager control must exist on the page.");
sm.RegisterScriptControl(this);
...
}
base.OnPreRender(e);
}
Then, Render must be modified to call RegisterScriptDescriptors:
protected override void Render(HtmlTextWriter writer)
{
if (!this.DesignMode)
sm.RegisterScriptDescriptors(this);
base.Render(writer);
}
HtmlEditor.js
Because the client-side behaviors for an HTML editor are fairly extensive, there is a fairly extensive amount of JavaScript required in the client control. Most of this is typical designMode client-side programming. More from the point of this article, the entire JavaScript code structure has been formatted to follow the client-side coding model recommended by Microsoft for all client controls built upon the AJAX client-side libraries. This includes:
- Namespace registration
- Constructor
- Prototype block with all methods comma-separated
- Prototype
getandsetmethods for each property passed from the server control - Prototype
initializemethod - Prototype
disposemethod -
Descriptormethod - Class registration
Namespace registration:
Type.registerNamespace("Winthusiasm");
Constructor:
Winthusiasm.HtmlEditor = function(element)
{
Winthusiasm.HtmlEditor.initializeBase(this, [element]);
this._htmlencodedTextID = "";
...
}
Prototype block with methods comma-separated:
Winthusiasm.HtmlEditor.prototype =
{
method1: function()
{
...
},
method2: function()
{
...
},
...
}
Prototype get and set methods for each property passed from the server control:
get_htmlencodedTextID: function()
{
return this._htmlencodedTextID;
},
set_htmlencodedTextID: function(value)
{
this._htmlencodedTextID = value;
},
...
Prototype initialize method:
initialize: function()
{
Winthusiasm.HtmlEditor.callBaseMethod(this, 'initialize');
...
},
Prototype dispose method:
dispose: function()
{
...
Winthusiasm.HtmlEditor.callBaseMethod(this, 'dispose');
},
Descriptor method:
Winthusiasm.HtmlEditor.descriptor =
{
properties: [ {name: 'htmlencodedTextID', type: String },
... ]
}
Class registration:
Winthusiasm.HtmlEditor.registerClass("Winthusiasm.HtmlEditor",
Sys.UI.Control);
Using the Code
Download the appropriate zip file and unzip it to a new directory. It includes:
- The Winthusiasm.HtmlEditor control project
- A sample website that uses the
HtmlEditorcontrol - A solution that contains both
Double-click the solution file to start Visual Studio, and then select Build/Rebuild Solution from the menu. This will build the project and copy the project DLL to the Bin folder of the sample website. Set Demo.aspx as the Start Page and press F5.
Use Model
- Create the website as an "ASP.NET AJAX-enabled Web Site"
- Copy the assembly Winthusiasm.HtmlEditor.dll to the Bin folder
- Add a
Registerstatement to the page - Add a custom control tag (s) to the page
- Use the
Textproperty to set the editor HTML - Save the HTML when appropriate
- Use the
Textproperty to get the "saved" HTML
Example Register statement:
<%@ Register TagPrefix="cc" Namespace="Winthusiasm.HtmlEditor" Assembly="Winthusiasm.HtmlEditor" %>
Example custom control tag:
<cc:HtmlEditor ID="Editor" runat="server" Height="400px" Width="600px" />
Example set Text:
Editor.Text = initialText;
Use Model Details: Saving the HTML When Appropriate
The editor's "client-side" Save method instructs the editor to store the current HTML (converting to XHTML, if appropriate), and clears the modified flag. When the editor property AutoSave is set to true (the default), the client-side Save method is called automatically as part of the client-side ASP.NET validation process before the form is submitted. All controls with a CausesValidation property set to true (the default) trigger the behavior. If the AutoSave implementation is not appropriate or sufficient, the client script to trigger the client-side Save can be attached through the optional SaveButtons property, or manually.
Retrieving the Saved Text
In the server-side event handler, the Text property is used to retrieve the "saved" text:
DataStore.StoreHtml(Editor.Text);
Points of Interest
Embedded Resources
To simplify deployment, the HtmlEditor.js file and the image files for the toolbar buttons are embedded as resources within the HtmlEditor.dll assembly.
HtmlEncode and HtmlDecode
Storing un-encoded HTML in a form control, such as a text area or a hidden input element, is problematic when submit behavior is triggered on the client:

This implementation uses HiddenField to store the edited HTML, and therefore always stores the text in an HtmlEncoded state.
Setting the Text Property on Postback
The HiddenField used to store the HTML text is created within UpdatePanel. If the Text property is set during an "asynchronous" postback, the server control responds by calling Update on UpdatePanel and registers DataItem with ScriptManager. Because the client control uses an endRequest handler to monitor all PageRequestManager updates, it detects that DataItem has been registered, and automatically updates the HTML in the editor.
XHTML Conversion
Both Internet Explorer and Firefox output "HTML" when in designMode. To convert to "XHTML", this implementation reads the "client-side" DOM tree and outputs the elements and attributes in XHTML format. This "client-side" conversion of HTML to its XHTML equivalent effectively "hides" the underlying HTML implementation. When the user switches from Design to HTML mode, the output displayed is XHTML. In addition, the server-side Text property retrieves XHTML. Note that the editor configuration property OutputXHTML is defaulted to true. If set to false, no XHTML conversion takes place and the output is browser-generated HTML.
Converting Deprecated Syntax
Internet Explorer and Firefox both output and "expect to modify" deprecated syntax while operating in designMode. Consequently, the implementation of this editor converts the deprecated syntax into a standards-based equivalent when converting to XHTML. It "restores" the deprecated syntax when converting back to designMode HTML. Note that the editor configuration property ConvertDeprecatedSyntax is defaulted to true. If set to false, no conversion takes place and the output includes the deprecated syntax.
Converting Paragraphs in Internet Explorer
Internet Explorer outputs and "expects to modify" paragraph elements while operating in designMode. If the editor configuration property ConvertParagraphs is set to true, the implementation of this editor "modifies" the displayed style of paragraph elements while in designMode. It converts the paragraph elements into appropriate break and/or div elements when converting to XHTML, and "restores" the paragraph elements when converting back to designMode HTML. Note that this configuration property applies only to Internet Explorer and is defaulted to false. Unless set to true, no conversion takes place, and the output includes the paragraph elements.
Caveats
Script Injection
A web page containing an HTML editor most likely stores the HTML created by the user. Later, it probably displays that HTML in another web page, perhaps for a different user. This presents a classic exposure to Script Injection, and perhaps SQL Injection as well. The client of the HTML editor should take appropriate steps to control these exposures.
Browser Testing
The control discussed in this article was tested on Firefox 2+, IE 6, IE 7, and Opera 9+.
Conclusion
Using the tutorial from Microsoft, as well as the designMode and execCommand resources listed below, the HTML editor server control has been implemented to work in a Microsoft AJAX environment. Possible enhancements include:
- Support for Safari
- Support for additional HTML constructs
- Additional configuration properties
Additional Resources
designMode and execCommand
- designMode Property
- execCommand Method
- Midas Specification
- Rich-Text Editing in Mozilla
- Mozilla Rich Text Editing Demo
- Midas - Mozilla Developer Center
- Converting an app using document.designMode from Internet Explorer to Mozilla
- Rich Text Editor- Part I
- Rich Text Editor- Part II
- Opera Browser Wiki - Textarea Editor
- FreeTextBox
- Selection Object (document) - Internet Explorer
- DOM: Selection - MDC
- TextRange Object - Internet Explorer
- DOM: Range - MDC
Other Tutorials and Articles
- Adding Client Capabilities to a Web Server Control by Using ASP.NET AJAX Extensions
- Embedding Resources in ASP.NET 2.0 Assemblies
- How To: Prevent Cross-Site Scripting in ASP.NET
Online Documentation
History
- July 1, 2009
- Reduced
ViewStatesize by 72%
- Reduced
- June 19, 2009
- Fix for client-side ASP.NET
Validatorsupport
- Fix for client-side ASP.NET
- June 17, 2009
- Full support for client-side ASP.NET
Validators - Fix
pretag conversion issues
- Full support for client-side ASP.NET
- June 7, 2009
- Fixed
XHTMLconversion issue with Internet Explorer duplicate DOM elements - Included
valignin the defaultAllowedAttributes - Converted deprecated
valignattribute to standards-based equivalent - Fixed
GetInitialHtmlEditorOuterHTMLmissingtextareaend tag
- Fixed
- April 29, 2009
- Refactor how the
Linkdialog reads thehrefattribute - Refactor how the
Imagedialog reads thesrcattribute - Refactor to support class extension
- Refactor client-side
descriptor - Workaround for
ModalPopupExtenderissue - Fixed client-side
Saveissue with an internal timer
- Refactor how the
- April 9, 2009
-
DesignModeEmulateIE7property - Workaround for Internet Explorer 8
designModescrollbars issue
-
- March 19, 2009
-
CLSCompliant(true)assembly attribute - Links to FAQ, etc. on demo page
- Force close of open dialog on
SetMode - Workaround for Visual Studio 2008 Designer rendering
- Workaround for IFrame
onloadvalidator issue - Fixed several W3C Validator issues
- Fixed
ToLowerCulture issue
-
- July 13, 2008
- Fixed Firefox 3 delete/backspace key issue
- June 29, 2008
- Fixed Firefox 3 initial render layout issue
- Fixed Opera 9.5 issues
- May 28, 2008
- Visual Studio 2008 (ASP.NET 3.5) source code
- Visual Studio 2005 (ASP.NET 2.0) source code
- May 25, 2008
- Fixed initialization issue
- Fixed Color.htm issue
- Fixed conversion issues
- Fixed Link.htm issue
- February 3, 2008
- Fixed Image.htm issue
- January 2, 2008
- Namespace changes to client-side classes
- Client-side
GetVersionmethod - Added
subandsupto default allowed tags - Fixed
DesignModeCssabsolute path issue - Fixed Designer embedded image issue
- December 3, 2007
-
AutoSaveValidationGroupsproperty - Fixed
ConvertParagraphshorizontal rule issues
-
- November 21, 2007
-
AutoSaveproperty -
Modifiedserver-side property -
ValidationPropertyattribute - Fixed
GetTextclient-side method - Fixed resource identifier
- Enforced pixel height and width
-
- October 30, 2007
-
SaveButtonsproperty - Added Selection and Range links to the Additional Resources section
-
- October 18, 2007
- Toolstrips
- Separator toolbar element
- Toolstrip background images
- Color schemes: Custom, Visual Studio, Default
-
ColorSchemeproperty -
CreateColorSchemeInfoserver-side event property -
ToolstripBackgroundImageproperty -
ToolstripBackgroundImageCustomPathproperty -
NoToolstripBackgroundImageproperty -
EditorInnerBorderColorproperty -
SelectedTabTextColorproperty -
DialogSelectedTabTextColorproperty - Demo options: Toggle mode, color scheme, and toolstrips
- Fixed
ScriptReferenceissue - Refactored Color.htm
- October 9, 2007
- Dialog framework
- Text color dialog
- Background color dialog
- Hyperlink properties dialog
- Image properties dialog
- Dialog color properties
-
DialogFloatingBehaviorproperty -
CreateDialogInfoevent property - Included
altandtitlein allowed attributes - Fixed context issues
- Fixed XHTML font conversion issues
- September 24, 2007
-
Toolbarsproperty - Removed
ToolbarButtonsTopproperty - Removed
ToolbarButtonsBottomproperty - Removed
ToolbarSelectListsproperty - Fixed empty toolbar issue
-
- August 29, 2007
- Optional toolbar buttons: Save, New, Design, HTML, View
-
ToggleModeproperty -
ToolbarDockedproperty -
ToolbarClassproperty -
EditorBorderSizeproperty -
EditorBorderColorproperty -
SelectedTabBackColorproperty -
ModifiedChangedclient-side event handler property -
ContextChangedclient-side event handler property -
Saveserver-side event handler property - Fixed
ConvertParagraphsissues
- August 7, 2007
-
ToolbarButtonsTopproperty -
ToolbarButtonsBottomproperty -
ToolbarSelectListsproperty -
CreateToolbarInfoevent property -
TextDirectionproperty - Included
dlin allowed tags
-
- August 5, 2007
-
ConvertParagraphsproperty -
ReplaceNoBreakSpaceproperty - Fixed Internet Explorer horizontal rule issue
- Fixed Internet Explorer ordered and unordered list issue
- Fixed
$findstartup issue
-
- May 29, 2007
- Additional fix for Internet Explorer 6 security context issue
-
EditorBackColorproperty -
EditorForeColorproperty -
DesignModeCssproperty -
NoScriptAttributesproperty
- May 25, 2007: Fixed Internet Explorer 6 security context issue
- May 15, 2007: Support for Opera 9+
- May 14, 2007: Added properties:
-
InitialMode -
DesignModeEditable -
HtmlModeEditable
-
- May 11, 2007: Fixed Firefox hide/show editor issue
- May 4, 2007
- Added Internet Explorer key-down handler
- Fixed postback setting initial
Textissue
- May 2, 2007: Fixed initial text issue
- May 1, 2007
- Added Modified and Save concepts
- Converted deprecated syntax for
u,blockquote, andalign
- April 10, 2007: XHTML output
- April 2, 2007: Fixed Internet Explorer focus issue
- March 31, 2007: Initial article
License
This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)
About the Author
| Eric Williams (winthusiasm.com)
Web Developer
Member | Eric Williams is a .NET and Web developer who has been working with ASP.NET AJAX since the March 2006 Atlas CTP. Eric is the founder of Winthusiasm (winthusiasm.com), a .NET technology company that offers consulting and development services, and Colorado Geographic (coloradogeographic.com). When not working on a software project, Eric likes to hike, explore and photograph the mountains around him. |
ASP.NET AJAX HTML编辑器
本文介绍如何为ASP.NET AJAX创建HTML编辑器服务器控件,包括实现原理、关键技术和使用方法,并提供源代码下载。
1072

被折叠的 条评论
为什么被折叠?



