/******************************************************************************************************	jQuery.NobleCount	Author Jeremy Horn	Version 1.0	Date: 3/21/2010	Copyright (c) 2010 Jeremy Horn- jeremydhorn(at)gmail(dot)c0m | http://tpgblog.com	Dual licensed under MIT and GPL.	DESCRIPTION		NobleCount... for a more 'proper' count of the characters remaining.				NobleCount is a customizable jQuery plugin for a more the improved counting of the remaining 		characters, and resulting behaviors, of a text entry object, e.g. input textfield, textarea.		As text is entered into the target text area an object for the purposes of tracking		the total number of characters remaining, defined as the maximum number of characters		minus the current total number of characters within the text entry object, and storing		that information visually and/or within the DOM as an HTML 5 compliant data-* attribute.				Events and CSS Class alterations, if defined, are triggered based on current user 		interaction with the target text entry object as well as the current state (positive or 		negative) of the character remaining value.		NobleCount supports pre-existing text within the text object.		NobleCount supports jQuery chaining.		Within NobleCount context...			NEGATIVE is defined as Integers < 0			POSITIVE is defined as Integers >= 0		[on_positive will fire when char_rem == 0]		BY DEFAULT		 - maximum characters EQUAL 140 characters		 - no events defined		 - no class changes defined		 - no DOM attributes are created/altered		 - user permitted to type past the maximum number of characters limit, resulting in		   negative number of characters remaining		IMPLEMENTATION		$('#textarea1').NobleCount('#characters_remaining1');		$('#textfield2').NobleCount('#characters_remaining2', { / * OPTIONS * / });			COMPATIBILITY		Tested in FF3.5, IE7		With jQuery 1.3.x, 1.4.x	METHOD(S)		To properly intialize, both the text entry object and the object that will store the		total number of characters remaining must exist and be passed to NobleCount.					$(TEXT_ENTRY_OBJECT).NobleCount(CHARACTERS_REMAINING_OBJECT);				Any callback functions assigned to any of the availale events are passed the following		parameters: t_obj, char_area, c_settings, char_rem					t_obj			text entry object						char_area		selection of the characters remaining object						c_settings		result of the options passed into NobleCount at time of 							initialization merged with the default options														** this is a GREAT way to pass in and remember other state							information that will be needed upon the triggering of							NobleCount events **						char_rem		integer representation of the total number of characters							remaining resulting from the calculated difference between							the target maximum number of characters and the current							number of characters currently within t_obj				Both TEXT_ENTRY_OBJECT and CHARACTERS_REMAINING_OBJECT must be specified and valid.				Upon successful initialization, all appropriate events and classes are applied to		the CHARACTERS_REMAINING_OBJECT, including the storage (if not disabled) visually		or only in the DOM (if enabled) of the integer representing the number of characters		remaining.				The target maximum number of characters (max_chars) are determined by the following 		precedence rules....						if max_chars passed via constructor					max_chars = max_chars passed				else if number exists within characters_remaining object and number > 0					max_chars = number within the text() of characters_remaining object				else use the NobleCount's default max_chars			CUSTOMIZATION		NobleCount(c_obj, <OPTIONS>)		e.g. $(t_obj).NobleCount(c_obj, {max_chars:100px});		on_negative				class (STRING) or FUNCTION that is applied/called 								when characters remaining is negative IF DEFINED											on_positive				class (STRING) or FUNCTION that is applied/called 								when characters remaining is positive IF DEFINED											on_update				FUNCTION that is called when characters remaining changes										max_chars				target maximum number of characters				block_negative			if TRUE, then all attempts are made to block entering 									more than max_characters; not effective against user									pasting in blocks of text that exceed the max_chars value								otherwise, text area will let individual entering the text									to exceed max_chars limit (characters remaining becomes									negative)										cloak: false,			if TRUE, then no visual updates of characters remaining 									object (c_obj) will occur; this does not have any effect									on the char_rem value returned via any event callbacks								otherwise, the text within c_obj is constantly updated to									represent the total number of characters remaining until									the max_chars limit has been reached								  		in_dom: false			if TRUE and cloak is ALSO TRUE, then the number of characters									remaining are stored as the attribute of c_obj									named 'data-noblecount'																		!NOTE: if enabled, due to constant updating of a DOM element										attribute user experience can appear sluggish while										the individual is modifying the text entry object (t_obj)										EXAMPLE	OPTIONS = 			{				on_negative: 'go_red',				on_positive: 'go_green',				max_chars: 25,				on_update: function(t_obj, char_area, c_settings, char_rem){					if ((char_rem % 10) == 0) {						char_area.css('font-weight', 'bold');						char_area.css('font-size', '300%');					} else {						char_area.css('font-weight', 'normal');						char_area.css('font-size', '100%');					}				}			};	MORE		For more details about NobleCount, its implementation, usage, and examples, go to:		http://tpgblog.com/noblecount/******************************************************************************************************/(function($) {	/**********************************************************************************		FUNCTION			NobleCount		DESCRIPTION			NobleCount method constructor						allows for customization of maximum length and related update/length			behaviors							e.g. $(text_obj).NobleCount(characters_remaining_obj);			REQUIRED: c_obj			OPTIONAL: options	**********************************************************************************/	$.fn.NobleCount = function(c_obj, options) {		var c_settings;		var mc_passed = false;		// if c_obj is not specified, then nothing to do here		if (typeof c_obj == 'string') {			// check for new & valid options			c_settings = $.extend({}, $.fn.NobleCount.settings, options);			// was max_chars passed via options parameter? 			if (typeof options != 'undefined') {				mc_passed = ((typeof options.max_chars == 'number') ? true : false);			}			// process all provided objects			return this.each(function(){				var $this = $(this);				// attach events to c_obj				attach_nobility($this, c_obj, c_settings, mc_passed);			});		}				return this;	};	/**********************************************************************************		FUNCTION			NobleCount.settings		DESCRIPTION			publically accessible data stucture containing the max_chars and 			event handling specifications for NobleCount						can be directly accessed by	'$.fn.NobleCount.settings = ... ;'	**********************************************************************************/	$.fn.NobleCount.settings = {		on_negative: null,		// class (STRING) or FUNCTION that is applied/called 								// 		when characters remaining is negative		on_positive: null,		// class (STRING) or FUNCTION that is applied/called 								// 		when characters remaining is positive		on_update: null,		// FUNCTION that is called when characters remaining 								// 		changes		max_chars: 140,			// maximum number of characters		block_negative: false,  // if true, then all attempts are made to block entering 								//		more than max_characters		cloak: false,			// if true, then no visual updates of characters 								// 		remaining (c_obj) occur		in_dom: false			// if true and cloak == true, then number of characters								//		remaining are stored as the attribute								//		'data-noblecount' of c_obj					};	//////////////////////////////////////////////////////////////////////////////////	// private functions and settings	/**********************************************************************************		FUNCTION			attach_nobility			DESCRIPTION			performs all initialization routines and display initiation						assigns both the keyup and keydown events to the target text entry			object; both keyup and keydown are used to provide the smoothest			user experience					if max_chars_passed via constructor					max_chars = max_chars_passed				else if number exists within counting_object (and number > 0)					max_chars = counting_object.number				else use default max_chars			PRE			t_obj and c_obj EXIST			c_settings and mc_passed initialized					POST			maximum number of characters for t_obj calculated and stored in max_char			key events attached to t_obj		**********************************************************************************/	function attach_nobility(t_obj, c_obj, c_settings, mc_passed){		var max_char 	= c_settings.max_chars;		var char_area	= $(c_obj);		// first determine if max_char needs adjustment		if (!mc_passed) {			var tmp_num = char_area.text();			var isPosNumber = (/^[1-9]\d*$/).test(tmp_num);			if (isPosNumber) {				max_char = tmp_num;			}		}		// initialize display of characters remaining		// * note: initializing should not trigger on_update		event_internals(t_obj, char_area, c_settings, max_char, true);		// then attach the events -- seem to work better than keypress		$(t_obj).keydown(function(e) {			event_internals(t_obj, char_area, c_settings, max_char, false);			// to block text entry, return false			if (check_block_negative(e, t_obj, c_settings, max_char) == false) {				return false;			} 		});		$(t_obj).keyup(function(e) {			event_internals(t_obj, char_area, c_settings, max_char, false);						// to block text entry, return false			if (check_block_negative(e, t_obj, c_settings, max_char) == false) {				return false;			} 		});	}	/**********************************************************************************		FUNCTION			check_block_negative			DESCRIPTION			determines whether or not text entry within t_obj should be prevented					PRE			e EXISTS			t_obj VALID			c_settings and max_char initialized / calculated					POST			if t_obj text entry should be prevented FALSE is returned				otherwise TRUE returned			TODO			improve selection detection and permissible behaviors experience			ALSO				doesnt CURRENTLY block from the pasting of large chunks of text that 				exceed max_char			**********************************************************************************/	function check_block_negative(e, t_obj, c_settings, max_char){		if (c_settings.block_negative) {			var char_code = e.which;			var selected;			// goofy handling required to work in both IE and FF			if (typeof document.selection != 'undefined') {				selected = (document.selection.createRange().text.length > 0);			} else {				selected = (t_obj[0].selectionStart != t_obj[0].selectionEnd);			}			//return false if can't write more  			if ((!((find_remaining(t_obj, max_char) < 1) &&				(char_code > 47 || char_code == 32 || char_code == 0 || char_code == 13) &&				!e.ctrlKey &&				!e.altKey &&				!selected)) == false) {								// block text entry				return false;			}		}				// allow text entry		return true;	}	/**********************************************************************************		FUNCTION			find_remaining			DESCRIPTION			determines of the number of characters permitted (max_char), the number of 			characters remaining until that limit has been reached  			PRE			t_obj and max_char EXIST and are VALID					POST			returns integer of the difference between max_char and total number of			characters within the text entry object (t_obj)		**********************************************************************************/	function find_remaining(t_obj, max_char){		return max_char - ($(t_obj).val()).length;	}	/**********************************************************************************		FUNCTION			event_internals			DESCRIPTION			primarily used for the calculation of appropriate behavior resulting from			any event attached to the text entry object (t_obj)				whenever the char_rem and related display and/or DOM information needs			updating this function is called			if cloaking is being used, then no visual representation of the characters			remaining, nor attempt by this plugin to change any of its visual 			characteristics will occur						if cloaking and in_dom are both TRUE, then the number of characters 			remaining are stored within the HTML 5 compliant attribute of the			character count remaining object (c_obj) labeled 'data-noblecount'					PRE			c_settings, init_disp initialized					POST			performs all updates to the DOM visual and otherwise required			performs all relevant function calls		**********************************************************************************/	function event_internals(t_obj, char_area, c_settings, max_char, init_disp) {		var char_rem	= find_remaining(t_obj, max_char);		// is chararacters remaining positive or negative		if (char_rem < 0) {			toggle_states(c_settings.on_negative, c_settings.on_positive, t_obj, char_area, c_settings, char_rem);		} else {			toggle_states(c_settings.on_positive, c_settings.on_negative, t_obj, char_area, c_settings, char_rem);		}			// determine whether or not to update the text of the char_area (or c_obj)		if (c_settings.cloak) {			// this slows stuff down quite a bit; TODO: implement better method of publically accessible data storage			if (c_settings.in_dom) {				char_area.attr('data-noblecount', char_rem);			}		} else {			// show the numbers of characters remaining 			char_area.text(char_rem);		}		// if event_internals isn't being called for initialization purposes and		// on_update is a properly defined function then call it on this update		if (!init_disp && jQuery.isFunction(c_settings.on_update)) {			c_settings.on_update(t_obj, char_area, c_settings, char_rem);		} 	}	/**********************************************************************************		FUNCTION			toggle_states			DESCRIPTION			performs the toggling operations between the watched positive and negative			characteristics						first, enables/triggers/executes the toggle_on behavior/class			second, disables the trigger_off class			PRE			toggle_on, toggle_off				IF DEFINED, 					must be a string representation of a VALID class					OR					must be a VALID function 					POST			toggle_on objects have been applied/executed			toggle_off class has been removed (if it is a class)		**********************************************************************************/	function toggle_states(toggle_on, toggle_off, t_obj, char_area, c_settings, char_rem){		if (toggle_on != null) {			if (typeof toggle_on == 'string') {				char_area.addClass(toggle_on);							} else if (jQuery.isFunction(toggle_on)) {				toggle_on(t_obj, char_area, c_settings, char_rem);			}		}				if (toggle_off != null) {			if (typeof toggle_off == 'string') {				char_area.removeClass(toggle_off);							}		}			}})(jQuery);
