// HTML Truncator for jQuery
// by Henrik Nyh <http://henrik.nyh.se> 2008-02-28.
// Free to modify and redistribute with credit.

// Modified By Bill Beckelman <http://beckelman.net> 2008-10-13 to include bigTarget technique found at <http://newism.com.au/blog/post/58/bigtarget-js-increasing-the-size-of-clickable-targets/>

// Modifed by Nathan Bingham <http://www.nathansbingham.com> 2009-10-08 to search for whitespace before truncating

(function($) {

    var trailing_whitespace = true;

    $.fn.truncate = function(options) {

        var opts = $.extend({}, $.fn.truncate.defaults, options);

        $(this).each(function() {

            var content_length = $.trim(squeeze($(this).text())).length;
            if (content_length <= opts.max_length)
                return;  // bail early if not overlong

            var actual_max_length = opts.max_length - opts.more.length - 3;  // 3 for " ()"    
            var truncated_node = recursivelyTruncate(this, actual_max_length);
            var full_node = $(this);

            truncated_node.insertAfter(full_node);
            // This is an ugly approximation for getting the last block tag:
            // we just pick the last <p> or else the container itself.
            truncated_node.find('p:last').add(truncated_node).eq(0).append(' <a href="#show more content">' + opts.more + '</a>');
			if(opts.addclass)
				truncated_node.parent().addClass('truncated');
			
            full_node.hide();
            full_node.find('p:last').add(full_node).eq(0).append(' <a href="#show less content">' + opts.less + '</a>');
			
			if(opts.big)
				var parent = full_node.parent().parent();
			else
				var parent = full_node.parent();
			
            parent.bind('click', function(e) {
	
				e.preventDefault();
				
				if(truncated_node.is(':visible'))
				{
					truncated_node.fadeOut(opts.fade, function(){
						
						full_node.fadeIn(opts.fade,
						function(){
							if(opts.scroll)
							{
								var x = $(full_node).offset().top;
								$("html:not(:animated),body:not(:animated)").animate({ scrollTop: x}, 1200);
							}
				
							});}
						);
					if(opts.addclass)
						full_node.parent().removeClass('truncated').addClass('expanded');

				}
				else
				{
					full_node.fadeOut(opts.fade, function(){truncated_node.fadeIn(opts.fade);});
					
					if(opts.addclass)
						full_node.parent().removeClass('expanded').addClass('truncated');
				}
	                return false;
            })
            .hover(function() {
                $(this).addClass(opts.hoverClass);
            }, function() {
                $(this).removeClass(opts.hoverClass);
            });
        });
    }

    // Note that the "more" link and its wrapping counts towards the max length:
    // so "more" and a max length of 10 might give "123 (more)"
    $.fn.truncate.defaults = {
        max_length: 100,
        more: ' more...',
        less: 'less',
        hoverClass: 'hover',
		scroll: true,
		big: true,
		fade: 500,
		addclass: false
    };

    function recursivelyTruncate(node, max_length) {
        return (node.nodeType == 3) ? truncateText(node, max_length) : truncateNode(node, max_length);
    }

    function truncateNode(node, max_length) {	
        var node = $(node);
        var new_node = node.clone().html("");
        node.contents().each(function() {
            var remaining_length = max_length - new_node.text().length;
            if (remaining_length == 0) return;
            new_node.append(recursivelyTruncate(this, remaining_length));
        });
        return new_node;
    }

    function truncateText(node, max_length) {
        var text = node.data;
		var split_text = text.substr(max_length);
		
		var split_point = split_text.substr(0,1);
		var white_space = new RegExp(/^\s+$/);
		for(var new_limit=max_length;new_limit < text.length;new_limit++)
		{	
			var new_split_text=text.substr(0,new_limit);
			var new_hidden_text=text.substr(new_limit);
			var new_split_point=new_split_text.slice(-1);
			
			if(white_space.test(new_split_point))
			{
				var text = text.slice(0, new_limit);
				text = $('<div/>').text(text).html();
				return text;
			}
		}
    }

    // Collapses a sequence of whitespace into a single space.
    function squeeze(string) {
        return string.replace(/\s+/g, ' ');
    }

})(jQuery);
