Получить выбранную текстовую позицию внутри div и сохранить

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

У меня есть некоторый контент, отображаемый внутри Div

Теперь я выбираю текст «зашифрованный раздел De finibus», который находится в строке 2 и с некоторым смещением от начала. Я заменяю этот текст диапазоном вокруг текста, например:

function textSelection() {
  var sel = window.getSelection();
  var range = sel.getRangeAt(0).cloneRange();
  var markerTextChar = range.extractContents();

  var markerEl, markerId = "sel_" + new Date().getTime() + "_" + Math.random().toString().substr(2);
  markerEl = document.createElement("span");
  markerEl.id = markerId;

  markerEl.appendChild(markerTextChar);

  range.insertNode(markerEl);

  markerEl.style.backgroundColor = ' rgba(246,195,66,0.3)';
  markerEl.style.cursor = 'pointer';

}
<div id='page-view' onmouseup='textSelection()'> In publishing and graphic design, lorem ipsum is a filler text or greeking commonly used to demonstrate the textual elements of a graphic document or visual presentation. Replacing meaningful content with placeholder text allows designers to design the
  form of the content before the content itself has been produced. The lorem ipsum text is typically a scrambled section of De finibus bonorum et malorum, a 1st-century BC Latin text by Cicero, with words altered, added, and removed to make it nonsensical,
  improper Latin.
</div>

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

  1. Есть ли способ добиться этого?
  2. Текст, содержащий Div, не имеет свойства contenteditable.
  3. Пока что у меня есть получение «clientRects» выделенного текста, создание div и добавление стиля к этому div и добавление к телу, но я не хочу этого делать
  4. HTML для фактического текста генерируется в бэкэнде с использованием синтаксического анализатора языка разметки, такого как MarkDown.

Редактировать :

Позвольте мне добавить больше деталей. Как и вики github, я отображаю содержимое вики, анализируя содержимое и генерируя html на основе выбранного языкового режима, такого как Markdown/Textile. Мне нужен способ каким-то образом сопоставить выделенный текст с фактическим номером текстовой строки при редактировании страницы. При нажатии на редактирование страницы содержимое отображается с помощью редактора кода codemirror.

Спасибо


person h-kach    schedule 15.03.2018    source источник
comment
Пожалуйста, исправьте фрагмент, который я сделал для вас, например, добавив обработчик событий   -  person mplungjan    schedule 15.03.2018
comment
@mplungjan Спасибо, только что исправил фрагмент   -  person h-kach    schedule 15.03.2018
comment
Downvoter: Пожалуйста, объясните..   -  person h-kach    schedule 15.03.2018
comment
@mplungjan у тебя есть идеи по этому поводу?   -  person h-kach    schedule 17.03.2018
comment
Не больше, чем вам дали. Пользователи SO действительно ожидают, что плакат будет иметь некоторый уровень способности принимать предложения и настраивать код для собственного использования, а не реализовывать все ваши спецификации бесплатно. В любом случае то, что вы пытаетесь сделать, может быть лучше обработано с помощью инструмента типа diff.   -  person mplungjan    schedule 17.03.2018


Ответы (2)


Во-первых, вам нужно будет получить содержимое вашего div, чтобы после этого вы могли получить позицию выделенного текста, используя indexOf. Сделайте это перед переносом выделенного текста в span. Теперь у вас будет индекс и длина выделенного текста, с этой информацией вы сможете восстановить выделение в любое время.

// extract page content first because content will be changed after a few selection.
var page_content = document.getElementById('page-view').innerText;

function textSelection() {
  var sel = window.getSelection();
  var range = sel.getRangeAt(0).cloneRange();
  var markerTextChar = range.extractContents();

  var selectedIndex = page_content.indexOf(markerTextChar.textContent);
  console.log("selected from ", selectedIndex, "length: ", markerTextChar.textContent.length)
  var markerEl, markerId = "sel_" + new Date().getTime() + "_" + Math.random().toString().substr(2);
  markerEl = document.createElement("span");
  markerEl.id = markerId;

  markerEl.appendChild(markerTextChar);

  range.insertNode(markerEl);

  markerEl.style.backgroundColor = ' rgba(246,195,66,0.3)';
  markerEl.style.cursor = 'pointer';

}
<div id='page-view' onmouseup='textSelection()'> In publishing and graphic design, lorem ipsum is a filler text or greeking commonly used to demonstrate the textual elements of a graphic document or visual presentation. Replacing meaningful content with placeholder text allows designers to design the
  form of the content before the content itself has been produced. The lorem ipsum text is typically a scrambled section of De finibus bonorum et malorum, a 1st-century BC Latin text by Cicero, with words altered, added, and removed to make it nonsensical,
  improper Latin.
  
  demonstrate the textual
</div>

person Hank Phung    schedule 15.03.2018
comment
Это не дает достаточно информации, когда мы повторяем тексты внутри div. Пожалуйста, смотрите мое дополнение. Вопрос в том, как отличить два одинаковых текста, которые находятся на разных позициях. - person h-kach; 15.03.2018
comment
Кроме того, может быть несколько абзацев, различные типы элементов, например, список. - person h-kach; 15.03.2018

Вы также можете извлечь информацию из диапазона выбора range.startOffset и range.endOffset.

Обновить:

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

// extract page content first because content will be changed after a few selection.
var page_content = document.getElementById('page-view').innerText;

function textSelection(element) {
  console.log('selected on', element.id);
  var sel = window.getSelection();
  //console.log(sel);
  var range = sel.getRangeAt(0).cloneRange();
  console.log("from", range.startOffset, "to", range.endOffset);
  var markerTextChar = range.extractContents();

  var markerEl, markerId = "sel_" + new Date().getTime() + "_" + Math.random().toString().substr(2);
  markerEl = document.createElement("span");
  markerEl.id = markerId;

  markerEl.appendChild(markerTextChar);

  range.insertNode(markerEl);

  markerEl.style.backgroundColor = ' rgba(246,195,66,0.3)';
  markerEl.style.cursor = 'pointer';

}
<div id='page-view' onmouseup='textSelection(this)'> In publishing and graphic design, lorem ipsum is a filler text or greeking commonly used to demonstrate the textual elements of a graphic document or visual presentation. Replacing meaningful content with placeholder text allows designers to design the
  form of the content before the content itself has been produced. The lorem ipsum text is typically a scrambled section of De finibus bonorum et malorum, a 1st-century BC Latin text by Cicero, with words altered, added, and removed to make it nonsensical,
  improper Latin. demonstrate the textual
</div>

person Hank Phung    schedule 15.03.2018
comment
Как я могу использовать эту информацию, чтобы снова выделить текст при обновлении страницы? Мне нужен номер строки, где был сделан выбор текста. Что еще более важно, может быть несколько абзацев, другие элементы, такие как список, теги привязки и т. Д., Как обычное содержимое страницы. - person h-kach; 15.03.2018
comment
Извините, если я не был ясен ранее. Текстовое содержимое преобразуется в html в бэкенде с помощью парсера Markdown. Таким образом, если у нас есть контент, например Test content here , он преобразуется в ‹p›Test content here‹/p› из бэкенда и просто отображает этот контент в div. Так что не может быть уникальных идентификаторов - person h-kach; 15.03.2018
comment
@h-kach, вы можете сохранить выбор в своей базе данных с помощью простого API и загрузить его как JSON во внешний интерфейс после загрузки страницы. После этого вы можете использовать javascript для повторного создания выборок из данных JSON. - person Hank Phung; 17.03.2018
comment
Под «Выборкой» вы имеете в виду выделенный текст? Да, я могу сохранить это. Но этой информации будет недостаточно, верно? Мне нужна точная позиция вместе с текстом, чтобы я мог повторно выделить. Если я просто сохраню текст, то если в другой части страницы будет похожий контент, то позиция выделения будет неправильной. - person h-kach; 17.03.2018