Marking text in a html document

不羁的心 提交于 2019-12-05 06:39:41
Anamika Shrivastava

If you want to highlight text in a document then this plug-in will be helpful for you.

https://github.com/julmot/jquery.mark

Example fiddle: https://jsfiddle.net/julmot/vpav6tL1/

Usage is as simple as:

$(".context").mark("keyword");

In principle you have to:

  • split the documents into words
  • identify the first word by parent element
  • skip the offset
  • mark matching words

Making changes at word level will prevent you from breaking the markup. I added a working example bellow. However I am not sure that it will work with all browsers.

Some of the functions like mergeWords are not used in the example but I included them because they can prove useful.

var splittedToWords = false;

function ignore(el) {
  return (el.nodeType == 8) || 
    (el.tagName == "BLOCKQUOTE") ||
    (el.tagName == "SCRIPT") ||
    (el.tagName == "DIV") ||
    (!el.hasChildNodes() && el.textContent.match(/\S+/) == null);
}

function splitToWords(el) {
  if (el.hasChildNodes()){
    var count = el.childNodes.length;
    for (var i = count - 1; i >= 0; i--) {
      var node = el.childNodes[i];
      if (!ignore(node))
        splitToWords(node);
    }
  }
  else {	//text node
    var words = el.textContent.match(/(\S+\s*)/g) || [];
    var count = words.length;
    var parentNode = el.parentNode;
    for (var i = 0; i < count; i++) {
      var wordNode = document.createElement("span");
      wordNode.className = "word";
      wordNode.innerText = words[i];

      wordNode.setAttribute["word-index"] = i;

      parentNode.insertBefore(wordNode, el);
    }
    parentNode.removeChild(el);
  }
  splittedToWords = true;
}

function unwrap(element) {
  var next = element.nextSibling;
  var parent = element.parentNode;
  parent.removeChild(element);
  var current;
  var frag = document.createDocumentFragment();
  do {
    current = element.nextSibling;
    frag.insertBefore(element, null);
  } while ((element = current));
  parent.insertBefore(frag, next);
}

function mergeWords(el) {
  var words = document.getElementsByClassName("word");
  count = words.length;
  if (count > 0)
    for (var i = 0; i < count; i++)
      uwrap(words[i]);
}

function markWord(el, pos, len) {
  var text = el.innerText;
  var pre = text.substr(0, pos);
  var mark = '<mark>' + text.substr(pos, len) + '</mark>';
  var post = text.substring(pos + len, text.length);
  el.innerHTML = pre + mark + post;
}

function mark(element, offset, text) {
  if (!splittedToWords) {
    var body = document.body;
    splitToWords(body);
  }

  var words = document.getElementsByClassName("word");
  var wordsCount = words.length;
  var first = null;
  for (var i = 0; i < wordsCount; i++ ) {
    if (words[i].parentElement == element) {
      first = i;
      break;
    }
  }

  done = false;
  var i = first;
  var pos = 0;

  do {
    var word = words[i];
    var wordLength = word.innerText.length;

    if (offset > pos + wordLength) {
      i++;
      pos += wordLength;
      continue;
    }
    else {
      done = true;
    }
  } while (!done);

  var tWords = text.match(/(\S+\s*)/g) || [];
  var tWordsCount = tWords.length;
  if (tWordsCount == 0)
    return;

  for (var ti = 0; ti < tWordsCount; ti++) {
    var wordEl = words[i++];
    var word = wordEl.innerText;
    var tWord = tWords[ti].trim();
    var pos = word.indexOf(tWord);

    if (pos == -1)
      continue;	//or maybe return.

    markWord(wordEl, pos, tWord.length);
  }

}
var e = document.getElementById("e");

//do the magic
mark(e, 1, 'irst paragraph Second');
<h1>Some title</h1>
<p id="e">First paragraph</p>
<p>Second paragraph</p>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!