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);
});