SiteExperts.com Logo Home | Community | Developer's Paradise | Jobs
User Groups | Site Tools | Site Information | Search

Inside Technique : HTML Text Editor : Creating the Editor

To add formatting to the HTMLArea element, we took advantage of the IE4/ 5 TextRange Object. The TextRange object is designed to easily manipulate and format any string of text.

In an editor, all formatting occurs on the user's selection. Using DHTML, you can obtain a TextRange object representing the selection by using the document's selection object. We obtained the selection as follows:

  var selection = document.selection.createRange()

This method returns a range object that represents the user's selection. One issue we had to solve is that the object model's selection is tied to the document, not to a particular input control. Therefore, we need to write code that only retrieves the selection when the user is within the HTMLArea element. Otherwise, the user would be able to select text anywhere in the page and used the formatting commands to format the text.

We solved this problem by binding a few events on the HTMLArea element itself. Only when these events occur (onmouseup, onkeyup, and onselect), do we retrieve the user's selection. Once we have the selection, the formatting of the text is done using the execCommand method. The execCommand supports a list of actions that you can perform on the text range. For example, to make text bold, you call textRange.execCommand("Bold"). The execCommands related to formatting automatically inserts the appropriate HTML around the user's text.

We generalized our use of execCommand into a format() function. This function takes the formatting arguments and calls execCommand. This format() function and the cacheSelection() function are the two functions that make up the entire editor. The cache function is used to retrieve the user's selection, and the format function is called whenever the user clicks one of the formatting buttons:

  // Cache the selection as the user types, selects text, or clicks the mouse
  function cacheSelection(el) {
    var temp = document.selection.createRange()
    if ((event.type!="select") || (temp.text!=""))
      el._selection= temp
  }

  // Apply formatting to the text selection
  function format(cmd) {
    if (document.all.editor._selection!=null) {
      document.all.editor._selection.select()
      if (arguments[1]==null)
        document.all.editor._selection.execCommand(cmd)
      else 
        document.all.editor._selection.execCommand(cmd,true,arguments[1])
      document.all.editor._selection.select()
    }
  }

The format function requires atleast one argument. However, since some commands require two arguments a second optional argument can be specified. Below demonstrates buttons that call the format function with one argument and two arguments.

 // 2 sample buttons
 <INPUT TYPE="Button" VALUE="B" ONCLICK="format('Bold')" >
 <INPUT TYPE="Button" VALUE="OL" ONCLICK="format('FormatBlock','<OL>')">

While this approach works great for creating an Internet Explorer 5.0 HTML editor, it is difficult to maintain and hard to get a downlevel friendly representation. In addition, the code is currently hard-coded to a single instance of the editor, so only one HTML editor can be added to a page at one time. While we can fix this latter problem, the other issues are much more difficult. For example, below is the complete HTML we used to create the editor:

<TABLE>
  <TR><TD></TD>
  <TD align=center>
    <INPUT TYPE="Button" VALUE="B" ONCLICK="format('Bold')">
    <INPUT TYPE="Button" VALUE="I" ONCLICK="format('Italic')">
    <INPUT TYPE="Button" VALUE="U" ONCLICK="format('Underline')">
    <INPUT TYPE="Button" VALUE="|==" ONCLICK="format('JustifyLeft')">
    <INPUT TYPE="Button" VALUE="=|=" ONCLICK="format('JustifyCenter')">
    <INPUT TYPE="Button" VALUE="==|" ONCLICK="format('JustifyRight')">
  </TD></TR>
  <TR><TD ID=blocks>
  <SCRIPT>
    // Generate H1-H6 through script
    for (var i=1; i<=6; i++)
      document.write("<INPUT TYPE=\"Button\" VALUE='H" + i + "' ONCLICK=\"format('FormatBlock','<H" + i + ">')\"><BR>")
  </SCRIPT>
  <INPUT TYPE="Button" VALUE="P" ONCLICK="format('FormatBlock','<P>')">
  <P><INPUT TYPE="Button" VALUE="OL" ONCLICK="format('FormatBlock','<OL>')"><BR>
  <INPUT TYPE="Button" VALUE="UL" ONCLICK="format('FormatBlock','&tl;UL>')">
  <P><INPUT TYPE="Button" VALUE=">>" ONCLICK="format('Indent')"><BR>
  <INPUT TYPE="Button" VALUE="<<" ONCLICK="format('OutDent')">
  </TD><TD>
  <HTMLAREA STYLE="width: 200; height: 100%" ID=editor 
            ONSELECT="cacheSelection(this)" 
            ONKEYUP="cacheSelection(this)" 
            ONMOUSEUP="cacheSelection(this)">
  <P>Hello World!
  </HTMLAREA>
  </TD></TR></TABLE>

Having to add all that code to use the editor is tedious. Also, if you use the editor on multiple pages, maintaining the editor through changes becomes a challenge as you have to update each page that uses it. On the next page, we demonstrate how to use DHTML Behaviors to solve all these issues and automatically enhance a page with HTML Editing and still work well with other browsers.