Сбросить содержимое редактируемой позиции каретки - PullRequest
4 голосов
/ 11 апреля 2020

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

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

Ниже приведен код, который я придумал.

html

<div id="editor" contentEditable="true" onkeyup="resetPosition(this)"></div>

<input type="text" onkeyup="resetPosition(this)" />

js

function getPos(e) {
    // for contentedit field
  if (e.isContentEditable) {
    e.focus()
    let _range = document.getSelection().getRangeAt(0)
    let range = _range.cloneRange()
    range.selectNodeContents(e)
    range.setEnd(_range.endContainer, _range.endOffset)

    return range.toString().length;
  }
  // for texterea/input element
  return e.target.selectionStart
}


function setPos(pos, e) {
  // for contentedit field
  if (e.isContentEditable) {
      e.focus()
      document.getSelection().collapse(e, pos);
      return
  }
  e.setSelectionRange(pos, pos)
}

function resetPosition(e) {
  if(e.isContentEditable) {
  let currentPosition = getPos(e);
  e.innerHTML=e.innerHTML.replace(/[0-9]/g, "a");
  setPos(currentPosition, e);

  return;
}

  e.value = e.value.replace(/[0-9]/g, "a");
  setPos(currentPosition, e);

}     

Это прекрасно работает для ввода текста, но не для contentEditable divs.

Когда я набираю что-то вроде function, я получаю otincfun.

ОБНОВЛЕНИЕ: Мне удалось исправить функцию setPos, изменив эту строку с document.getSelection().collapse(e, pos); на document.getSelection().collapse(e.firstChild, pos);, но возникла новая ошибка.

Когда я нажимаю клавишу ВВОД, каретка возвращается к первой строке и первому символу. Пожалуйста, как мне исправить?


Ниже находится ссылка на скрипку

https://jsfiddle.net/oketega/bfeh9nm5/35/

Спасибо.

1 Ответ

2 голосов
/ 18 апреля 2020

Проблемы

document.getSelection().collapse(element, index) сворачивает курсор на дочерний узел, на который указывает index, а не на индекс символа.

Мне удалось исправить setPos функция, изменяя эту строку с document.getSelection().collapse(e, pos); на document.getSelection().collapse(e.firstChild, pos);

Это будет работать, если вы заменяете только символы, но если вы создаете подсветку синтаксиса, вам нужно будет заключать символы в span элементов для их оформления. e.firstChild тогда будет устанавливать позицию индекса только в первом дочернем элементе e, исключая последнего span

Еще одна вещь, которую следует учитывать, это то, что вы можете захотеть автозаполнение определенных символов. Положение каретки перед манипулированием текстом может не совпадать с позицией после этого.

Решение

Я рекомендую создать элемент <span id="caret-position"></span>, чтобы отслеживать, где находится каретка.

Это будет работать так:

function textChanged(element) {
    // 1
    const text = setCursorMarker(element.innerText, element);

    // 2
    const html = manipulate(text);
    element.innerHTML = html;

    // 3
    const index = findCursorIndex(element);
    document.getSelection().collapse(element, index)
}

  1. Каждый раз, когда пользователь печатает, вы можете получить текущую позицию каретки и вставить туда элемент #caret-position.
  2. Перезаписать существующий html с выделенным синтаксисом текста
  3. Узнайте, где находится #caret-position и поместите туда курсор.

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

Пример

Здесь есть рабочая скрипка js: https://jsfiddle.net/Vehmloewff/0j8hzevm/132/

Известная проблема: после того, как вы дважды нажмете Enter, он теряет направление к положению каретки. Я не совсем уверен, почему это так.

...