0

I have some content generated by a ML model in 100s of paragraphs, each para has some highlighted content.

Sometimes, highlighted data is incorrect, we want the user to select the text and get it highlighted again to correct it.

<p> Contrary to popular belief, <span class='highlighted'>Lorem</span>Ipsum is not simply random text. It has roots in a piece of popular classical Latin literature from 45 <span class='highlighted'>BC</span>, making it over 2000 years old.</p>

In this example, the user might want to select:

  1. Lorem Ipsum
  2. Latin
  3. 45 BC
  4. 2000 years

Below code works for #2 and #4, but I am not able to do it for #1 and #3 as its already highlighted.

I am using this function getSelectionText() to select the text.

$('div.content>p').on('mouseup', function(e){
    var toselected = getSelectionText();
    var para = $(this).html();
    var start = para.indexOf(toselected);
    var end = start + toselected.length;
    var html = para.replace(toselected, '<span class="highlighted">' toselected + '</span>');
    var obj = {"content": $(this).text(), "indices_range":[[start, end]]}
    $.post('/update/<content_id>', data:tojson(obj), function(){        $(e.target).html(html);}) 

});

Also wondering, how can I get the start, end indices if same text occurs twice or multiple times eg. popular.?

Laxmikant
  • 2,046
  • 3
  • 30
  • 44
  • You want the user to be able to unhighlight something previously highlighted? – zer00ne Mar 26 '19 at 20:32
  • "Sometimes, highlighted data is incorrect, we want the user to select the text and get it highlighted." – Richard Uie Mar 27 '19 at 00:52
  • @zer00ne - Indirectly yes, unhighlight highlighted if highlighted is selected, and highlight the entire correct word/phrase. – Laxmikant Mar 27 '19 at 10:20
  • I was creating something similiar and to fully restore / set selection. First every html element have in my code unique id. I set contenteditable to true and for selected text I set background color and turn off contenteditable. parameters to do it startOffset endOffset startID, endID - to correctly restore selection. range.setStart(el, offset); range.setEnd(el, offset); see: https://developer.mozilla.org/en-US/docs/Web/API/range/setStart – Zydnar Mar 27 '19 at 10:30

1 Answers1

1

Use Range and Selection APIs to control selection of text nodes. Instead of using <span>, use <mark> tags.
Reasons to use <mark>

  • 100% semantic
  • It's use is uncommon which means there's very little chance of CSS selector conflicts.
  • By default it already highlights it's content.

Usage: Highlight text with mouse like you would normally. The <mark>s do not nest (that's a good thing). In order to remove a highlighted area, click it using the right mouse button.

const mark = event => {
  const current = event.currentTarget;
  const target = event.target;
  const select = document.getSelection();
  if (event.which === 1) {
    const range = select.getRangeAt(0);
    const text = range.toString();
    const content = range.extractContents();
    const mark = document.createElement('MARK');
    mark.textContent = text;
    range.insertNode(mark);
  } else if (event.which === 3) {
    event.preventDefault();
    if (target.tagName === 'MARK') {
      const text = target.textContent;
      const tNode = document.createTextNode(text);
      target.parentNode.replaceChild(tNode, target);
    }
  }
  select.removeAllRanges();
  current.normalize();
  return false;
}

$(document).on("contextmenu mouseup", mark);
::selection {
  background: tomato;
  color: white;
}
<p> Contrary to popular belief, <mark>Lorem</mark>Ipsum is not simply random text. It has roots in a piece of popular classical Latin literature from 45 <mark>BC</mark>, making it over 2000 years old.</p>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
zer00ne
  • 41,936
  • 6
  • 41
  • 68