Click here to Skip to main content
Click here to Skip to main content

ASP.NET HTML Editor Control

By , 22 Dec 2012
 

Introduction

Nowadays lots of web applications such as forums and blogs use HTML editors as a primary tool for users publications. Web based HTML editor is a kind of control that allows online users to create and edit their html documents in a way that user can write text and set font, color, size, and hyperlink for it and also insert image,swf, files in that. Furthermore the user can view the HTML code of his document and edit it and view the result in design mode and vice versa.

This article discusses how can create an HTML editor server control with some security considerations.

Background 

Four years ago I was working in a company which was so cautious about developing secure products, thus our technical manager asked me about developing an HTML text editor as a module in our CMS Portal for our important customers which security was their first priority. So I developed an HTML editor which considered some important security issues such as XSS. Generally it is not more secure than Current new versions of text editors like FCKEditor but it was a good opportunity for me to create a useful, user friendly and above all a unique experience for my mind necessity for programming some creative web-based software. I hope this article helps you too.

System Requirements 

  • ASP.NET 2+

UI

Component appearance:

  • Three toolbar rows across the top
  • Dialog bars for adding elements like table,button, etcetera.
  • An editor area that displays and/or edits the document in either mode

Asp.net HTML Editor component

Component Parts

There are two part for this custom control, server side and client side.server side undertakes some tasks such as security stuffs using AntiXSS, providing the html source of html editor,setting leveles of security,providing some methods like setting value for editor and getting secure value from editor,script registration,storing uploaded files, providing decoded data which has been sent from html editor and providing WebResources for control.

The client side guarantees eliminating some dangerous stuffs(XSS aspects) from html editor source which will send to the server side and encoding them, sending data to the serve side , etc.

In client side there are six JavaScript source files

  • RichText.js is the main javascript source , all things which is related with editor abilities is done here.
  • Encoder.js provides all methods for encoding data
  • Loading.js provides optional loader for editor.(some part of it has been commented, if you want to have loader,uncomment them)
  • Slider.js provides a slider for resizing the editor text area
  • jscolor.js is an open source javascript which i just used it

In server side there are five classes included:

  • HtmlSourceInitializer.cs : Initializes the editor HTML
  • Registrar.cs : Registers a list of scripts into our control
  • Security.cs : Responsibles for security using AntiXSS AND HtmlSanitizationLibrary
  • SourceActions.cs : Get the data which has been sent from cleint
  • RichTextBox.cs : Establishes accessible methods and properties of HtmlEditor control

EditorStyles , RichTextBoxIcons , Colorpicker are another parts.

HtmlSourceInitializer.cs

The component has some its own HTML sources which creates HTML editor view.This class uses StringBuilder to append HTML Editor view parts which has been added in_HtmlSource with InitializeHtmlSource method and then places the _HtmlSource into the Static RichTextHtmlSource property.

 
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

For preventing cross-site scripting,i decided to use Microsoft AntiXSS library. As you can read in its overview :

"The Microsoft Anti-Cross Site Scripting Library V4.2 (AntiXSS V4.2) is an encoding library designed to help developers protect their ASP.NET web-based applications from XSS attacks. It differs from most encoding libraries in that it uses the white-listing technique -- sometimes referred to as the principle of inclusions -- to provide protection against XSS attacks.

This approach works by first defining a valid or allowable set of characters, and encodes anything outside this set (invalid characters or potential attacks). The white-listing approach provides several advantages over other encoding schemes."

The _SetHighLevelSecurityForHtmlTags field, has been setted as True which means the html document which has been sent from client side,will decode in two levels and it will change to only text codes. For instance the "<b>hello</b>" will be something like this ";&lt;b&gt;hello&lt;/b&gt;".It is useful in some cases which you want to get much more secured html code and after checking it,you can decode it to get a pure HTML source again.

The EncodeHtml method encodes the string HTML source of created document AntiXSS HtmlEncode

method. Also the GetSafeHtmlFragment method returns HTML fragments with tags intact.

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

The SourceActions class provides the HTML source code which has been sent from client with SourceProvider.

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 method

This method will set some values like HTML document for editor. For instant if you want to use some documents which have been stored in database or other resources, you can use this method to insert your documents into the editor for edition.

        
/// <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 method

This function gets the data which has been provided in text editor for some purposes such as : demonstration in a specified page,storing in database,etc.

       public string GetValue()
       {
            return this.Page.Server.HtmlDecode(AntiXss.HtmlAttributeEncode(GetDecodedValue()));
          }

OnPreRender must be modified to call RegisterStartupScript, as follows:

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

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.

This includes some significant functions which undertake some tasks such as :

  • Commands execution on editor
  • Elements creation
  • All other design mode activities
  • Making handlers for handeling events

The document is created and design with these javascript functions and then if someone wants to use it on server side (for example: storing/decoding)should send it to the server.This action happens with sendValue().

sendValue() function send created document to the server,as well as it eliminates some of the risky tags over XSS attacks like script,iframe,javascript and encode the document using Encoder.js(with htmlEncode() function) before sending it to the server. Actually there will be two step of encoding process,first step in the client and the second one is in the server side.

//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);

}

 The most vital function which in another word is the hurt of this editor,is  textEdit(x,y) function which responses for all requests over text editing issues.The essential idea behind of it is using a fundamental function of the browsers which enables you to execute a command on the current document, current selection, or the given range such as bold,italic,underline,copy,delete,reformat and so on ,named execCommand  .

The code generated by the execCommand method is different in browsers. Internet Explorer uses HTML tags, Firefox, Google Chrome and Safari generate inline styles and Opera sometimes uses HTML tags, sometimes styles.

For example, if the 'bold' command is executed on a non-bold text,

•Internet Explorer and Opera generate a strong element around it, 

•Firefox, Google Chrome and Safari generate a span element around it and set the fontWeight style property of the span element to 'bold'. If an element exists around the non-bold text, then Firefox, Google Chrome and Safari set the fontWeight style property of this element to 'bold'. 

If the 'bold' command is executed on a bold text, browsers remove the specified style property and/or the element including the text.

This caused that i encountered with problems in recognizing bold or underline and italic text to demonstrate it in the shape of bold,italic and underline button.Anyway i resolved it for firefox and IE but it has some problems in other browsers such Chrome,opera and firefox. getActiveButtons() method do that as follows :

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);
} 

 

The StringtoXML()  Method converts input string (which is generated from getRangeNode() method) to 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() method gets the selected text parent node and its styles for recognizing the selected text style : 

 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;
} 

The syntax is :  object.execCommand(cmdID, showUI, value). The execCommand function abilities and compatibilities are different in various browsers,hence in this component there are some abilities like "document saving" or "background color" which are not executed in other browsers except IE. As you can see below there are lots of incompatibilities between browsers which makes our job more difficult and it seems it goes to be more improved than before. 

Method or propertyExplorer 6/7 Firefox 2Safari 3Opera 9
backcolor
yesyesyesyes

Moz/Saf require the #. Moz/Op give bgcolor to block-level element selection is part of, IE/Saf to selection itself.
To get the IE/Saf effect in Moz, use hilitecolor.

bold
yesyesyesyes
Notes
contentReadOnly
noyes?no
IE gives error
copy
yesprotectedyesprotected
Ctrl+C always works
createbookmark
????
Notes
createlink
yesyesyesyes
Notes
cut
yesprotectedyesprotected
Ctrl+X always works
Method or propertyExplorer 6/7Firefox 2Safari 3Opera 9
decreasefontsize
noyes?incorrect
Op allows only 1 decrease; the 2nd reverts text to original font size.
delete
yesyesyesyes
Notes
fontname
yesyesyesyes
Notes
fontsize
nohorridyeshorrid

Moz/Op generate a (gulp!) <font> tag with size equal to parseInt(value). Saf creates a normal font-size CSS declaration.

forecolor
yesyesyesyes
Moz/Saf require #
formatblock
(put selection in header or paragraph)
noyesbuggyincomplete
Opera changes only the first block-level element in the selection to the desired block.
Method or propertyExplorer 6/7Firefox 2Safari 3Opera 9
heading
noyesnono
Notes
hilitecolor
noyesnoyes

Does the same as bgcolor in IE/Saf: it gives only the selection (and not the containing block) the defined bgcolor.

increasefontsize
noyes?incorrect
Op allows only 1 increase; the 2nd reverts text to original font size.
indent
incorrectyesbuggymore incorrect

Moz adds 40px of margin-left per indent. IE/Op add a (gulp!) blockquote for every indent.

When applied to an <li>, Moz/IE generate a nested <ol/ul>, but Op again inserts a <blockquote>.

inserthorizontalrule
yesyesyesyes
Notes
inserthtml
noyes?no
Notes
Method or propertyExplorer 6/7Firefox 2Safari 3Opera 9
insertimage
yesyesyesyes
IE allows resizing of image
insertorderedlist
almostyesalmostyes
If the newly created ordered list borders an existing list, IE and Safari merge the two.
insertunorderedlist
almostyesyesyes
If the newly created unordered list borders an existing list, IE merges the two.
insertparagraph
yesalternativeyesyes
Mozilla adds a paragraph around the selected block. The other browsers delete the selected block and insert an empty paragraph which the user can fill.
italic
yesyesyesyes
Notes
justifycenter
yesyesyesyes
Notes
Method or propertyExplorer 6/7Firefox 2Safari 3Opera 9
justifyfull
yesyesyesyes
Notes
justifyleft
yesyesyesyes
Notes
justifyright
yesyesyesyes
Notes
multipleselection
????
Notes
outdent
yesyesbuggyyes

When applied to an <li> that's a child of a single <ol/ul>, Moz/IE move the <li> to outside the <ol/ul>, while Op doesn't react.

Unfortunately IE has an extra bug in my test page: it moves the <li> to entirely outside my test element.

overwrite
????
Notes
paste
yesprotectedyesprotected
Ctrl+V always works
print
????
Notes
redo
yesyesyesyes
Redo works in Safari, but if you do Undo/Redo too often, it crashes. Solved in 3. 
If you make your own changes in the editable area, Undo/Redo continues to work in Mozilla and Safari (though it ignores your custom changes), but in IE and Opera it stops working.
Method or propertyExplorer 6/7Firefox 2Safari 3Opera 9
refresh
????
Notes
removeformat
????
Notes
saveas
????
Notes
selectall
????
Notes
strikethrough
yesyesyesyes
Notes
styleWithCSS
noyes?no
Gives a generic command that styles should be applied with CSS (true; default) or with tags (false). When doing execCommand("bold")the first would generate a <span style="font-weight: bold";>, the second a <b> tag.
subscript
yesyesyesyes
IE/Moz/Op: using the same command again removes the subscript. Using subscript and superscript together gives odd effects.
superscript
yesyesyesyes
IE/Moz/Op: using the same command again removes the superscript. Using subscript and superscript together gives odd effects.
Method or propertyExplorer 6/7Firefox 2Safari 3Opera 9
unbookmark
????
Notes
underline
yesyesyesyes
Notes
undo
yesyesyesyes
Undo works in Safari, but if you do Undo/Redo too often, it crashes. Solved in 3. 
If you make your own changes in the editable area, Undo/Redo continues to work in Mozilla and Safari (though it ignores your custom changes), but in IE and Opera it stops working.
unlink
yesyesyesyes
Notes
Method or propertyExplorer 6/7Firefox 2Safari 3Opera 9 

Another crucial  issue is finding the last point of cursor which has been there. this will cause the editor knows which text element should be effected by current execCommand. This function mostly is used in IE because Firefox and others by default have this ability by theme self. This tasks is being responsible by checkCursor() Method As you observe : 

//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()   is the other vital method which allocates the specified  event handlers to their own buttons which dynamically created like all buttons in dialogs such as table creator, link adder,ETC. 

 <span style="white-space: pre-wrap;">//Allocates an event to the generated buttons</span> based on their action types 
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);
    }
}

The Setposition() method set the created object position. When an object is created  it needs to located on the page. This method set objects position based on mouse and page.For instance when you drag a dialog bar, it uses this method with set the related argument to "mouse" and when an object maker is created, it uses this function with "page" as related argument. 

//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 is not based on object oriented programming but i tried to make it clear and useable. 

Using this Code

For using this control you should add the control's DLL from RichTextBox\Control_dll folder in your Visual Studio Toolbox and then just drag it on your ASPX page. you will see something like below:

<%@ 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>

if you want to get the created document, first you should send it with OnClientClick="sendValue()" to the server and then get safe data with setting OnClick event on your event raiser control like button and write your code like this:

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();
    }
} 

Browser Testing 

The control discussed in this article was tested on Firefox 5+, IE 8 , Opera , Safari and Chrome.

IE 9 : There are no error in IE 9 but exist some lacks in its appearance :

  • Two excessive  scroll bar
  • Dialog bars disappear at the behind of tables or texts 

How to open this project with Visual studio 2010 or lower versions 

Since last time i opened this project with Visual Studio 2012 for checking its reliability, maybe you have problem with opening this project by lower versions than VS2012. For fixing this problem just follow below steps:

  • Open project SLN file with a text editor like notepad. In the second line you'll see this line : Microsoft Visual Studio Solution File, Format Version 12.00.  Change the version to 11.00 or lower
  • Save text and open the project with your VS. Enjoy it ! 

Conclusion 

I tried that this control be user friendly and altogether I believe that working with it is so simple. Entirely it is not fault-free but it was good experience for me during all 6 months which I developed it and I hope this source code learns you some valuable points about creating an asp.net custom control and web-based HTML Editor.

There will be lots of tiny points for your learning like : addressing images from CSS files into a custom control project and Assemblyinfo and lots of other stuffs in Javascript sources. Hope to be useful.

History

November 5, 2012

  • The  onclick javascript error for firefox  over color picker actions was fixed 
  • Created table appearance on Chrome and Opera  was improved 

October 26, 2012

  • Fixing for Safari Browser

November 23 , 2009

  • GetValue and SetValue methods was Added

April 10, 2009

Added features :

  • SWF support
  • Special characters support
  • Preview support

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Amir Jalilifard
Software Developer (Senior) TBank
Iran (Islamic Republic Of) Iran (Islamic Republic Of)
Member
I started software development about 7 years ago and it seems like now it consumes most every part of my life.
You know, my life is my computer and solving problems is my passion. Apart from daily programming for food, it is also a hobby; I mostly enjoy areas like Computer Vision, Robotics and AI. Also, I am excited about Content based image recognition(CBIR).
My major goal in my life is getting my doctoral degree in software engineering and then joining one of the Google software development teams. However my Mom tells me I am over-ambitious about joining Google. Ohhhh!
Anyway, I tell you, I'm definitely committed to achieving it!

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Questiontanksmemberzahra111 Apr '13 - 10:39 
AnswerRe: tanksmemberAmir Jalilifard13 Apr '13 - 6:22 
GeneralMy vote of 5memberhassan wasef4 Apr '13 - 7:24 
GeneralMy vote of 5memberAvik Ghosh224 Mar '13 - 19:45 
GeneralMy vote of 5memberSavalia Manoj M26 Dec '12 - 20:24 
QuestionMy vote of 1 [modified]memberBCantor24 Dec '12 - 8:58 
AnswerRe: My vote of 1 [modified]memberAmir Jalilifard25 Dec '12 - 18:36 
GeneralRe: My vote of 1memberAmir Jalilifard3 Jan '13 - 3:42 
Generalnicememberyincj23 Dec '12 - 13:21 
GeneralRe: nicememberAmir Jalilifard23 Dec '12 - 18:49 
QuestionVery NicememberShahab Farahbakhsh22 Dec '12 - 9:00 
GeneralMy vote of 4memberMas0ud14 Dec '12 - 19:54 
GeneralRe: My vote of 4memberAmir Jalilifard14 Dec '12 - 20:21 
GeneralMy vote of 5membersaanj19 Nov '12 - 0:12 
GeneralRe: My vote of 5memberAmir Jalilifard19 Nov '12 - 5:59 
GeneralMy vote of 5membersabitu12 Nov '12 - 8:04 
GeneralMy vote of 5memberJustin Cooney9 Nov '12 - 5:26 
GeneralRe: My vote of 5memberAmir Jalilifard11 Nov '12 - 20:50 
GeneralRe: My vote of 5memberJustin Cooney12 Nov '12 - 9:02 
GeneralMy vote of 1memberarh667 Nov '12 - 15:54 
AnswerRe: My vote of 1memberAmir Jalilifard7 Nov '12 - 22:52 
GeneralMy vote of 5memberNnsS646 Nov '12 - 22:32 
QuestionMy vote of 5memberphpfreak5 Nov '12 - 8:02 
Generalgood articlememberhamid.karimy4 Nov '12 - 20:02 
GeneralMy vote of 4memberfahad121 Nov '12 - 0:29 
QuestionMy Vote of 5memberAlirezaDehqani31 Oct '12 - 18:57 
QuestionThanks for your nice tip.memberS.A.Esmaeily30 Oct '12 - 19:32 
Questionسلام داش امیرmemberpcrun28 Oct '12 - 21:51 
AnswerRe: سلام داش امیرmemberAmir Jalilifard29 Oct '12 - 2:37 
GeneralRe: سلام داش امیرmemberpcrun29 Oct '12 - 3:29 
GeneralMy vote of 5memberHaBiX24 Oct '12 - 22:55 
GeneralMy vote of 5memberCarsten V2.024 Oct '12 - 18:36 
GeneralRe: My vote of 5memberAmir Jalilifard29 Oct '12 - 2:02 
GeneralAppropriate articlememberw3web317 Oct '12 - 23:47 
GeneralGood article to understand the html editormemberOmmrudraksha Shri17 Oct '12 - 18:52 
Question[My vote of 2] Doesn't workmemberForogar17 Oct '12 - 10:02 
AnswerRe: [My vote of 2] Doesn't workmemberAmir Jalilifard22 Oct '12 - 21:10 
GeneralRe: [My vote of 2] Doesn't workmemberForogar28 Oct '12 - 4:37 
GeneralRe: [My vote of 2] Doesn't workmemberAmir Jalilifard28 Oct '12 - 20:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 22 Dec 2012
Article Copyright 2012 by Amir Jalilifard
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid