diff -r 902822492a68 -r fe660c52c48f includes/clientside/static/autocomplete.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/includes/clientside/static/autocomplete.js Wed Jun 13 16:07:17 2007 -0400 @@ -0,0 +1,308 @@ +/* + * Auto-completing page/username fields + */ + +// The ultimate Javascript app: AJAX auto-completion, which responds to up/down arrow keys, the enter key, and the escape key +// The idea was pilfered mercilessly from vBulletin, but uses about 8 +// bytes of vB code. All the rest was coded by me, Mr. Javascript Newbie... + +// ...in about 8 hours. +// You folks better like this stuff. + +function nameCompleteEventHandler(e) +{ + if(!e) e = window.event; + switch(e.keyCode) + { + case 38: // up + unSelectMove('up'); + break; + case 40: // down + unSelectMove('down'); + break; + case 27: // escape + case 9: // tab + destroyUsernameDropdowns(); + break; + case 13: // enter + unSelect(); + break; + default: return false; break; + } + return true; +} + +function unSelectMove(dir) +{ + if(submitAuthorized) return false; + var thediv = document.getElementById(unObjDivCurrentId); + thetable = thediv.firstChild; + cel = thetable.firstChild.firstChild; + d = true; + index = false; + changed = false; + // Object of the game: extract the username, determine its index in the userlist array, and then color the menu items and set unObjCurrentSelection + while(d) // Set to false if an exception occurs or if we arrive at our destination + { + //* + if(!cel) d=false; + celbak = cel; + cel = cel.nextSibling; + if(!cel) d=false; + try { + if(cel.firstChild.nextSibling) html = cel.firstChild.nextSibling.innerHTML; + else html = cel.firstChild.innerHTML; + cel.firstChild.className = 'row1'; + if(cel.firstChild.nextSibling) cel.firstChild.nextSibling.className = 'row1'; + thename = html.substr(7, html.length-15); + // FINALLY! we have extracted the username + // Now get its position in the userlist array + if(thename == unObjCurrentSelection) + { + index = parseInt(in_array(thename, userlist)); + } + if(typeof(index) == 'number') + { + if(dir=='down') + n = index+1; + else if(dir == 'up') + n = index - 1; + + // Try to trap moving the selection up or down beyond the top of bottom + if(n > userlist.length-1 || n < 0) + { + cel.firstChild.className = 'row2'; + if(cel.firstChild.nextSibling) cel.firstChild.nextSibling.className = 'row2'; + return; + } + + if(dir=='down') no=cel.nextSibling; + else if(dir=='up') no=cel.previousSibling; + no.firstChild.className = 'row2'; + if(no.firstChild.nextSibling) no.firstChild.nextSibling.className = 'row2'; + if(no.firstChild.id) + { + scroll = getScrollOffset() + getHeight(); + elemht = getElementHeight(no.firstChild.id); + elemoff = fetch_offset(no.firstChild); + whereto = elemoff['top'] + elemht; + if(whereto > scroll) + { + window.location.hash = '#'+no.firstChild.id; + unObj.focus(); + } + } + cel=cel.nextSibling; + unObjCurrentSelection = userlist[n]; + index = false; + changed = true; + return; + } + } catch(e) { } + //*/ d = false; + } +} + +function unSelect() +{ + if(!unObj || submitAuthorized) return false; + if ( unObjCurrentSelection ) + unObj.value = unObjCurrentSelection; + destroyUsernameDropdowns(); +} + +function in_array(needle, haystack) +{ + for(var i in haystack) + { + if(haystack[i] == needle) return i; + } + return false; +} + +function ajaxUserNameComplete(o) +{ + if(!o) {destroyUsernameDropdowns(); return;} + if(!o.value) {destroyUsernameDropdowns(); return;} + if(o.value.length < 3) {destroyUsernameDropdowns(); return;} + //if(IE) return; // This control doesn't work in IE. Yes, it's true! document.createElement doesn't work. + if(!o.id) + { + o.id = 'usernametextboxobj_' + Math.floor(Math.random() * 10000000); + } + unObj = o; + o.setAttribute("autocomplete","off"); + o.onkeyup = function(e, o) { o=unObj; if(!nameCompleteEventHandler(e)) ajaxUserNameComplete(o); } + val = escape(o.value).replace('+', '%2B'); + ajaxGet(stdAjaxPrefix+'&_mode=fillusername&name='+val, function() + { + if(ajax.readyState==4) + { + // Determine the appropriate left/top positions, then create a div to use for the drop-down list + // The trick here is to be able to make the div dynamically destroy itself depending on how far the user's mouse is from it + destroyUsernameDropdowns(); + off = fetch_offset(unObj); + dim = fetch_dimensions(unObj); + left = off['left']; + i1 = off['top']; + i2 = dim['h']; + var top = 0; + top = i1 + i2; + var thediv = document.createElement('div'); + thediv.className = 'tblholder'; + thediv.style.marginTop = '0px'; + thediv.style.position = 'absolute'; + thediv.style.top = top + 'px'; + thediv.style.left = left + 'px'; + thediv.style.zIndex = getHighestZ() + 2; + id = 'usernamehoverobj_' + Math.floor(Math.random() * 10000000); + unObjDivCurrentId = id; + thediv.id = id; + unObj.onblur = function() { destroyUsernameDropdowns(); } + + eval(ajax.responseText); + if(errorstring) + { + html = ''+errorstring+''; + } + else + { + html = ''; + cls = 'row2'; + unObjCurrentSelection = userlist[0]; + for(i=0;i'; + if(cls=='row2') cls='row1'; + } + html = html + '
Username matches
'+userlist[i]+'
'; + } + + thediv.innerHTML = html; + var body = document.getElementsByTagName('body'); + body = body[0]; + unSelectMenuOn = true; + submitAuthorized = false; + body.appendChild(thediv); + } + }); +} + +function ajaxPageNameComplete(o) +{ + if(!o) {destroyUsernameDropdowns(); return;} + if(!o.value) {destroyUsernameDropdowns(); return;} + if(o.value.length < 3) {destroyUsernameDropdowns(); return;} + if(IE) return; // This control doesn't work in IE. Yes, it's true! document.createElement doesn't work. + if(!o.id) + { + o.id = 'usernametextboxobj_' + Math.floor(Math.random() * 10000000); + } + o.setAttribute("autocomplete","off"); + unObj = o; + o.onkeyup = function(e, o) { o=unObj; if(!nameCompleteEventHandler(e)) ajaxPageNameComplete(o); } + val = escape(o.value).replace('+', '%2B'); + ajaxGet(stdAjaxPrefix+'&_mode=fillpagename&name='+val, function() + { + if(!ajax) return; + if(ajax.readyState==4) + { + // Determine the appropriate left/top positions, then create a div to use for the drop-down list + // The trick here is to be able to make the div dynamically destroy itself depending on how far the user's mouse is from it + destroyUsernameDropdowns(); + off = fetch_offset(unObj); + dim = fetch_dimensions(unObj); + left = off['left']; + top = off['top'] + dim['h']; + var thediv = document.createElement('div'); + thediv.className = 'tblholder'; + thediv.style.marginTop = '0px'; + thediv.style.position = 'absolute'; + thediv.style.top = top + 'px'; + thediv.style.left = left + 'px'; + thediv.style.zIndex = getHighestZ() + 2; + id = 'usernamehoverobj_' + Math.floor(Math.random() * 10000000); + unObjDivCurrentId = id; + thediv.id = id; + + eval(ajax.responseText); + if(errorstring) + { + html = ''+errorstring+''; + } + else + { + html = ''; + cls = 'row2'; + unObjCurrentSelection = userlist[0]; + for(i=0;i'; + if(cls=='row2') cls='row1'; + } + html = html + '
Page name matches
Page titlePage ID
'+namelist[i]+''+userlist[i]+'
'; + } + + thediv.innerHTML = html; + var body = document.getElementsByTagName('body'); + body = body[0]; + unSelectMenuOn = true; + submitAuthorized = false; + body.appendChild(thediv); + + unObj.onblur = function() { CheckDestroyUsernameDropdowns(thediv.id); }; + } + }); +} + +function CheckDestroyUsernameDropdowns(id) +{ + elem = document.getElementById(id); + if(!elem) return; + if(queryOnObj(elem, 100)) + { + destroyUsernameDropdowns(); + } +} + +function destroyUsernameDropdowns() +{ + var divs = document.getElementsByTagName('div'); + var prefix = 'usernamehoverobj_'; + for(i=0;i