Вставьте html, когда каретка была в редактируемом содержимом div

Я хочу вставить некоторый html в contenteditable div.

При редактировании содержимого пользователь нажимает на значок, появляется диалоговое окно, и он вводит текст url и anchor в диалоговом окне. Это приводит к тому, что редактируемый div теряет фокус, и ссылка вставлена ​​в начале div, а не когда карет был. Я пробовал много вещей, но я застрял.

"rte" id моего редактируемого контента div

"link_add" id кнопки в диалоговом окне

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

});

Я также попробовал решение от установить execcommand только для div, используя:

function execCommandOnElement(el, commandName, value)

Но это опустошает div и просто вставляет новый контент.

Ответ 1

Я считаю, что это диалоговое окно "inline" (например, диалоговое окно StackOverflow), которое перемещает фокус и, следовательно, выбор. Решение, похоже, заключается в сохранении и восстановлении выбора. Вызовите getSelection(), чтобы получить ссылку на выбор и сохранить свойства anchorNode, anchorOffset, focusNode и focusOffset, а затем используйте collapse(anchorNode, anchorOffset) и extend(focusNode, focusOffset), чтобы восстановить выделение, как только вы сосредоточили контент дела. (Если вас не интересуют оба узла, вы можете просто collapse(focusNode, focusOffset).)

Ответ 2

Вам нужно сохранить и восстановить выбор. IE для одного теряет его, если выбор свернут (т.е. Просто карет), когда редактируемый элемент теряет фокус. Следует отметить, что IE < 9 имеет совершенно разные объекты выбора и диапазона из других браузеров. Вот какой код для этого, который будет работать во всех основных браузерах, включая более старый IE. Однако обратите внимание, что он не восстановит исходное направление выделения. Если вам нужно это сделать, решение становится более сложным и не может быть выполнено в 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();
        }
    };
}

Прежде чем открыть диалог:

var savedSel = saveSelection();

После закрытия диалога:

restoreSelection(savedSel);

В качестве альтернативы, если вы делали много манипуляций по выбору/диапазону, вы могли бы использовать модуль сохранения/восстановления выбора моего Rangy, но это было бы излишним только для этого использования.

Ответ 3

Возможно, предложенное выше не будет работать должным образом из-за двух причин: сначала нужно использовать window.getSelection(). getRangeAt (i).cloneRange(), и есть второй, - выбор и диапазон - это живые данные и автоматически обновляются с помощью связанных с пользователем действий, таких как новые выборы и фокусы.