Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Selection object behaving strange in Chrome contentEditable element

I'm working on a realtime syntax highlighter in javascript using contenteditable. When parsing content I extract the text of the div and use regex patterns to style it properly. Then I set the innerHtml of the div to the parsed content. However, this makes the cursor disappear from the screen.

I have created this function to reset the cursor, and it works fine in Firefox. But in Chrome the cursor is moving in a wierd way that is semi-predictable. It's usually set at the first space-char in the document instead of the place it was right before the parsing.

The caret char that is stored in the variable cc is at the place it should be though.

/**
* Put cursor back to its original position after every parsing, and
* insert whitespace to match indentation level of the line above this one.
*/
findString : function()
{
    cc = '\u2009'; // carret char

    if ( self.find(cc) )
    {
        var selection = window.getSelection();
        var range = selection.getRangeAt(0);

        if ( this.do_indent && this.indent_level.length > 0 )
        {
            var newTextNode = document.createTextNode(this.indent_level);
            range.insertNode(newTextNode);
            range.setStartAfter(newTextNode);

            this.do_indent = false;
        }

        selection.removeAllRanges();
        selection.addRange(range);
    }
}

Some facts about calling these functions:

  • When I uncomment the code that switches the innerHtml content the cursor usually moves to the end of the document instead.
  • If I uncomment the findString() caller the parsing is done but the cursor disappears until I put focus back in the div.
  • If I uncomment both lines the div is behaving as one would expect except, ofcourse, for the parsing.

What is causing this misbehaviour in Chrome while it works in Firefox?

EDIT: More information

I was doing some logging on window.getSelection() and noticed that it contained different information when comparing Chrome and Firefox. Which made the script behave just as it should, but with an argument that's wrong.

The really wierd thing is that when I log window.getSelection() as the very first action of the keyhandler script it behaves like this:

  • Without any modification I get the "wrong" object.
  • With a breakpoint set right under the console.log() directive, the script pauses and the log shows a "correct" object, just the way I want it.

The logger:

console.log(window.getSelection());
// Do keyhandling stuff...
like image 361
Christoffer Avatar asked Nov 15 '22 12:11

Christoffer


1 Answers

Try to make a copy of the original range and add it to the selection rather than the original range at the end of the function, since the range can have dynamic boundaries, and you will end up setting back a "wrong" one.

like image 154
Alexander Pavlov Avatar answered Dec 05 '22 14:12

Alexander Pavlov