В статье описывается опыт создания текстового поля с возможностью вставки смайлов, проблемы которые мне встретились и их решения, а так же ссылка на репозиторий с готовым jQuery плагином. Если вам интересно, прошу под кат.
Во время разработки моего первого проекта мне поставили задачу, создать чат со смайлами. Основной функционал чата был готов, но приступив к смайлам у меня возникла проблема, я не мог вставить смайл в текущую позицию курсора, получалось только в начало или конец текстового поля. Опыта у меня было ноль, как в программировании так и в поиске нужной информации, поэтому не смог найти ничего «работоспособного» и тем более готовых решений. Помучавшись две-три недели я сдался и пришлось сказать ненавистные мне слова «Я не могу это реализовать».
Прошло уже около трех лет и недавно у моего коллеги встала та же задача, он спросил меня, как это можно сделать. Воспоминания о неудаче вдруг хлынули волной и мне захотелось решить мою давнюю неосуществимую задачу.
Поиски готового решения снова закончились безрезультатно, но с документацией было уже намного лучше, узнав о document.getSelection() тут же кинулся писать код и конечно же встретил еще несколько проблем и как всегда на одну из них ушло больше всего времени.
Нашел примерно такое решение
if (window.getSelection) {
var sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
var range = window.getSelection().getRangeAt(0);
range.insertNode(document.createTextNode(text));
}
}
Что было очевидно, при клике на смайл фокус переходил к нему и нужный нам контент вставлялся в него, а не в наше текстовое поле. Решение было простым, запретить фокусироваться на блоке с эмоциями.
$emojiContainer.attr({
unselectable: 'on',
onselectstart: 'return false;',
onmousedown: 'return false;'
});
Вторая проблема оказалась для меня посложнее, смайл вставлялся после курсора, но сам курсор не двигался вперед в связи с чем каждая последующая эмоция была впереди предыдущей.
После прочтения замечательной статьи от bur все немного прояснилось.
Написал функцию которая вставляет курсор после элемента, решение оказалось простым.
function SetCursorAfterElement(element)
{
var selection = window.getSelection();
selection.removeAllRanges();
var range = document.createRange();
range.setStartAfter(element);
selection.addRange(range);
}
На данный момент это jQuery плагин и поддерживается браузерами IE9+. В ближайших планах переписать код без использованием jQuery и с поддержкой старых браузеров, да и код написан не продумано, без особой гибкости. Буду рад если кому то сэкономил время.
Автор: kwofy