// HTML Truncator for jQuery
// by Henrik Nyh <http://henrik.nyh.se> 2008-02-28.
// Free to modify and redistribute with credit.

(function($) {

  var trailing_whitespace = true;

  $.fn.truncate = function(options) {

    var opts = $.extend({}, $.fn.truncate.defaults, options);
//    alert(this.length);
    $(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 + opts.morePrefix.length + opts.moreSuffix.length);  // 3 for " ()"
      var truncated_node = recursivelyTruncate(this, actual_max_length);
      var full_node = $(this).hide();

//      alert(truncated_node.length);
      
      truncated_node.insertAfter(full_node);
      
      findNodeForMore(truncated_node).append('<span class="truncate_show_more">' + opts.morePrefix + '<a href="#show_more_content">'+opts.more+'</a>' + opts.moreSuffix + '</span>');
      findNodeForLess(full_node).append('<span class="truncate_show_less">' + opts.lessPrefix + '<a href="#show_less_content">'+opts.less+'</a>' + opts.lessSuffix + '</span>');

      truncated_node.find('a:last').bind(opts.event, opts.moreCallback ? opts.moreCallback(truncated_node, full_node) : function() {
        truncated_node.hide(); full_node.show(); return false;
      });
      full_node.find('a:last').bind(opts.event, opts.lessCallback ? opts.lessCallback(truncated_node, full_node) : function() {
        truncated_node.show(); full_node.hide(); return false;
      }); 
//      truncated_node.find('a:last').click(function() {
//        truncated_node.hide(); 
//        full_node.slideDown('slow'); return false;
//      });
//      full_node.find('a:last').click(function() {
//        full_node.slideUp('slow', function () {
//        		truncated_node.show();  
//        		return false;
//        });
//      });

    });
  }

  // Note that the " (Émore)" bit counts towards the max length Ð so a max
  // length of 10 would truncate "1234567890" to "12 (Émore)".
  $.fn.truncate.defaults = {
    max_length: 100,
    more: 'more',
    morePrefix: '...&nbsp;(',
    moreSuffix: ')',
    less: 'less', 
    lessPrefix: ' (',
    lessSuffix: ')', 
    event: 'click', 
   	moreCallback: null, 
   	lessCallback: null
  };

  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().empty();
    var truncatedChild;
    node.contents().each(function() {
      var remaining_length = max_length - new_node.text().length;
      if (remaining_length == 0) return;  // breaks the loop
      truncatedChild = recursivelyTruncate(this, remaining_length);
      if (truncatedChild) new_node.append(truncatedChild);
    });
    return new_node;
  }

  function truncateText(node, max_length) {
    var text = squeeze(node.data);
    if (trailing_whitespace)  // remove initial whitespace if last text
      text = text.replace(/^ /, '');  // node had trailing whitespace.
    trailing_whitespace = !!text.match(/ $/);
    var text = text.slice(0, max_length);
    // Ensure HTML entities are encoded
    // http://debuggable.com/posts/encode-html-entities-with-jquery:480f4dd6-13cc-4ce9-8071-4710cbdd56cb
    text = $('<div/>').text(text).html();
    return text;
  }

  // Collapses a sequence of whitespace into a single space.
  function squeeze(string) {
    return string.replace(/\s+/g, ' ');
  }
  
  // Finds the last, innermost block-level element
  function findNodeForMore(node) {
    var $node = $(node);
    var last_child = $node.children(":last");
    if (!last_child) return node;
    var display = last_child.css('display');
    if (!display || display=='inline') return $node;
    return findNodeForMore(last_child);
  };

  // Finds the last child if it's a p; otherwise the parent
  function findNodeForLess(node) {
    var $node = $(node);
    var last_child = $node.children(":last");
    if (last_child && last_child.is('p')) return last_child;
    return node;
  };

})(jQuery);



//jQuery.fn.truncate = function( max, settings ) {
//    settings = jQuery.extend( {
//        chars: /\s/,
//        trail: [ "...", "" ]
//    }, settings );
//    var myResults = {};
//    var ie = $.browser.msie;
//    function fixIE( o ) {
//        if ( ie ) {
//            o.style.removeAttribute( "filter" );
//        }
//    }
//    return this.each( function() {
//        var $this = jQuery(this);
//        var myStrOrig = $this.html().replace( /\r\n/gim, "" );
//        var myStr = myStrOrig;
//        var myRegEx = /<\/?[^<>]*\/?>/gim;
//        var myRegExArray;
//        var myRegExHash = {};
//        var myResultsKey = $("*").index( this );
//        while ( ( myRegExArray = myRegEx.exec( myStr ) ) != null ) {
//            myRegExHash[ myRegExArray.index ] = myRegExArray[ 0 ];
//        }
//        myStr = jQuery.trim( myStr.split( myRegEx ).join( "" ) );
//        if ( myStr.length > max ) {
//            var c;
//            while ( max < myStr.length ) {
//                c = myStr.charAt( max );
//                if ( c.match( settings.chars ) ) {
//                    myStr = myStr.substring( 0, max );
//                    break;
//                }
//                max--;
//            }
//            if ( myStrOrig.search( myRegEx ) != -1 ) {
//                var endCap = 0;
//                for ( eachEl in myRegExHash ) {
//                    myStr = [ myStr.substring( 0, eachEl ), myRegExHash[ eachEl ], myStr.substring( eachEl, myStr.length ) ].join( "" );
//                    if ( eachEl < myStr.length ) {
//                        endCap = myStr.length;
//                    }
//                }
//                $this.html( [ myStr.substring( 0, endCap ), myStr.substring( endCap, myStr.length ).replace( /<(\w+)[^>]*>.*<\/\1>/gim, "" ).replace( /<(br|hr|img|input)[^<>]*\/?>/gim, "" ) ].join( "" ) );
//            } else {
//                $this.html( myStr );
//            }
////            myResults[ myResultsKey ] = '<span class="truncate_more_begin">' + $this.html() + '</span>' + myStrOrig;
//            myResults[ myResultsKey ] = '<span class="truncate_more_begin">' + $this.html() + '</span>' + myStrOrig.substring($this.html().length);
//            $this.html( [ "<div class='truncate_less_prop'>&nbsp;</div>", "<div class='truncate_less'>", $this.html(), "<span class='truncate_show_whole'>", settings.trail[0], '</span>', "</div>" ].join( "" ) )
//            .find(".truncate_show",this).click( function() {
//                if ( $this.find( ".truncate_more" ).length == 0 ) {
//                    $this.append( [ "<div class='truncate_more' style='display:none; '>", myResults[myResultsKey], settings.trail[1], "</div>"/*, "<span class='truncate_clear'>", "</span>" */].join( "" ) )
//                    .find( ".truncate_hide" ).click( function() {
//                    	$this.find('.truncate_show_whole').css('visibility', 'hidden');//hide();
//                    	$this.find('.truncate_more_begin').css('visibility', 'hidden');
//                    	$this.find( ".truncate_less" ).show()/*.css( "background", "#fff" )*/.css('position', 'absolute');//.fadeIn('normal');
//                        $this.find( ".truncate_more" )/*.css( "background", "#fff" )*/.slideUp( 'slow', function() {
////                            $this.find( ".truncate_less" ).css( "background", "#fff" ).css('position', 'absolute').show();//fadeIn( "normal", function() {
////                            	alert('after_less');
//								$this.find('.truncate_show_whole').css('visibility', '').show();
//								$this.find( ".truncate_less" ).css('top', '').css('position', 'relative').width('');//.height('');
//                                fixIE( this );
////                                $(this).css( "background", "none" );
////                            });
//                            fixIE( this );
//                        });
//                        return false;
//                    });
//                }
////                $this.find('.truncate_less_prop')
//                // fix to preserve text wraping when setting position to absolute
//                $tmp = $this.find(".truncate_less");
//                $tmp.width($tmp.width()).height($tmp.height()).css({margin: 0, padding: 0});
////                $this.find(".truncate_less").css('backgroundColor', 'blue').end().parent().css('backgroundColor', 'green');
//                $this.find('.truncate_show_whole').css('visibility', 'hidden');//.hide();
//                $this.find(".truncate_less").css({position: 'absolute'/*, top: $this.find(".truncate_less").offset().top  + 'px'*/});//.fadeOut('normal');//.fadeOut( "normal");//, function() {
//                	$this.find('.truncate_more_begin').css('visibility', 'hidden');
//                    $this.find( ".truncate_more" ).width($tmp.width()).height($this.find( ".truncate_more" ).height()).slideDown( 'slow', function() {
//                    	$this.find('.truncate_more_begin').css('visibility', '');
//                    	$this.find( ".truncate_less" ).hide();
////                    $this.find( ".truncate_more" ).width($tmp.width()).animate({height: $this.find( ".truncate_more" ).height()}, 5000/*, 'linear', function() {
////                            	alert('after_more');
////						$this.find('.truncate_show_whole').css('visibility', '');//.show();
////						$this.find( ".truncate_less" ).hide().css('position', 'relative');
//                        fixIE( this );
//                    }).width('');
//                    fixIE( this );
////                });
//
//
//
//                $(".truncate_show",$this).click( function() {
//                	$tmp = $this.find(".truncate_less");
//                	$tmp.width($tmp.width()).height($tmp.height()).css({margin: 0, padding: 0});
//                	$this.find('.truncate_show_whole').css('visibility', 'hidden');//.hide();
//                    $this.find( ".truncate_less" )/*.css( "background", "#fff" )*/.css({position: 'absolute'/*, top: $this.find(".truncate_less").offset().top + 'px'*/});//.fadeOut( "normal");//, function() {
//                    	$this.find('.truncate_more_begin').css('visibility', 'hidden');
//                        $this.find( ".truncate_more" ).width($tmp.width()).height($this.find( ".truncate_more" ).height())/*.css( "background", "#fff" )*/.slideDown( 'slow', function() {
//                        	$this.find('.truncate_more_begin').css('visibility', '');
//                        	$this.find( ".truncate_less" ).hide();
////                        $this.find( ".truncate_more" ).width($tmp.width()).animate({height: $this.find( ".truncate_more" ).height()}, 5000/*, 'linear', function() {
////                        	alert('after_more_x2');
////							$this.find('.truncate_show_whole').css('visibility', '');//.show();
////							$this.find( ".truncate_less" ).hide().css('position', 'relative');
//                            fixIE( this );
//                            $(this).css( "background", "none" );
//                        }).width('');
//                        fixIE( this );
////                    });
//                    return false;
//                });
//                return false;
//                $tmp.width('').height('');
//            });
//        }
//    });
//};