Files
Facilitor/APPL/Shared/Suggest/suggest.js
2018-10-09 11:59:49 +00:00

1332 lines
46 KiB
JavaScript
Raw Blame History

/*
$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.multitoggle (true|false voor alle, of [0-6] voor plaatsselector, t/m alg_level #multitoggle
params.addemptyoption voegt een 'Leeg' toe met key=-2
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.
*/
var $suggestbusy;
var suggesttimer;
function Suggest(inParams)
{
// Genereer een enkel stukje busy-html die voor alle suggests in deze pagina hergebruiken
if (!$suggestbusy)
$suggestbusy = $("<i class='fa fa-gear fa-spin suggestbusy'></i>").appendTo($("body"));
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;
var $currentField = $(params.queryField); // Either the INPUT or the SELECT field
// De this. functies zijn zo extern ook beschikbaar
this.makeReadOnly = makeReadOnly;
this.undoReadOnly = undoReadOnly;
this.isReadOnly = isReadOnly;
this.makeHidden = makeHidden;
this.undoHidden = undoHidden;
this.isHidden = isHidden;
this.getKeyField = getKeyField;
this.setValue = setValue;
this.getValue = getValue;
this.sgType = params.sgType;
this.isMulti = isMulti;
this.updateMultiSuggest = updateMultiSuggest;
this.CheckJustOne = CheckJustOne;
this.reloadUrlAdd = reloadUrlAdd;
this.changeQueryUrl = changeQueryUrl;
this.sendQuery = sendQuery;
thisdoc = document; // Hier wordt de AutocompleteDiv aan gehangen
function updateMultiSuggest()
{
// Niet mooi, wel effectief
toggleSelect();
toggleSelect();
}
function isMulti()
{
return $currentField.prop("tagName") == "SELECT";
}
function getKeyField()
{
return params.keyField;
}
function multiToggle($fld, adv)
{
$fld.addClass(adv ? "advMultiSuggest" : "multiSuggest");
var $lbl = $("<span fcltfor='" + $fld.attr("id") + "' class='multi_suggest_toggle' />").on("click", function() { toggleSelect(this); }).html("&raquo;");
var $div = $("<div />").addClass(adv ? "advmultitoggle" : "multitoggle");
$fld.add($fld.next(".suggestklikker")).wrapAll($div);
$fld.before($lbl);
}
// 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 == "")
{
// FcltMgr.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)
{
FcltMgr.alert("Internal error. " + document.referrer + " moet suggest.css ook includen!");
// debugger;
}
*/
}
var icon = inParams.icon || "fa-asterisk";
if (params.embedded && params.site)
{
suggesticon = params.suggesticon || (params.site + "/appl/shared/suggest/suggest.png");
var $klikker = $("<div class='suggestklikker' style='cursor:pointer'><img src='" + suggesticon + "'></i></div>");
}
else
var $klikker = $("<div class='suggestklikker'><i class='fa fa-fw " + icon + " suggestklikker'></i></div>");
$(params.queryField).after($klikker)
.addClass("hasIcon");
params.queryField.setAttribute("sgKey", params.initKey);
if (params.multitoggle)
multiToggle($(params.queryField), params.multitoggle == "advanced");
// 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<74>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") FcltMgr.alert("initKey = " + params.initKey);
//if (params.initKey == -1) FcltMgr.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");
}
// Geavanceerd scherm waarvan een suggest geladen wordt met meerdere waarden automatisch uitklappen,
// indien maar 1 waarde aanwezig, dan met setValue de sgKey en sgCurrentvalue setten.
if (params.multitoggle == "advanced")
{
var storedVars = $(params.queryField).val().split(",");
if (storedVars.length == 1 && storedVars[0] != "")
setValue(params.keyField.value, storedVars[0]);
else if (storedVars.length > 1 && params.keyField.value == storedVars)
toggleSelect();
}
/**
*
* 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 ||
document.activeElement == $suggestbusy[0] ||
document.activeElement == $klikker[0] ||
$("body").hasClass("modal") || // Zou anders in IE9 sluiten bij klikken op scrollbar
thisdoc.activeElement.parentElement == _completeDiv))
return;
if (isAutocompleteDivVisible())
{
if ($(_completeDiv).is(":hover")) // IE 11 bug, klik op scrollbar hide de dropdown
{
$(params.queryField).focus(); // reset focus want die is er al afgehaald.
return;
}
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);
});
$klikker.click(function (e)
{
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");
$(params.queryField).focus(); // zodat anderen door onblur verbergen
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 toggleSelect(label)
{
var $suggestField; // The suggest field, INPUT or SELECT
if (!label) // Interne call van sgXxx.toggleSelect(), use $currentField
{
$suggestField = $currentField;
label = $suggestField.prev("span.multi_suggest_toggle");
}
else
$suggestField = $(label).next(".multiSuggest, .advMultiSuggest");
if ($(label).hasClass("disabled"))
return;
var isMultiSuggest = $suggestField.prop("tagName") == "SELECT";
var multiClass = $suggestField.hasClass("multiSuggest") ? "multiSuggest" : "advMultiSuggest";
// toggle label between <20> and <20>
$(label).html().indexOf("<22>") == -1 ? $(label).html("&raquo;") : $(label).html("&laquo;");
// toggle suggestklikker Icon
$suggestField.next(".suggestklikker").toggle();
// toggle subsequent plaatsselector levels
var sgType = $suggestField.attr("sgType");
// relevant, subsequent suggests of the same type in sgRel
var sgRel = [];
var thisSgObj = null;
for (var key in window)
{
if (window[key] instanceof Suggest)
{
if (thisSgObj != null && window[key].sgType && (window[key].sgType === sgType || (typeof params.sgRelType != "undefined" && window[key].sgType === params.sgRelType)))
sgRel.push(window[key]);
if (window[key].getKeyField() === params.keyField) // keyField used as unique identifier
thisSgObj = window[key];
}
}
// Toggle subsequent multiSuggest SELECT's of the same sgType, back to input's (not in advanced popup)
$suggestField.closest("tr").nextAll("tr").find("select.multiSuggest[sgType=\"" + sgType + "\"]").prev("span.multi_suggest_toggle").click();
// hide|show subsequent suggests of the same type
for (var key in sgRel)
{
sgRel[key].setValue(-1, "");
if (isMultiSuggest)
sgRel[key].undoHidden();
else
sgRel[key].makeHidden();
}
if (isMultiSuggest) // Replace multi-suggest back to single-suggest with new or empty value.
{
var sgKey = $suggestField.find(":selected").eq(0).val() || -1;
var sgDesc = $suggestField.find(":selected").eq(0).text() || "";
$suggestField.replaceWith($(params.queryField));
$currentField = $(params.queryField);
thisSgObj.setValue(sgKey, sgDesc);
}
else // if (!isMultiSuggest)
{
// Make multi-SELECT
var url = params.queryUrl + _urlAddParams(params.urlAdd) + "&SuggestAll=1&k=*";
$.getJSON(url, function(data, textStatus)
{
if (data)
{
var sgKey = $currentField[0].getAttribute("sgKey");
var $sel = $("<select size=\"5\" multiple=\"1\" class=\""+multiClass+"\">").attr("id", $currentField.attr("id"))
.attr("name", params.keyField.id)
.attr("sgType", sgType);
if (data.hasMore)
$sel.append($("<option>").attr("disabled", true)
.attr("title", L("lcl_shared_suggest_toomany"))
.text(L("lcl_shared_suggest_toomany")));
var $option;
var keys_arr = storeKeyField.value.split(",");
for (var i=0; i < data.result.length; i++)
{
$option = $("<option>").attr("value", data.result[i].key)
.attr("title", data.result[i].desc)
.text(data.result[i].txt);
if (sgKey == data.result[i].key || (keys_arr.length > 1 && $.inArray(String(data.result[i].key), keys_arr) > -1))
{
$option.attr("selected", true);
}
$sel.append($option);
}
$suggestField.replaceWith($sel);
$currentField = $sel;
if (thisSgObj)
thisSgObj.setValue(-1, "");
}
});
}
}
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 makeHidden()
{
if (!$currentField.isHidden)
$currentField.parents("tr").eq(0).addClass("hidden");
}
function undoHidden()
{
$currentField.parents("tr").eq(0).removeClass("hidden");
}
function isHidden()
{
return $currentField.parents("tr").eq(0).hasClass("hidden");
}
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});
// Update related multiSuggests
if (typeof params.sgRelType != "undefined")
{
// We hebben niet de objectName dus we togglen gewoon handmatig 2x zodat de multisuggest update
$(params.queryField).closest("tr").nextAll("tr").find("select.multiSuggest[sgType=\"" + params.sgRelType + "\"]").prev("span.multi_suggest_toggle").click()
.click();
}
}
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
FcltMgr.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<><6D>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;
}
if (typeof mobile === "undefined") // Voor niet-Mobile
{
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)
{
var pos = $(params.queryField).next().position();
$suggestbusy.css("top", pos.top);
$suggestbusy.css("left", pos.left);
window.suggesttimer = setTimeout(function () { $suggestbusy.show(); }, 500);
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 (params.queryField.value == '' || 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)
{
clearTimeout(window.suggesttimer);
$suggestbusy.hide();
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;
if (params.addfixedoption)
resultsObj.result.unshift(params.addfixedoption);
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 = "&nbsp;";
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 (resultsObj.result[i].isHTML)
xSpan.innerHTML = resultsObj.result[i].txt;
else 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 ("txtextra" in resultsObj.result[i])
{
var $Text = $("<span>").text(resultsObj.result[i].txtextra)
.addClass("suggestextratext");
$(xDiv).append("<br>");
$(xDiv).append($Text);
}
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)
{
// Alleen IE komt hier, FF niet!
// alert(JSON.stringify(params));
// var el = document.getElementById("sgRoom");
// var range = el.createTextRange();
// range.move("character", 1);
// range.select();
var oRange = params.queryField.createTextRange();
// alert(JSON.stringify(params.queryField)); // = {"jQuery{blablabla": 103}
// alert(JSON.stringify(oRange)); // oRange = {}
// oRange.collapse(true);
// oRange.moveEnd('character', 1);
// oRange.moveStart('character', 1);
oRange.move("character", 1);
oRange.select();
// oRange.setSelectionRange(1,1);
}
// 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()
{
$(window).on("resize", setCompleteDivSize) // Also runs after "orientationchange"(tilting) for Mobile
.on("scroll", setCompleteDivSize);
setCompleteDivSize(); // voor de zekerheid
_completeDiv.style.display="block";
}
function hideAutocompleteDiv()
{
$(window).off("resize", setCompleteDivSize)
.off("scroll", setCompleteDivSize);
_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();
};
}