Ranges and Character Clicked
by blueseal
HTML
<div class="parent">
<div class="child" style="white-space: pre-wrap;">Bacon ipsum dolor amet meatball bresaola t-bone tri-tip brisket. Jowl pig picanha cupim landjaeger, frankfurter spare ribs chicken. Porchetta jowl pancetta drumstick shankle cow spare ribs jerky tail kevin biltong capicola brisket venison bresaola. Flank sirloin jowl andouille meatball venison salami ground round rump boudin turkey capicola t-bone. Sirloin filet mignon tenderloin beef, biltong doner bresaola brisket shoulder pork loin shankle turducken shank cow. Bacon ball tip sirloin ham.</div>
</div> <div id="info">Click somewhere in the paragraph above</div>
JavaScript
function isClickInRects(rects,x,y) {
for (var i = 0; i < rects.length; ++i) {
var r = rects[i]
if (r.left<x && r.right>x && r.top<y && r.bottom>y) {
return r;
}
}
return false;
}
function findBetween(elem,x,y,start,stop){
console.log(start,stop)
if(start==stop || start == stop-1){
return start
}
var half = Math.round((stop-start)/2)+start
var range = document.createRange();
range.setStart(elem, start);
range.setEnd(elem, half);
// not getBoundingClientRect as word could wrap
var rects = range.getClientRects();
if(isClickInRects(rects,x,y)){
// click is in first half
return findBetween(elem,x,y,start,half)
} else {
return findBetween(elem,x,y,half,stop)
}
}
function onClick(e) {
var info = document.getElementById('info');
info.innerHTML = 'Nothing Clicked';
var elem = e.target.childNodes[0]
if (elem.nodeName !== '#text') {
return
}
var s = elem.textContent
var clicked = findBetween(elem,e.clientX,e.clientY,0,s.length)
if (clicked !== null) {
info.innerHTML = 'character clicked:'+clicked
}
}
document.addEventListener('click', onClick);