开发者

how to highlight user selected text within a piece of text which has already been highlighted?

开发者 https://www.devze.com 2023-01-19 06:25 出处:网络
I have a page where I am displaying some text in a div and I need to highlight this text in certain parts. I have done this by surrounding the text I need to highlight with atag and appropriate css st

I have a page where I am displaying some text in a div and I need to highlight this text in certain parts. I have done this by surrounding the text I need to highlight with a tag and appropriate css styling. E.g. <div> My text will look like this with <span class="highlight">highlighted bits</span> in it. </div>

This works fine. However, another requirement fo开发者_如何学Gor this page is that the user must be able to select texts, click a button, and the selected text must be highlighted too.

The problem I have is when trying to identify the range of the selected text to grab (using window.getSelection.getRangeAt(0)), this gives me the range which resets after every <span> tag in the text, not from the beginning of the text.


For those who would like to know in the future this is how I did it:

jQuery.fn.highlight = function(startOffset,endOffset,type) {
 function innerHighlight(node, startOffset,endOffset) {
     var calledStartOffset = parseInt(startOffset);
     var startOffsetNode=getChildNodeForOffset(node,parseInt(startOffset));
     var endOffsetNode=getChildNodeForOffset(node,parseInt(endOffset));
     startOffset = resizeOffsetForNode(startOffsetNode,parseInt(startOffset));

     if (startOffsetNode == endOffsetNode){
         endOffset = resizeOffsetForNode(endOffsetNode,parseInt(endOffset));
         highlightSameNode(startOffsetNode, parseInt(startOffset),parseInt(endOffset),type,calledStartOffset);
     } else {
         highlightDifferentNode(startOffsetNode,endOffsetNode,parseInt(startOffset),parseInt(endOffset),type,calledStartOffset);
     }
 }
 return this.each(function() {
     innerHighlight(this, startOffset,endOffset);
 });
};

function resizeOffsetForNode(offsetNode,offset){
 if (offsetNode.id >= 0){
     offset = parseInt(offset)-parseInt(offsetNode.id);
 } else if (offsetNode.previousSibling != null && offsetNode.previousSibling.id > 0){
     offset = parseInt(offset)-parseInt(offsetNode.previousSibling.id)-parseInt(offsetNode.previousSibling.textContent.length);
 }  
 return offset;
}

function getChildNodeForOffset(testNode,offset) {
    if (testNode.nodeType == 1 && testNode.childNodes && !/(script|style)/i.test(testNode.tagName)) {
       var offsetNode=null;
       var currentNode;
       for (var i = 0; i < testNode.childNodes.length; ++i) {
           currentNode=testNode.childNodes[i];
           if (currentNode.id >= 0 && parseInt(currentNode.id) <= parseInt(offset) && ((parseInt(currentNode.id) + parseInt(currentNode.textContent.length)) >= parseInt(offset))){
               offsetNode = currentNode;
               break;
           } else if (currentNode.id >= 0 && parseInt(currentNode.id) > parseInt(offset)){
               offsetNode = currentNode.previousSibling;
               break;
           }
        }
       if (offsetNode==null){
           offsetNode = testNode.childNodes[testNode.childNodes.length-1]; 
       }
       return offsetNode;
    }
}

function highlightSameNode(node, startOffset,endOffset,type,calledStartOffset) {
   var skip = 0;
   if (node.nodeType == 3) {
   if (startOffset >= 0) {
    var spannode = document.createElement('span');
    spannode.className = 'entity '+ type;
    spannode.id=calledStartOffset;
    var middlebit = node.splitText(startOffset);
    var endbit = middlebit.splitText(endOffset-startOffset);
    var middleclone = middlebit.cloneNode(true);
    spannode.appendChild(middleclone);
    middlebit.parentNode.replaceChild(spannode, middlebit);
   }
  } else if (node.nodeType == 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) {
    var childnode = node.childNodes[0];
    highlightSameNode(childnode, startOffset,endOffset,type,calledStartOffset);
  }
}

function highlightDifferentNode(startnode, endnode, startOffset,endOffset,type,calledStartOffset) {
   var skip = 0;
   if (startnode.nodeName == "#text") {
       if (startOffset >= 0) {
            var spannode = document.createElement('span');
            spannode.className = 'entity '+ type;
            spannode.id=calledStartOffset;
            var endbit = node.splitText(startOffset);
            var endclone = endbit.cloneNode(true);
            spannode.appendChild(endclone);
            endbit.parentNode.replaceChild(spannode, endbit);
       }
   } else if (startnode.nodeName == "SPAN") {
       if (startOffset >= 0) {
            var spannode = document.createElement('span');
            spannode.className = 'entity '+ type;
            spannode.id=calledStartOffset;
            var endTextbit = startnode.childNodes[0].splitText(startOffset);
            spannode.appendChild(endTextbit);
            startnode.parentNode.insertBefore(spannode, startnode.nextSibling);
       }
   }
   var currentTestNode=startnode.nextSibling;
   while (currentTestNode!=endnode){
       if (currentTestNode.nodeName == "#text") {
            var spannode = document.createElement('span');
            spannode.className = 'entity '+ type;
            spannode.id=parseInt(currentTestNode.previousSibling.id)+parseInt(currentTestNode.previousSibling.textContent.length);
            var currentNodeClone=currentTestNode.cloneNode(true);
            spannode.appendChild(currentNodeClone);
            endbit.parentNode.replaceChild(spannode, currentTestNode);
       } else if (currentTestNode.nodeName == "SPAN") {
            currentTestNode.className = 'entity overlap';
       }
       currentTestNode=currentTestNode.nextSibling;
   }
   var previousNodeEnd = parseInt(endnode.previousSibling.id)+parseInt(endnode.previousSibling.textContent.length);
   var spannode = document.createElement('span');
   spannode.className = 'entity '+ type;
   spannode.id=previousNodeEnd;
   if (endnode.nodeName == "#text") {
       if (endOffset >= 0) {
            //end offset here is the original end offset from the beginning of the text, not node
            var unwantedbit = endnode.splitText(parseInt(endOffset)-parseInt(previousNodeEnd));
            var endclone = endnode.cloneNode(true);
            spannode.appendChild(endclone);
            endnode.parentNode.replaceChild(spannode, endnode);
       }
   } else if (endnode.nodeName == "SPAN") {
       if (endOffset >= 0) {
            var wantTextbit = endnode.childNodes[0].splitText(parseInt(endOffset)-parseInt(previousNodeEnd));
            spannode.appendChild(wantTextbit);
            wantTextbit.parentNode.parentNode.insertBefore(spannode, endnode);
       }
   }
   if (startnode.textContent.length < 1){
    startnode.parentNode.removeChild(startnode);
   }
   if (endnode.textContent.length < 1){
       endnode.parentNode.removeChild(endnode);
   }
}

jQuery.fn.removeHighlight = function() {
 return this.find("span.entity").each(function() {
  this.parentNode.firstChild.nodeName;
  with (this.parentNode) {
   replaceChild(this.firstChild, this);
   normalize();
  }
 }).end();
};

function contains(a, b){
      return a.contains ? a != b && a.contains(b) : !!(a.compareDocumentPosition(b) & 16);
} 
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号