Middle ellipsis
by Ron Valstar
HTML
<main>
<h1 data-middle-ellipsis>A Javascript solution to middle ellipsis</h1>
<div data-middle-ellipsis>The quick fox</div>
<div data-middle-ellipsis class="inline-block">The lazy dog</div>
<div data-middle-ellipsis>theQuickBrownFoxJumpsOverTheLazyDog</div>
<div data-middle-ellipsis class="bold">The quick brown fox jumps over the lazy dog</div>
<div data-middle-ellipsis class="small">The quick brown fox jumps over the lazy dog</div>
<div data-middle-ellipsis class="small bold">The quick brown fox jumps over the lazy dog</div>
<div data-middle-ellipsis class="large">The quick brown fox jumps over the lazy dog</div>
<div data-middle-ellipsis>The quick brown fox jumps over the lazy dog</div>
<div data-middle-ellipsis="70">The quick brown fox jumps over the lazy dog</div>
<div data-middle-ellipsis="30">The quick brown fox jumps over the lazy dog</div>
<div data-middle-ellipsis="1">The quick brown fox jumps over the lazy dog</div>
<div data-middle-ellipsis="99">The quick brown fox jumps over the lazy dog</div>
<div data-middle-ellipsis="-3">The quick brown fox jumps over the lazy dog</div>
<div data-middle-ellipsis="-3">The quick brown dog</div>
<div data-middle-ellipsis="0">The quick brown dog</div>
<div data-middle-ellipsis="-1">The quick brown dog</div>
<div data-middle-ellipsis="-99">The quick brown dog</div>
</main>
SCSS
$width: 130px;
html,body{
width: 100%;
height: 100%;
line-height: 170%;
}
main {
width: 100%;
height: 100%;
font-family: Arial;
background: #fff linear-gradient(90deg
,transparent $width
,#f0f0f0 $width
,#f0f0f0 2*$width
,transparent 2*$width
);
}
[data-middle-ellipsis]{
max-width: $width;
white-space: nowrap;
box-shadow: -1px 0 0 red inset;
}
.inline-block { display: inline-block; }
.bold { font-weight: bold; }
.small { font-size: 10px; }
.large { font-size: 32px; }
JavaScript
/**
* Attibute modifier to create middle ellipsis
* When the attribute value is left blank the ellipsis will be in the middle
* When positive the attribute value will be used as a percentage
* When negative the attribute value will be used as character index counted from the end
* @example
* <div data-middle-ellipsis>A Javascript solution to middle ellipsis</div>
* <div data-middle-ellipsis="20">A Javascript solution to middle ellipsis</div>
* <div data-middle-ellipsis="-3">A Javascript solution to middle ellipsis</div>
*/
const attributeName = 'data-middle-ellipsis'
const attributeTextName = attributeName+'-text'
const attributeFontName = attributeName+'-font'
const clamp = (val,min=Number.NEGATIVE_INFINITY,max=Number.POSITIVE_INFINITY)=>Math.max(min,Math.min(max,val))
const ellipsis = '…'
const map = new Map()
let timeoutId
testMiddleEllipsis()
window.addEventListener('resize', onResize, { capture: true, passive: true })
function onResize(e){
clearTimeout(timeoutId)
timeoutId = setTimeout(testMiddleEllipsis, 200)
}
function testMiddleEllipsis() {
Array.from(document.querySelectorAll(`[${attributeName}]`)).forEach(elm=>{
// do not recalculate variables a second time
const mapped = map.get(elm)
let {text, textLength, from, multiplier, font, textWidth, elementWidth} = mapped||{}
// first time
if (!mapped) {
text = elm.textContent
textLength = text.length
from = parseFloat(elm.getAttribute(attributeName))||50
multiplier = from>0&&from/100
const computedStyle = window.getComputedStyle(elm, null)
font = `${computedStyle.getPropertyValue('font-weight')} ${computedStyle.getPropertyValue('font-size')} ${computedStyle.getPropertyValue('font-family')}`
textWidth = getTextWidth(text, font)
elementWidth = elm.offsetWidth
map.set(elm, {text, textLength, from, multiplier, font, textWidth, elementWidth})
}
//
const {offsetWidth} = elm
const widthChanged =...