Rangy + ContentEditable + Установить каретку и заменить выбор - PullRequest
4 голосов
/ 13 декабря 2011

У меня есть следующий фрагмент кода для установки каретки с заданным индексом index

var el = $("#subjectMessage"), index = 9 ;
var range = rangy.createRange();
range.setStart(el[0].childNodes[0], index);
range.collapse(true);
var sel = rangy.getSelection();
sel.setSingleRange(range);

Проблемы возникают, когда я добавляю элементы ввода в contentEditable div, я больше не могу последовательно устанавливать курсор в нужной позиции.

Я хочу рассматривать эти входные данные как одну позицию в div (как если бы они были просто одним символом).

Кроме этого, мне также понадобился бы аналогичный код для замены выделения в этом contentEditable div на мой собственный текст, и я не очень знаком ( вообще ) с ранги в понять, как сделать эту работу ...

Вся помощь приветствуется!

Вот скрипка, с которой можно играть:

http://jsfiddle.net/ee93P/

1 Ответ

7 голосов
/ 13 декабря 2011

API выбора и диапазона Rangy являются надмножествами стандартных API выбора и диапазона DOM, поэтому применяется документация из таких мест, как MDN ( Диапазон , Выбор ).

Проблема, с которой вы столкнулись, состоит в том, что границы диапазона выражаются в виде смещения внутри содержащего DOM-узла.Например, в приведенном ниже HTML-коде, где символ каретки обозначен как символ канала:

<p>Foo<br>b|ar</p>

... Начальная и конечная границы диапазона каретки идентичны и установлены на смещение 1 на панели «текстового узла»Msgstr ".

Если вы хотите установить позицию в качестве смещения в текстовом содержимом элемента <p>, вам потребуется выполнить некоторый обход DOM.Я написал реализацию этого на основе другого моего ответа .Это наивная реализация: она не учитывает какой-либо текст, который может быть сделан невидимым (например, CSS или внутри элемента или, например) и может иметь расхождения в браузере (IE и все остальное) с переносами строк, и принимаетне учитывается свернутый пробел (например, 2 или более последовательных пробела, свернутых в одно видимое пространство на странице).Это сложно сделать правильно, поэтому я не рекомендую это делать.Я планирую написать текстовый модуль для Rangy, который будет обрабатывать все это, но я еще не начал его.

http://jsfiddle.net/ee93P/2/

Код:

function setCaretCharIndex(containerEl, index) {
    var charIndex = 0, stop = {};

    function traverseNodes(node) {
        if (node.nodeType == 3) {
            var nextCharIndex = charIndex + node.length;
            if (index >= charIndex && index <= nextCharIndex) {
                rangy.getSelection().collapse(node, index - charIndex);
                throw stop;
            }
            charIndex = nextCharIndex;
        }
        // Count an empty element as a single character. The list below may not be exhaustive.
        else if (node.nodeType == 1
                 && /^(input|br|img|col|area|link|meta|link|param|base)$/i.test(node.nodeName)) {
            charIndex += 1;
        } else {
            var child = node.firstChild;
            while (child) {
                traverseNodes(child);
                child = child.nextSibling;
            }
        }
    }

    try {
        traverseNodes(containerEl);
    } catch (ex) {
        if (ex != stop) {
            throw ex;
        }
    }
}
...