adit
adit

Reputation: 33674

contenteditable div issue when restore/saving selection

I have a div (#recommendTextArea) which is editable, in which that I try to modify the innerHTML of this div when a user clicks on a list (this is called .display_box), the function looks like this. Basically it appends a span to the innerHTML of the div and then it hides the friendList, upon hiding it also tries to restoreTheSelection and before appending the extra span I called saveSelection.

$(".display_box").live("click",function() 
    {
        selRange = saveSelection();
        console.log(selRange);
        var username = $(this).attr('title');
        var old = $("#recommendTextArea").html();
        var content = old.replace(word, " "); //replacing @abc to (" ") space
        var E ="<span contenteditable='false'>"+ username + "</span> ";
        content = [content.slice(0, start), E, content.slice(start)].join('');
        $("#recommendTextArea").html(content);
        $("#friendsList").hide(function(){
            restoreSelection(selRange);
        });
    });

I have the following function to restore and save selection:

function saveSelection() {
    if (window.getSelection) {
        sel = window.getSelection();
        if (sel.getRangeAt && sel.rangeCount) {
            return sel.getRangeAt(0);
        }
    } else if (document.selection && document.selection.createRange) {
        return document.selection.createRange();
    }
    return null;
}

function restoreSelection(range) {
    if (range) {
        if (window.getSelection) {
            sel = window.getSelection();
            sel.removeAllRanges();
            sel.addRange(range);
        } else if (document.selection && range.select) {
            range.select();
        }
    }
}

However this doesn't work as expected, the cursor is no where to be seen when I click on an item. What am I doing wrong here?

Upvotes: 1

Views: 2110

Answers (1)

Damyan Petev
Damyan Petev

Reputation: 1635

You have a few issues:

1) Timing: the "click" event is way too late to grab selection (ALWAYS debug this, it's super easy to see the editable DIV has long lost focus and selection by that time). Use "mousedown" instead.

2) You can't store selection range like this - changing the selection context (in your case the innerHTML of the commonAncestorContainer) will wipe that range (for some reason even cloned range objects get wiped for me). If you manage to get a copy (via jQuery.extend for example) it will become invalid because the text node inside is not guaranteed to remain the same. My best guess is to go with storing start/end offset and if needed the related nodes as required by the range. Restore the range properties after the HTML is modified.

3) As with 1) focus is crucial to maintain selection, so that click on the list.. make sure you prevent the default before exiting the handler so focus and you new selection will remain in the DIV.

Can't figure out the exact use case from your code but this is my test sample and you can adjust from here as needed: http://jsfiddle.net/damyanpetev/KWDf6/

Upvotes: 2

Related Questions