2

I have an html div whose width is fixed. I want to put some text content in it. If the text is too long I want to truncate the text. However, unlike text-overflow: ellipsis property I want to have truncation in the middle. I want to hear any interesting idea that you got.

Jigar Solanki
  • 91
  • 1
  • 5

3 Answers3

2

You can use a "test" div to determine the size of your values and resize them by trimming the middle until it fits the desired width.

This jsfiddle example is a rough implementation. It sizes down the value one character at a time (something that could fairly easily be improved upon) until the size + ellipsis is less than the container width

javascript / jQuery

// Text excision for generating middle ellipsis values to fit a specific size.

String.prototype.cutMiddleChar = function() {
    var charPosition = Math.floor(this.length / 2)
    return this.substr(0, charPosition) + this.substr(charPosition + 1);
};
String.prototype.insertMiddleEllipsis = function() {
    var charPosition = Math.floor(this.length / 2)
    return this.substr(0, charPosition) + '...' + this.substr(charPosition);
};

var w = 0,
    t = '',
    $test = $('.excision-test');

$('div').each(function() {
    // re-usable $this
    var $this = $(this);
    // get current width, this is the width we need to fit the value to
    w = $this.width();
    // get current text value, we'll be manipulating this till it's sized right
    t = $this.text();
    // set our test div to the value (plus our ellipsis) for sizing
    $test.text(t + '...');

    //console.log(w);
    //console.log($test.width());

    // when the value's width is greater than the width of the container loop through to size it down
    if ($test.width() > w) {
        while ($test.width() > w) {
            t = t.cutMiddleChar()
            //console.log('str cut: ' + t);
            $test.text(t + '...');
            //console.log('str len: ' + t.length);
            //console.log('width:   ' + $test.width());
        }
        $this.text(t.insertMiddleEllipsis());
    }
});​

CSS

/* manipulate font-family, font-size as needed */
body {font-family:arial;font-size:12px;}

/* div and test div must use same formatting (font-size, font-family, etc) */
div {width:300px;border:1px solid red}
.excision-test {position:absolute;left:-10000em;width:auto;}

HTML

<div>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vel orci quis nunc vulputate tristique quis id tortor. Donec dui ante, condimentum quis iaculis ut, venenatis vel lorem. Etiam ullamcorper aliquam imperdiet. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis tincidunt ligula lorem. Pellentesque pharetra ipsum nec erat tempor vel sagittis libero volutpat. Donec malesuada convallis pharetra.
</div>
<div class="excision-test"></div>​

The general concept is functional but not very performant especially if you have a lot of these values on a page.

Before

enter image description here

After

enter image description here

Some additional considerations to improve this would be to

  • trim by word instead of character so that words are not cut apart
  • add some basic guessing to trim the value quicker (example: width of text is 1000 and container is only 100, could fairly easily chop off ~80% of the value and trim one at a time from there)
  • set the title attribute on the div so the hover tooltip would still show the full value
MikeM
  • 27,227
  • 4
  • 64
  • 80
  • I had it working similar way. But instead of using 'excision-test' div. I was just using it on the div it self. Thanks for the fiddle example! – Jigar Solanki Jul 26 '12 at 20:22
0

You could use .substring to do this. Say your width can hold 10 characters plus the ellipsis, you could do the following:

var myText = "This is a sentence that needs to be reduced";

myText = myText.substring(0,5) + "..." + myText.substring(myText.length-5);
Ben
  • 872
  • 7
  • 18
0

The question has been asked before here on SO. Maybe my answer here gives more clues?

Community
  • 1
  • 1
KooiInc
  • 119,216
  • 31
  • 141
  • 177