Ranges and Character Clicked

HTML

<div class="parent">
    <div class="overflow-mid">Bacon ipsum dolor amet meatball bresaola t-bone tri-tip brisket. Jowl pig picanha cupim landjaeger, frankfurter spare ribs chicken. Porchetta jowl panhttps://jsfiddle.net/amvebozn/2/#runcetta 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>

CSS

.overflow-mid {
    overflow: hidden;
    text-overflow: ellipsis; /* will be overwritten */
    white-space: nowrap;
    height: 2em;
}

JavaScript

function applyMidOverflow(el, delimiter) {
    if (delimiter === undefined || 
    	Number.isInteger(delimiter)  // forEach index
    ) {
      var cs = getComputedStyle(el);     
      if (cs.textOverflow === 'ellipsis' || cs.textOverflow === '') {
      	delimiter = '…';
      } else {
        // remove quotes
        delimiter = s.textOverflow.substring(1, s.textOverflow.length - 1)
      }
    }
    var r = el.getBoundingClientRect();
    var half_width_pos = r.x + (r.width/2);    
    if (el.childNodes.length !== 1 || el.childNodes[0].nodeType !== 3) {
    	console.warn('midOverflow: need a single TEXT_NODE child', el);
      return;
    }    
    const textChild = el.childNodes[0];
    var range = document.createRange();    
    var end = textChild.textContent.length;
    
    // set the following to zero to be sure
    var approx_mid = Math.round(end * 0.4);
    
    for (var i = approx_mid; i < end; i++) {
        // TODO: binary search
        range.setStart(textChild, i);
        range.setEnd(textChild, end);
        // not getBoundingClientRect as word could wrap
        var rects = range.getClientRects();
        var selected_t = Array.from(rects, (r)=>r.width).reduce((a, b)=>a+b, 0);
        if (selected_t < half_width_pos) {
         	break;   
        }        
    }   
    el.style.textOverflow = '" ' + delimiter + ' ' + textChild.textContent.substring(i).replace(/"/, '\\"').replace('\n', '').replace(/\s+$/g, '') + '"';
}

addEventListener('load', () => {
  document.querySelectorAll('.overflow-mid').forEach(applyMidOverflow);	
});