1

I am trying to get the position of the selected text, replace it with some HTML and then I want to persist the position of the selected text, so that the next time I render the html I want to show the highlight on the selected text

I have some content displayed inside a Div

Now I select the text "scrambled section of De finibus" which is in line 2 and from some offset from the start. I replace this text with the span around the text like :

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>

Now I add styles to this span to highlight the selection. Now what I want to do is to save this position so that the next time the html page is displayed, I want to highlight the same selection. Note that, there might be repetition of the same selected text in some other location, so I don't want to inadvertently highlight the wrong position.

  1. Is there a way I can achieve this?
  2. The text containing Div does not have the property 'contenteditable'
  3. So far what I have is getting the 'clientRects' of the selected text and creating a div and adding style to that div and appending to the body, but I don't want to do that
  4. The HTML for the actual text is generated in the backend using Markup language parser like MarkDown

Edit :

Let me add more details. Like a github wiki , I am displaying the contents of the wiki by parsing the contents and generating the html based on the selected language mode like Markdown/Textile. I want a way to somehow map the selected text to the actual text line number when the page is edited. When the page edit is clicked the contents are shown using codemirror code editor.

Thanks

h-kach
  • 351
  • 2
  • 8
  • 25
  • 1
    Please fix the snippet I made for you - for example by adding an event handler – mplungjan Mar 15 '18 at 08:25
  • @mplungjan Thanks, just corrected the snippet – h-kach Mar 15 '18 at 08:57
  • Downvoter : Please explain.. – h-kach Mar 15 '18 at 10:28
  • @mplungjan do you have any ideas regarding this? – h-kach Mar 17 '18 at 09:31
  • Not more than what you have been given. SO users do expect the poster to have some level of ability to take suggestions and customise the code to their own use rather than implementing all your specs for free. In any case what you are trying to do might be better handled with a diff type tool – mplungjan Mar 17 '18 at 09:36

2 Answers2

0

First, you will have to get the content of your div so after that you can get the position of selected text by using indexOf. Do that before you wrap the selected text in span. Now you will have the index and the length of the selected text, with those informations you can rebuild the selection anytime.

// 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>
h-kach
  • 351
  • 2
  • 8
  • 25
Hank Phung
  • 2,059
  • 1
  • 23
  • 38
  • 1
    It does not give enough information when we have repeated texts inside the div. Please see my addition. The question is how to distinguish between the 2 same texts selection which are at different positions – h-kach Mar 15 '18 at 09:39
  • Also, there might be multiple paragraphs, different kinds of elements, like list – h-kach Mar 15 '18 at 09:55
0

You can also extract the information from selection range range.startOffset and range.endOffset.

update:

You can just pass the selected element as a param, then from there, you will know which node was used. FOr easy, just set a unique id for every element you allow the user to make a selection on.

// 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>
Community
  • 1
  • 1
Hank Phung
  • 2,059
  • 1
  • 23
  • 38
  • How can I use this information to highlight the text again when the page refreshes? I need the line number where the text selection was made. More importantly, there might be multiple paragraphs, other elements too like list, anchor tags etc like a normal page content – h-kach Mar 15 '18 at 10:02
  • Sorry if I was not clear earlier. The text content are converted to html in the backend using Markdown parser. So if we have a content like "Test content here" , this is converted to

    Test content here

    from the backend and simply render this content in a div. So there cannot be unique ids
    – h-kach Mar 15 '18 at 10:20
  • @h-kach you can save the selections into your database by a simple API and load it as JSON into frontend once the page is loaded. After that, you can use javascript to re-produce the selections from JSON data. – Hank Phung Mar 17 '18 at 08:23
  • By 'Selections' , you mean the selected text? Yes, I can save that. But that wont be enough information right? I need the exact position along with the text so that I can re highlight. If I just save the text then if there are similar content in other part of the page then the highlight position will be incorrect – h-kach Mar 17 '18 at 09:30