Більшість відповідей, які ви знайдете при змістовному позиціонуванні курсору, є досить спрощеними, оскільки вони задовольняють лише введення тексту з простим ванільним текстом. Після використання елементів html у контейнері введений текст розбивається на вузли та розподіляється вільно по всій структурі дерева.
Для встановлення позиції курсору у мене є ця функція, яка циклічно обводить всі дочірні текстові вузли в межах наданого вузла і встановлює діапазон від початку початкового вузла до символу chars.count :
function createRange(node, chars, range) {
if (!range) {
range = document.createRange()
range.selectNode(node);
range.setStart(node, 0);
}
if (chars.count === 0) {
range.setEnd(node, chars.count);
} else if (node && chars.count >0) {
if (node.nodeType === Node.TEXT_NODE) {
if (node.textContent.length < chars.count) {
chars.count -= node.textContent.length;
} else {
range.setEnd(node, chars.count);
chars.count = 0;
}
} else {
for (var lp = 0; lp < node.childNodes.length; lp++) {
range = createRange(node.childNodes[lp], chars, range);
if (chars.count === 0) {
break;
}
}
}
}
return range;
};
Потім я викликаю розпорядок роботи з цією функцією:
function setCurrentCursorPosition(chars) {
if (chars >= 0) {
var selection = window.getSelection();
range = createRange(document.getElementById("test").parentNode, { count: chars });
if (range) {
range.collapse(false);
selection.removeAllRanges();
selection.addRange(range);
}
}
};
Range.collapse (false) встановлює курсор в кінець діапазону. Я перевірив це на останніх версіях Chrome, IE, Mozilla та Opera, і всі вони чудово працюють.
PS. Якщо когось цікавить, я отримую поточну позицію курсора за допомогою цього коду:
function isChildOf(node, parentId) {
while (node !== null) {
if (node.id === parentId) {
return true;
}
node = node.parentNode;
}
return false;
};
function getCurrentCursorPosition(parentId) {
var selection = window.getSelection(),
charCount = -1,
node;
if (selection.focusNode) {
if (isChildOf(selection.focusNode, parentId)) {
node = selection.focusNode;
charCount = selection.focusOffset;
while (node) {
if (node.id === parentId) {
break;
}
if (node.previousSibling) {
node = node.previousSibling;
charCount += node.textContent.length;
} else {
node = node.parentNode;
if (node === null) {
break
}
}
}
}
}
return charCount;
};
Код виконує протилежну функцію набору - він отримує поточне window.getSelection (). FocusNode та focusOffset і відраховує назад всі текстові символи, що зустрічаються, поки він не потрапить на батьківський вузол з ідентифікатором контейнера контейнераId. Функція isChildOf перед тим, як запустити, перевіряє, чи підтримуваний вузол насправді є дочірньою частиною наданого parentId .
Код повинен працювати прямо без змін, але я щойно взяв його з розробленого плагіном jQuery, тому зламав пару цього - дайте мені знати, якщо щось не працює!