代码之家  ›  专栏  ›  技术社区  ›  ControlAltDel

创建、设置范围上的样式

  •  0
  • ControlAltDel  · 技术社区  · 4 年前

    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.
    

    regex正在工作,address类正在应用。我将范围应用于窗口选择,因为当仅应用于范围时,rangy中似乎有一个bug(我收到一条错误消息)。但不知何故,当我创建范围时,跨度出现在地址开始之前5个字符,并提前9个字符结束。提前结束的部分可能是因为在16街的“th”附近的标签。但是为什么范围比我在innerText中找到的要早5个字符呢?

    0 回复  |  直到 4 年前
        1
  •  1
  •   ControlAltDel    4 年前

    //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");
      }
    }
    

    然后创建范围。与相比,文本节点具有额外的换行符和空格字符元素.innerText. 在下面的函数中,我跟踪额外字符数和总字符数,以跟踪innerText和node.node值有多少个“in”字。

    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;
    }