Skip to content

Instantly share code, notes, and snippets.

@HeimMatthias
Created May 26, 2023 21:48
Show Gist options
  • Select an option

  • Save HeimMatthias/3ccdccb6fce644842966d8da54fe01dc to your computer and use it in GitHub Desktop.

Select an option

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