I'm building a content management type website and wanted to include a nice WYSIWYG editor. Unfortunately all the editors I tested are either too unpredictable and erratic, cost a fortune, or are not customizable enough for my needs (out of the box anyways).
In the end I just didn't want to deal with the awful (x)html that they produce. I also didn't want to deal with my end users, whom have never heard of HTML and won't want to "View Source" to fix the HTML when the WYSIWYG fails.
So, I decided to build my own. After a smidgen of research and testing I decided not to build my own. Now I'm going for a Wiki style code editor with a toolbar. With this I can generate clean consistent simple markup. It's not WYSIWYG but at least it will be consistent and predictable.
I quickly found that I'd need to be able to retrieve and adjust the current text selection in the textarea control. So, after not finding any satisfactory solutions via Google I've come up with my own.
Textarea Cursor Position in IE
First off I'd like to give credit to the sites that provided good tips, suggestions, and solutions.
- parentNode - The best written and closest solution I found.
- Mishoo - A good idea but the comments were more helpful
- Scott Van Vliet - Also a very interesting approach. The comments were also helpful
- Thanks to WikkaWiki which has a good solution for their text editor.
- MSDN Library
My solution works like this:
- Make 2 TextRanges.
- The first TextRange selects from the beginning of the textarea to the beginning of the selected text.
- The second TextRange is a duplicate of the selection.
- Restore missing new line characters in both TextRanges
- The TextRange.text property right trims all the \r\n characters from the selection. We must restore the new lines to calculate the correct cursor position.
- Calculate the start position which is the untrimmed length of the 1st TextRange.text property.
- Calculate the end position which is the untrimmed length of the 2nd TextRange.text property plus the start position.
- Calculate the complete untrimmed selection using textarea.value.substring(startPoint, endPoint).
Internet Explorer makes this whole process very difficult. The biggest issues are:
- It treats \r\n as one character when working with the TextRanges
- It trims \r\n from the end of the TextRange.text so you don't know the real selection length.
All the string methods (substring, indexOf, length, etc.) treat \r\n as 2 characters, however, the TextRange methods (moveStart, moveEnd, etc.) treat \r\n as 1 character. So just moving the TextRange until we reach the beginning and counting how many times we moved will be off by exactly the number of new lines passed along the way.
A Word About Changing the Selection
The TextRange.text \r\n trim issue also causes problems when attempting to change the selection's position. You need to count the newlines between the beginning and the target index and then subtract count from the target index. Then you can use this adjusted index with the TextRange.moveStart and TextRange.moveEnd methods to get the correct selection.
In my code I use 3 TextRanges (instead of 2 as described above) so that I can re-assemble the entire string and compare it to the original textarea.value. I do this to make sure I performed the untrimming correctly.
You will also notice that I only use a single do..while loop to untrim all the TextRanges. I could have done this with 3 separate loops. Even better, I probably should move the untrim bit to a separate function. I purposely made these design decisions but it could be done differently.
Also note that this bit of code was only tested in IE 6.0. Please don't complain because it doesn't work in Opera, Firefox, Safari or Lynx.