开发者

Insert html when the caret was in a content editable div

I want to insert some html in a contenteditable div.

When editin开发者_运维知识库g the content, the user clicks on an icon, a dialog pops and he enters the url & anchor text in the dialog. This causes that the editable div loses its focus and the link is inserted at the beginning of the div, not when the caret was. I tried many things but I'm stuck.

"rte" id of my editable content div

"link_add" id of button in dialog

$('#link_add').click(function (e)
{       
    $('#rte').focus();                  
    document.execCommand('insertHTML', false, 'html content test');         
    close_modal ();
    e.preventDefault();

});

I also tried the solution from set execcommand just for a div, using:

function execCommandOnElement(el, commandName, value)

But this empties the div and just paste the new content.


I take it this is an "inline" dialog (much like StackOverflow's link dialog, for instance), which moves the focus and therefore the selection. The solution seems to be to save and restore the selection. Call getSelection() to get a reference to the selection and save the anchorNode, anchorOffset, focusNode and focusOffset properties and then use collapse(anchorNode, anchorOffset) and extend(focusNode, focusOffset) to restore the selection once you have focused the contenteditable div. (If you're not interested in both nodes you could just collapse(focusNode, focusOffset).)


You need to save and restore the selection. IE for one loses it if the selection is collapsed (i.e. just a caret) when the editable element loses focus. Note that IE < 9 has completely different selection and range objects from other browsers. Here is some code for doing this that will work in all major browsers, including older IE. Note that it won't restore the original direction of the selection, however. If you need to do that, the solution becomes more complicated and can't be done in IE.

var saveSelection, restoreSelection;
if (window.getSelection) {
    // IE 9 and non-IE
    saveSelection = function() {
        var sel = window.getSelection(), ranges = [];
        if (sel.rangeCount) {
            for (var i = 0, len = sel.rangeCount; i < len; ++i) {
                ranges.push(sel.getRangeAt(i));
            }
        }
        return ranges;
    };

    restoreSelection = function(savedSelection) {
        var sel = window.getSelection();
        sel.removeAllRanges();
        for (var i = 0, len = savedSelection.length; i < len; ++i) {
            sel.addRange(savedSelection[i]);
        }
    };
} else if (document.selection && document.selection.createRange) {
    // IE <= 8
    saveSelection = function() {
        var sel = document.selection;
        return (sel.type != "None") ? sel.createRange() : null;
    };

    restoreSelection = function(savedSelection) {
        if (savedSelection) {
            savedSelection.select();
        }
    };
}

Before opening your dialog:

var savedSel = saveSelection();

After closing the dialog:

restoreSelection(savedSel);

Alternatively, if you were doing a lot of selection/range manipulation you could use the selection save/restore module of my Rangy library, but that would be overkill for just this one use.


Probably suggested above wouldnt work properly, because of two reasons: first, need to use window.getSelection().getRangeAt(i).cloneRange(), and there is second, - selection and range are living data and refreshes automatically with user related actions, like new selections and focuses.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜