简体   繁体   English

查找给定插入符位置的Node(javascript)

[英]Find Node given a caret position (javascript)

I have an HTML file and I have a supposed caret position. 我有一个HTML文件,并且我有一个插入符号的位置。 With JS I need to find the html node on which the caret would be placed if it was at the given position. 使用JS时,如果插入符位于给定位置,我需要找到放置插入符的html节点。

function findNodeForCaretPosition(caretPosition) {
    var node = null; // type Node (https://developer.mozilla.org/en-US/docs/Web/API/Node)
  // TODO find node
  return node;
}


Example HTML HTML范例

<html>
<body>
    <div>
        <p id="a">Time waits for no man. Unless that man is Chuck Norris.</p>
    </div>
    <div>
        <p id="b">Chuck Norris can touch <span id="c" style="color:blue">MC Hammer</span>.</p>
    </div>
</body>
</html>


Example HTML plain text 示例HTML纯文本

Time waits for no man. 时间不等人。 Unless that man is Chuck Norris. 除非那个男人是查克·诺里斯。

Chuck Norris can touch MC Hammer. Chuck Norris可以接触MC Hammer。


Tests 测验

Caret position = 4 (Time| waits) 插入位置= 4(时间|等待)
Answer = <p id="a"> 答案= <p id="a">

Caret position = 16 (can| touch). 插入位置= 16(可以触摸)。
Answer = <p id="b"> 答案= <p id="b">

Caret position = 25 (MC| Hammer). 插入位置= 25(MC |锤)。
Answer = <span id="c"> 答案= <span id="c">

Caret position = 1000), no answer ( null ). 插入位置= 1000),无应答( null )。

I've commented the code quite a bit, so I don't think it needs much more of an explanation. 我已经对代码进行了很多评论,所以我认为它不需要更多的解释。 Just call caretPosition with the parent node and an index as parameters. 只需使用父节点和索引作为参数调用caretPosition As strings in JavaScript are UTF-16, any emojis or non-ASCII characters should count as one character and not multiple. 由于JavaScript中的字符串为UTF-16,因此任何表情符号或非ASCII字符都应视为一个字符,而不是多个字符。

Of note, whitespace is important. 值得注意的是,空格很重要。 So the HTML from your question technically wouldn't work, as it first counts newlines and leading spaces. 因此,问题中的HTML从技术上讲是行不通的,因为它首先会计算换行符和前导空格。 I've removed that here for simplicity. 为了简单起见,我将其删除。

If you have any questions, let me know in the comments. 如果您有任何疑问,请在评论中让我知道。

 /** * @param {Element} parent * @param {number} index */ function caretPosition(parent, index) { // The index is too large to fit in the element, return `null` per requirements. // We also return `null` if the element isn't a text or element node, // as there is no text to check against. if ( (parent.nodeType === Node.ELEMENT_NODE && index > parent.innerText.length) || (parent.nodeType === Node.TEXT_NODE && index > parent.data.length) || ![Node.ELEMENT_NODE, Node.TEXT_NODE].includes(parent.nodeType) ){ return null; } // The length of all text combined to this point // (zero is the beginning of `parent`). let combinedLength = 0; // Iterate over the children until we find // the element where we cross the boundry. for (const child of parent.childNodes) { // Store this in case we need to recurse. const previousLength = combinedLength; // For the current child, add the length of its text content. // As text and element nodes don't share a common property, // we need to explicitly check for both. Other node types // (such as comments) are irrelevant to the task at hand. if (child.nodeType === Node.TEXT_NODE) { combinedLength += child.data.length; } else if (child.nodeType === Node.ELEMENT_NODE) { combinedLength += child.innerText.length; } else { // We don't have a text or element node, // so there's no text that we could care about. // The recursive case will handle the fact that nothing changed, // and will return `null`. continue; } // Our cursor is inside or at the end of this node. if (index <= combinedLength) { // We are in a text node and have nothing to recurse on. // Return the parent element of the text node, // which is a DOM element. if (child.nodeType === Node.TEXT_NODE) { return child.parentElement; } // If we are in an element node, then we have no children. // Without children, there is nothing to recurse on; // we should return the element. // If we are _not_ in an element node, // this will be `false`, and we will enter the recursive case. else if (child.childElementCount === 0) { return child; } // We have children to iterate over, so do that. // It is necessary to change the index to search for // as we've got a new reference frame. return caretPosition(child, index - previousLength); } } } // Make sure everything works! const div = document.querySelectorAll('div'); console.assert(caretPosition(div[0], 4) === document.querySelector('#a')); console.assert(caretPosition(div[1], 16) === document.querySelector('#b')); console.assert(caretPosition(div[1], 25) === document.querySelector('#c')); console.assert(caretPosition(div[0], 1000) === null); console.assert(caretPosition(div[1], 1000) === null); 
 <div><p id='a'>Time waits for no man. Unless that man is Chuck Norris.</p></div> <div><p id='b'>Chuck Norris can touch <span id='c' style='color:blue'>MC Hammer</span>.</p></div> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM