On 17-Mar-17 9:09 AM, justaguy wrote:
> Hi,
>
> jQuery is neat
No it's not! Now I have to learn React for some reason after the fads of
Angular, bootstrap, et al :-(
>
> Doable? With pure JS, how do we go about doing this?
>
I do it this way: -
/**
* Copyright (c) Richard Maher. All rights reserved.
*
* Generic predictive text utility for Text and Select elements.
*/
function Tier3Suggest(
targetElement,
lovDetent,
divClass,
selClass,
maxRows,
dataFetch,
singleton)
{
var lovTarget = targetElement;
if (arguments.length < 7)
throw new Error("Insufficient arguments for Tier3Suggest");
if (!lovTarget.id)
throw new Error('"id" attribute must be defined for element');
if (Tier3Suggest.LOV[lovTarget.id])
throw new Error("A list of values is already defined for this
element");
var lovDetent = lovDetent || 0;
var stagger = null;
var currVintage = 0;
var lastSearch = "";
var lastSelected = -1;
var dataFetch = dataFetch;
var singleton = singleton;
var lovMax = maxRows || 10;
var targetStyle = getStyle(targetElement);
var selClass = selClass || "";
var targetDiv = document.createElement("div");
targetDiv.className = divClass || lovTarget.className;
targetDiv.style.visibility = "hidden";
targetDiv.style.position = "absolute";
targetDiv.style.width = "auto";
targetDiv.style.height = "0px";
targetDiv.style.overflowY = "auto";
targetDiv.style.overflowX = "hidden";
targetDiv.style.padding = targetStyle.padding;
targetDiv.style.whiteSpace = "nowrap";
var dimTarget = lovTarget;
var offsetTop = dimTarget.offsetTop + dimTarget.offsetHeight;
var offsetLeft = dimTarget.offsetLeft;
while(dimTarget = dimTarget.offsetParent){
offsetTop += dimTarget.offsetTop;
offsetLeft += dimTarget.offsetLeft;
}
targetDiv.style.top = offsetTop + "px";
targetDiv.style.left = offsetLeft + "px";
document.body.appendChild(targetDiv);
var divStyle = getStyle(targetDiv);
var suggestList = document.createElement("ul");
suggestList.style.padding = "0px";
suggestList.style.margin = "0px";
suggestList.style.listStyleType
= "none";
var getLOV =
function()
{
var lovVintage = ++currVintage;
var rowCnt = 0;
targetDiv.style.height = "0px";
targetDiv.style.visibility = "hidden";
return function(rowKey, rowData)
{
if (lovVintage != currVintage)
return;
var listItem = document.createElement("li");
var listData = document.createTextNode(rowData.rTrim());
listItem.appendChild(listData);
listItem._key = rowKey;
suggestList.appendChild(listItem);
rowCnt++;
if (rowCnt == 1) {
targetDiv.style.height = "auto";
targetDiv.style.visibility = "visible";
}
if (rowCnt == lovMax)
targetDiv.style.height = targetDiv.clientHeight +
"px";
if (targetDiv.clientWidth < targetDiv.scrollWidth)
targetDiv.style.width = (targetDiv.scrollWidth
+ (targetDiv.scrollWidth -
targetDiv.clientWidth)) + "px";
}
}
var clickHandler =
function(evt)
{
var lclTarget = evt.target || evt.srcElement;
if (lclTarget.tagName.toLowerCase() == "option")
lclTarget = lclTarget.parentNode;
if (lclTarget.tagName.toLowerCase() != "select")
return;
if (lclTarget.selectedIndex == lastSelected) {
lclTarget.selectedIndex = -1;
lastSelected = -1;
targetDiv.style.height = "0px";
targetDiv.style.visibility="hidden";
return;
}
lastSelected = lovTarget.selectedIndex;
newLOV();
}
var keyHandler =
function()
{
if (falseAlarm())
return;
if (stagger)
clearTimeout(stagger);
stagger = setTimeout(newKey, lovDetent);
};
function newKey()
{
stagger = null;
if (falseAlarm())
return;
lastSearch = lovTarget.value;
newLOV();
}
function falseAlarm()
{
if (lovTarget.value == lastSearch &&
targetDiv.style.visibility == "visible")
return true;
if (lovTarget.value.length == 0) {
targetDiv.style.height = "0px";
targetDiv.style.visibility="hidden";
lastSearch = "";
return true;
}
return false;
}
function newLOV()
{
targetDiv.style.height = "auto";
targetDiv.style.width = "auto";
while (suggestList.lastChild) {
suggestList.removeChild(suggestList.lastChild);
}
rowCallback = getLOV();
dataFetch.call(this, lovTarget, rowCallback);
};
var listHandler =
function(evt) {
var lclTarget = evt.target || evt.srcElement;
if (lclTarget.nodeType == 3)
lcltarget = lclTarget.parentNode;
if (lclTarget.tagName.toLowerCase() == "li") {
if (evt.type == "mouseover") {
if (selClass != "") {
lclTarget.className = selClass;
}else{
lclTarget.style.color = divStyle.backgroundColor;
lclTarget.style.backgroundColor = divStyle.color;
}
}
if (evt.type == "mouseout") {
if (selClass != "") {
lclTarget.className = "";
}else{
lclTarget.style.color = "";
lclTarget.style.backgroundColor = "";
}
}
if (evt.type == "click") {
singleton.call(this, lovTarget, lclTarget._key,
lclTarget.firstChild.nodeValue);
lovTarget.focus();
if (lovTarget.type.toLowerCase() == "text")
lovTarget.value = lovTarget.value;
}
}
}
var hideLOV =
function(e) {
var evt = e || window.event;
var lclTarget = evt.target || evt.srcElement;
if (lclTarget.nodeType != 1)
return;
if (lclTarget != lovTarget &&
lclTarget != targetDiv &&
targetDiv.style.visibility == "visible") {
targetDiv.style.height = "0px";
targetDiv.style.visibility = "hidden";
currVintage++;
resetCriteria();
}
}
listenerRegistry.checkIn(suggestList,"mouseover",listHandler);
listenerRegistry.checkIn(suggestList,"mouseout", listHandler);
listenerRegistry.checkIn(suggestList,"click", listHandler);
if (window.addEventListener) {
document.addEventListener("focus", hideLOV, true);
} else {
if (!document.attachEvent('onfocusin', hideLOV))
throw new Error("Unable to focusin listener");
}
switch (lovTarget.type.toLowerCase())
{
case "text":
listenerRegistry.checkIn(lovTarget,"keyup",keyHandler);
var resetCriteria =
function() {
lovTarget.value = "";
lastSearch = "";
}
break;
case "select-one":
listenerRegistry.checkIn(lovTarget,"click",clickHandler);
var resetCriteria =
function() {
lovTarget.selectedIndex = -1;
lastSelected = -1;
}
break;
default:
throw new Error("Unsupported field type for LOV");
}
targetDiv.appendChild(suggestList);
Tier3Suggest.LOV[lovTarget.id] = this;
return this;
}
Tier3Suggest.LOV = {};