I want to find the range of the selected text with respect to the parent element. So in this <p>
element, the anchorOffset
& focusOffset
for “fox” is [16,19]
<p>The quick brown fox jumps over the lazy dog.</p>
But if we add a <b>
tag before “fox” then the values change to [1,4].
<p>The quick <b>brown</b> fox jumps over the lazy dog.</p>
My best guess is, the index count starts from the end of </b>
tag. But I want it to still show the original value, irrespective of the HTML within <p>
. For this, I tried creating a Range, but still couldn’t figure it out. Following is the code, as a function.
function rangefun() { var range = document.createRange(); var referenceNode = document.getElementsByTagName('P').item(0); range.selectNode(referenceNode); var selection = window.getSelection(); var start = selection.anchorOffset; var end = selection.focusOffset; console.log("start: " + start); }
Advertisement
Answer
Below is a modified version of your code that does what you want.
It takes both the anchor
and extent
nodes which are children of <p>
from the selection
variable (i.e. window.getSelection()
).
These two nodes are passed to the calculateOffset
function. For each of the nodes, the sum of the text length of the preceding siblings is calculated. Incrementing this total text length with the selection’s relative offset (the one in the child node) will yield the start
and end
offsets with respect to the <p>
text length.
function rangefun() { var selection = window.getSelection(); var start = selection.anchorOffset; var end = selection.extentOffset; var anchorNode = selection.anchorNode; var extentNode = selection.extentNode; var startIndex = calculateOffset(anchorNode, start); var endIndex = calculateOffset(extentNode, end); console.log('start: ' + startIndex); console.log('end: ' + endIndex); } function calculateOffset(child, relativeOffset) { var parent = child.parentElement; // verify whether or not the correct parent element is selected, modify if necessary if (parent.tagName != 'P') { parent = parent.closest('p'); child = child.parentElement; } var children = []; // add the child's preceding siblings to an array for (var c of parent.childNodes) { if (c === child) break; children.push(c); } // calculate the total text length of all the preceding siblings and increment with the relative offset return relativeOffset + children.reduce((a, c) => a + c.textContent.length, 0); }