/* $Revision$ $Id$ File: Suggest.js Description: Parameters: params.objectName, params.queryField, params.queryUrl, params.initKey, params.initExtraParam, params.keyField, params.fieldReadonly, params.urlAdd, params.extraParamField, params.isBad, params.highlightDescript, params.noJustOne, params.JSONP params.embedded Kijk nooit naar het parent document (embedded) Context: Note: Pas op met gebruiken functies uit andere modules. Dit bestand wordt ook bij vinder/vanuit API\phonebook_js.asp gebruikt en dan heb je die andere bestanden niet. */ function Suggest(inParams) { var params = inParams; var storeKeyField; // = inStoreKeyField; // use function withKeyField() to assign field var storeExtraParamField; // = instoreExtraParamField; // use function withExtraParamField() to assign field var _completeDiv = null; var _comboDiv = null; //thisdoc.onclick = function(){debugger;}; // Kopie uit FcltJquery.js. Die hebben we niet vanuit API\phonebook_js.asp var myEncode = function (s) { return unescape(encodeURIComponent(escape(s))).replace(/\+/g, "%2B"); } var req; var suggestionValues=[]; var resultsObj; var selected = -1; var latestServerQuery = ""; var THROTTLE_PERIOD = 250; var timerID = null; var lastHighlight = null; var divWidth = 500; var emptyKey = ("emptyKey" in params)?params.emptyKey:-1; var emptyText = ""; var currentKey = -1; var currentText = null; var currentExtraParam = null; // De this. functies zijn zo extern ook beschikbaar this.makeReadOnly = makeReadOnly; this.undoReadOnly = undoReadOnly; this.isReadOnly = isReadOnly; this.setValue = setValue; this.getValue = getValue; this.CheckJustOne = CheckJustOne; this.reloadUrlAdd = reloadUrlAdd; this.changeQueryUrl = changeQueryUrl; this.sendQuery = sendQuery; thisdoc = document; // Hier wordt de AutocompleteDiv aan gehangen // TODO: Controleren of parent wel in hetzelfde domein zit? if (!params.embedded && self != top && window.name != "fclttop" && document.body.id!="searchbody") { thisdoc = parent.document; // We gaan de AutocompleteDiv aan de parent hangen, uit het frame breken // Mogelijke fix voor PNBR#22301 if (FcltMgr._pageManager.name == 'defaultManager' && parent.window.name != "fclttop" && parent.FcltMgr && !parent.FcltMgr.IsTheManager) thisdoc = parent.parent.document; // Nog eentje hoger if (!window.name || window.name == "") { //alert("Internal error. " + document.referrer + " heeft een IFRAME zonder 'name' en 'id' voor " + window.location.pathname); thisdoc = document; //debugger; } /* Sommige mobile/3G proxies embedden de CSS 'netjes' zodat het bestand niet te vinden is var cssfound = false; for (i = 0; i < thisdoc.styleSheets.length; i++) { try { // TODO faalt op FF? if (thisdoc.styleSheets[i].href.match(/suggest.css/i)) cssfound = true; } catch(e){}; } if (!cssfound) { alert("Internal error. " + document.referrer + " moet suggest.css ook includen!"); // debugger; } */ } params.queryField.setAttribute("sgKey", params.initKey); // IE6 en IE7 hebben functie hasAttribute niet if (!params.queryField.hasAttribute) params.queryField.hasAttribute = function (attr) { return !!params.queryField.getAttribute(attr) }; if (params.keyField) { storeKeyField = params.keyField; //storeKeyField.value = params.queryField.getAttribute("sgKey"); storeKeyField.value = params.keyField.value; } else this.withKeyField = function (inStoreKeyField) { storeKeyField = inStoreKeyField; //storeKeyField.value = params.queryField.getAttribute("sgKey"); storeKeyField.value = params.keyField.value; return this; } if (params.extraParamField) { storeExtraParamField = params.extraParamField; if (params.queryField.hasAttribute("sgExtraParam")) storeExtraParamField.value = params.queryField.getAttribute("sgExtraParam"); } else this.withExtraParamField = function (instoreExtraParamField) { storeExtraParamField = instoreExtraParamField; if (params.queryField.hasAttribute("sgExtraParam")) storeExtraParamField.value = params.queryField.getAttribute("sgExtraParam"); return this; } // Kan verwijderd worden. Kan ook bereikt worden door initiële waarde -1 mee te geven this.withEmpty = function (eKey, eText) { emptyText = eText? eText : ""; emptyKey = eKey; return this; } // Niet extern bedoeld maar noodzakekelijk voor setTimeout this.requestLoop = requestLoop; //if (params.objectName == "sgPerson") alert("initKey = " + params.initKey); //if (params.initKey == -1) alert(params.objectName + " " + params.initKey); // Alleen als verplicht if (params.initKey == -1 && !params.noJustOne && $(params.queryField).hasClass('required')) CheckJustOne(); if (params.fieldReadonly) { params.queryField.readOnly = true; setClass("suggestReadOnly"); } else startup(); if (params.isBad) { setValue(emptyKey, null, true, false, emptyText); setClass("suggestBad"); } else this.isBad = function () { setValue(emptyKey, null, true, false, emptyText); setClass("suggestBad"); } /** * * It all starts here! * */ function startup() { createAutocompletDiv(); hideAutocompleteDiv(); params.queryField.autocomplete = "off"; params.queryField.title = L("lcl_shared_suggest_hint"); params.queryField.onkeydown = keypressHandler; params.queryField.onkeyup = keyupHandler; params.queryField.onblur = function () { if (document.activeElement && typeof thisdoc.activeElement != "unknown" && (document.activeElement == params.queryField || thisdoc.activeElement == _completeDiv || document.activeElement == _comboDiv || $("body").hasClass("modal") || // Zou anders in IE9 sluiten bij klikken op scrollbar thisdoc.activeElement.parentElement == _completeDiv)) return; if (isAutocompleteDivVisible()) { if (params.queryField.getAttribute("sgCurrentValue") == null) setValues(true); else //houden we de huidige waarde setValue(params.queryField.getAttribute("sgKey"), params.queryField.getAttribute("sgCurrentValue"), false, false, params.queryField.getAttribute("sgExtraParam")); hideAutocompleteDiv(); } }; // http://stackoverflow.com/questions/3380458/looking-for-a-better-workaround-to-chrome-select-on-focus-bug $(params.queryField).focus(function () { $(params.queryField).select().mouseup(function (e) { e.preventDefault(); $(this).unbind("mouseup"); }); if (!timerID) timerID = setTimeout(params.objectName + '.requestLoop(-1);', THROTTLE_PERIOD); }); params.queryField.onclick = function (evt) { if (!isReadOnly()) { // Als je op vergrootglas hebt gedrukt moet checkExist altijd false zijn want je wilt een lijst. // Anders krijg je ook het verschijnsel dat je 2 keer moet klikken voordat je de lijst krijgt. params.queryField.removeAttribute("checkExist"); evt = evt||window.event; var offX = evt.offsetX || evt.layerX; // layerX is FireFox if (params.queryField.clientWidth-offX<20) // op de 'combodiv' geklikt { if (!isAutocompleteDivVisible()) { autoOpen(); } else { setValue(params.queryField.getAttribute("sgKey"), params.queryField.getAttribute("sgCurrentValue"), false, false, params.queryField.getAttribute("sgExtraParam")); hideAutocompleteDiv(); } return; } } }; params.queryField.onmousemove = function (evt) { if (!isReadOnly()) { evt = evt||window.event; var offX = evt.offsetX || evt.layerX; // layerX is FireFox if (params.queryField.clientWidth-offX<20) // op de 'combodiv' geklikt params.queryField.style.cursor="pointer"; else params.queryField.style.cursor="auto"; } }; params.queryField.setAttribute("sgCurrentValue", params.queryField.defaultValue); requestLoop(0); } function setClass(oneClass) { $(params.queryField).removeClass("suggest suggestBad suggestBusy suggestReadOnly"); $(params.queryField).addClass(oneClass); } function makeReadOnly() { params.queryField.readOnly = true; setClass("suggestReadOnly"); params.queryField.title = ""; } function undoReadOnly() { params.queryField.readOnly = false; setClass("suggest"); params.queryField.title = L("lcl_shared_suggest_hint"); } function isReadOnly() { return params.queryField.readOnly; } function setValue(key, txt, doonChange, checkExist, extraParam, lastTry) { // Onthoudt de huidige waarde als je checkt of de te zetten waarde bestaat. // Als de nieuwe waarde niet voorkomt in de query en niet kan worden gezet // dan wordt geprobeerd om de huidige waarde weer opnieuw te zetten. // In dat laatste geval is dan lastTry == true. Indien ook de huidige waarde niet // meer aanwezig is in de query, dan wordt de suggestbox leeg gemaakt. // Als alleen de nieuwe waarde moet worden geprobeerd, // kan ook direct voor lastTry de waarde true worden meegegeven. if (checkExist && !lastTry) { currentKey = params.queryField.getAttribute("sgKey"); currentText = params.queryField.value; currentExtraParam = params.queryField.getAttribute("sgExtraParam"); } if (params.queryField) { // Afhankelijk van het readonly zijn de suggest class zetten zodat de suggestBusy wordt vervangen. // De suggest class toont het vergrootglas in beeld. if (!isReadOnly()) setClass("suggest"); params.queryField.setAttribute("sgKey", key); if (storeKeyField) storeKeyField.value = key; if (extraParam != null) // De waarde 0 moet niet als false worden opgevat. { params.queryField.setAttribute("sgExtraParam", extraParam); if (storeExtraParamField) storeExtraParamField.value = extraParam; } else { if (storeExtraParamField) storeExtraParamField.value = ""; // Als storeExtraParamField bestaat dan leeg maken (vullen met "") } if (!checkExist && txt != null) { params.queryField.value = txt; params.queryField.setAttribute("sgCurrentValue", txt); //latestServerQuery = txt.toLowerCase(); if (txt != "" && (document.activeElement && (typeof thisdoc.activeElement != "unknown") && (document.activeElement == params.queryField || thisdoc.activeElement == _completeDiv || thisdoc.activeElement == _comboDiv || thisdoc.activeElement.parentElement == _completeDiv ) ) ) // selectRange zou focus stelen // Alleen focus stelen als element al focus had (activeElement) selectRange(0,0); } // bij 'checkExist' hoeven we nu nog geen onChange te doen: die komt later nog wel if (!checkExist && doonChange && params.queryField.getAttribute("sgonChange")) { eval(params.queryField.getAttribute("sgonChange")).call(null, key, txt, {suggestid: params.queryField.id}); } if (checkExist) params.queryField.setAttribute("checkExist", true); else params.queryField.removeAttribute("checkExist"); if (doonChange) params.queryField.setAttribute("doonChange", doonChange); else params.queryField.removeAttribute("doonChange"); if (checkExist) { sendQuery(txt, false, checkExist); } } } function getValue() { return (params.queryField.getAttribute("sgKey")); } function process_one_choice_info(data, textStatus) { if (textStatus == "success") { // setValue(key, txt, doonChange, checkExist, extraParam, lastTry) if (data && data.result.length == 1) { var txt = data.result[0].txt; var key = data.result[0].key; var extraParam = data.result[0].extra; setValue(key, txt, true, false, extraParam); } // initiele waarden worden met initkey gezet //else //setValue(emptyKey, emptyText, true, false, emptyText); // Er zijn geen waarden. Suggestbox leeg maken. } else alert("process_one_choice_info: " + textStatus); } // Een urlAdd kan zijn meegegeven als val, field of jqfield function _urlAddParams(urlAdd) { if (!urlAdd) return ""; var urlAddParams = ""; for (var i = 0; i < urlAdd.length; i++) { // Url parameter aan link toevoegen urlAddParams += "&" + urlAdd[i].urlParam + "="; var theVal = urlAdd[i].val; if (typeof theVal == "undefined") { var selector = urlAdd[i].jqfield; var hasselector = ""; if (!selector || selector == "") // JQuery selector, handig voor radio { selector = "#" + urlAdd[i].field; hasselector = "#has_" + urlAdd[i].field; } // Is het misschien een checkbox? Dan is de waarde niet belangrijk maar of deze is aangevinkt. if (hasselector != "" && $(hasselector).length > 0) { // Het is een checkbox. Controleer of de checkbox is aangevinkt. theVal = $(selector).prop("checked")? 1 : 0; // Wel (1) of niet (0) aangevinkt. } else theVal = $(selector).val()? $(selector).val() : -1; // Indien niets geselecteerd dan -1; } urlAddParams += theVal; } return urlAddParams; } function CheckJustOne() { var url = params.queryUrl + _urlAddParams(params.urlAdd) + "&k=*"; // eerste 10 is méér dan genoeg url += "&SuggestAll=1&"; $.getJSON(url, process_one_choice_info); } function reloadUrlAdd(newUrlAdd) { params.urlAdd = newUrlAdd; } function changeQueryUrl(new_inQueryUrl) { params.queryUrl = new_inQueryUrl; latestServerQuery = null; // gaat mis bij kostenplaats fe res setValue(-1, ""); // TODO: vriendelijk via checkExist? } function calculateOffsetLeft(r){ return SumAttr(r,"offsetLeft") } function calculateOffsetTop(r){ return SumAttr(r,"offsetTop") } function SumAttr(r,attr){ var kb = 0; while(r) { kb += r[attr]; r = r.offsetParent } return kb } function createAutocompletDiv() { //_completeDiv=$(thisdoc).find("div#"+params.objectName+"completeDiv")[0]; if (true||!_completeDiv) { _completeDiv=thisdoc.createElement("DIV"); _completeDiv.id=params.objectName+"completeDiv"; _completeDiv.className = "suggestautocompleteContainer"; _completeDiv.onblur = function () { params.queryField.onblur(); } _completeDiv.style.zIndex="2199"; // JQuery dialog begint bij 1000, daar zitten we ruim boven thisdoc.body.appendChild(_completeDiv); //_completeDiv.appendChild(thisdoc.createTextNode("DIVVERtje")); } // pas bij echt openen afmetingen zetten setCompleteDivSize(); } function setCompleteDivSize() { var _inputField = params.queryField; if(_inputField && _completeDiv) { var newdivWidth = Math.min(divWidth, thisdoc.body.offsetWidth); // Voor Mobile var newLeft = calculateOffsetLeft(_inputField); var newTop =calculateOffsetTop(_inputField)+_inputField.offsetHeight-1; if (thisdoc != document) { newTop += calculateOffsetTop(thisdoc.getElementById(window.name))+2; newLeft += calculateOffsetLeft(thisdoc.getElementById(window.name))+2; } newTop -= $(document).scrollTop(); if (newLeft + newdivWidth > thisdoc.body.offsetWidth) { // Wel in beeld houden newLeft = Math.max(0, thisdoc.body.offsetWidth - newdivWidth - 20); // ook speling voor scrollbar } _completeDiv.style.left=newLeft+"px"; _completeDiv.style.top=newTop+"px"; _completeDiv.style.width=newdivWidth + "px"; } } function doRequest(keyword, bAll) { setClass("suggestBusy"); sendQuery(keyword, bAll); latestServerQuery = keyword; } var ESCAPE = 27; var KEYUP = 38; var KEYDOWN = 40; var KEYENTER = 13; var KEYTAB = 9; var KEYPGUP = 33; var KEYPGDOWN = 34; // Deze functie is via een timer gescheduled function requestLoop(toetskey) { // Toetskey // -1: Geen toets, focus op veld // 0: Initialisatie // >0: Toets aangeklikt // Als de suggest readonly is hoef ik niet verder te kijken. if (isReadOnly()) return; setClass("suggest"); timerID = null; if (params.queryField.value == "" && params.queryField.getAttribute("sgKey") != emptyKey) setValue(emptyKey, emptyText, true, false, emptyText); // Bepaal wat de gebruiker heeft ingetikt exclusief het deel wat gehighlight is var keyword = query().toLowerCase(); // Is het een te snelle tab zonder popup selectie. Dan is er geen waarde gezet. Focus terug. var isToFastTab = (toetskey == KEYTAB && (params.queryField.value != params.queryField.getAttribute("sgCurrentValue"))) if (isToFastTab) params.queryField.select(); var isUpDownKey = (toetskey == KEYUP || toetskey == KEYDOWN || toetskey == KEYPGUP || toetskey == KEYPGDOWN); var isNoSpecialKey = (toetskey > 0 && !isUpDownKey && toetskey != KEYENTER && toetskey != KEYTAB); // Bij toestsaanslag altijd popup scherm. Ook bij default waarde. Omschrijving tekst kan vaker voorkomen. if (toetskey != 0 && (keyword!=latestServerQuery) && (keyword != '') && ((params.queryField.value != params.queryField.defaultValue) || (toetskey > 0 && !isUpDownKey)) && (params.queryField.value != params.queryField.getAttribute("sgCurrentValue") || isNoSpecialKey)) { doRequest(query().toLowerCase(), false); } if (keyword == '' || params.queryField.value == params.queryField.defaultValue) { hideAutocompleteDiv(); suggestionValues = []; latestServerQuery = null; selected = 0; if (params.queryField.value == params.queryField.defaultValue && toetskey == 0) setValue(params.initKey, null, false, false, params.initExtraParam) else if (params.queryField.value == "" && params.queryField.getAttribute("sgKey") != emptyKey) setValue(emptyKey, emptyText, true, false, emptyText); if (keyword == "" && toetskey > 0) { // Eventuele sgCascade uitvoeren als suggest veld wordt leeg gemaakt. eval(params.queryField.getAttribute("sgCascade")); } } } // Bepaal wat de gebruiker heeft ingetikt exclusief het deel wat gehighlight is function query() { var textbox = params.queryField; var N; if(textbox.createTextRange) // IE { // IE6/7 soms bij het opstarten: htmlfile: unspecified error. Daarom de catch try { var fa = document.selection.createRange().duplicate(); N = fa.text.length; } catch(e) { N=0; } } else if(textbox.setSelectionRange) // Mozilla { try { N = textbox.selectionEnd-textbox.selectionStart; } catch(e) // Firefox-->Error { N = 0; } } return textbox.value.substring(0, textbox.value.length-N); } function sendQuery(txt, bAll, checkExist) { var url = params.queryUrl + _urlAddParams(params.urlAdd) + "&k=" + myEncode(txt); if (bAll) url += "&SuggestAll=1"; if (checkExist) url += "&checkExist=1"; jQuery.ajax({type: "GET", url: url, dataType: params.JSONP? "jsonp" : "json", success: process }); } // Callback functie van HTTP Request function process(data, textStatus) { var checkExist = params.queryField.hasAttribute("checkExist"); var doonChange = params.queryField.getAttribute("doonChange"); // Afhankelijk van het readonly zijn de suggest class zetten zodat de suggestBusy wordt vervangen. // De suggest class toont het vergrootglas in beeld. if (!isReadOnly()) setClass("suggest"); showAutocompleteDiv(); resultsObj = data; selected = resultsObj.isAll? Math.min(resultsObj.result.length - 1, 10 - 1) : 0; // voorheen htmlFormat(checkExist, doonChange), nu ingeplakt lastHighlight = null; while(_completeDiv.childNodes.length > 0) { _completeDiv.removeChild(_completeDiv.childNodes[0]); } if (!resultsObj.result.length) // Hmm, geen resultaten gevonden { if (params.queryField.value.length > 0 && params.queryField.value != "*") { // Als de nieuwe waarde niet voorkomt in de query en niet kan worden gezet // dan wordt geprobeerd om de huidige waarde weer opnieuw te zetten (currentKey > 0). // Indien ook de huidige waarde niet meer aanwezig is in de query, // dan wordt de suggestbox leeg gemaakt. if (checkExist && currentKey > 0) { var pcurrentKey = currentKey; var pcurrentText = currentText; var pcurrentExtraParam = currentExtraParam; currentKey = emptyKey; currentText = ""; currentExtraParam = null; setValue(pcurrentKey, pcurrentText, doonChange, true, pcurrentExtraParam, true); } else { setValue(emptyKey, (checkExist? "" : null), true, false, (checkExist? "" : null)); } if (!checkExist) { setClass("suggestBad"); } } else { // Geen resultaten gevonden en params.queryField was leeg. // Zet nu opnieuw de lege waarde. setValue(-1, "", true, false, null, true); } hideAutocompleteDiv(); return; } // Maak suggestbox leeg indien checkExist is true en gevonden key en ingevoerde key komen niet overeen: if (checkExist && resultsObj.result.length == 1 && resultsObj.result[0].key != params.queryField.getAttribute("sgKey")) { // Maak suggestbox leeg if (params.queryField.value.length > 0) { setValue(emptyKey, "", true, false, ""); setClass("suggestBad"); } hideAutocompleteDiv(); return; } // Indien checkExist is true en er zijn meerdere waarden gevonden (Begin gedeelte van de omschrijving komt overeen) dan: // 1) Komt maar van 1 van deze de gevonden key en ingevoerde key overeen, dan deze selecteren // 2) Anders selectbox leeg maken. else if (checkExist && resultsObj.result.length > 1) { var nr_of_hits = 0; for (var i = 0; i < resultsObj.result.length; i++) { if (resultsObj.result[i].key == params.queryField.getAttribute("sgKey")) { nr_of_hits++; var hit_i = i; } } if (nr_of_hits == 1) { // Geselecteerde text selecteren (enige overeenkomende resultaat van de meerdere gevonden waarden) selected = hit_i; // Kies wel de juiste overeenkomende resultaat met de juiste key setValues(doonChange); if (!checkExist) selectRange(0,0); hideAutocompleteDiv(); return; } else { // Gevonden key en ingevoerde key komen vaker overeen. Maak suggestbox leeg if (params.queryField.value.length > 0) { setValue(emptyKey, "", true, false, ""); setClass("suggestBad"); } hideAutocompleteDiv(); return; } } if (checkExist && resultsObj.result.length == 1 && resultsObj.result[0].key == params.queryField.getAttribute("sgKey")) { // geselecteerde text selecteren (enige resultaat) setValues(doonChange); if (!checkExist) selectRange(0,0); hideAutocompleteDiv(); return; } suggestionValues = []; if (params.queryField.getAttribute("sgCurrentValue") && params.queryField.getAttribute("sgKey") > 0) { // Plak de current er voor als eerste keuze resultsObj.result = [ { txt: params.queryField.getAttribute("sgCurrentValue"), key: params.queryField.getAttribute("sgKey"), desc: L("lcl_shared_suggest_huidig")}].concat(resultsObj.result); } if (resultsObj.similar) $(_completeDiv).addClass("suggestsimilar"); else $(_completeDiv).removeClass("suggestsimilar"); for (var i = 0; i < resultsObj.result.length; i++) { if (resultsObj.result[i].txt) { suggestionValues.push(resultsObj.result[i].txt); var xDiv = thisdoc.createElement("div"); xDiv.sgIndex = i; if (i==selected) { xDiv.className = "suggestsrs"; lastHighlight = xDiv; } else { xDiv.className = "suggestsr"; } xDiv.onmouseover = function() { highlight(this.sgIndex, this); return false; }; xDiv.onmousedown = function() { setValues(true);hideAutocompleteDiv(); return true; }; if ("title" in resultsObj.result[i]) xDiv.title = resultsObj.result[i].title; if (resultsObj.anyfoto) { var fotourl = resultsObj.result[i].foto; if (fotourl && fotourl.match(/\.(png|jpg|jpeg)$/i)) // het is een image { var xFoto = thisdoc.createElement("img"); xFoto.setAttribute("src", fotourl); xFoto.setAttribute("height", "40"); xFoto.className = "suggestfoto"; xDiv.appendChild(xFoto); } else { var xFoto = thisdoc.createElement("div"); xFoto.innerHTML = " "; xFoto.className = "suggestfoto"; xDiv.appendChild(xFoto); } } var xSpan = thisdoc.createElement("span"); xSpan.className = "suggestsrt"; if (i == 0 && params.queryField.getAttribute("sgCurrentValue") && params.queryField.getAttribute("sgKey") > 0) // eerste krijgt aparte opmaak { xSpan.style.borderBottom = "1px solid black"; // TODO: Stijl voor verzinnen xSpan.style.paddingBottom = "10px"; } var ll = 0; // first matching part bold var lsq = latestServerQuery; if (lsq && lsq.charAt(0) == "*") lsq = lsq.substring(1); ll = resultsObj.result[i].txt.toLowerCase().indexOf(lsq); if (ll >= 0 && lsq.length) { if (ll > 0) xSpan.appendChild(thisdoc.createTextNode(resultsObj.result[i].txt.substring(0, ll))); var xb = thisdoc.createElement("b"); xb.appendChild(thisdoc.createTextNode(resultsObj.result[i].txt.substring(ll, ll + lsq.length))); xSpan.appendChild(xb); xSpan.appendChild(thisdoc.createTextNode(resultsObj.result[i].txt.substring(ll + lsq.length))); } else xSpan.appendChild(thisdoc.createTextNode(resultsObj.result[i].txt)); xDiv.appendChild(xSpan); if ("desc" in resultsObj.result[i]) // Extra description present { var x3 = thisdoc.createElement("span"); x3.className = "suggestsrc"; var desc = resultsObj.result[i].desc || ""; ll = desc && desc.toLowerCase().indexOf(lsq); if (params.highlightDescript && ll >= 0) { x3.appendChild(thisdoc.createTextNode(desc.substring(0, ll))); var xb = thisdoc.createElement("b"); xb.appendChild(thisdoc.createTextNode(desc.substring(ll, ll + lsq.length))); x3.appendChild(xb); x3.appendChild(thisdoc.createTextNode(desc.substring(ll + lsq.length))); } else x3.appendChild(thisdoc.createTextNode(desc)); xDiv.appendChild(x3); } _completeDiv.appendChild(xDiv); } } // xDiv is op dit moment de laatste if (!xDiv || (xDiv.offsetTop + xDiv.clientHeight < 300)) _completeDiv.style.height = ""; // Auto else { //_completeDiv.style.overflow = "hidden"; _completeDiv.style.height = "300px"; if (/MSIE 7.0/.test(navigator.userAgent)) _completeDiv.style.paddingRight = "16px"; // Anders valt bij IE7 een deel achter de scrollbar _completeDiv.style.overflowY = "auto"; _completeDiv.style.overflowX = "hidden"; } if (resultsObj.hasMore) // Is gezet als er 10 of meer records zijn { var xDiv = thisdoc.createElement("div"); xDiv.className = "suggestsr"; var xSpan = thisdoc.createElement("span"); xSpan.className = "suggestMore"; if (resultsObj.isAll) xSpan.appendChild(thisdoc.createTextNode(resultsObj.hasMoreMsg)); // Maximum bereikt else { $(xDiv).mousedown(function (evt) { doRequest(latestServerQuery, true); evt.preventDefault(); // Voorkom blur }); xSpan.appendChild(thisdoc.createTextNode(resultsObj.hasMoreMsg)); // Er is meer } xDiv.appendChild(xSpan); _completeDiv.appendChild(xDiv); } //requestSuggestions(); } function keyupHandler (evt) { // make sure we have a valid event variable if(!evt && window.event) { evt = window.event; } var key = evt.keyCode; if (key < 32 || (key >= 33 && key <= 46) || (key >= 112 && key <= 123)) { //ignore } else { //request suggestions from the suggestion provider // Backspace key(8), Delete key (48) if (key != 8 && key != 48) { requestSuggestions(); } } return true; } function keypressHandler (evt) { params.queryField.removeAttribute("checkExist"); params.queryField.setAttribute("doonChange", true); // make sure we have a valid event variable if (!evt && window.event) { evt = window.event; } var key = evt.keyCode; // if this key isn't one of the ones we care about, just return if (timerID) // reset oude. Is goed voor de performance/response clearTimeout(timerID); timerID = setTimeout(params.objectName + ".requestLoop(" + key + ");", THROTTLE_PERIOD); // don't do anything if the div is hidden if (!isAutocompleteDivVisible()) { if (key == KEYDOWN || key == KEYPGDOWN) autoOpen(); return; } if (key == KEYPGDOWN) { if (resultsObj.hasMore && !resultsObj.isAll) { doRequest(latestServerQuery, true); } else if (isAutocompleteDivVisible) { _completeDiv.scrollTop += _completeDiv.clientHeight; //selected += 20; //highlight(selected); } return false; } if (key == KEYPGUP) { if (isAutocompleteDivVisible) { _completeDiv.scrollTop -= _completeDiv.clientHeight; //selected -= 20; //highlight(selected); } return false; } if (key == KEYUP) { if ((selected-1) >= 0) selected = selected -1; else if (!resultsObj.hasMore) selected = resultsObj.result.length-1; highlight(selected); return false; } if (key == KEYDOWN) { if ((selected + 1) < resultsObj.result.length) selected = selected + 1; else if (resultsObj.hasMore && !resultsObj.isAll) doRequest(latestServerQuery, true); else selected = 0; highlight(selected); return false; } if (key == ESCAPE) { params.queryField.onblur(); } if (key == KEYENTER) { setValues(true); selectRange(0,0); hideAutocompleteDiv(); return false; } return true; } // De gewone scrollIntoView() heeft wel eens de neiging de complete pagina ook te scrollen function myScrollIntoView(theDiv, toView) { if (theDiv.scrollTop + theDiv.clientHeight < toView.offsetTop + toView.clientHeight) theDiv.scrollTop = toView.offsetTop + toView.clientHeight - theDiv.clientHeight; if (theDiv.scrollTop > toView.offsetTop) theDiv.scrollTop = toView.offsetTop; } function highlight(number) { selected = number; // Herstel vorige highlight if (lastHighlight && lastHighlight.className) lastHighlight.className = "suggestsr"; // Zet nieuwe highlight var ieDIVs = $(_completeDiv).find('div').not(".suggestfoto"); lastHighlight = ieDIVs[selected]; if (lastHighlight && lastHighlight.className) lastHighlight.className = "suggestsrs"; myScrollIntoView(_completeDiv, lastHighlight); } function setValues(doonChange) { if (resultsObj) { var result = resultsObj.result[selected][resultsObj.storeDesc? "desc" : "txt"]; setValue(resultsObj.result[selected].key, result, doonChange, false, resultsObj.result[selected].extra) // doonChange } } function autoOpen() { params.queryField.value = latestServerQuery || "*"; //"*"; doRequest(params.queryField.value, false); if (params.queryField.createTextRange) { var oRange = params.queryField.createTextRange(); oRange.move("character", 1); oRange.select(); } // TODO: else wat voor FireFox? //set focus back to the textbox (when field is not disabled) //if (!textbox.disabled) textbox.focus(); //params.queryField.focus(); //selectRange(0,1); } function showAutocompleteDiv() { setCompleteDivSize(); // voor de zekerheid _completeDiv.style.display="block"; } function hideAutocompleteDiv() { _completeDiv.style.display="none"; } function isAutocompleteDivVisible() { return (_completeDiv.style.display == "block"); } function requestSuggestions() { var sTextboxValue = query().toLowerCase(); var aSuggestions = []; if (suggestionValues.length > 0) { //search for matching states for (var i=0; i < suggestionValues.length; i++) { if (suggestionValues[i].toLowerCase().indexOf(sTextboxValue) == 0) aSuggestions.push(suggestionValues[i]); } autosuggest(aSuggestions); } }; function autosuggest(aSuggestions) { //make sure there's at least one suggestion if (aSuggestions.length == 1) typeAhead(aSuggestions[0]); } function typeAhead(sSuggestion) { var textbox = params.queryField; //check for support of typeahead functionality if (textbox.createTextRange || textbox.setSelectionRange) { var iLen = query().length; textbox.value = sSuggestion; selectRange(iLen, sSuggestion.length); } }; function selectRange(iStart, iLength) { var textbox = params.queryField; //use text ranges for Internet Explorer if (textbox.createTextRange) { var oRange = textbox.createTextRange(); oRange.moveStart("character", iStart); oRange.moveEnd("character", iLength - textbox.value.length); oRange.select(); //use setSelectionRange() for Mozilla } else if (textbox.setSelectionRange) { textbox.setSelectionRange(iStart, iLength); } //set focus back to the textbox (when field is not disabled) if (!textbox.disabled) textbox.focus(); }; }