I have this piece of code which is supposed to return the start and end offsets of the user selection:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function getSelRange() {
var selObj = window.getSelection();
var range = selObj.getRangeAt(0);
alert(range.startOffset+"-"+range.endOffset);
}
</script>
</head>
<body>
<button onclick="getSelRange()">Get the selected text!</button>
<p>Select some text!</p>
</body>
</html>
When I select some text from the p
by dragging, it alerts the numbers correctly. However, when I select the entire text in the p
by triple clicking on it, it alerts 0-1. Looks like in Firefox only, triple click doesn't return the selection range correctly.
How do I get the correct start and end points on triple click as well?
Firefox is returning the correct range. The problem is that your assumption that a range must have its start and end boundaries relative to a text node is incorrect.
What is happening is that Firefox is reporting the range as starting before the zeroth child node of the <p>
element and ending after the first child of the <p>
element. This is perfectly valid.
You could do something like the following to adjust such a range to make its boundaries lie inside the text node within the <p>
element:
Demo: http://jsfiddle.net/DbmjH/2/
Code:
function adjustRange(range) {
range = range.cloneRange();
if (range.startContainer.nodeType != 3) {
var nodeAfterStart = range.startContainer.childNodes[range.startOffset];
if (nodeAfterStart && nodeAfterStart.nodeType == 3) {
range.setStart(nodeAfterStart, 0);
}
}
if (range.endContainer.nodeType != 3 && range.endOffset >= 1) {
var nodeBeforeEnd = range.endContainer.childNodes[range.endOffset - 1];
if (nodeBeforeEnd && nodeBeforeEnd.nodeType == 3) {
range.setEnd(nodeBeforeEnd, nodeBeforeEnd.data.length);
}
}
return range;
}
Check this fiddle ( Updated )
I have made it in a way that it will work on triple click when paragraph contains multiple lines.
<script>
function getSelRange() {
var selObj = window.getSelection();
var range = selObj.getRangeAt(0);
var r = document.getElementById('txt').innerHTML.split('<br>');
if (r[(range.endOffset-1)/2] == selObj) {
alert(0+"-"+r[(range.endOffset-1)/2].length);
} else if (range.startOffset >= range.endOffset) {
alert(range.startOffset + "-" + r[(range.endOffset-1)/2].length);
} else {
alert(range.startOffset + "-" + range.endOffset);
}
}
</script>
New Added Fiddle
<script>
function getSelRange() {
var selObj = window.getSelection();
var range = selObj.getRangeAt(0);
var r=document.getElementById('txt').innerHTML.split('<br>');
var selLines = selObj.toString().split('\n');
var Str = document.getElementById('txt').innerHTML;
Str=Str.replace(/<br>/g,"xzznlzzx");
var pr=selObj.toString().replace(/\r?\n/g,"xzznlzzx");
var rStr=Str.substring(0,Str.indexOf(pr));
var rSplit=rStr.split('xzznlzzx');
var prSplit=pr.split('xzznlzzx');
var countStart=0;
var countEnd=0;
var i=0;
for(;i<(rSplit.length-1);i++)
{
countStart=countStart+r[i].length;
}
for(j=0;j<(prSplit.length-1);i++,j++)
{
countEnd=countEnd+r[i].length;
}
countEnd=countEnd+countStart;
if(r[(range.endOffset-1)/2]==selObj)
{
alert((0+countStart)+"-"+(r[(range.endOffset-1)/2].length+countEnd));
}
else{
if(r[i].length<selObj.toString().length)
{
var indx = selObj.toString().indexOf(r[i]);
}
else{
var indx = r[i].indexOf(selObj.toString());
var vals=selObj.toString().length;
var res = r[i].substring(indx+vals,indx+vals+1);
if(res==""){indx=1}
else{indx=-1}
}
if(indx!=-1)
{
alert((range.startOffset+countStart)+"-"+(r[i].length+countEnd));
}
else{
alert((range.startOffset+countStart)+"-"+(range.endOffset+countEnd));
}
}
}
</script>
Note : for the above fiddles to work the string within <p>
tag must be in a single line otherwise it will add the extra spaces between words to the range.