I had a requirement to be able to show a long description for an item in a limited space. The descriptions were coming from a 3rd party database and could be of any length. The design called for the description area being two lines tall. There is a CSS attribute called text-overflow: ellipsis. It had several problems, however. First of all it only worked on a single line basis. Mostly it had the big issue of not working at all in Firefox as it was a non-standard CSS call.
I found a jquery plugin to duplicate the functionality of the CSS call but like the CSS call it only worked on a single line. My design spec also called for a More/Less link to be affixed to the block of text to expand it/ contract it. The More/Less also had to support different cultures.
//ellipsis plugin http://devongovett.wordpress.com/2009/04/06/text-overflow-ellipsis-for-firefox-via-jquery/ + comments + custom mods (function($) { $.fn.ellipsis = function(lines, enableUpdating, moreText, lessText) { return $(this).each(function() { var el = $(this); var resetDescription = function(height, originalText) { el.html(originalText); el.animate({ "height": height }, "normal", null, function() { el.ellipsis(true, true, moreText, lessText); }); } if (el.css("overflow") == "hidden") { var originalText = el.html(); var availWidth = el.width(); var availHeight = el.height(); var MoreLessTag; if (moreText) { enableUpdating = true; MoreLessTag = " <a class='MoreLessTag' href='#' >" + moreText + "</a>"; } else MoreLessTag = ""; var t = $(this.cloneNode(true)) .hide() .css({ 'position': 'absolute', 'overflow': 'visible', 'max-width': 'none', 'max-height': 'none' }); if (lines) t.css("height", "auto").width(availWidth); else t.css("width", "auto"); el.after(t); t.append(" <a class='MoreLessTag' href='#' >" + lessText + "</a>"); var fullHeight = t.height(); var avail = (lines) ? availHeight : availWidth; var test = (lines) ? t.height() : t.width(); var foundMin = false, foundMax = false; if (test > avail) { //Binary search style trimming of the temp element to find its optimal size var min = 0; var max = originalText.length; while (min <= max) { var trimLocation = (min + max) / 2; var text = originalText.substr(0, trimLocation); t.html(text + "…" + MoreLessTag); test = (lines) ? t.height() : t.width(); if (test > avail) { if (foundMax) foundMin = true; max = trimLocation - 1; if (min > max) { //If we would be ending decrement the min and regenerate the text so we don't end with a //slightly larger text than there is space for trimLocation = (max + max - 2) / 2; text = originalText.substr(0, trimLocation); t.html(text + "…" + MoreLessTag); break; } } else if (test < avail) { min = trimLocation + 1; } else { if (foundMin && foundMax && ((max - min) / max < .2)) break; foundMax = true; min = trimLocation + 1; } } } el.html(t.html()); t.remove(); if (moreText) { jQuery(".MoreLessTag", this).click(function(event) { event.preventDefault(); el.html(originalText); el.animate({ "height": fullHeight }, "normal", null, function() { }); el.append(" <a class='MoreLessTag' href='#' >" + lessText + "</a>"); jQuery(".MoreLessTag", el).click(function(event) { event.preventDefault(); resetDescription(availHeight, originalText); }); }); } else { var replaceTags = new RegExp(/<\/?[^>]+>/gi); el.attr("alt", originalText.replace(replaceTags, '')); el.attr("title", originalText.replace(replaceTags, '')); } if (enableUpdating == true) { var oldW = el.width(); var oldH = el.height(); el.one("resize", function() { if (el.width() != oldW || (lines && el.height != oldH)) { el.html(originalText); el.ellipsis(lines, enableUpdating, moreText, lessText); } }); } } }); }; })(jQuery);
The following features are added from the original:
- More/Less link with expansion
- multiple lines
- title and alt text if no more/less text is provided
This hasn't been tested extensively under different conditions.
Things I would do if I had an infinite amount of time:
- More Testing
- Ability to override the More/Less text click event
Enjoy – I hope someone finds this useful. This was my first foray into doing a jQuery plugin. Even though a good chunk of the code was copied, I still learned quite a bit.