With me: print life

The Wild West of Javascript.

Just last week, I was working on the new version of Xinha.  If you don’t know, Xinha’s a web-based document editor.  Embed it in your blog, your web software, so that you and your users can create web documents. Xinha is WYSIWYG, so there’s no need to know HTML.  The Open Planning Project, my employer, uses Xinha to power OpenPlans, which is why I get to work on it.  Xinha is Open Source Software, so we use it, and contribute fixes and enhancements back to the original project.

I was working with Nicholas Bergson-Shilcock, my colleague, on his new plugin for Xinha.  With this plugin, you can finally make great footnotes in your documents.  We were testing his code on Internet Explorer, and we noticed IE acting strange.  Now I don’t mean normal IE strange, IE is the bane of all web developers, so I’m used to strange.  (If you use IE, then please don’t.  I don’t care whether you use Mozilla FirefoxGoogle ChromeOperaApple Safari, or if you connect to web servers directly with telnet.  Just do all web developers a favor and stop using IE.)

When I say strange, I mean screwy.  Certain places in the document just didn’t seem to exist.  His code used Xinha in different ways than the rest of the plugins, so we were expecting edge cases.  But black holes?  Nobody expects black holes!

Editable documents are still the wild west of web development, and so I shouldn’t be surprised.  Javascript and DOM has its Wyatt Earp and Doc Holliday, but document editing is too new to have seen the same kind of law enforcement.  When it comes to selection, manipulation, and document processing, the browser differences aren’t well defined, and there are no libraries to abstract the problems.  Even Peter-Paul Koch (of QuirksMode) told me that “IE’s TextRange is a disaster” when I asked for help.

After a bit of exploring the problem we figured out exactly what happens.  In Internet Explorer, you can’t select the end of a text node (in javascript) if it’s followed by a block node.  That means that for the valid HTML snippet:

1
2
3
4
<div>
  This is my first line
  <p>This is my second line</p>
</div>

You can’t touch the end of the first line.  Let me say that again, you can’t touch the end of the first line. What does that mean?  All of you DOM jockeys know how to get a reference to the node, and could manipulate the elements, but that’s no help for the user.

Your user pushes that cursor beyond the event horizon.  They click on your footnote button to bring up a dialog.  You insert the text they type, and BAM!  The cursor’s not where the user left it; you’ve just crapped markup at some other place in the document.  When you do things like that, users start to fear pressing buttons, and we can’t have that.

Why haven’t we seen it before?  Xinha was using pop-ups for dialogs, and they don’t change the original selection.  Now that we’ve moved to a lightbox-style dialog system, we’re moving the cursor about on the page, and we don’t have a way to move it back.

How do we fix it?  Our first step was to test in IE8 beta to see if it was fixed.  No such luck; sometimes I wonder why I’m an optimist. ;–)  My next step was to try out StackOverflow, the new Jeff Atwood / Joel Spolsky software development community.  It’s pretty hot right now, so I thought it would be a good place to get help, but again, no go.  The only answer I got was someone who seemed to remember some comments related to this bug in Javascript.  I tried to find the software he was referring to, but no bugfix there.  FCKeditor doesn’t have a fix.  Neither does TinyMCE. Wikipedia offered up this link to a list of 5000 web-based editors.  I tried them all, and all of the software not using pop-ups had the exact same bug.

So, what can we do?  Unfortunately, I tried to see if there was a way to trick IE into moving the selection to where we want.  I tried moving the selection left, or right, and then back again.  I tried inserting content, then deleting it, but there was no direct way to solve the problem.  We ended up with three different workarounds, all of which have drawbacks, but are better than no solution at all:

Change the justification
If you change the justification on the current selection, IE modifies the document so that the selection continues to work.  Set it to no justification, and you even get valid HTML! Unfortunately, it re-parents the following element, moving it one node closer to the root of the document.
Insert an empty span
This works by making sure that you are attempting to select the span element, rather than a text node, and element selection actually works in IE.  It craps spans all over the document, though. and even though we try to clean these up, you never know.
Insert a visual cue
The final method works by inserting a visual cue for the user in the form of a little block (□), then selecting it.  If we’re about to modify the document, or the user begins to type, the block will be removed automatically.  In any other case, the user will see the block and naturally want to delete it from the text.

All three are written in to the code, but we decided to default to the visual cue, because it’s the safest in terms of damaging the markup.  Otherwise, we’ve done everything we could to avoid triggering the error, so we hope it won’t affect too many users; it’s always a trade off.

I wrote this to get some visibility for this problem.  This is probably just some sort of off by one error, and IE8 is still in beta, so maybe it can still get fixed.  If not, at least you’ll have a way to work around the problem when you run into it.