/* TODO: I still need to add code to track the requests in the requests object indexed by the textFieldName */ /* TODO: cache returned results for recent prefixes such that if users are backing up in the textfield we don't need to bother the server */ /* TODO: keyboard navigation, and automatically select best match. Insert this match in the textfield and select the untyped remainder */ var req; var requests; var target; var browser; function getElementX(element) { var targetLeft = 0; while (element) { if (element.offsetParent) { targetLeft += element.offsetLeft; if (browser === "IE") { // IE targetLeft += 3; } } else { if (element.x) { targetLeft += element.x; } } element = element.offsetParent; } return targetLeft; } function getElementY(element) { var targetTop = 0; while (element) { if (element.offsetParent) { targetTop += element.offsetTop; } else { if (element.y) { targetTop += element.y; } } element = element.offsetParent; } return targetTop; } function getWidth(element) { if (element.clientWidth && element.offsetWidth && element.clientWidth < element.offsetWidth) { return element.clientWidth; /* some mozillas (like 1.4.1) return bogus clientWidth so ensure it's in range */ } else { if (element.offsetWidth) { return element.offsetWidth; } else { if (element.width) { return element.width; } else { return 0; } } } } function initRequest() { defineBrowser(); if (browser === "FF") { req = new XMLHttpRequest(); } else { if (browser === "IE") { req = new ActiveXObject("Microsoft.XMLHTTP"); } } } function defineBrowser() { if (window.XMLHttpRequest) { browser = "FF"; } else { if (window.ActiveXObject) { browser = "IE"; } } } function handleAjaxRequest(url, hiddenFieldName, textFieldName, menu, varNotUsed, ondisplay) { if (!requests) { requests = new Object(); } requests.menu = menu; requests.ondisplay = ondisplay; requests.textFieldName = textFieldName; requests.hiddenFieldName = hiddenFieldName; if (url.match("ajax-autocomplete")) { req.onreadystatechange = processAutoCompleteRequest; } else { if (url.match("ajax-autofill")) { req.onreadystatechange = processAutoFillRequest; } } req.open("GET", url, true); req.send(null); } function autoComplete(hiddenFieldName, textFieldName, menuName, method, userType, ondisplay) { initRequest(); document.getElementById(hiddenFieldName).value = ""; var target = document.getElementById(textFieldName); var menu = document.getElementById(menuName); menu.style.left = getElementX(target) + "px"; menu.style.top = getElementY(target) + target.offsetHeight + "px"; var width = getWidth(target); if (width > 0) { menu.style.width = "auto"; } if (userType === null || userType == "null") { userType = document.getElementById("userType").value; } var url; if (userType) { url = "ajax-autocomplete.ajax?method=" + escape(method) + "&prefix=" + escape(target.value) + "&userType=" + userType; } else { url = "ajax-autocomplete.ajax?method=" + escape(method) + "&prefix=" + escape(target.value); } handleAjaxRequest(url, hiddenFieldName, textFieldName, menu, null, ondisplay); } function autoFill(hiddenFieldName, textFieldName, menuName, method, userType, ondisplay) { initRequest(); var target = document.getElementById(textFieldName); var menu = document.getElementById(menuName); var url; if (userType === null || userType == "null") { userType = document.getElementById("userType").value; } if (userType) { url = "ajax-autofill.ajax?method=" + escape(method) + "&prefix=" + escape(target.value) + "&userType=" + userType; } else { url = "ajax-autofill.ajax?method=" + escape(method) + "&prefix=" + escape(target.value); } handleAjaxRequest(url, hiddenFieldName, textFieldName, menu, null, ondisplay); } function stopCompletion(menuName) { var menu = document.getElementById(menuName); if (menu !== null) { clearItems(menu); menu.style.visibility = "hidden"; } } /* Stop completion shortly. This is necessary because I want to stop completion from the blur (focus loss event) of the completion text field, but that will also happen, right BEFORE a link click in the completion dialog is processed. If this is done synchronously, the link is deleted before it is processed by stop completion. Therefore, I use the delayed variety which schedules stop completion instead such that the link is processed first. */ function stopCompletionDelayed(menuName) { /* Would like to shorten timeout but this seems to trip up Safari */ setTimeout("stopCompletion('" + menuName + "')", 150); } function autoFillDelayed(hiddenFieldName, textFieldName, menuName, method, userType, ondisplay) { /* Would like to shorten timeout but this seems to trip up Safari */ var methodToLoad = "autoFill('" + hiddenFieldName + "','" + textFieldName + "','" + menuName + "','" + method + "','" + userType + "',null)"; setTimeout(methodToLoad, 400); setTimeout("stopCompletion('" + menuName + "')", 450); } function processAutoCompleteRequest() { if (req.readyState == 4) { if (req.status == 200) { parseMessages(requests.menu); } else { if (req.status == 204) { clearItems(requests.menu); } } } } /** * Fill the hidden value with the one returned by the AjaxPhaseListener auto-matching method. */ function processAutoFillRequest() { if (req.readyState == 4) { if (req.status == 200) { var items = req.responseXML.getElementsByTagName("item"); var hidden = document.getElementById(requests.hiddenFieldName); var label = document.getElementById(requests.textFieldName); if (items.length > 1) { thereIsNoMatching(); } else { if (items.length == 1) { hidden.value = items[0].childNodes[0].firstChild.nodeValue; label.value = convertXMLSpecialCharacters(items[0].childNodes[1].firstChild.nodeValue); } else { if (items.length == 0) { thereIsNoMatching(); } } } } else { if (req.status == 204 || req.status == 1223) { // 1223 is the status code IE returns when receiving a 204 status code thereIsNoMatching(); } } } } /** Sets the background in red */ function thereIsNoMatching() { if (document.getElementById(requests.textFieldName).value !== "") { document.getElementById(requests.textFieldName).style.background = "red"; clearItems(requests.menu); } } /** Parse XML response and add the relevant items */ function parseMessages(menu) { clearItems(menu); menu.style.visibility = "visible"; var items = req.responseXML.getElementsByTagName("item"); // alert(items.childNodes[0].firstChild.nodeValue); // alert(items.childNodes[1].firstChild.nodeValue); for (loop = 0; loop < items.length; loop++) { var id = items[loop].childNodes[0].firstChild.nodeValue; var text = items[loop].childNodes[1].firstChild.nodeValue; addItem(menu, id, text); } } /** Clear the ajax menu */ function clearItems(menu) { if (menu) { for (loop = menu.childNodes.length - 1; loop >= 0; loop--) { menu.removeChild(menu.childNodes[loop]); } } } /** Add an item in the ajax popup */ function addItem(menu, id, text) { var item = document.createElement("div"); menu.appendChild(item); var linkElement = document.createElement("a"); linkElement.className = "popupItem"; linkElement.href = "#"; var displayName = convertXMLSpecialCharacters(text); linkElement.onclick = function () { chooseItem(requests.textFieldName, id, displayName); stopCompletion(); return false; }; if (requests.ondisplay) { displayName = requests.ondisplay(text); } var textToDisplay = document.createTextNode(displayName); linkElement.appendChild(textToDisplay); item.appendChild(linkElement); } /** Sets the values of the hidden and text fields with the chosen ones */ function chooseItem(textFieldName, id, text) { var target = document.getElementById(requests.textFieldName); var hidden = document.getElementById(requests.hiddenFieldName); hidden.value = id; target.value = text; } /** Converts special characters encoded in the XML response */ function convertXMLSpecialCharacters(displayName) { displayName = displayName.replace(/ /g, " "); displayName = displayName.replace(/&/g, "&"); displayName = displayName.replace(/"/g, "\""); displayName = displayName.replace(/'/g, "'"); displayName = displayName.replace(/é/g, "é"); //? displayName = displayName.replace(/É/g, "É"); //? displayName = displayName.replace(/è/g, "è"); //? displayName = displayName.replace(/È/g, "È"); //? displayName = displayName.replace(/À/g, "À"); //? displayName = displayName.replace(/à/g, "à"); //? displayName = displayName.replace(/û/g, "û"); //? displayName = displayName.replace(/Û/g, "Û"); //? displayName = displayName.replace(/ô/g, "ô"); //? displayName = displayName.replace(/Ô/g, "Ô"); //? displayName = displayName.replace(/Ê/g, "ê"); //? displayName = displayName.replace(/ê/g, "Ê"); //? displayName = displayName.replace(/â/g, "â"); //? displayName = displayName.replace(/Â/g, "Â"); //? return displayName; } /**************************************************** Autosubmit of a search */ function ajaxSearch(methodName, type, searchCriteria, returnTable,sessionId) { initRequest(); if (!requests) { requests = new Object(); } requests.returnTable = returnTable; requests.searchCriteria = searchCriteria; var processMethod; if(methodName == "searchProduct"){ url = "ajax-autosearch-product.ajax;jsessionid="+sessionId+"?type="+type+"&prefix=" + escape(searchCriteria); processMethod=processAutoSearchProductRequest; } else{ url = "ajax-autosearch-project.ajax?prefix=" + escape(searchCriteria); processMethod=processAutoSearchRequest; } handleSimpleAjaxRequest(url, processMethod); } function handleSimpleAjaxRequest(url, returnProcess) { req.onreadystatechange = returnProcess; req.open("GET", url, true); req.send(null); } /** * Fill the results returned by the AjaxPhaseListener auto-search method. */ function processAutoSearchRequest() { //alert("processAutoSearchRequest"); if (req.readyState == 4) { if (req.status == 200) { parseResults(requests.returnTable); } else { if (req.status == 204) { clearResults(requests.returnTable); } } } } function processAutoSearchProductRequest() { if (req.readyState == 4) { if (req.status == 200) { parseProductResults(requests.returnTable); } else { if (req.status == 204) { clearResults(requests.returnTable); } } } } function thereIsNoResult() { } function parseResults(returnTable) { clearResults(returnTable); var items = req.responseXML.getElementsByTagName("item"); for (loop = 0; loop < items.length; loop++) { var id = items[loop].childNodes[0].firstChild.nodeValue; var code = items[loop].childNodes[1].firstChild.nodeValue; var desc = items[loop].childNodes[2].firstChild.nodeValue; var number = items[loop].childNodes[3].firstChild.nodeValue; var name = items[loop].childNodes[4].firstChild.nodeValue; var endDate = items[loop].childNodes[5].firstChild.nodeValue; var initialBudget = items[loop].childNodes[6].firstChild.nodeValue; addResult(returnTable, id, code, number, name, endDate, initialBudget, desc, loop); } } function parseProductResults(returnTable){ clearResults(returnTable); var items = req.responseXML.getElementsByTagName("item"); for(loop=0; loop "; desc = desc.replace(requests.searchCriteria, "" + requests.searchCriteria + ""); desc = desc.replace(requests.searchCriteria.toUpperCase(), "" + requests.searchCriteria.toUpperCase() + ""); // var codeText = document.createTextNode(convertXMLSpecialCharacters(code)); linkCode.innerHTML = convertXMLSpecialCharacters(code); var trNode = document.createElement("tr"); var tdNode = document.createElement("td"); // tdNode.innerHTML = link + code + ""; tdNode.appendChild(linkCode); trNode.appendChild(tdNode); tdNode = document.createElement("td"); // var descText = document.createTextNode(convertXMLSpecialCharacters(desc)); linkDesc.innerHTML = convertXMLSpecialCharacters(desc); // tdNode.innerHTML = link + desc + ""; tdNode.appendChild(linkDesc); trNode.appendChild(tdNode); returnTable.appendChild(trNode); // returnTable.innerHTML = lastResults + "" + link + code + "" + link + desc + ""; } function boldSearchCriteria(label,type){ var toBold; if(type == "translation"){ var sep = "-"; var pos = label.indexOf(sep); if (pos == -1){ toBold = label; } else{ toBold= label.substr(pos+sep.length, label.length); } } else{ toBold = label; } toBold=toBold.replace(requests.searchCriteria, "" + requests.searchCriteria + ""); toBold=toBold.replace(requests.searchCriteria.toUpperCase(), "" + requests.searchCriteria.toUpperCase() + ""); if(type == "translation"){ if(pos == -1){ return toBold; } else{ return label.substr(0,pos)+sep+toBold; } } else{ return toBold; } } function addProductResult(returnTable, value, label) { var linkCode = document.createElement("a"); linkCode.className = "linkProject"; linkCode.href="javascript:selectProduct('" + value + "')"; linkCode.onclick="javascript:selectProduct('" + value + "')"; var type=document.forms[0].type.value; label = boldSearchCriteria(label, type); linkCode.innerHTML = convertXMLSpecialCharacters(label); var trNode = document.createElement("tr"); var tdNode = document.createElement("td"); tdNode.appendChild(linkCode); trNode.appendChild(tdNode); returnTable.appendChild(trNode); } function clearResults(returnTable) { if (returnTable) { for (loop = 0; loop < 100; loop++) { if (returnTable.rows[loop]) { returnTable.deleteRow(loop); loop--; } } } } function selectProject(id, code, number, name, endDate, initialBudget) { if (id != '') { self.opener.updateProjects(id, code, number, name, endDate, initialBudget); self.close(); } }