动态突出显示符合特定条件的单词 [英] Dynamically Highlight Words That Fit a Specific Criteria

查看:45
本文介绍了动态突出显示符合特定条件的单词的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我之前曾发布过类似的问题,但这是太静态了.现在,我想进行更改以使代码具有动态性.

I have posted a similar question before, but it was too static. Now I want to make changes such that the code is dynamic.

目标

我想要以"t"开头的单词在用户输入时突出显示.如果单词不是以"t"开头,则返回"0".然后什么都不做.基本上,用户将具有正常的打字体验,但是"t"字样不会被用户接受.单词将突出显示.

I want words that begin with "t" to be highlighted as a user types. If the word does not begin with "t" then do nothing. Basically, the user would have a normal typing experience but "t" words will be highlighted.

版本详细信息

  1. 我有一个可行"的版本,onmousemove,但这很烦人用户.我不希望他们必须移动鼠标来获取文本突出显示.
  2. 我有一个可行"的版本,onkeypress,但问题是光标总是返回到初始位置(这会导致文本反向输入),并且一旦突出显示,它就不会停止.

版本1:event = onmousemove

//highlight ANY word that starts with t

function highlighter(ev) {
        var content = ev.innerHTML;
        var tokens = content.split(" ");
        for (var i = 0; i < tokens.length; i++) {
                if (tokens[i][0] == 't') {
                        tokens[i] = "<mark style='background-color:red; color:white;'>" + tokens[i] + "</mark>";
                      } 
              }
        ev.innerHTML = tokens.join(" ");
}

/* NOT REQUIRED AT ALL, JUST TO MAKE INTERACTION MORE PLEASANT */
.container {
  outline: none;
  border: 3px solid black;
  height: 100px;
  width: 400px;
}

<div class="container" onmousemove=highlighter(this) contenteditable>
</div>

版本2:event = onkeypress

//highlight ANY word that starts with t

function highlighter(ev) {
        var content = ev.innerHTML;
        var tokens = content.split(" ");
        for (var i = 0; i < tokens.length; i++) {
                if (tokens[i][0] == 't') {
                        tokens[i] = "<mark style='background-color:red; color:white;'>" + tokens[i] + "</mark>";
                      } 
              }
        ev.innerHTML = tokens.join(" ");
}

/* NOT REQUIRED AT ALL, JUST TO MAKE INTERACTION MORE PLEASANT */
.container {
  outline: none;
  border: 3px solid black;
  height: 100px;
  width: 400px;
}

<div class="container" onkeypress=highlighter(this) contenteditable>
</div>

推荐答案

这是草稿示例.我使用了此要点的插入符号获取/设置代码段.基本上,想法很简单-插入符号的位置,进行修改,然后重新设置.还将您的 innerHTML 方法交换为 innerText ,因为您无需在t-finder逻辑中解析HTML代码.

Here are draft example. I've used caret get/set snippet from this gist. Basically idea is simple - get caret position, do modification, set it back. Also swapped your innerHTML method to innerText, because you don't need to parse HTML code in your t-finder logic.

function highlighter(ev) {
  // Get current cursor position
  const currpos = getSelectionDirection(ev) !== 'forward' ? getSelectionStart(ev) : getSelectionEnd(ev);
  // Change innerHTML to innerText, you
  // dont need to parse HTML code here
  var content = ev.innerText;
  var tokens = content.split(" ");
  
  for (var i = 0; i < tokens.length; i++) {
    if (tokens[i][0] == 't') {
      tokens[i] = "<mark style='background-color:red; color:white;'>" + tokens[i] + "</mark>";
    } 
  }
  ev.innerHTML = tokens.join(" ");
  // Set cursor on it's proper position
  setSelectionRange(ev, currpos, currpos);
}

/* NOT REQUIRED AT ALL, JUST TO MAKE INTERACTION MORE PLEASANT */
.container {
  outline: none;
  border: 3px solid black;
  height: 100px;
  width: 400px;
}

<div class="container" onkeypress=highlighter(this) contenteditable>
</div>

<script>
// Usage:
// var x = document.querySelector('[contenteditable]');
// var caretPosition = getSelectionDirection(x) !== 'forward' ? getSelectionStart(x) : getSelectionEnd(x);
// setSelectionRange(x, caretPosition + 1, caretPosition + 1);
// var value = getValue(x);

// it will not work with "<img /><img />" and, perhaps, in many other cases.

  function isAfter(container, offset, node) {
    var c = node;
    while (c.parentNode != container) {
      c = c.parentNode;
    }
    var i = offset;
    while (c != null && i > 0) {
      c = c.previousSibling;
      i -= 1;
    }
    return i > 0;
  }
  function compareCaretPositons(node1, offset1, node2, offset2) {
    if (node1 === node2) {
      return offset1 - offset2;
    }
    var c = node1.compareDocumentPosition(node2);
    if ((c & Node.DOCUMENT_POSITION_CONTAINED_BY) !== 0) {
      return isAfter(node1, offset1, node2) ? +1 : -1;
    } else if ((c & Node.DOCUMENT_POSITION_CONTAINS) !== 0) {
      return isAfter(node2, offset2, node1) ? -1 : +1;
    } else if ((c & Node.DOCUMENT_POSITION_FOLLOWING) !== 0) {
      return -1;
    } else if ((c & Node.DOCUMENT_POSITION_PRECEDING) !== 0) {
      return +1;
    }
  }

  function stringifyElementStart(node, isLineStart) {
    if (node.tagName.toLowerCase() === 'br') {
      if (true) {
        return '\n';
      }
    }
    if (node.tagName.toLowerCase() === 'div') { // Is a block-level element?
      if (!isLineStart) { //TODO: Is not at start of a line?
        return '\n';
      }
    }
    return '';
  }
  function* positions(node, isLineStart = true) {
    console.assert(node.nodeType === Node.ELEMENT_NODE);
    var child = node.firstChild;
    var offset = 0;
    yield {node: node, offset: offset, text: stringifyElementStart(node, isLineStart)};
    while (child != null) {
      if (child.nodeType === Node.TEXT_NODE) {
        yield {node: child, offset: 0/0, text: child.data};
        isLineStart = false;
      } else {
        isLineStart = yield* positions(child, isLineStart);
      }
      child = child.nextSibling;
      offset += 1;
      yield {node: node, offset: offset, text: ''};
    }
    return isLineStart;
  }
  function getCaretPosition(contenteditable, textPosition) {
    var textOffset = 0;
    var lastNode = null;
    var lastOffset = 0;
    for (var p of positions(contenteditable)) {
      if (p.text.length > textPosition - textOffset) {
        return {node: p.node, offset: p.node.nodeType === Node.TEXT_NODE ? textPosition - textOffset : p.offset};
      }
      textOffset += p.text.length;
      lastNode = p.node;
      lastOffset = p.node.nodeType === Node.TEXT_NODE ? p.text.length : p.offset;
    }
    return {node: lastNode, offset: lastOffset};
  }
  function getTextOffset(contenteditable, selectionNode, selectionOffset) {
    var textOffset = 0;
    for (var p of positions(contenteditable)) {
      if (selectionNode.nodeType !== Node.TEXT_NODE && selectionNode === p.node && selectionOffset === p.offset) {
        return textOffset;
      }
      if (selectionNode.nodeType === Node.TEXT_NODE && selectionNode === p.node) {
        return textOffset + selectionOffset;
      }
      textOffset += p.text.length;
    }
    return compareCaretPositons(selectionNode, selectionOffset, contenteditable, 0) < 0 ? 0 : textOffset;
  }
  function getValue(contenteditable) {
    var value = '';
    for (var p of positions(contenteditable)) {
      value += p.text;
    }
    return value;
  }
  function setSelectionRange(contenteditable, start, end) {
    var selection = window.getSelection();
    var s = getCaretPosition(contenteditable, start);
    var e = getCaretPosition(contenteditable, end);
    selection.setBaseAndExtent(s.node, s.offset, e.node, e.offset);
  }
  //TODO: Ctrl+A - rangeCount is 2
  function getSelectionDirection(contenteditable) {
    var selection = window.getSelection();
    var c = compareCaretPositons(selection.anchorNode, selection.anchorOffset, selection.focusNode, selection.focusOffset);
    return c < 0 ? 'forward' : 'none';
  }
  function getSelectionStart(contenteditable) {
    var selection = window.getSelection();
    var c = compareCaretPositons(selection.anchorNode, selection.anchorOffset, selection.focusNode, selection.focusOffset);
    return c < 0 ? getTextOffset(contenteditable, selection.anchorNode, selection.anchorOffset) : getTextOffset(contenteditable, selection.focusNode, selection.focusOffset);
  }
  function getSelectionEnd(contenteditable) {
    var selection = window.getSelection();
    var c = compareCaretPositons(selection.anchorNode, selection.anchorOffset, selection.focusNode, selection.focusOffset);
    return c < 0 ? getTextOffset(contenteditable, selection.focusNode, selection.focusOffset) : getTextOffset(contenteditable, selection.anchorNode, selection.anchorOffset);
  }
</script>

这篇关于动态突出显示符合特定条件的单词的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆