/************************************* * RapidSuggest 1.0 * ************************************** * Copyright (c) 2005 rapidsoft GmbH * * http://www.rapidsoft.de * * * * Author: Moritz Mertinkat * * E-Mail: mmertinkat@rapidsoft.de * * * * Last update: 2006-02-07 * ************************************** * This script is based on and * * requires our RapidFramework that * * can be downloaded for free from * * http://labs.rapidsoft.de * **************************************/ var RapidSuggest = RapidClass('RapidSuggest', { _suggest_field: null, _suggest_field_left: null, _suggest_field_bottom: null, _suggest_field_width: null, _suggest_div: null, _suggest_iframe: null, _suggest_table: null, _ie_cellspacing: null, _query_url: null, _query_set: null, _query_set_add: null, _query_callback: null, _count_letters: null, _tid: null, _keycode: null, _visible: null, _suggest_list: null, _suggest_index: null, _suggest_value: null, create: function() { if (arguments.length == 0) { return RapidError('RapidSuggest::create() - missing field id'); } if (arguments.length == 1) { return RapidError('RapidSuggest::create() - missing query URL or callback'); } try { this._suggest_field = document.getElementById(arguments[0]); this._suggest_field_left = getObjectX(this._suggest_field); this._suggest_field_bottom = getObjectY(this._suggest_field) + this._suggest_field.offsetHeight; this._suggest_field_width = this._suggest_field.offsetWidth; this._suggest_field.setAttribute('autocomplete', 'off'); if (typeof(arguments[1]) == 'string') { this._query_set = document.getElementById(arguments[1]); } if (typeof(arguments[2]) == 'string') { this._query_url = arguments[2]; } else if (typeof(arguments[2]) == 'function') { this._query_callback = arguments[2]; } else { return RapidError('RapidSuggest::create() - invalid query URL or callback found'); } if (typeof(arguments[3]) == 'string') { this._query_set_add = document.getElementById(arguments[3]); } this._suggest_div = document.createElement('div'); this._suggest_div.className = 'RapidSuggest'; this._suggest_div.style.display = 'none'; this._suggest_div.style.visibility = 'hidden'; this._suggest_div.style.position = 'absolute'; this._suggest_iframe = document.createElement('iframe'); this._suggest_iframe.style.display = 'none'; this._suggest_iframe.style.visibility = 'hidden'; this._suggest_iframe.style.position = 'absolute'; this._suggest_list = new Array(); if (window.getComputedStyle) { var zindex = window.getComputedStyle(this._suggest_div, '').getPropertyValue('z-index'); if (zindex == null || zindex == 0) { this._suggest_div.style.zIndex = 100; this._suggest_iframe.style.zIndex = 99; } else { this._suggest_iframe.style.zIndex = zindex - 1; } } else { this._suggest_div.style.zIndex = 100; this._suggest_iframe.style.zIndex = 99; } if (window.addEventListener) { this._suggest_field.addEventListener('keyup', this._keyup.bindAsEventListener(this), false); this._suggest_field.addEventListener('keydown', this._keydown.bindAsEventListener(this), false); this._suggest_field.addEventListener('blur', function() { setTimeout(this._hide.bind(this), 150); }.bindAsEventListener(this), true); } else { this._suggest_field.attachEvent('onkeyup', this._keyup.bindAsEventListener(this)); this._suggest_field.attachEvent('onkeydown', this._keydown.bindAsEventListener(this)); this._suggest_field.attachEvent('onblur', function() { setTimeout(this._hide.bind(this), 150); }.bindAsEventListener(this)); document.body.insertBefore(this._suggest_iframe, document.body.firstChild); } document.body.insertBefore(this._suggest_div, document.body.firstChild); this._visible = false; this.setIECellSpacing(0); } catch (e) { return RapidError('RapidSuggest::create() - exception: ' + e); } return true; }, setIECellSpacing: function(spacing) { this._ie_cellspacing = spacing; }, _show: function() { if (this._visible) { return; } // the following three lines are just for our beloved IE this._suggest_field_left = getObjectX(this._suggest_field); this._suggest_field_bottom = getObjectY(this._suggest_field) + this._suggest_field.offsetHeight; this._suggest_field_width = this._suggest_field.offsetWidth; this._suggest_div.style.left = this._suggest_field_left + 'px'; this._suggest_div.style.top = this._suggest_field_bottom + 'px'; this._suggest_div.style.width = this._suggest_field_width + 'px'; this._suggest_iframe.style.zIndex = this._suggest_div.style.zIndex - 1; this._suggest_iframe.style.display = 'block'; this._suggest_div.style.display = 'block'; this._suggest_iframe.style.left = this._suggest_div.style.left; this._suggest_iframe.style.top = this._suggest_div.style.top; this._suggest_iframe.style.width = this._suggest_div.offsetWidth + 'px'; this._suggest_iframe.style.height = this._suggest_div.offsetHeight + 'px'; this._suggest_iframe.style.visibility = 'visible'; this._suggest_div.style.visibility = 'visible'; this._visible = true; }, _hide: function() { if (this._tid != null) { clearTimeout(this._tid); } this._suggest_div.style.display = 'none'; this._suggest_div.style.visibility = 'hidden'; this._suggest_iframe.style.visibility = 'hidden'; this._visible = false; }, _keyup: function(e) { if(e && e.which){ //if which property of event object is supported (NN4) this._keycode = e.which //character code is contained in NN4's which property } else{ this._keycode = e.keyCode //character code is contained in IE's keyCode property } if (this._suggest_field.value.trim() != '') { if ((this._keycode > 8 && this._keycode < 32) || (this._keycode >= 33 && this._keycode <= 46) || (this._keycode >= 112 && this._keycode <= 123)) { return; } this._suggest_value = this._suggest_field.value.trim(); this._count_letters = this._suggest_value.length; e.cancelBubble = true; if (e.stopPropagation) { e.preventDefault? e.preventDefault() : e.returnValue = false; e.stopPropagation(); } if (this._tid != null) { clearTimeout(this._tid); } this._tid = setTimeout(this._show_list.bind(this), 250); } else { this._hide(); } }, _keydown: function(e) { if(e && e.which){ //if which property of event object is supported (NN4) this._keycode = e.which //character code is contained in NN4's which property } else{ this._keycode = e.keyCode //character code is contained in IE's keyCode property } if (this._keycode == 9) { this._hide(); } if (this._suggest_field.value.trim() != '') { if (this._keycode == 13) { if (this._visible) { e.cancelBubble = true; if (e.stopPropagation) { e.preventDefault? e.preventDefault() : e.returnValue = false; e.stopPropagation(); } } this._scroll_list_select(); this._suggest_field.blur(); return (e.cancelBubble == false); } if (this._keycode == 38 || this._keycode == 40) { this._scroll_list(); } } }, _show_list: function() { if (this._suggest_field.value.trim() != '') { this._update_list(); } else { this._hide(); } }, _scroll_list: function() { if (this._suggest_list.length > 0) { this._show(); var old_suggest_index = this._suggest_index; if (this._keycode == 40) { // cursor down this._suggest_index ++; if (this._suggest_index > this._suggest_list.length - 1) { this._suggest_index = -1; } } if (this._keycode == 38) { // cursor up this._suggest_index --; if (this._suggest_index < -1) { this._suggest_index = this._suggest_list.length - 1; } } if (old_suggest_index > -1 && old_suggest_index < this._suggest_table.rows.length) { this._suggest_table.rows[old_suggest_index].cells[0].className = ''; } if (this._suggest_index == -1) { this._suggest_field.value = this._suggest_value; } else { this._suggest_field.value = this._suggest_list[this._suggest_index]; } if (this._suggest_index > -1 && this._suggest_index < this._suggest_table.rows.length) { this._suggest_table.rows[this._suggest_index].cells[0].className = 'selected'; } } else { this._show_list(); } }, _scroll_list_select: function() { if (this._suggest_index > -1 && this._suggest_index < this._suggest_list.length) { this._suggest_field.value = this._suggest_list[this._suggest_index]; } if (this._suggest_field.createTextRange) { var range = this._suggest_field.createTextRange(); range.moveStart('character', this._suggest_field.value.length); range.moveEnd('character', this._suggest_field.value.length); range.select(); } else if (this._suggest_field.setSelectionRange) { this._suggest_field.setSelectionRange(this._suggest_field.value.length, this._suggest_field.value.length); } this._hide(); }, _scroll_list_mouseover: function(e) { var target = e.targetElement || e.srcElement; var old_suggest_index = this._suggest_index; if (old_suggest_index > -1 && old_suggest_index < this._suggest_list.length) { this._suggest_table.rows[old_suggest_index].cells[0].className = ''; } if (target.parentNode.rowIndex > -1 && target.parentNode.rowIndex < this._suggest_list.length) { this._suggest_table.rows[target.parentNode.rowIndex].cells[0].className = 'selected'; this._suggest_index = target.parentNode.rowIndex; } }, _scroll_list_mouseclick: function(e) { var target = e.targetElement || e.srcElement; if (target.parentNode.rowIndex > -1 && target.parentNode.rowIndex < this._suggest_list.length) { this._suggest_index = target.parentNode.rowIndex; this._scroll_list_select(); } this._hide(); }, _update_selection: function() { var update_selection = (this._keycode != 8 && this._keycode != 38 && this._keycode != 40); if (update_selection) { var firstcity = this._suggest_list[0]; var oldcity = this._suggest_value; strLeftPart = firstcity.substring(0, this._count_letters); if (this._suggest_field.value.toLowerCase() != strLeftPart.toLowerCase()) return; this._suggest_field.value = firstcity; if (this._suggest_field.createTextRange) { var range = this._suggest_field.createTextRange(); range.moveStart('character', oldcity.length); range.moveEnd('character', firstcity.length - oldcity.length); range.select(); } else if (this._suggest_field.setSelectionRange) { this._suggest_field.setSelectionRange(oldcity.length, firstcity.length); } this._suggest_index = 0; if (this._suggest_index > -1 && this._suggest_index < this._suggest_table.rows.length) { this._suggest_table.rows[this._suggest_index].cells[0].className = 'selected'; } } }, _update_table: function() { try { this._suggest_table = document.createElement('table'); this._suggest_table.cellSpacing = this._ie_cellspacing; for (var i = 0; i < this._suggest_list.length; ++i) { var row = this._suggest_table.insertRow(-1); var cell = row.insertCell(-1); var strLeftPart = this._suggest_list[i].substring(0, this._count_letters); var strRightPart = this._suggest_list[i].substring(this._count_letters); var boldLettersDOM = document.createElement("B"); boldLettersDOM.appendChild(document.createTextNode(strLeftPart)); cell.appendChild(boldLettersDOM); cell.appendChild(document.createTextNode(strRightPart)); if (window.addEventListener) { cell.addEventListener('mouseover', this._scroll_list_mouseover.bindAsEventListener(this), false); cell.addEventListener('click', this._scroll_list_mouseclick.bindAsEventListener(this), false); } else { cell.attachEvent('onmouseover', this._scroll_list_mouseover.bindAsEventListener(this)); cell.attachEvent('onclick', this._scroll_list_mouseclick.bindAsEventListener(this)); } } if (this._suggest_div.firstChild == null) { this._suggest_div.appendChild(this._suggest_table); } else { this._suggest_div.replaceChild(this._suggest_table, this._suggest_div.firstChild); } } catch (Exception) { } }, _update_list_ready: function(list) { if (list != null) { this._suggest_list = list; this._suggest_index = -1; if (this._suggest_list.length > 0) { this._update_table(); this._show(); this._update_selection(); } else { this._hide(); } } }, _update_list_xmlhttp: function(xmlhttp) { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { var list = new Array(); var xmldoc = xmlhttp.responseXML; try { var rapidsuggest = xmldoc.getElementsByTagName('rapidsuggest').item(0); for (var j = 0; j < rapidsuggest.getElementsByTagName('suggestion').length; ++j) { list[list.length] = rapidsuggest.getElementsByTagName('suggestion').item(j).firstChild.data; } } catch (e) { } this._update_list_ready(list); } }, _update_list: function() { if (this._query_url != null) { var xmlhttp = null; try { xmlhttp = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) { try { xmlhttp = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) { xmlhttp = null; } } if (xmlhttp == null && typeof(XMLHttpRequest) != 'undefined') { xmlhttp = new XMLHttpRequest(); } if (xmlhttp != null) { xmlhttp_query = this._query_url + '?query_set=' + encodeURIComponent(this._query_set.value) + '&query=' + encodeURIComponent(this._suggest_field.value); if (this._query_set_add) { xmlhttp_query += '&adv=' + this._query_set_add.value; } xmlhttp.open('GET', xmlhttp_query, true); xmlhttp.onreadystatechange = function() { this._update_list_xmlhttp(xmlhttp); }.bind(this); xmlhttp.send(null); } } else { this._update_list_ready(this._query_callback(this._suggest_field.value, this._query_set.value)); } } });