How to Create a WYSIWYG Rich Text Editor in JavaScript. Pt. 1 | 2 | WebReference

How to Create a WYSIWYG Rich Text Editor in JavaScript. Pt. 1 | 2

To page 1current pageTo page 3
[previous][next]

How to Create a WYSIWYG Rich Text Editor in JavaScript. Pt. 1

Internet Explorer on the other hand will not allow invisible HTML elements to gain the focus, otherwise both browsers could have shared the same code. However it does allow keyboard events to go to almost any HTML element, so the input handlers can be attached to the <div> element.

 

  {

     // in IE, just attach everything to the <div>

    this.oDiv.onkeypress = RichEdit.prototype.onKeyPress;

    this.oDiv.onkeydown = RichEdit.prototype.onKeyDown;

    this.oDiv.onfocus = RichEdit.prototype.onDivFocus;

    this.oDiv.onblur = RichEdit.prototype.onDivBlur;

  }


Lastly the cursor object is created although it is not inserted into the RichEdit control until it gets the user's input focus.


  // create the cursor

  this.oCursor = document.createElement('span');

  this.copyStyle(this.oCursor, this.style);

  this.oCursor.innerHTML = '|';

 

  this.oCursor.style.position = 'absolute';

  this.oCursor.style.verticalAlign = 'bottom';


Making it blink requires a little work. In the early days of the web, Netscape introduced a <blink> tag that would cause the contained text to blink on and off continuously. This prompted a veritable gold rush of web sites that had text blinking in as many colors as can be imagined as the <blink> tag was used for any conceivable purpose. While the <blink> tag would be ideal for making the cursor blink, indeed a blinking cursor would be one of the few good reasons to use <blink>, other browser implementers have not joined the blinking bandwagon and so the <blink> tag has thankfully faded into obscurity. I have chosen a manual approach; starting a half-second timer that alternately hides and shows the cursor using the visibility style.

 

  // make it blink

  var oCursor = this.oCursor;

  window.setTimeout(function(){RichEdit.prototype.onBlinkCursor(oCur sor);},500);

 

  this.oInsertionPoint.appendChild(this.oDiv);

}

RichEdit.prototype.onBlinkCursor = function(oCursor)

{

  if ( oCursor.style.visibility == 'hidden' ) oCursor.style.visibility = 'visible';

  else oCursor.style.visibility = 'hidden';

 

  window.setTimeout(function(){RichEdit.prototype.onBlinkCursor(oCur sor);},500);

}

 

Now let's look at some of the methods the RichEdit object must support to fulfil its role as an editor:

The focus() method on an HTML element instructs it to grab the input focus and start listening to user input. In the RichEdit class, this function is implemented to redirect the focus to the appropriate component.

 

RichEdit.prototype.focus = function()

{

  // grab the input focus

  if ( bIsNetscape ) this.oTextbox.focus();

  else this.oDiv.focus();

}

 

The cursor, or more accurately the cursor position is used by many parts of the RichEdit code to perform the various operations at the correct location. The RichEdit object implements getCursorPos(), which generates an object describing the current cursor position and surrounding nodes. This object contains ‘previous', ‘current' and ‘next' members that describe the RichEdit document elements surrounding the current position. The current element is the one that would be deleted using the del key and is also where new text is inserted. It also contains an ‘insert' member to hold the actual HTML node to insert before as this can sometimes be different from the ‘current' member value.

There are two distinct cases to consider when calculating the cursor position; when the RichEdit control has the user input focus,the cursor will be visible to the user so the position can be calculated around that, otherwise when the RichEdit control is out of focus or the input focus is directed elsewhere, the cursor is removed and so a copy of the last known cursor position is used.

 

RichEdit.prototype.getCursorPos = function()

{

  // return an object describing the current cursor position:

  //    previous: the node before the cursor

  //    current: the current node

  //    next: the node following the cursor

  //    insert: A node to insert new nodes before. Not always the same as current

  if ( this.bInFocus )

  {

     var oParent = this.oCursor.parentNode;

     if ( oParent == this.oDiv )

     {

       // this can happen when an element other than <span> is current.

       var oCurrent = this.oCursor.nextSibling;

       var oNext = oCurrent ? oCurrent.nextSibling : null;

       return {prev:this.oCursor.previousSibling,current:oCurrent,next:oNext,insert:thi s.oCursor};

     }

     if ( !oParent )

     {

       return {prev:this.oDiv.lastChild,current:null,next:null,insert:null};

     }

    return {prev:oParent.previousSibling,current:oParent,next:oParent.nextSibling,in sert:oParent};

  }

 

  if ( !this.oLastCursorPos )

  {

    this.oLastCursorPos = {prev:this.oDiv.lastChild,current:null,next:null,insert:null};

  }

  return this.oLastCursorPos;

}

 

The RichEdit control also needs some way to set the cursor position. Again the in-focus state of the RichEdit control must be taken into account, only moving the cursor element when the control is in focus.

 

RichEdit.prototype.setCursorPos = function(oSpan, bCopyStyle)

{

  // set the position of the cursor to just before oSpan

  // or if null/undefined, append to the end.

  var oElt;

  if ( oSpan )

  {

     if ( this.bInFocus )

     {

       if ( oSpan.tagName.toLowerCase() != 'span' )

       {

         this.oDiv.insertBefore(this.oCursor, oSpan);

       }

       else if ( oSpan.firstChild )

       {

         oSpan.insertBefore(this.oCursor, oSpan.firstChild);

       }

       else oSpan.appendChild(this.oCursor);

     }

     else this.oLastCursorPos = {prev:oSpan.previousSibling,current:oSpan,next:oSpan.nextSibling};

     oElt = oSpan;

  }

  else

  {

     oElt = this.oDiv.lastChild;

     if ( this.bInFocus ) this.oDiv.appendChild(this.oCursor);

     else this.oLastCursorPos = null;

  }

 

  if ( (bCopyStyle == undefined) || (bCopyStyle == true) ) this.assimilateStyle(oElt);

}

 

 

To page 1current pageTo page 3
[previous][next]

Created: March 27, 2003
Revised: February 2, 2005

URL: http://webreference.com/programming/javascript/gr/column11/1