在范围内创建、设置样式

Creating, setting styles on a range

我正在尝试自动检测页面上的地址并在找到的地方添加 class“地址”。

var rangyPatternApplier = function(element, pattern, style) {
  var innerText = element.innerText;
  var matches = innerText.match(pattern);
  if (matches) {
    for (var i = 0; i < matches.length; i++) {
      console.log("Match: " + matches[i]);
      var start = innerText.indexOf(matches[i]);
      var end = start + matches[i].length;

      let range = document.createRange();
      var start = innerText.indexOf(matches[i]);
      console.log('inner text: ' + innerText);
      console.log('start: ' + start);
      console.log('starts with: ' + innerText.substring(start));
      var end = start + matches[i].length;
      var startNode = element.childNodes[0];
      var endNode = startNode;
      while (startNode.nodeValue.length < start) {
        start -= startNode.nodeValue.length;
        end -= startNode.nodeValue.length;
        startNode = startNode.nextSibling;
        endNode = startNode;
        if (startNode == null) {
          error.reportError("Just wrong in Sections.rangyPatternApplier");
          return;
        }
      }
      while (endNode.nodeValue.length < end) {
        end -= endNode.nodeValue.length;
        if (endNode.nextSibling) endNode = endNode.nextSibling;
        while (!endNode.nodeValue) {
          endNode = endNode.childNodes[0];
        }
        if (endNode == null) {
          error.reportError("Just wrong in Sections.rangyPatternApplier");
        }
      } 
      range.setStart(startNode, start);
      console.log("starts with: " + startNode.nodeValue.substring(start));
      range.setEnd(endNode, end);

          var applier  = rangy.createClassApplier(style, {
                    elementTagName: "span",
                    elementProperties: {
                    },
          });
      window.getSelection().addRange(range);
      applier.toggleSelection();
    }
  }
}

调用方式:

  $("P").each(function () {
    rangyPatternApplier(this, new RegExp("\d+\s[A-z]+\s[A-z0-9]+\s(Street|St|Avenue|Av|Ave|Road|Rd)", "mgi"), "Address");
  });

关于段落中的文字:

If the income renders the household ineligible for CA/CILOCA, the case will be systemically referred to the Administration for Children s Services Transitional Child Care Unit at 109 East 16th Street 3rd floor for evaluation of Transitional Child Care (TCC) benefits. The TCC Worker determines eligibility for up to 12 months of TCC benefits.

正则表达式正在运行,正在应用地址 class。我将范围应用于 window 选择,因为当仅应用于范围时,rangy 中似乎存在错误(我收到一条错误消息)。但不知何故,当我创建范围时,跨度出现在地址开始前 5 个字符并提前 9 个字符结束。提前结束的部分可能是由于第 16 街“th”周围的标签。但为什么范围比我在 innerText 中找到的范围早 5 个字符?

天哪,这很痛苦,但我让它工作了。在这里添加我的解决方案,希望至少有一些人不必经历在我看来应该更“built-in”的事情

//nextTextNode is for getting the next text node from the DOM

function nextTextNode(node) {
  if (node.nodeType == 1) { //element
    while (node.nodeType != 3) {
      node = node.firstChild;
    }
    return node;
  }
  if (node.nodeType == 3) { //text node
    if (node.nextSibling) {
      if (node.nextSibling.nodeType == 3) {
        return node.nextSibling;
      } else {
        return nextTextNode(node.nextSibling);
      }
    } else {
      while (!node.nextSibling) {
        node = node.parentNode;
        if (!node) return null;
      }
      if (node.nextSibling.nodeType == 3) {
        return node.nextSibling;
      } else {
        return nextTextNode(node.nextSibling);
      }
    }
  } else {
    throw new Error("nextTextNode: Node is either null, not connected to the DOM, or is not of node type 1 or 3");
  }
}

然后创建范围。与 element.innerText 相比,文本节点具有额外的换行符和 space 字符。在下面的函数中,我跟踪了额外字符的数量和总字符数,以跟踪 innerText 和 node.nodeValue 之间的不一致以及它“在”中的字符数。

function createRangeForString(startElement, text) {
  var extras = 0;
  var innerText = startElement.innerText;
  var start = innerText.indexOf(text);
  if (start === -1) throw new Error ("createRangeForString. text: " + text + " not found in startElement");
  var textNode = nextTextNode(startElement);
  var totalCharsSeen = 0;
  var range = document.createRange();
  for (var i = 0; i < start; i++) { // I don't think I have to add extras in limit for i. Is already included
    if ((i + extras) - totalCharsSeen >= textNode.nodeValue.length) { //check if textNode is long enough
      totalCharsSeen += textNode.nodeValue.length;
      textNode = nextTextNode(textNode);
    }
    while (textNode.nodeValue.charAt(i + extras - totalCharsSeen) == "\n") {
      extras++;
    }
    while (textNode.nodeValue.charAt(i + extras - totalCharsSeen) == " " && innerText.charAt(i) != " ") {
      extras++;
    }
  }
  range.setStart(textNode, i + extras - totalCharsSeen);

  var end = start + text.length;

  for (var i = start + 1; i < end; i++) { // I don't think I have to add extras in limit for i. Is already included
    if ((i + extras) - totalCharsSeen >= textNode.nodeValue.length) { //check if textNode is long enough
      totalCharsSeen += textNode.nodeValue.length;
      textNode = nextTextNode(textNode);
    }
    while (textNode.nodeValue.charAt(i + extras - totalCharsSeen) == "\n") {
      extras++;
    }
    while (textNode.nodeValue.charAt(i + extras - totalCharsSeen) == " " && innerText.charAt(i) != " ") {
      extras++;
    }
  }
  range.setEnd(textNode, i + extras - totalCharsSeen);
  return range;
}