
if (!window['$hnj'] || !$hnj.registry.included('/scripts/libraries/jquery/plugins/jquery.threedots/jquery.threedots.js')) { 
/******************************************************************************************************

jQuery.ThreeDots

Author Jeremy Horn
Version 1.0.3 (Developed in Aptana Studio 1.5.1)
Date: 10/30/2009

Copyright (c) 2009 Jeremy Horn- jeremydhorn(at)gmail(dot)c0m | http://tpgblog.com
Dual licensed under MIT and GPL.

For more detailed documentation, including the latest updates and links to more usage and 
examples, go to:
	
http://tpgblog.com/ThreeDots/

******************************************************************************************************/


(function ($) {

	/**********************************************************************************

	METHOD
	ThreeDots {PUBLIC}

	DESCRIPTION
	ThreeDots method constructor
			
	allows for the customization of ellipsis, delimiters, etc., and smart 
	truncation of provided objects' text
					
	e.g. $(something).ThreeDots();

	**********************************************************************************/

	$hnj.fn.ThreeDots = function (options) {
		var return_value = this;

		// check for new & valid options
		if ((typeof options == 'object') || (options == undefined)) {
			$hnj.fn.ThreeDots.the_selected = this;

			var return_value = $hnj.fn.ThreeDots.update(options);

		}

		return return_value;
	};


	/**********************************************************************************

	METHOD
	ThreeDots.update {PUBLIC}

	DESCRIPTION
	applies the core logic of ThreeDots
			
	allows for the customization of ellipsis, delimiters, etc., and smart 
	truncation of provided objects' text
			
	updates the objects' visible text to fit within its container(s)
		
	TODO
	instead of having all options/settings calls be constructive have 
	settings associated w/ object returned also accessible from HERE 
	[STATIC settings, associated w/ the initial call] 

	**********************************************************************************/

	$hnj.fn.ThreeDots.update = function (options) {
		// initialize local variables
		var curr_this, last_word = null;
		var lineh, paddingt, paddingb, innerh, temp_height;
		var curr_text_span, lws; /* last word structure */
		var last_text, three_dots_value, last_del;

		// check for new & valid options
		if ((typeof options == 'object') || (options == undefined)) {

			// then update the settings
			// CURRENTLY, settings are not CONSTRUCTIVE, but merged with the DEFAULTS every time
			$hnj.fn.ThreeDots.c_settings = $hnj.extend({}, $hnj.fn.ThreeDots.settings, options);
			var max_rows = $hnj.fn.ThreeDots.c_settings.max_rows;
			if (max_rows < 1) {
				return $hnj.fn.ThreeDots.the_selected;
			}

			// make sure at least 1 valid delimiter
			var valid_delimiter_exists = false;
			$hnj.each($hnj.fn.ThreeDots.c_settings.valid_delimiters, function (i, curr_del) {
				if (((new String(curr_del)).length == 1)) {
					valid_delimiter_exists = true;
				}
			});
			if (valid_delimiter_exists == false) {
				return $hnj.fn.ThreeDots.the_selected;
			}

			// process all provided objects
			$hnj.fn.ThreeDots.the_selected.each(function () {

				// element-specific code here
				curr_this = $hnj(this);

				// obtain the text span
				if ($hnj(curr_this).children('.' + $hnj.fn.ThreeDots.c_settings.text_span_class).length == 0) {
					// if span doesnt exist, then go to next
					return true;
				}
				curr_text_span = $hnj(curr_this).children('.' + $hnj.fn.ThreeDots.c_settings.text_span_class).get(0);

				// pre-calc fixed components of num_rows
				var nr_fixed = num_rows(curr_text_span, true);

				// remember where it all began so that we can see if we ended up exactly where we started
				var init_text_span = $hnj(curr_text_span).text();

				// if the object has been initialized, then user must be calling UPDATE
				// THEREFORE refresh the text area before re-operating
				if ((three_dots_value = $hnj(curr_this).attr('threedots')) != undefined) {
					$hnj(curr_text_span).text(three_dots_value);
					$hnj(curr_this).children('.' + $hnj.fn.ThreeDots.c_settings.e_span_class).remove();
				}

				last_text = $hnj(curr_text_span).text();
				if (last_text.length <= 0) {
					last_text = '';
				}
				$hnj(curr_this).attr('threedots', last_text);

				if (num_rows(curr_text_span, nr_fixed) > max_rows) {

					$hnj(curr_text_span).attr("title", $hnj(curr_text_span).text());
					// remove 1 word at a time UNTIL max_rows
					while (num_rows(curr_text_span, nr_fixed) > max_rows) {

						lws = the_last_word($hnj(curr_text_span).text());

						$hnj(curr_text_span).text(lws.updated_string);

						/* add the ellipsis string for each calculation */
						$hnj(curr_text_span).html($hnj(curr_text_span).html() + $hnj.fn.ThreeDots.c_settings.ellipsis_string);

						last_word = lws.word;
						last_del = lws.del;

						if (lws.del == null) {
							break;
						}
					}

				}

			});
		}

		return $hnj.fn.ThreeDots.the_selected;
	};


	/**********************************************************************************

	METHOD
	ThreeDots.settings {PUBLIC}

	DESCRIPTION
	data structure containing the max_rows, ellipsis string, and other
	behavioral settings
			
	can be directly accessed by '$hnj.fn.ThreeDots.settings = ...... ;'

	**********************************************************************************/

	$hnj.fn.ThreeDots.settings = {
		valid_delimiters: [' ', ',', '.'], 	// what defines the bounds of a word to you?
		ellipsis_string: '&hellip;',
		max_rows: 1,
		text_span_class: 'ellipsis_text',
		e_span_class: 'threedots_ellipsis',
		whole_word: true,
		allow_dangle: false,
		alt_text_e: false, 				// if true, mouse over of ellipsis displays the full text
		alt_text_t: false  					// if true & if ellipsis displayed, mouse over of text displays the full text
	};


	/**********************************************************************************

	METHOD
	num_rows {private}

	DESCRIPTION
	returns the number of rows/lines that the current object's text covers if
	cstate is an object
			
	this function can be initially called to pre-calculate values that will 
	stay fixed throughout the truncation process for the current object so
	that the values do not have to be called every time; to do this the
	num_rows function is called with a boolean value within the cstate
			
	when boolean cstate, an object is returned containing padding and line
	height information that is then passed in as the cstate object on
	subsequent calls to the function

	**********************************************************************************/

	function num_rows(obj, cstate) {
		var the_type = typeof cstate;

		if ((the_type == 'object')
			|| (the_type == undefined)) {

			var paddingt = cstate.pt;
			var paddingb = cstate.pb;
			var lineheight = cstate.lh;

			// do the math
			var innerh = parseInt($hnj(obj).innerHeight()); // get the latest height

			var n_rows = (innerh - (paddingt + paddingb)) / lineheight;

			return n_rows;

		} else if (the_type == 'boolean') {

			// ASSUMPTION:  assuming padding returned ALWAYS in pixel scale 
			var paddingt = parseInt(($hnj(obj).css('padding-top')).replace('px', ''));
			var paddingb = parseInt(($hnj(obj).css('padding-bottom')).replace('px', ''));
			var lineheight = lineheight_px($hnj(obj));

			return {
				pt: paddingt,
				pb: paddingb,
				lh: lineheight
			};
		}
	}


	/**********************************************************************************

	METHOD
	the_last_word {private}

	DESCRIPTION
	return a data structure containing...
			 
	[word] 				the last word within the specified text	defined 
	by the specified valid_delimiters, 
	[del] 				the delimiter occurring	directly before the 
	word, and 
	[updated_string] 	the updated text minus the last word 
			
	[del] is null if the last word is the first and/or only word in the text 
	string

	**********************************************************************************/

	function the_last_word(str) {
		var temp_word_index;
		var v_del = $hnj.fn.ThreeDots.c_settings.valid_delimiters;

		// trim the string
		str = $hnj.trim(str);

		// initialize variables
		var lastest_word_idx = -1;
		var lastest_word = null;
		var lastest_del = null;

		// for all given delimiters, determine which delimiter results in the smallest word cut
		$hnj.each(v_del, function (i, curr_del) {
			if (((new String(curr_del)).length != 1)
				|| (curr_del == null)) {  // implemented to handle IE NULL condition; if only typeof could say CHAR :(
				return false; // INVALID delimiter; must be 1 character in length
			}

			var tmp_word_index = str.lastIndexOf(curr_del);
			if (tmp_word_index != -1) {
				if (tmp_word_index > lastest_word_idx) {
					lastest_word_idx = tmp_word_index;
					lastest_word = str.substring(lastest_word_idx + 1);
					lastest_del = curr_del;
				}
			}
		});

		// return data structure of word reduced string and the last word
		if (lastest_word_idx > 0) {
			return {
				updated_string: $hnj.trim(str.substring(0, lastest_word_idx/*-1*/)),
				word: lastest_word,
				del: lastest_del
			};
		} else { // the lastest word
			return {
				updated_string: '',
				word: $hnj.trim(str),
				del: null
			};
		}
	}


	/**********************************************************************************

	METHOD
	lineheight_px {private}

	DESCRIPTION
	returns the line height of a row of the provided text (within the text 
	span) in pixels

	**********************************************************************************/

	function lineheight_px(obj) {
		// shhhh... show
		$hnj(obj).append("<div id='temp_ellipsis_div' style='position:absolute; visibility:hidden'>H</div>");
		// measure
		var temp_height = $hnj('#temp_ellipsis_div').height();
		// cut
		$hnj('#temp_ellipsis_div').remove();

		return temp_height;
	}

})($hnj);
}
if (window['$hnj']) { $hnj.registry.register('/scripts/libraries/jquery/plugins/jquery.threedots/jquery.threedots.js', false); };


