简体   繁体   English

javascript在遇到意外的anchorOffset时执行多个createrange()

[英]javascript doing multiple createrange() while encountering unexpected anchorOffset

My goal:我的目标:

Let users highlight different substring in a single long string.让用户在单个长字符串中突出显示不同的子字符串。

However, once I've highlighted one substring with range.surroundContents(newNode) (newNode is a span with yellow background), the innerHTML of the whole long string changed-- it started to contain the span element;但是,一旦我用range.surroundContents(newNode)突出显示了一个子字符串(newNode 是一个黄色背景的span ),整个长字符串的innerHTML发生了变化——它开始包含span元素; consequently, if the user wants to highlight a substring after the previous highlighted substring in the same long string, the anchorOffset will return the index starting after the previous span.因此,如果用户想在同一长字符串中突出显示前一个突出显示的子字符串之后的子字符串, anchorOffset将返回从前一个跨度after开始的索引。

For example, in this long string:例如,在这个长字符串中:

"Mr. and Mrs. Dursley, of number four, Privet Drive, were proud to say that they were perfectly normal, thank you very much." “女贞路四号的德思礼夫妇很自豪地说他们完全正常,非常感谢你们。”

this long sentence is wrapped by a p whose class name is noting .这个长句子被一个p包裹着,它的类名是noting If the range.surroundContents() method the substring "Privet Drive", then, when I want to get the window.getSelection().anchorOffset of the substring "thank", the answer wrongly is 53 while the correct answer should be 102 .如果range.surroundContents()方法是子字符串“Privet Drive”,那么,当我想获取子字符串“thank”的window.getSelection().anchorOffset时,错误的答案是53而正确的答案应该是102 How should I do?我应该怎么做? Thank you!!谢谢!!

PS I don't want to use substring method to find the position, thank you! PS我不想用substring方法找位置,谢谢!

$(".noting").mouseup(function(e){            
    $("#noteContent").val("");/*flushing*/
    curSentNum = $(this).attr("id").split("-")[1];
    $('#curSentNum').val(curSentNum);
    highlightLangName = $(this).attr("id").split("-")[2];
    $('#highlightLangName').val(highlightLangName);
    //console.log(".noting $(this).html()"+$(this).html()+" "+$(this).attr("id"));//id, for example: p-2-French
    if (window.getSelection) {
        highlightedText = window.getSelection().toString();
        curAnchorOffset = window.getSelection().anchorOffset;

        $('#anchorAt').val(curAnchorOffset);
        $('#highlightLen').val(highlightedText.length);

    }
    else if (document.selection && document.selection.type != "Control") {
        highlightedText = document.selection.createRange().text;
    }

});

And then I'll save the anchorAt information to db;然后我将anchorAt信息保存到db; after the db operation, I'll immediately call this function using the previous variables remained:在 db 操作之后,我会立即使用之前保留的变量调用这个函数:

function highlightNoteJustSaved(){
    var curI = noteCounter;
    var anchorAt = parseInt($("#anchorAt").val());
    var highlightLen = parseInt($("#highlightLen").val());
    /*p to find, for example: p-2-French*/
    var curP = document.getElementById('p-'+curSentNum.toString()+"-"+$("#highlightLangName").val());
    var range = document.createRange();
    root_node = curP;

    range.setStart(root_node.childNodes[0], anchorAt);
    range.setEnd(root_node.childNodes[0], anchorAt+highlightLen);

    var newNode = document.createElement("span");
    newNode.style.cssText="background-color:#ceff99";//yellow
    newNode.className = alreadyNoteStr;
    newNode.setAttribute('id','already-note-'+curI.toString());

    range.surroundContents(newNode);
}

for HTML tree node structure, please take a look at the comment below( I didn't figure out how to copy-paste the code at this asking area).对于 HTML 树节点结构,请看下面的评论(我没有弄清楚如何在此询问区域复制粘贴代码)。

I replaced your method to highlight text with 2 methods.我用两种方法替换了您突出显示文本的方法。 highlightTextNodes finds the word in the content of the node. highlightTextNodes在节点的内容中查找单词。 Searching each child.寻找每一个孩子。 Also I implemented a highlight remover to show how it works.我还实现了一个高光去除器来展示它是如何工作的。 I replaced the span with a mark tag.我用mark标签替换了span

 let alreadyNoteStr = 'already'; let noteCounter = 0; let elementId; $('p.noting').mouseup(function(e) { elementId = $(this).attr('id'); $('#noteContent').val(''); /*flushing*/ curSentNum = elementId.split('-')[1]; $('#curSentNum').val(curSentNum); highlightLangName = elementId.split('-')[2]; $('#highlightLangName').val(highlightLangName); //console.log(".noting $(this).html()"+$(this).html()+" "+$(this).attr("id"));//id, for example: p-2-French if (window.getSelection) { highlightedText = window.getSelection().toString(); curAnchorOffset = window.getSelection().anchorOffset; $("#noteContent").val(highlightedText); $('#anchorAt').val(curAnchorOffset); $('#highlightLen').val(highlightedText.length); highlight(elementId, highlightedText); } else if (document.selection && document.selection.type != "Control") { highlightedText = document.selection.createRange().text; } }); function highlightNoteJustSaved() { let curI = noteCounter; let anchorAt = parseInt($("#anchorAt").val()); let highlightLen = parseInt($("#highlightLen").val()); /*p to find, for example: p-2-French*/ let curP = document.getElementById('p-' + curSentNum.toString() + "-" + $("#highlightLangName").val()); let range = document.createRange(); rootNode = curP; let childNode = rootNode.childNodes[0]; range.setStart(rootNode.childNodes[0], anchorAt); range.setEnd(rootNode.childNodes[0], anchorAt + highlightLen); var newNode = document.createElement("span"); newNode.style.cssText = "background-color:#ceff99"; //yellow newNode.className = alreadyNoteStr; newNode.setAttribute('id', 'already-note-' + curI.toString()); range.surroundContents(newNode); } /* * Takes in an array of consecutive TextNodes and returns a document fragment with `word` highlighted */ function highlightTextNodes(nodes, word) { if (!nodes.length) { return; } let text = ''; // Concatenate the consecutive nodes to get the actual text for (var i = 0; i < nodes.length; i++) { text += nodes[i].textContent; } let fragment = document.createDocumentFragment(); while (true) { // Tweak this if you want to change the highlighting behavior var index = text.toLowerCase().indexOf(word.toLowerCase()); if (index === -1) { break; } // Split the text into [before, match, after] var before = text.slice(0, index); var match = text.slice(index, index + word.length); text = text.slice(index + word.length); // Create the <mark> let mark = document.createElement('mark'); mark.className = 'found'; mark.appendChild(document.createTextNode(match)); // Append it to the fragment fragment.appendChild(document.createTextNode(before)); fragment.appendChild(mark); } // If we have leftover text, just append it to the end if (text.length) { fragment.appendChild(document.createTextNode(text)); } // Replace the nodes with the fragment nodes[0].parentNode.insertBefore(fragment, nodes[0]); for (var i = 0; i < nodes.length; i++) { let node = nodes[nodes.length - i - 1]; node.parentNode.removeChild(node); } } /* * Highlights all instances of `word` in `$node` and its children */ function highlight(id, word) { let node = document.getElementById(id); let children = node.childNodes; let currentRun = []; for (var i = 0; i < children.length; i++) { let child = children[i]; if (child.nodeType === Node.TEXT_NODE) { // Keep track of consecutive text nodes currentRun.push(child); } else { // If we hit a regular element, highlight what we have and start over highlightTextNodes(currentRun, word); currentRun = []; // Ignore text inside of our <mark>s if (child.nodeType === Node.ELEMENT_NODE && child.className !== 'found') { highlight(child, word); } } } // Just in case we have only text nodes as children if (currentRun.length) { highlightTextNodes(currentRun, word); } } /* * Removes all highlighted <mark>s from the given node */ function unhighlight(id) { let node = document.getElementById(id); let marks = [].slice.call(node.querySelectorAll('mark.found')); for (var i = 0; i < marks.length; i++) { let mark = marks[i]; // Replace each <mark> with just a text node of its contents mark.parentNode.replaceChild(document.createTextNode(mark.childNodes[0].textContent), mark); } }
 label { display: block; position: relative; padding-left: 100px; } button { margin-top: 20px; margin-bottom: 20px; padding: 10px; } label>span { position: absolute; left: 0; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <button type="button" onclick="unhighlight(elementId);">Unhighlight</button> <div id="div-0" class="only-left-border"> <p class="lan-English noting" id="p-1-English">Mr. and Mrs. Dursley, of number four, Privet Drive, were proud to say that they were perfectly normal, thank you very much.</p> </div> <label><span>Content:</span><input type="text" id="noteContent"></input></label> <label><span>Numer:</span><input type="text" id="curSentNum"></input></label> <label><span>Language:</span><input type="text" id="highlightLangName"></input></label> <label><span>Anchor:</span><input type="text" id="anchorAt"></input></label> <label><span>Length:</span><input type="text" id="highlightLen"></input></label>

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

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