/** * Javascript file for AJAX select widget * * @author Nathan Gray <nathangray@sourceforge.net> * * @param widget_id the id of the ajax_select_widget * @param onchange function to call if the value of the select widget is changed * @param options the query object containing callback and settings * * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @package etemplate * @subpackage extensions * @link http://www.egroupware.org * * @version $Id$ */ //xajaxDebug = 1; var current_app = 'etemplate'; /** * Settings for the timeout to prevent flooding the server with requests * * Adjust ajax_select_timeout to change how long to wait before sending the request (in ms) */ var ajax_select_timer_id = 0; var ajax_select_timeout = 300; var ajax_select_event = null; // These keys will not trigger a search if the results box is currently displayed var no_search_keys = [ '9', // Tab '38', '63232', // Up '40', '63233' // Down ]; function ajax_select_widget_setup(widget_id, onchange, options, currentapp) { current_app = currentapp; if(onchange) { if(onchange == 1) { onchange = function() {submitit(this.form, this.value);}; } else { eval("onchange = function(e) { " + onchange + ";}"); } var value = document.getElementById(widget_id + '[value]'); if(value) { if(value.addEventListener) { value.addEventListener('change', onchange, true); } else { var old = (value.onchange) ? value.onchange : function() {}; value.onchange = function(e) { old(e); onchange(e); }; } } } var widget = document.getElementById(widget_id + '[search]'); if(widget) { widget.setAttribute('autocomplete', 'off'); if(widget.addEventListener) { widget.addEventListener('keydown', checkKey, true); widget.addEventListener('keyup', timer_change, false); widget.addEventListener('blur', hideBox, false); } else { widget.onkeyup = timer_change; widget.onblur = hideBox; widget.onkeydown = checkKey; } // Set results var results = document.createElement('div'); results.id = widget_id + '[results]'; results.className = 'resultBox'; results.style.position = 'absolute'; // check if IE, if it is, fix the position if (document.all) { results.style.marginLeft = 0 - widget.offsetWidth - 2 * widget.offsetLeft - 1; results.style.marginTop = widget.offsetHeight + 1; } results.style.zIndex = 50; results.options = options; results.innerHTML = ""; widget.parentNode.appendChild(results); } var value = document.getElementById(widget_id + '[value]'); if(value) { value.style.display = 'none'; } } function checkKey(e, value) { if(!e) { var e = window.event; } /* * We check for Tab, Up and Down */ var interested = false; for(var i = 0; i < no_search_keys.length; i++) { if(e.keyCode == no_search_keys[i]) { interested = true; break; } } if (!interested) { return; // The user has not pressed anything we're interested in } if(e.target) { var target = e.target; } else if (e.srcElement) { var target = e.srcElement; } if(target) { if (target.nodeType == 3) { // defeat Safari bug target = target.parentNode; } } var id = target.id; var base_id = id.substr(0, id.lastIndexOf('[')); var results = document.getElementById(base_id + '[results]'); // Consume event so search doesn't go if(results.childNodes.length > 0) { e.cancelBubble = true; if(e.stopPropegation) e.stopPropegation(); clearTimeout(ajax_select_timer_id); } else { return false; } // Up and down arrows switch (e.keyCode) { // Up case 38: case 63232: if(results.current) { results.current.className = results.current.className.replace(' resultBoxSelected',''); } if(results.current && results.current.previousSibling && results.current.previousSibling.childNodes.length > 2) { results.current = results.current.previousSibling; } else { var elements = results.childNodes; results.current = elements[elements.length - 1]; } results.current.className += ' resultBoxSelected'; break; // Down case 40: case 63233: if(results.current) { results.current.className = results.current.className.replace(' resultBoxSelected',''); } if(results.current && results.current.nextSibling && results.current.nextSibling.childNodes.length > 2) { results.current = results.current.nextSibling; } else { var elements = results.childNodes; for (var i = 0; i < elements.length; i++) { elem = elements.item(i); if (elem.value) { results.current = elem; break; // We have found the first selection } } } results.current.className += ' resultBoxSelected'; break; // Tab: Select current element case 9: var elem; if(results.current && results.current.value) { elem = results.current; } else { var elements = document.getElementById(base_id + '[results]').childNodes; for (var i = 0; i < elements.length; i++) { elem = elements.item(i); if (elem.value) { break; // We have found the first selection } } } if (!elem) return; var event; if(document.createEvent && document.dispatchEvent) { // Most event = document.createEvent('MouseEvents'); event.initEvent('click', true, true); elem.dispatchEvent(event); } else { // IE event = document.createEventObject(); elem.fireEvent('onclick', event); } break; } } /** * Set a timeout to prevent user from flooding the server with requests as * they type. Waits to see if the user is still typing before sending the * request. Adjust ajax_select_timeout to change how long to wait (in ms). */ function timer_change(e, value) { if ( ajax_select_timer_id != 0) { clearTimeout(ajax_select_timer_id); } if(!e) { var e = cloneObject(window.event); } else { var e = cloneObject(e); } ajax_select_event = e; ajax_select_timer_id = setTimeout( function() { change(e, value); }, ajax_select_timeout ); } function change(e, value) { if(!e) { var e = window.event; } if(e.target) { var target = e.target; } else if (ajax_select_event) { var e = ajax_select_event; ajax_select_event = null; if(e.target) { var target = e.target; } else if (e.srcElement) { var target = e.srcElement; } } else if (e.srcElement) { var target = e.srcElement; } if(target) { if (target.nodeType == 3) { // defeat Safari bug target = target.parentNode; } var id = target.id; var value = target.value; } else if (typeof(e) == 'string' ) { var id = e; if(value) { var value = value; } else { var value = e.value; } var set_id = id.substr(0, id.lastIndexOf('[')); } else { alert('Error in events'); return; } var base_id = id.substr(0, id.lastIndexOf('[')); if(document.getElementById(base_id + '[results]')) { set_id = base_id + '[results]'; /* * We check for Tab, Up and Down */ var interested = false; var keycode = ''; for(var i = 0; i < no_search_keys.length; i++) { if(e.which) { keycode = e.which; } else if(e && e.keyCode) { keycode = e.keyCode; } if(keycode == no_search_keys[i]) { interested = true; break; } } if (interested && document.getElementById(set_id).style.display == 'block') { clearTimeout(ajax_select_timer_id); return; // Results are shown, allow keys to move the selection cursor } } else { set_id = base_id + '[search]'; } var query = document.getElementById(set_id).options; if(document.getElementById(base_id + '[filter]')) { query.filter = document.getElementById(base_id + '[filter]').value; } // Hide selectboxes for IE if(document.all) { var selects = document.getElementsByTagName('select'); for(var i = 0; i < selects.length; i++) { selects[i].style.visibility = 'hidden'; } } xajax_doXMLHTTP(current_app + ".ajax_select_widget.ajax_search.etemplate", id, value, set_id, query, document.getElementById('etemplate_exec_id').value); } /** * Deep copy an object * Used because IE thinks its a good idea to use a global var for events */ function cloneObject(obj) { var clone = {}; for(var i in obj) { clone[i] = obj[i]; } return clone; } /* Remove options from a results box * @param id - The id of the select */ function remove_ajax_results(id) { if(document.getElementById(id)) { var element = document.getElementById(id); if (element.tagName == 'DIV') { element.innerHTML = ''; } } } /* Add an option to a result box * @param id - The id of the result box * @param key - The key of the option * @param value - The value of the option * @param row - The html for the row to display */ function add_ajax_result(id, key, value, row) { var resultbox = document.getElementById(id); if(resultbox) { if (resultbox.tagName == 'DIV') { var base_id = resultbox.id.substr(0, resultbox.id.lastIndexOf('[')); var search_id = base_id + '[search]'; var value_id = base_id + '[value]'; resultbox.style.display = 'block'; var result = document.createElement('div'); result.className = (resultbox.childNodes.length % 2) ? 'row_on' : 'row_off'; if(key) { result.value = new Object(); result.value.key = key; result.value.value = value; result.value.search_id = search_id; result.value.value_id = value_id; result.innerHTML = row; // when they click, add that item to the value hidden textbox if(result.addEventListener) { result.addEventListener('click', select_result, true); } else { result.onclick = select_result; } } else { result.innerHTML += row + "<br />"; } resultbox.appendChild(result); } } } function select_result(e) { // when they click, add that item to the value textbox & call onchange() if(!e) { var e = window.event; } if(e.target) { var target = e.target; } else if (e.srcElement) { var target = e.srcElement; } while(!target.value && target != document) { target = target.parentNode; } var value = document.getElementById(target.value.value_id); var search = document.getElementById(target.value.search_id); if(value) { value.value = target.value.key; } if(search) { var string = target.value.value; string = string.replace(/&/g, '&'); string = string.replace(/</g, '<'); string = string.replace(/>/g, '>'); search.value = string; var event; if(document.createEvent) { // Most event = document.createEvent('HTMLEvents'); event.initEvent('change', true, true); return value.dispatchEvent(event); } else { // IE event = document.createEventObject(); return value.fireEvent('onchange', event); } } } function hideBox(e) { if(!e) { var e = window.event; } if(e.target) { var target = e.target; } else if (e.srcElement) { var target = e.srcElement; } if(target) { if (target.nodeType == 3) { // defeat Safari bug target = target.parentNode; } } var set_id = target.id.substr(0, target.id.lastIndexOf('[')) + '[results]'; setTimeout("document.getElementById('" + set_id + "').style.display = 'none'", 200); var selects = document.getElementsByTagName('select'); // Un-hide select boxes for IE if(document.all) { for(var i = 0; i < selects.length; i++) { selects[i].style.visibility = 'visible'; } } }