/** * o------------------------------------------------------------------------------o * | This package is licensed under the Phpguru license. A quick summary is | * | that for commercial use, there is a small one-time licensing fee to pay. For | * | registered charities and educational institutes there is a reduced license | * | fee available. You can read more at: | * | | * | http://www.phpguru.org/static/license.html | * o------------------------------------------------------------------------------o * * © Copyright 2008,2009 Richard Heyes */ /** * Global vars */ __AutoComplete = new Array(); __AutoComplete_CSSOK = 0; // Basic UA detection isIE = document.all ? true : false; isGecko = navigator.userAgent.toLowerCase().indexOf('gecko') != -1; isOpera = navigator.userAgent.toLowerCase().indexOf('opera') != -1; /** * Remove the autocomplete object from a form element * * @param string formElement Name of form element to attach to */ function AutoComplete_Remove(id) { if(__AutoComplete[id] == undefined) return; if(__AutoComplete[id]['iframe']) __AutoComplete[id]['element'].parentNode.removeChild(__AutoComplete[id]['iframe']); if(__AutoComplete[id]['dropdown']) __AutoComplete[id]['element'].parentNode.removeChild(__AutoComplete[id]['dropdown']); var lid=0, nid; for (nid in __AutoComplete) { if (__AutoComplete[nid]['id']==id){ __AutoComplete.slice(lid,lid); } //lid=nid; lid++; } } /** * Attachs the autocomplete object to a form element. Sets * onkeypress event on the form element. * * @param string formElement Name of form element to attach to * @param array data Array of strings of which to use as the autocomplete data */ function AutoComplete_Create(id, data) { if(!document.getElementById(id)) return; var iv=document.getElementById(id).style.visibility; if(iv=='none') return; // pour le moment impossible d'avoir des autocomplete pour des elements encore cachés if(__AutoComplete[id] != undefined) return; __AutoComplete[id] = {'data':data, 'isVisible':false, 'element':document.getElementById(id), 'dropdown':null, 'highlighted':null, 'id':id }; __AutoComplete[id]['element'].setAttribute('autocomplete', 'off'); __AutoComplete[id]['element'].onkeydown = function(e) {return AutoComplete_KeyDown(this.getAttribute('id'), e);} __AutoComplete[id]['element'].onkeyup = function(e) {return AutoComplete_KeyUp(this.getAttribute('id'), e);} __AutoComplete[id]['element'].onkeypress = function(e) {if (!e) e = window.event; if (e.keyCode == 13 || isOpera) return false;} __AutoComplete[id]['element'].ondblclick = function() {AutoComplete_ShowDropdown(this.getAttribute('id'));} __AutoComplete[id]['element'].onclick = function(e) {if (!e) e = window.event; e.cancelBubble = true; e.returnValue = false;} if(!__AutoComplete_CSSOK){ var css1; css1=addCSSRule(".autocomplete"); css1.style.fontFamily="Tahoma"; css1.style.fontSize= "8pt"; css1.style.backgroundColor= "white"; css1.style.border= "1px solid black"; css1.style.position= "absolute"; css1.style.cursor= "default"; css1.style.overflow= "auto"; css1.style.overflowX= "hidden"; css1=addCSSRule(".autocomplete_item"); css1.style.padding="1px"; css1.style.paddingLeft="5px"; css1.style.color="black"; css1.style.width="100%"; css1=addCSSRule(".autocomplete_item_highlighted"); css1.style.padding="1px"; css1.style.paddingLeft="5px"; css1.style.color="white"; css1.style.backgroundColor="#0A246A"; __AutoComplete_CSSOK=1; } // Hides the dropdowns when document clicked var docClick = function() { for (id in __AutoComplete) { if (__AutoComplete[id]['isVisible']) AutoComplete_HideDropdown(id); } } if (document.addEventListener) { document.addEventListener('click', docClick, false); } else if (document.attachEvent) { document.attachEvent('onclick', docClick, false); } // Max number of items shown at once if (arguments[2] != null) { __AutoComplete[id]['maxitems'] = arguments[2]; __AutoComplete[id]['firstItemShowing'] = 0; __AutoComplete[id]['lastItemShowing'] = arguments[2] - 1; } AutoComplete_CreateDropdown(id); // Prevent select dropdowns showing thru if (isIE) { __AutoComplete[id]['iframe'] = document.createElement('iframe'); __AutoComplete[id]['iframe'].id = id +'_iframe'; __AutoComplete[id]['iframe'].style.position = 'absolute'; __AutoComplete[id]['iframe'].style.top = '0'; __AutoComplete[id]['iframe'].style.left = '0'; __AutoComplete[id]['iframe'].style.width = '0px'; __AutoComplete[id]['iframe'].style.height = '0px'; __AutoComplete[id]['iframe'].style.zIndex = '98'; __AutoComplete[id]['iframe'].style.visibility = 'hidden'; __AutoComplete[id]['element'].parentNode.insertBefore(__AutoComplete[id]['iframe'], __AutoComplete[id]['element']); } } /** * Creates the dropdown layer * * @param string id The form elements id. Used to identify the correct dropdown. */ function AutoComplete_CreateDropdown(id) { var left = AutoComplete_GetLeft(__AutoComplete[id]['element']); var top = AutoComplete_GetTop(__AutoComplete[id]['element']) + __AutoComplete[id]['element'].offsetHeight; var width = __AutoComplete[id]['element'].offsetWidth; __AutoComplete[id]['dropdown'] = document.createElement('div'); __AutoComplete[id]['dropdown'].className = 'autocomplete'; // Don't use setAttribute() __AutoComplete[id]['element'].parentNode.insertBefore(__AutoComplete[id]['dropdown'], __AutoComplete[id]['element']); // Position it __AutoComplete[id]['dropdown'].style.left = left + 'px'; __AutoComplete[id]['dropdown'].style.top = top + 'px'; __AutoComplete[id]['dropdown'].style.width = width + 'px'; __AutoComplete[id]['dropdown'].style.zIndex = '99'; __AutoComplete[id]['dropdown'].style.visibility = 'hidden'; } /** * Gets left coord of given element * * @param object element The element to get the left coord for */ function AutoComplete_GetLeft(element) { var curNode = element; var left = 0; do { left += curNode.offsetLeft; curNode = curNode.offsetParent; } while(curNode == null || curNode.tagName.toLowerCase() != 'body'); return left; } /** * Gets top coord of given element * * @param object element The element to get the top coord for */ function AutoComplete_GetTop(element) { var curNode = element; var top = 0; do { top += curNode.offsetTop; curNode = curNode.offsetParent; } while(curNode.tagName.toLowerCase() != 'body'); return top; } /** * Shows the dropdown layer * * @param string id The form elements id. Used to identify the correct dropdown. */ function AutoComplete_ShowDropdown(id) { AutoComplete_HideAll(); var value = __AutoComplete[id]['element'].value; var toDisplay = new Array(); var newDiv = null; var text = null; var numItems = __AutoComplete[id]['dropdown'].childNodes.length; // Remove all child nodes from dropdown while (__AutoComplete[id]['dropdown'].childNodes.length > 0) { __AutoComplete[id]['dropdown'].removeChild(__AutoComplete[id]['dropdown'].childNodes[0]); } // Go thru data searching for matches for (i=0; i<__AutoComplete[id]['data'].length; ++i) { if (__AutoComplete[id]['data'][i].substr(0, value.length).toLowerCase() == value.toLowerCase()){ toDisplay[toDisplay.length] = __AutoComplete[id]['data'][i]; } } // No matches? if (toDisplay.length == 0) { AutoComplete_HideDropdown(id); return; } // Add data to the dropdown layer for (i=0; i __AutoComplete[id]['maxitems'] && navigator.userAgent.indexOf('MSIE') == -1) { newDiv.style.width = parseInt(__AutoComplete[id]['element'].offsetWidth) - 22 + 'px'; } newDiv.onmouseover = function() {AutoComplete_HighlightItem(__AutoComplete[id]['element'].getAttribute('id'), this.getAttribute('index'));}; newDiv.onclick = function() {AutoComplete_SetValue(__AutoComplete[id]['element'].getAttribute('id')); AutoComplete_HideDropdown(__AutoComplete[id]['element'].getAttribute('id'));} text = document.createTextNode(toDisplay[i]); newDiv.appendChild(text); __AutoComplete[id]['dropdown'].appendChild(newDiv); } // Too many items? if (toDisplay.length > __AutoComplete[id]['maxitems']) { __AutoComplete[id]['dropdown'].style.height = (__AutoComplete[id]['maxitems'] * 15) + 2 + 'px'; } else { __AutoComplete[id]['dropdown'].style.height = ''; } /** * Set left/top in case of document movement/scroll/window resize etc */ __AutoComplete[id]['dropdown'].style.left = AutoComplete_GetLeft(__AutoComplete[id]['element']) + 'px'; __AutoComplete[id]['dropdown'].style.top = AutoComplete_GetTop(__AutoComplete[id]['element']) + parseInt(__AutoComplete[id]['element'].offsetHeight) + 'px'; // Show the iframe for IE if (isIE) { __AutoComplete[id]['iframe'].style.top = parseInt(__AutoComplete[id]['dropdown'].style.top) +'px'; __AutoComplete[id]['iframe'].style.left = parseInt(__AutoComplete[id]['dropdown'].style.left) +'px'; __AutoComplete[id]['iframe'].style.width = parseInt(__AutoComplete[id]['dropdown'].offsetWidth) +'px'; __AutoComplete[id]['iframe'].style.height = parseInt(__AutoComplete[id]['dropdown'].offsetHeight) +'px'; __AutoComplete[id]['iframe'].style.visibility = 'visible'; } // Show dropdown if (!__AutoComplete[id]['isVisible']) { __AutoComplete[id]['dropdown'].style.visibility = 'visible'; __AutoComplete[id]['isVisible'] = true; } // If now showing less items than before, reset the highlighted value if (__AutoComplete[id]['dropdown'].childNodes.length != numItems) { __AutoComplete[id]['highlighted'] = null; } } /** * Hides the dropdown layer * * @param string id The form elements id. Used to identify the correct dropdown. */ function AutoComplete_HideDropdown(id) { if (__AutoComplete[id]['iframe']) __AutoComplete[id]['iframe'].style.visibility = 'hidden'; __AutoComplete[id]['dropdown'].style.visibility = 'hidden'; __AutoComplete[id]['highlighted'] = null; __AutoComplete[id]['isVisible'] = false; } /** * Hides all dropdowns */ function AutoComplete_HideAll() { for (id in __AutoComplete) AutoComplete_HideDropdown(id); } /** * Highlights a specific item * * @param string id The form elements id. Used to identify the correct dropdown. * @param int index The index of the element in the dropdown to highlight */ function AutoComplete_HighlightItem(id, index) { if (__AutoComplete[id]['dropdown'].childNodes[index]) { for (var i=0; i<__AutoComplete[id]['dropdown'].childNodes.length; ++i) { if (__AutoComplete[id]['dropdown'].childNodes[i].className == 'autocomplete_item_highlighted') { __AutoComplete[id]['dropdown'].childNodes[i].className = 'autocomplete_item'; } } __AutoComplete[id]['dropdown'].childNodes[index].className = 'autocomplete_item_highlighted'; __AutoComplete[id]['highlighted'] = index; } } /** * Highlights the menu item with the given index * * @param string id The form elements id. Used to identify the correct dropdown. * @param int index The index of the element in the dropdown to highlight */ function AutoComplete_Highlight(id, index) { // Out of bounds checking if (index == 1 && __AutoComplete[id]['highlighted'] == __AutoComplete[id]['dropdown'].childNodes.length - 1) { __AutoComplete[id]['dropdown'].childNodes[__AutoComplete[id]['highlighted']].className = 'autocomplete_item'; __AutoComplete[id]['highlighted'] = null; } else if (index == -1 && __AutoComplete[id]['highlighted'] == 0) { __AutoComplete[id]['dropdown'].childNodes[0].className = 'autocomplete_item'; __AutoComplete[id]['highlighted'] = __AutoComplete[id]['dropdown'].childNodes.length; } // Nothing highlighted at the moment if (__AutoComplete[id]['highlighted'] == null) { __AutoComplete[id]['dropdown'].childNodes[0].className = 'autocomplete_item_highlighted'; __AutoComplete[id]['highlighted'] = 0; } else { if (__AutoComplete[id]['dropdown'].childNodes[__AutoComplete[id]['highlighted']]) { __AutoComplete[id]['dropdown'].childNodes[__AutoComplete[id]['highlighted']].className = 'autocomplete_item'; } var newIndex = __AutoComplete[id]['highlighted'] + index; if (__AutoComplete[id]['dropdown'].childNodes[newIndex]) { __AutoComplete[id]['dropdown'].childNodes[newIndex].className = 'autocomplete_item_highlighted'; __AutoComplete[id]['highlighted'] = newIndex; } } } /** * Sets the input to a given value * * @param string id The form elements id. Used to identify the correct dropdown. */ function AutoComplete_SetValue(id) { __AutoComplete[id]['element'].value = html_entity_decode( __AutoComplete[id]['dropdown'].childNodes[__AutoComplete[id]['highlighted']].innerHTML ); } /** * Checks if the dropdown needs scrolling * * @param string id The form elements id. Used to identify the correct dropdown. */ function AutoComplete_ScrollCheck(id) { // Scroll down, or wrapping around from scroll up if (__AutoComplete[id]['highlighted'] > __AutoComplete[id]['lastItemShowing']) { __AutoComplete[id]['firstItemShowing'] = __AutoComplete[id]['highlighted'] - (__AutoComplete[id]['maxitems'] - 1); __AutoComplete[id]['lastItemShowing'] = __AutoComplete[id]['highlighted']; } // Scroll up, or wrapping around from scroll down if (__AutoComplete[id]['highlighted'] < __AutoComplete[id]['firstItemShowing']) { __AutoComplete[id]['firstItemShowing'] = __AutoComplete[id]['highlighted']; __AutoComplete[id]['lastItemShowing'] = __AutoComplete[id]['highlighted'] + (__AutoComplete[id]['maxitems'] - 1); } __AutoComplete[id]['dropdown'].scrollTop = __AutoComplete[id]['firstItemShowing'] * 15; } /** * Function which handles the keypress event * * @param string id The form elements id. Used to identify the correct dropdown. */ function AutoComplete_KeyDown(id) { // Mozilla if (arguments[1] != null) { event = arguments[1]; } var keyCode = event.keyCode; switch (keyCode) { // Return/Enter case 13: if (__AutoComplete[id]['highlighted'] != null) { AutoComplete_SetValue(id); AutoComplete_HideDropdown(id); } event.returnValue = false; event.cancelBubble = true; break; // Escape case 27: AutoComplete_HideDropdown(id); event.returnValue = false; event.cancelBubble = true; break; // Up arrow case 38: if (!__AutoComplete[id]['isVisible']) { AutoComplete_ShowDropdown(id); } AutoComplete_Highlight(id, -1); AutoComplete_ScrollCheck(id, -1); return false; break; // Tab case 9: if (__AutoComplete[id]['isVisible']) { AutoComplete_HideDropdown(id); } return; // Down arrow case 40: if (!__AutoComplete[id]['isVisible']) { AutoComplete_ShowDropdown(id); } AutoComplete_Highlight(id, 1); AutoComplete_ScrollCheck(id, 1); return false; break; } } /** * Function which handles the keyup event * * @param string id The form elements id. Used to identify the correct dropdown. */ function AutoComplete_KeyUp(id) { // Mozilla if (arguments[1] != null) { event = arguments[1]; } var keyCode = event.keyCode; switch (keyCode) { case 13: event.returnValue = false; event.cancelBubble = true; break; case 27: AutoComplete_HideDropdown(id); event.returnValue = false; event.cancelBubble = true; break; case 38: case 40: return false; break; default: AutoComplete_ShowDropdown(id); break; } } /** * Returns whether the dropdown is visible * * @param string id The form elements id. Used to identify the correct dropdown. */ function AutoComplete_isVisible(id) { return __AutoComplete[id]['dropdown'].style.visibility == 'visible'; } function getCSSRule(ruleName, deleteFlag) { // Return requested style obejct ruleName=ruleName.toLowerCase(); // Convert test string to lower case. if (document.styleSheets) { // If browser can play with stylesheets for (var i=0; i