/*

	filename:	/js/ajaxSuggests.js
	version:	1.3 - 2007-03-28 - mkr

	author:		martin (dot) krause (at) gpm (dot) de 

*/

/*
	1.3 - mkr: added autocomplete="off"
	1.2 - mkr: added param outputParent on constructor.
*/

/*!
@function ajaxSuggests()
@abstract constructor, inititalizes ajaxSuggests, ajaxSuggests = new ajaxSuggests();
@result type ahead suggestions, featuring keyboard enabled scrolling results 
*/
function ajaxSuggests (outputParent) {

	// DOM check
	if ( 
		!document.getElementById || 
		!document.getElementsByTagName ||
		!document.createElement ||
		!document.appendChild
		) { return true; }


	// check for self
	if (!self) {this.self = this; }

	// input element aka searchbox
	self.input = {
			id: 'searchInput'
	}
	
	// output element, containing results
	self.output = {
			id: 'searchsuggest',
			cnHide:'skip',
			HTMLElement:'div'
	}

	// suggestion elements
	self.suggestion = {
			cnSelected: 'selected'
	};
	
	// create output element, refer parent element
	this.createOutputEl(outputParent);
	
	// chache elements
	self._inputEl = document.getElementById(self.input['id']);
	self._outputEl = document.getElementById(self.output['id']);

	// prepare collection
	self.col = [];
	
	// just be safe
	self._inputEl.disabled = false;
}


/*!
@function ajaxSuggests.updateResults()
@abstract updates results array after request
@result returns an updated array of elements inside output element
*/
ajaxSuggests.prototype.updateResults = function () {
		if (!self._outputEl) { self._outputEl = document.getElementById(self.output['id']); }
		self.col = self._outputEl.getElementsByTagName('a');
}


/*!
@function ajaxSuggests.createRoot(_parent)
@abstract checks for output element, creates and append it if necessary - uses document.body as fallback
@param parent element or parent's element.id as string 
@result being sure that the output element is part of the DOM but not visible
*/
ajaxSuggests.prototype.createOutputEl = function (_parent) {
		if (!self._outputEl) {
			var _parent = ( (typeof(_parent) == 'string') ? document.getElementById(_parent) : _parent ) || document.body;
			var _nE = document.createElement(self.output['HTMLElement']);
			_nE.id = self.output['id'];
			_nE.className = self.output['cnHide'];
			_parent.appendChild(_nE);
		}
}


/*!
@function ajaxSuggests.hideOutputEl()
@abstract cheks for outputElement and its classname. If self.output.cnHide ain't part of the classes, add it
@result hidden output element
*/
ajaxSuggests.prototype.hideOutputEl = function () {
	if( self._outputEl && !self._outputEl.className.strstr(self.output['cnHide']) ) {
		self._outputEl.className += (' '+self.output['cnHide'] );
	}
}


/*!
@function ajaxSuggests.showOutputEl()
@abstract cheks for outputElement and its classname. If self.output.cnHide is part of the classes, remove it
@result visible output element
*/
ajaxSuggests.prototype.showOutputEl = function () {
	if( self._outputEl && self._outputEl.className.strstr(self.output['cnHide']) ) {
		self._outputEl.className = self._outputEl.className.strReplace(self.output['cnHide'],'')
	}
}

/*!
@function ajaxSuggests.run
@abstract listen to keystrokes, if searchbox is the event element, and a valid key is pressed - run httprequest. If key is esc,  quit and hide suggesgtions, if the user pressed either arrow up or arrwo down, call private function 'updateView' that scrolls trought suggestions, writes current into input element.
@param window.event
@result nice srolling suggestions
*/
ajaxSuggests.prototype.run = function (e) {

	// check event
	var e = e || window.event;

	// grab keycode
	_keycode = e.keyCode;

	// key: escape - hide'n exit
	if ( _keycode==27) {
		ajaxSuggests.hideOutputEl();
		return;
	}

	// key: neither up nor down arrow - run request
	if ( _keycode!=38 && _keycode!=40 )  {
		loadXMLDoc('/inc/inc.search.php?suggest=1&s='+document.forms.formSearch.searchInput.value);
	}

	// cache n
	var n = self.col.length;

	// set focus to input - disables ie pagescroll
	self._inputEl.focus();

	// key: arrow up
	if ( _keycode == 40 ) 
	{
		var _direction = +1;
		updateView();
	}
	// key: arrow down
	if ( _keycode == 38 ) 
	{
		var _direction = -1;
		updateView();
	}
	
	
	/*!
	@function private - ajaxSuggests.run.updateView
	@abstract 'scroll trought suggestions' - aka change classnames, write currend into input element. be aware of border elements, jump to first/last element.
	@result nice srolling suggestions
	*/
	function updateView() {
		// max steps equals number of elements
		var _max = n;
		while (n--)
		{
			// cache current element
			var _el = self.col[n];
			var _elcn = _el.className;
			// current element equals current selection
			if (_elcn.strstr(self.suggestion['cnSelected'])) 
			{
				// get sibling becoming the new selection, check border elements
				var _nSib = ( (n+_direction) < 0 ) ? (_max-1) : ( (n+_direction > _max-1) ? 0 : (n+_direction) );
				var sib = self.col[_nSib];
				// change classnames 
				_el.className = _elcn.replace(self.suggestion['cnSelected'],'');
				sib.className += (' '+self.suggestion['cnSelected']);
				// print value 
				// self._inputEl.value = (sib.text);
				var _highlight = sib.firstChild.firstChild.nodeValue;
				var _slice = sib.lastChild.nodeValue;
				_slice = (_slice != null ) ? _slice : '';
				self._inputEl.value = (_highlight+_slice);
				return;
			}
		}
	}
};

/*!
@function String.trim()
@abstract removes trailing / leading spaces jump to first/last element.
@result use php-like trim on strings
*/
String.prototype.trim = function() {
		return this.replace(/^\s+|\s+$/g, '');
}

/*!
@function String.strstr (str) {
@abstract strstr, test for given substring
@param string to search for 
@result use php-like strstr on strings
*/
String.prototype.strstr = function(str) {
	return !!this.match("\\b"+str+"\\b");
}

/*!
@function String.strReplace (foe,friend)
@abstract sreplace foe with friend
@param foe: string to replace, friend: string being insert
@result use php-like strReplace on strings
*/
String.prototype.strReplace = function(foe,friend) {
	return this.replace(foe.trim(),friend);
}

// add events
addEvent(window,'load', function () { var _el = document.getElementById('formSearch'); document.getElementById('searchInput').setAttribute('autocomplete','off');  ajaxSuggests = new ajaxSuggests('formSearch');  addEvent(_el,'keyup',ajaxSuggests.run); addEvent(_el,'blur',ajaxSuggests.hideOutputEl);});

