Created
May 26, 2023 21:48
-
-
Save HeimMatthias/3ccdccb6fce644842966d8da54fe01dc to your computer and use it in GitHub Desktop.
JavaScript function to wrap selected Text in spans, efficient version without multi-range support
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| function wrapSelectionTextNodes(id, className) { | |
| let selection = window.getSelection(); | |
| let range = selection.getRangeAt(0); | |
| // if the entire range is contained within one text node, there is a quick fix with surroundContents | |
| if (range.startContainer === range.endContainer && range.endContainer.nodeType === Node.TEXT_NODE) { | |
| let span = document.createElement('span'); | |
| span.id=id; | |
| span.classList.add(className); | |
| range.surroundContents(span); | |
| selection.selectAllChildren(span); | |
| } else { | |
| // if there are several nodes to the range, we will iterate over all text nodes from the common ancester of the range and wrap them all in spans | |
| let textIterator = document.createNodeIterator(range.commonAncestorContainer, NodeFilter.SHOW_TEXT, (node) => selection.containsNode(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT ); | |
| let selNodes=[]; | |
| let node; | |
| while (node = textIterator.nextNode()) if (node !== range.startContainer && node !== range.endContainer) selNodes.push(node); | |
| let span; | |
| let startSpan; | |
| let endSpan; | |
| // surround partial selection from last text node with span | |
| if (range.endContainer.nodeType === Node.TEXT_NODE) { | |
| endSpan = document.createElement('span'); | |
| endSpan.setAttribute("for",id); | |
| endSpan.classList.add(className); | |
| let newRange=new Range(); | |
| newRange.setStart(range.endContainer, 0); | |
| newRange.setEnd(range.endContainer, range.endOffset); | |
| newRange.surroundContents(endSpan); | |
| } | |
| // surround partial selection from first text node with span | |
| if (range.startContainer.nodeType === Node.TEXT_NODE) { | |
| startSpan = document.createElement('span'); | |
| startSpan.id=id; | |
| startSpan.classList.add(className); | |
| let newRange=new Range(); | |
| newRange.setStart(range.startContainer, range.startOffset); | |
| newRange.setEnd(range.startContainer, range.startContainer.nodeValue.length); | |
| newRange.surroundContents(startSpan); | |
| } | |
| // surround each text node inside selection with span | |
| selNodes.forEach(node => { | |
| span = document.createElement('span'); | |
| node.after(span); | |
| span.setAttribute("for",id); | |
| span.classList.add(className); | |
| span.appendChild(node); | |
| }); | |
| // reset selection | |
| selection.setBaseAndExtent(startSpan,0,endSpan,1); | |
| } | |
| } | |
| // test: find and select all occurrences of a word in document and wrap them in spans | |
| i=1; | |
| for (i=0; window.find("Knallgasprobe", true, false, false); i++) | |
| wrapSelectionTextNodes("selection-"+i,"selection"); | |
| // test: remove wrapper elements | |
| for (const selection of document.querySelectorAll(".selection")) selection.replaceWith(selection.childNodes[0]); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment