Вот мой подход к решению вопроса о пользовательских элементах перетаскивания на редактируемые элементы. Большая проблема заключается в том, что невозможно определить смещение текста курсора мыши при наведении курсора на редактируемый элемент. Я попытался сфальсифицировать щелчок мыши, чтобы установить каретку в нужном положении, но это не сработало. Даже если бы это было так, визуально не было бы видно расположение курсора при перетаскивании, а только получилось бы падение.
Поскольку можно привязывать события наведения мыши к элементам, а не к текстовым узлам, можно сделать редактируемый элемент временно недоступным для редактирования. Найдите все элементы и оберните каждый текстовый узел в промежуток, чтобы не нарушать поток текста. Каждому диапазону должно быть присвоено имя класса, чтобы мы могли найти его снова.
После переноса нужно снова найти все завернутые текстовые узлы и обернуть каждый символ другим диапазоном с именем класса, чтобы их можно было найти снова.
Используя делегирование событий, можно добавить событие в основной редактируемый элемент, который будет применять стиль к каждому диапазону символов, который будет отображать каретку, мигающее изображение GIF в качестве фона.
Опять-таки, используя делегирование событий, нужно добавить событие для события «мыши» (событие выпадения) для каждого символа. Теперь можно определить смещение, используя позицию символьного промежутка (смещение) внутри его родителя (обернутый текстовый узел). Теперь можно отменить все переносы, сохранив ссылку на вычисленное смещение и отменив перенос, сохранив ссылку на соответствующий текстовый узел.
Используя объекты диапазона и выделения в браузере, теперь можно установить выделение, используя вычисленное смещение для соответствующего текстового узла, и ввести требуемый HTML-код во вновь установленное выделение (позиция каретки), и так далее!
Ниже приведен фрагмент с использованием jQuery, который найдет текстовые узлы, оберните их:
editElement.find("*:not(.text-node)").contents().filter(function(){
return this.nodeType != 1;
}).wrap("<span class=\"text-node\"/>");
Чтобы найти каждый текстовый узел и обернуть каждый символ, используйте:
editElement.find(".text-node").each(function()
{
var textnode = $(this), text = textnode.text(), result = [];
for (var i = 0; i < text.length; i++) result.push(text.substr(i, 1));
textnode.html("<span class=\"char\">"
+ result.join("</span><span class=\"char\">") + "</span>");
});
Чтобы отменить упаковку:
editElement.find(".text-node").each(function()
{
this.parentNode.replaceChild(document.createTextNode($(this).text()), this);
});
Надеюсь, что этот подход поможет тем, кто сталкивается с аналогичными проблемами