I have a webpage with an elastic layout that changes its width if the browser window is resized.
In this layout there are headlines (h2
) that will have
I built this code using a number of other posts, with the following enhancements:
display: block
to the style, so spans workCSS:
.ellipsis {
white-space: nowrap;
overflow: hidden;
display: block;
}
.ellipsis.multiline {
white-space: normal;
}
jquery.ellipsis.js
(function ($) {
// this is a binary search that operates via a function
// func should return < 0 if it should search smaller values
// func should return > 0 if it should search larger values
// func should return = 0 if the exact value is found
// Note: this function handles multiple matches and will return the last match
// this returns -1 if no match is found
function binarySearch(length, func) {
var low = 0;
var high = length - 1;
var best = -1;
var mid;
while (low <= high) {
mid = ~ ~((low + high) / 2); //~~ is a fast way to convert something to an int
var result = func(mid);
if (result < 0) {
high = mid - 1;
} else if (result > 0) {
low = mid + 1;
} else {
best = mid;
low = mid + 1;
}
}
return best;
}
// setup handlers for events for show/hide
$.each(["show", "toggleClass", "addClass", "removeClass"], function () {
//get the old function, e.g. $.fn.show or $.fn.hide
var oldFn = $.fn[this];
$.fn[this] = function () {
// get the items that are currently hidden
var hidden = this.find(":hidden").add(this.filter(":hidden"));
// run the original function
var result = oldFn.apply(this, arguments);
// for all of the hidden elements that are now visible
hidden.filter(":visible").each(function () {
// trigger the show msg
$(this).triggerHandler("show");
});
return result;
};
});
// create the ellipsis function
// when addTooltip = true, add a title attribute with the original text
$.fn.ellipsis = function (addTooltip) {
return this.each(function () {
var el = $(this);
if (el.is(":visible")) {
if (el.css("overflow") === "hidden") {
var content = el.html();
var multiline = el.hasClass('multiline');
var tempElement = $(this.cloneNode(true))
.hide()
.css('position', 'absolute')
.css('overflow', 'visible')
.width(multiline ? el.width() : 'auto')
.height(multiline ? 'auto' : el.height())
;
el.after(tempElement);
var tooTallFunc = function () {
return tempElement.height() > el.height();
};
var tooWideFunc = function () {
return tempElement.width() > el.width();
};
var tooLongFunc = multiline ? tooTallFunc : tooWideFunc;
// if the element is too long...
if (tooLongFunc()) {
var tooltipText = null;
// if a tooltip was requested...
if (addTooltip) {
// trim leading/trailing whitespace
// and consolidate internal whitespace to a single space
tooltipText = $.trim(el.text()).replace(/\s\s+/g, ' ');
}
var originalContent = content;
var createContentFunc = function (i) {
content = originalContent.substr(0, i);
tempElement.html(content + "…");
};
var searchFunc = function (i) {
createContentFunc(i);
if (tooLongFunc()) {
return -1;
}
return 0;
};
var len = binarySearch(content.length - 1, searchFunc);
createContentFunc(len);
el.html(tempElement.html());
// add the tooltip if appropriate
if (tooltipText !== null) {
el.attr('title', tooltipText);
}
}
tempElement.remove();
}
}
else {
// if this isn't visible, then hook up the show event
el.one('show', function () {
$(this).ellipsis(addTooltip);
});
}
});
};
// ellipsification for items with an ellipsis
$(document).ready(function () {
$('.ellipsis').ellipsis(true);
});
} (jQuery));
There is a simple jQuery solution by Devon Govett:
https://gist.github.com/digulla/5796047
To use, just call ellipsis() on a jQuery object. For example:
$("span").ellipsis();
There's actually a pretty straightforward way to do this in CSS exploiting the fact that IE extends this with non-standards and FF supports :after
You can also do this in JS if you wish by inspecting the scrollWidth of the target and comparing it to it's parents width, but imho this is less robust.
Edit: this is apparently more developed than I thought. CSS3 support may soon exist, and some imperfect extensions are available for you to try.
That last one is good reading.
I made a really cool jQuery plugin for handling all varieties of ellipsis of text is one called ThreeDots @ http://tpgblog.com/threedots
It's much more flexible than the CSS approaches, and supports much more advanced, customizable behaviors and interactions.
Enjoy.
I'd done something similar for a client recently. Here's a version of what I did for them (example tested in all latest browser versions on Win Vista). Not perfect all around the board, but could be tweaked pretty easily.
Demo: http://enobrev.info/ellipsis/
Code:
<html>
<head>
<script src="http://www.google.com/jsapi"></script>
<script>
google.load("jquery", "1.2.6");
google.setOnLoadCallback(function() {
$('.longtext').each(function() {
if ($(this).attr('scrollWidth') > $(this).width()) {
$more = $('<b class="more">…</b>');
// add it to the dom first, so it will have dimensions
$(this).append($more);
// now set the position
$more.css({
top: '-' + $(this).height() + 'px',
left: ($(this).attr('offsetWidth') - $more.attr('offsetWidth')) + 'px'
});
}
});
});
</script>
<style>
.longtext {
height: 20px;
width: 300px;
overflow: hidden;
white-space: nowrap;
border: 1px solid #f00;
}
.more {
z-index: 10;
position: relative;
display: block;
background-color: #fff;
width: 18px;
padding: 0 2px;
}
</style>
</head>
<body>
<p class="longtext">This is some really long text. This is some really long text. This is some really long text. This is some really long text.</p>
</body>
</html>
trunk8 jQuery plugin supports multiple lines, and can use any html, not just ellipsis characters, for the truncation suffix: https://github.com/rviscomi/trunk8
Demo here: http://jrvis.com/trunk8/