Skip to content Skip to sidebar Skip to footer

Highlight Text Fragments Selected By User Without Nesting Tags

I have a
some test phrase
and I need to allow user to select different fragments of text and highlight them in different colors. Also I need to allow user to

Solution 1:

I think you can start with this. You should thouroughly test it if it satisfy your case. Perhaps you should also refactor it to better fit you needs.

function mark() {

  let selection = document.getSelection();  
  if(selection.type !== 'Range') { return;}

  let pos = window.placeOfSelections;
  
  let ranges = [];      
  let start = 0;
  Array.prototype.forEach.call(pos.childNodes, function(chD)
  {
    ranges.push([start, start + chD.textContent.length, chD.nodeName === 'MARK']);
    start += chD.textContent.length;
  });
    
  let text = pos.textContent;  
  
  let range = selection.getRangeAt(0);  
  
  let firstNode = range.startContainer;
  let lastNode = range.endContainer;
    
  selection.removeAllRanges();
    
  let firstNodeIndex = Array.prototype.findIndex.call(pos.childNodes, node => node === firstNode || node.firstChild === firstNode);
  let lastNodeIndex =  Array.prototype.findIndex.call(pos.childNodes, node => node === lastNode || node.firstChild === lastNode);
  
  let newSelectionStart = ranges[firstNodeIndex][0] + range.startOffset;  
  let newSelectionEnd = ranges[lastNodeIndex][0] + range.endOffset;  
    
  pos.innerHTML = text;  
  
  range.setStart(pos.childNodes[0], newSelectionStart);
  range.setEnd(pos.childNodes[0], newSelectionEnd);
  
  let node = document.createElement('MARK');      
  let cnt = range.extractContents();
  
  node.appendChild(cnt);
  range.insertNode(node);
      
  let marks = ranges.filter(r => r[2]);  
  while(marks.length != 0)
  {
    let startEnd = marks.shift();
    if(startEnd[0]>= newSelectionStart && startEnd[1] <= newSelectionEnd)
    {
      continue;
    }
    
    if(startEnd[0]>= newSelectionStart && startEnd[0] <= newSelectionEnd)
    {
      startEnd[0] = newSelectionEnd;
    }
    else
    if(startEnd[1]>= newSelectionStart && startEnd[1] <= newSelectionEnd)
    {
      startEnd[1] = newSelectionStart;
    }
    else
    if(startEnd[0] <=newSelectionStart && startEnd[1] >= newSelectionEnd)
    { 
      marks.push([newSelectionEnd, startEnd[1]]);
      startEnd[1] = newSelectionStart;
    }
    
    let tnStart = 0, tnEnd = 0;
    let textNode =  Array.prototype.find.call(pos.childNodes, function(tn) 
    {
      tnEnd += tn.textContent.length;
      
      if(tnStart <= startEnd[0] && startEnd[1] <= tnEnd )
      {
        return true;
      }
      
      tnStart += tn.textContent.length ;
    });
    
    range.setStart(textNode, startEnd[0] - tnStart);
    range.setEnd(textNode,  startEnd[1] - tnStart);
    
    node = document.createElement('MARK');    
    node.appendChild(range.extractContents());
    range.insertNode(node);
  }
}

window.placeOfSelections.addEventListener('keyup', mark);
window.placeOfSelections.addEventListener('mouseup', mark);

function unmark(e) {
  var tgt = e.target;
  if ((tgt.tagName === 'MARK' || (e.parentNode && e.parentNode.tagName === "MARK")) && e.ctrlKey) {
    let txt = tgt.textContent;
    tgt.parentNode.replaceChild(document.createTextNode(txt), tgt);
  }
}

window.placeOfSelections.addEventListener('mousedown', unmark);
mark {background-color: #BCE937 ;}
<p id="placeOfSelections">some test phrase</p>

Post a Comment for "Highlight Text Fragments Selected By User Without Nesting Tags"