Contenteditable DIV - как определить, находится ли курсор в начале или конце содержимого

У меня есть contenteditable div, который содержит типичный редактор WYSIWYG html (полужирный, якоря, списки).

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

я возился с диапазонами, но когда вы работаете с html внутри стихии все довольно сложно.

Я надеюсь, что я должен упустить какое-то простое решение.

есть ли относительно простой способ определить это - я открыт для использования библиотеки как стройный.

спасибо!

Edit: я думаю что-то в этом роде:

$('.mycontenteditable').bind('keydown', handle_keydown)

handle_keydown = function(e) {

  range = window.getSelection().getRangeAt(0)
  start_range = document.createRange()
  start_range.selectNodeContents(this.firstChild)
  start_range.collapse(true) // collapse to start
  is_start = start_range.compareBoundaryPoints(Range.START_TO_START,range)
  end_range = document.createRange()
  end_range.selectNodeContents(this.lastChild)
  end_range.collapse(false)
  is_end = end_range.compareBoundaryPoints(Range.END_TO_END,range)
}

Я собираюсь столкнуться с какими-либо странными проблемами с чем-то вроде этого?

2 ответов


Я бы использовал аналогичный подход к вашему, за исключением использования toString() метод Range объектов, а не cloneContents() чтобы избежать ненужных клонирования. Кроме того, в IE text собственность TextRange.

обратите внимание, что это будет иметь проблемы, когда есть начальные и/или конечные разрывы в содержании, потому что toString() метод комплекс работает так же, как textContent свойство узла и учитывает только текстовые узлы, поэтому не принимая во внимание разрывы строк, подразумеваемые <br> или элементы блока. Также CSS не учитывается: например, текст внутри элементов, которые скрыты через display: none включен.

вот пример:

live demo:http://jsfiddle.net/YA3Pu/1/

код:

function getSelectionTextInfo(el) {
    var atStart = false, atEnd = false;
    var selRange, testRange;
    if (window.getSelection) {
        var sel = window.getSelection();
        if (sel.rangeCount) {
            selRange = sel.getRangeAt(0);
            testRange = selRange.cloneRange();

            testRange.selectNodeContents(el);
            testRange.setEnd(selRange.startContainer, selRange.startOffset);
            atStart = (testRange.toString() == "");

            testRange.selectNodeContents(el);
            testRange.setStart(selRange.endContainer, selRange.endOffset);
            atEnd = (testRange.toString() == "");
        }
    } else if (document.selection && document.selection.type != "Control") {
        selRange = document.selection.createRange();
        testRange = selRange.duplicate();

        testRange.moveToElementText(el);
        testRange.setEndPoint("EndToStart", selRange);
        atStart = (testRange.text == "");

        testRange.moveToElementText(el);
        testRange.setEndPoint("StartToEnd", selRange);
        atEnd = (testRange.text == "");
    }

    return { atStart: atStart, atEnd: atEnd };
}

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

handle_keydown = function(e) {
  // Get the current cusor position
  range = window.getSelection().getRangeAt(0)
  // Create a new range to deal with text before the cursor
  pre_range = document.createRange();
  // Have this range select the entire contents of the editable div
  pre_range.selectNodeContents(this);
  // Set the end point of this range to the start point of the cursor
  pre_range.setEnd(range.startContainer, range.startOffset);
  // Fetch the contents of this range (text before the cursor)
  this_text = pre_range.cloneContents();
  // If the text's length is 0, we're at the start of the div.
  at_start = this_text.textContent.length === 0;
  // Rinse and repeat for text after the cursor to determine if we're at the end.
  post_range = document.createRange();
  post_range.selectNodeContents(this);
  post_range.setStart(range.endContainer, range.endOffset);
  next_text = post_range.cloneContents();
  at_end = next_text.textContent.length === 0;
}

все еще не совсем уверен, что есть какие - либо другие крайние случаи, поскольку я не совсем уверен, как это проверить, так как это требует взаимодействия с мышью-вероятно, есть библиотека, чтобы справиться с этим где-то.