//This code Copyright 2008 Feedjit Inc. 
//This code is NOT open source and is protected by domestic copyright laws and international treaties.
//Reproduction in any form is prohibited. 
//Violators will be prosecuted to the fullest extent of the law.
var SUGGEST_DEBUG = false;function fjalert(msg){ if(SUGGEST_DEBUG){ alert(msg); }}var Suggest = Class.create();Suggest.prototype = { initialize: function(params) { this.inputId = params.inputElem || fjalert('missing inputId'); this.baseURL = params.baseURL || fjalert('missing baseURL'); this.template = params.template || fjalert('missing template'); this.selectedClass = params.selectedClass || fjalert('missing selectedClass'); this.unselectedClass = params.unselectedClass || fjalert('missing unselectedClass'); this.zIndex = params.zIndex ? parseInt(params.zIndex) : 11; this.otherElems = params.otherElems ? params.otherElems : []; this.otherElems.each(function(elem){ $(elem) || alert('Element "' + elem + '" does not exist!'); }); this.otherElems.each(function(elem){ Event.observe($(elem), 'click', this.otherElementClick.bindAsEventListener(this), true); }.bind(this)); this.otherValues = params.otherValues ? params.otherValues : {}; this.onListClick = params.onListClick ? params.onListClick : false; this.onLoseFocus = params.onLoseFocus ? params.onLoseFocus : false; this.onListOver = params.onListOver ? params.onListOver : false; this.listCaches = new Array();  this.listHTMLCaches = new Array(); this.fetchesInProgress = new Array();  this.ajaxRequests = new Array(); this.validInputMatch = /[^\s\t\r\n]+/i; this.AjaxRequestsBusy = 0; this.numLoadingDots = 1; this.inputHasFocus = false; this.listSelected = false; this.lastArrowKeyTime = 0; this.messages = new Array(); this.isIE = navigator.userAgent.indexOf('MSIE') > -1; Event.observe($(this.inputId), 'focus', this.inputOnFocus.bindAsEventListener(this), false); Event.observe($(this.inputId), 'blur', this.inputOnBlur.bindAsEventListener(this), false); Event.observe($(this.inputId), 'keydown', this.inputOnKeyDown.bindAsEventListener(this), false);  Event.observe($(this.inputId), 'keypress', this.inputOnKeyPress.bindAsEventListener(this), false);  this.refreshInputPositions(); this.sBoxName = 'GJSResults'; new Insertion.Top($$('html body')[0], '<div id="' + this.sBoxName + '" style="display:none; position: absolute; left: ' + this.inputPosLeft + 'px; top: ' + (this.inputPosTop + this.inputDimHeight) + 'px; width: ' + (this.inputDimWidth - 8) + 'px; height: 100px; overflow: auto; border: 1px solid #666; z-index: ' + this.zIndex + '; background-color: #FFF;" class="fb">Loading...<br />asdf<br />asdf<br />asdf</div>'); Event.observe($(this.sBoxName), 'click', this.sBoxOnClick.bindAsEventListener(this), false); Event.observe($(this.inputId), 'click', this.inputOnClick.bindAsEventListener(this), false); Event.observe($(this.sBoxName), 'scroll', this.sBoxOnScroll.bindAsEventListener(this), false); this.initialSBoxHeight = this.calculateSBoxHeight(); window.gjsOMO = this.listOnMouseOver.bindAsEventListener(this); window.gjsCLK = this.listOnClick.bindAsEventListener(this); this.disabled = false; }, refreshInputPositions: function() { var offsets = Position.cumulativeOffset($(this.inputId)); this.inputPosLeft = offsets[0]; this.inputPosTop = offsets[1]; var dimensions = $(this.inputId).getDimensions(); this.inputDimWidth = dimensions.width; this.inputDimHeight = dimensions.height; }, repositionSBox: function() { this.refreshInputPositions(); $(this.sBoxName).style.left = this.inputPosLeft + 'px'; $(this.sBoxName).style.top = (this.inputPosTop + this.inputDimHeight) + 'px'; }, disable: function() { this.disabled = true; this.stopLoadingMessage(); this.hideList(); }, enable: function() { this.disabled = false; }, otherElementClick: function(evt) { Event.stop(evt); }, dumpMessages: function() { this.messages.each(function(msg) { GLog.write(msg); }); }, addMessage: function(msg) { this.messages.push(msg); }, inputOnKeyPress: function(evt, fromKeyPress){ if( ((new Date()).getTime() - this.lastKeyDownTime > 100) && (evt.keyCode == 38 || evt.keyCode == 40 || evt.keyCode == 8)  ){ this.inputOnKeyDown(evt, true); this.lastKeyPressTime = (new Date()).getTime(); return; } else { return false; } }, inputOnKeyDown: function(evt, fromKeyPress) { if(! fromKeyPress){ this.lastKeyDownTime = (new Date()).getTime(); if((new Date()).getTime() - this.lastKeyPressTime < 100){ return; } } this.inputHasFocus = true; if(this.disabled) return; switch (evt.keyCode) { case 13:  if(this.onListClick) { var key = this.makeReqKey(); if(this.listCaches[key]){ var edata = this.listCaches[key][this.listSelected - 1]; this.onListClick(edata); this.loseFocus(); } } return; case 27:  this.loseFocus(); return; case 9:  this.loseFocus(); return; case 38:  this.handleUp(); Event.stop(evt); return; case 40:  this.handleDown(); Event.stop(evt); return; case 34:  this.handlePageDown(); Event.stop(evt); return; case 33:  this.handlePageUp(); Event.stop(evt); return; default: setTimeout(function(){this.handleInputChange();}.bind(this), 1); } }, handleUp: function() { this.lastArrowKeyTime = (new Date()).getTime(); if(! this.listSelected) return; if(! $('gjsel' + this.listSelected)) return; if(this.selectPrevOption()) { this.scrollIntoView(); this._onListOverForCurrentSelection(); } }, _onListOverForCurrentSelection: function(){ var key = this.makeReqKey(); if(this.listCaches[key]) { var edata = this.listCaches[key][this.listSelected - 1]; this.onListOver(edata); } }, handleDown: function() { this.lastArrowKeyTime = (new Date()).getTime(); if(! this.listSelected) return; if(! $('gjsel' + this.listSelected)) return; if(this.selectNextOption()) { this.scrollIntoView(); this._onListOverForCurrentSelection(); } }, handlePageDown: function() { this.lastArrowKeyTime = (new Date()).getTime(); if(! this.listSelected) return; if(! $('gjsel' + this.listSelected)) return; var i = this.listSelected; var totalHeight = 0; while($('gjsel' + i) && totalHeight < $(this.sBoxName).clientHeight) { totalHeight += $('gjsel' + i).offsetHeight; i++; } this.selectListOption(i - 1); this.scrollIntoView(); this._onListOverForCurrentSelection(); }, handlePageUp: function() { this.lastArrowKeyTime = (new Date()).getTime(); if(! this.listSelected) return; if(! $('gjsel' + this.listSelected)) return; var i = this.listSelected; var totalHeight = 0; while(i > 0 && totalHeight < $(this.sBoxName).clientHeight) { totalHeight += $('gjsel' + i).offsetHeight; i--; } this.selectListOption(i + 1); this.scrollIntoView(); this._onListOverForCurrentSelection(); }, scrollIntoView: function() { if(! this.listSelected) return; if(! $('gjsel' + this.listSelected)) return; var selElem = $('gjsel' + this.listSelected); var ePos = Position.positionedOffset(selElem); var elemTop = ePos[1]; var eDim = Element.getDimensions(selElem); var elemBottom = elemTop + eDim.height; var scrollTop = $(this.sBoxName).scrollTop; var scrollBottom = scrollTop + $(this.sBoxName).clientHeight; var reqKey = this.makeReqKey(); if($('gjLastNotice') && this.listSelected > this.listCaches[reqKey].length - 5) { this.scrollToBottom(); } else { if(elemBottom > scrollBottom) { $(this.sBoxName).scrollTop += elemBottom - scrollBottom; } else if(elemTop < scrollTop) { $(this.sBoxName).scrollTop -= scrollTop - elemTop; } } }, makeReqKey: function() { var k = ""; this.otherElems.each(function(elem){ k += $F(elem); }); k += $F(this.inputId); return k.replace(/\s/, '_'); }, inputIsValid: function() { if(this.validInputMatch.test($F(this.inputId))) { return true; } else { return false} }, isListComplete: function(reqKey) { if(this.listCaches[reqKey] && this.listCaches[reqKey].length > 0 && this.listCaches[reqKey].last().cc == '0' ) { return true; } else { return false; } }, makeSVals: function() { var sVals = {}; if(this.otherElems) { this.otherElems.each(function(elem){ sVals[elem] = $F(elem); }); } if(this.otherValues) { for(var k in this.otherValues) { sVals[k] = this.otherValues[k](); } } return sVals; }, handleInputChange: function() { if(this.disabled) return; if(this.inputIsValid()) { var reqKey = this.makeReqKey(); if(this.currentlyDrawnList != reqKey || $(this.sBoxName).style.display == 'none') { if(this.listCaches[reqKey]) { this.stopLoadingMessage(); this.drawList(reqKey, 0); return; } else if(this.fetchesInProgress[reqKey]) { return; } else {  this.loadList($F(this.inputId), this.makeSVals(), reqKey, 0); return; } } else { } } else { this.stopLoadingMessage(); this.hideList(); return; } }, calculateSBoxHeight: function() { var cumu = Position.cumulativeOffset($(this.sBoxName)); var docHeight = window.innerHeight ? window.innerHeight : document.documentElement.offsetHeight; docHeight -= cumu[1];  if(docHeight < 240) { boxHeight = 200; } else { boxHeight = Math.floor(docHeight * 0.8); } return boxHeight; }, reportError: function(msg) { this.reset(); if(this.lastErrorTime && (new Date()).getTime() - this.lastErrorTime < 1000) return; this.lastErrorTime = (new Date()).getTime(); alert('We encountered an error. Please ensure your Internet connection is working.\nRetype your search request to try again. If you continue to experience problems, click your browsers "Reload" button.\n\nThe error message was:\n' + msg); this.lastErrorTime = (new Date()).getTime(); return; }, loadList: function(iVal, sVals, reqKey, loadIndex) { this.fetchesInProgress[reqKey] = true; if(loadIndex == 0) { this.startLoadingMessage(); } else { this.startLoadingMessage(true); } var delay = (this.AjaxRequestsBusy * 200 + 1); delay = (delay <= 1000) ? delay : 1000; setTimeout(function(){ if(iVal == $F(this.inputId)) { this.startAjax(reqKey, iVal, sVals, loadIndex); } else { this.fetchesInProgress[reqKey] = false; } }.bind(this), (this.AjaxRequestsBusy * 200 + 1)); }, startAjax: function(reqKey, iVal, sVals, loadIndex) { var tmpParams = { q: iVal, l: loadIndex }; for(var k in sVals) { tmpParams[k] = sVals[k]; } var params = $H(tmpParams).toQueryString(); this.AjaxRequestsBusy++; this.ajaxRequests[reqKey] = new Ajax.Request( this.baseURL, { method: 'post', parameters: params, onComplete: function(ajaxReq, json){ this.completeAjax(ajaxReq, reqKey, loadIndex, json); }.bind(this), onException: function(ajaxReq, e){ this.AjaxException(reqKey, ajaxReq, e); }.bind(this), onFailure: function(){ this.AjaxFailure(reqKey); }.bind(this) }); }, AjaxException: function(reqKey, AjaxRequest, e) { if(FJ_DEBUG) { alert('Ajax exception for key "' + reqKey + '":' + e.toString()); } if(! this.inputHasFocus) return; this.abortThisRequest(reqKey); return; }, AjaxFailure: function(reqKey, b) { if(FJ_DEBUG) { alert('Ajax failure for key "' + reqKey + ':' + b.toString()); } if(! this.inputHasFocus) return; this.abortThisRequest(reqKey); return; }, reset: function() { this.stopLoadingMessage(); this.hideList(); $(this.inputId).value = ""; $(this.inputId).focus(); for(var reqKey in this.ajaxRequests) { if(this.ajaxRequests[reqKey].abort) { this.ajaxRequests[reqKey].abort(); } } this.ajaxRequests = new Array(); this.inputHasFocus = true; this.listSelected = false; this.lastArrowKeyTime = 0; this.listCaches = new Array(); this.listHTMLCaches = new Array(); this.fetchesInProgress = new Array(); this.AjaxRequestsBusy = 0; this.numLoadingDots = 1; }, abortThisRequest: function(reqKey) { if(this.makeReqKey() == reqKey && this.inputHasFocus) { this.stopLoadingMessage(); this.listCaches[reqKey] = [{ cc: 2 }]; this.drawList(reqKey, 0); } this.fetchesInProgress[reqKey] = false; return; }, completeAjax: function(ajaxReq, reqKey, loadIndex) { if(ajaxReq.status != 200) { this.abortThisRequest(reqKey); return; } this.AjaxRequestsBusy--; if(! reqKey) { return; } var startDrawAt = 0; if(loadIndex > 0) { if(! this.listCaches[reqKey]) { return; } var newList; try { newList = eval('(' + ajaxReq.responseText + ')'); } catch(e) { this.abortThisRequest(reqKey); return; } startDrawAt = this.listCaches[reqKey].length;  this.listCaches[reqKey] = this.listCaches[reqKey].concat(newList);  } else { if(this.listCaches[reqKey]) { return; } try { this.listCaches[reqKey] = eval('(' + ajaxReq.responseText + ')'); } catch(e) { this.abortThisRequest(reqKey); return; } } if(this.makeReqKey() == reqKey) { this.stopLoadingMessage(); this.drawList(reqKey, startDrawAt); } this.fetchesInProgress[reqKey] = false; }, startLoadingMessage: function(isMore) { this.repositionSBox(); if(! this.loadingMessageInterval) { if(isMore) { this.loadingMoreElem = 'gjLM'; new Insertion.Top($$('html body')[0], '<div id="' + this.loadingMoreElem + '" style="display: none; z-index: ' + (this.zIndex + 1) + '; position: absolute;" class="lmore"></div>'); var offsets = Position.positionedOffset($(this.sBoxName)); var dimensions = $(this.sBoxName).getDimensions(); $(this.loadingMoreElem).style.left = offsets[0] + 'px'; $(this.loadingMoreElem).style.top = (offsets[1] + dimensions.height) + 'px'; $(this.loadingMoreElem).style.display = 'block'; $(this.loadingMoreElem).style.width = '200px'; } this.loadingMessageInterval = setInterval(function(){ if(! this.loadingMessageInterval) return;  var dots = this.numLoadingDots % 10; var msg = isMore ? 'Loading more results.' : 'Searching.'; for(var i = 0; i <= dots; i++) { msg += '.'; } if(isMore) { $(this.loadingMoreElem).innerHTML = msg; } else { $(this.sBoxName).style.display = 'block'; $(this.sBoxName).innerHTML = msg; $(this.sBoxName).style.height = '20px'; } this.numLoadingDots++; }.bind(this), 50); } }, stopLoadingMessage: function() { if(this.loadingMessageInterval) { clearInterval(this.loadingMessageInterval); this.loadingMessageInterval = false; if($(this.loadingMoreElem)) { $(this.loadingMoreElem).remove(); } else { $(this.sBoxName).style.display = 'none'; $(this.sBoxName).innerHTML = ''; } } }, redrawList: function() { if($(this.sBoxName).style.display == 'block') { var reqKey = this.makeReqKey(); if(this.listCaches[reqKey]) { this.stopLoadingMessage(); this.drawList(reqKey, 0); return; } } }, drawList: function(cacheKey, startDrawAt) { this.repositionSBox(); if(! this.listCaches[cacheKey]) { return; } if(startDrawAt > this.listCaches[cacheKey].length - 1) { return; } if(startDrawAt > 0 && (! $(this.sBoxName).firstChild) ) { return; } if(startDrawAt == 0) { this.scrollToTop(); this.listSelected = false; $(this.sBoxName).innerHTML = ''; var edata = this.listCaches[cacheKey][0]; if(edata && edata.cc != '0' && edata.cc != '1') { this.onListOver(edata); } } $(this.sBoxName).style.display = 'block'; if( this.listCaches[cacheKey].length > 1 ) { var htm = ""; if(startDrawAt == 0 && this.listHTMLCaches[cacheKey]) { $(this.sBoxName).innerHTML = this.listHTMLCaches[cacheKey]; } else { for(var i = startDrawAt; i < this.listCaches[cacheKey].length; i++) { if(this.listCaches[cacheKey][i].cc == '0') { break; } var divId; var txt; if(this.listCaches[cacheKey][i].cc == '1') { divId = 'gjLastNotice'; txt = "<b>You've reached the maximum number of search results that Feedjit displays.</b>"; } else { divId = 'gjsel' + (i + 1); txt = this.template.evaluate(this.listCaches[cacheKey][i]); } htm += '<div id="'+ divId + '" class="' + this.unselectedClass + '" onmouseover="window.gjsOMO(event);" onclick="window.gjsCLK(event);">' + txt + '</div>'; } if(startDrawAt == 0) { $(this.sBoxName).innerHTML = htm; this.listHTMLCaches[cacheKey] = htm; } else { $(this.sBoxName).innerHTML += htm; this.listHTMLCaches[cacheKey] += htm; } } } else if(startDrawAt == 0 && this.listCaches[cacheKey].length == 1 && this.listCaches[cacheKey][0].cc == 2) { $(this.sBoxName).style.height = '20px'; $(this.sBoxName).innerHTML = '<div id="gjNoMatchNotice">Search failed! Please check your Internet connection.</div>'; this.listCaches[cacheKey] = false;  } else { this.listSelected = false; $(this.sBoxName).style.height = '20px'; $(this.sBoxName).innerHTML = '<span id="gjNoMatchNotice">No matching landmarks found</span>'; } this.resizeSBox(); if(startDrawAt == 0) { if(this.listCaches[cacheKey].length > 0) { this.selectListOption(1); } } else { if($('gjLastNotice')) { this.scrollToBottom(); } } this.currentlyDrawnList = cacheKey; }, showMessage: function(msg) { this.repositionSBox(); $(this.sBoxName).innerHTML = msg; $(this.sBoxName).style.height = '20px'; $(this.sBoxName).style.display = 'block'; }, removeMessage: function() { this.repositionSBox(); $(this.sBoxName).style.display = 'none'; $(this.sBoxName).innerHTML = ''; }, resizeSBox: function() { var bHeight = this.calculateSBoxHeight(); var totalHeight  = this.getListHeight(); $(this.sBoxName).style.height = (totalHeight > bHeight ? bHeight : totalHeight) + 'px'; }, getListHeight: function() { var i = 1; var height = 0; while($('gjsel' + i)) { height += $('gjsel' + i).offsetHeight; i++; } if($('gjLastNotice')) { height += $('gjLastNotice').offsetHeight; } if($('gjNoMatchNotice')) { height += $('gjNoMatchNotice').offsetHeight; } return height; }, scrollToBottom: function() { $(this.sBoxName).scrollTop = $(this.sBoxName).scrollHeight - $(this.sBoxName).clientHeight; }, scrollToTop: function() { $(this.sBoxName).scrollTop = 0; }, getTotalListEntries: function() { var i = 1; while($('gjsel' + i)) { i++; } return i - 1; }, sBoxOnScroll: function(evt) { $(this.inputId).focus();  this.appendIfNeeded(); }, appendIfNeeded: function() { var reqKey = this.makeReqKey(); if(this.fetchesInProgress[reqKey]) return; if(this.isListComplete(reqKey)) return; var scrollBottom = $(this.sBoxName).scrollTop + $(this.sBoxName).clientHeight; var distanceFromBottom = $(this.sBoxName).scrollHeight - scrollBottom; if(distanceFromBottom < $(this.sBoxName).firstChild.offsetHeight * 1) { this.loadList($F(this.inputId),this.makeSVals(),reqKey, this.getTotalListEntries()); return; } }, extractInt: function(str) { var reg = new RegExp("^[a-zA-Z]*(\\d+$)"); mymatch = reg.exec(str); return parseInt(mymatch[1]); }, listOnMouseOver: function(event) { var evt = event || window.event; Event.stop(evt); if((new Date()).getTime() - this.lastArrowKeyTime < 100) return; var elem = this.getParentListItem(evt); if(this.lastListMOEvt == elem.id) { return; } else { this.lastListMOEvt = elem.id; } if(this.listSelected) { if(! $('gjsel' + this.listSelected) ) { return; } $('gjsel' + this.listSelected).className = this.unselectedClass; } elem.className = this.selectedClass; this.listSelected = this.extractInt(elem.id); $(this.inputId).focus(); if(this.onListOver) { var key = this.makeReqKey(); if(this.listCaches[key]) { var edata = this.listCaches[key][this.listSelected - 1]; this.onListOver(edata); } } }, listOnClick: function(event) { var evt = event || window.event; var elem = this.getParentListItem(evt); Event.stop(evt); var elId = this.extractInt(elem.id) - 1; var key = this.makeReqKey(); var edata = this.listCaches[key][elId]; this.loseFocus(); if(this.onListClick) { this.onListClick(edata); } }, selectListOption: function(sel) { if(! $('gjsel' + sel)) return; if($('gjsel' + this.listSelected)) { $('gjsel' + this.listSelected).className = this.unselectedClass; } this.listSelected = sel; $('gjsel' + this.listSelected).className = this.selectedClass; }, selectNextOption: function() { if(! this.listSelected) return; if(! $('gjsel' + this.listSelected)) return; var n = this.listSelected + 1; if($('gjsel' + n)) { $('gjsel' + this.listSelected).className = this.unselectedClass; this.listSelected++; $('gjsel' + this.listSelected).className = this.selectedClass; return true; } else { return false; } }, selectPrevOption: function() { if(! this.listSelected) return; if(! $('gjsel' + this.listSelected)) return; if(this.listSelected > 1) { $('gjsel' + this.listSelected).className = this.unselectedClass; this.listSelected--; $('gjsel' + this.listSelected).className = this.selectedClass; return true; } else { return false; } }, hideList: function() { this.listSelected = false; $(this.sBoxName).style.display = 'none'; }, inputOnFocus: function(evt) { this.inputHasFocus = true; $(this.inputId).select();  if(! this.documentClickObserver) { this.documentClickObserver = this.documentOnClick.bindAsEventListener(this); Event.observe(document, 'click', this.documentClickObserver, false); } this.handleInputChange(); }, inputOnBlur: function(evt) { this.inputHasFocus = false; }, inputOnClick: function(evt) { Event.stop(evt); }, sBoxOnClick: function(evt) { Event.stop(evt); }, documentOnClick: function(evt) { this.loseFocus(); }, loseFocus: function() { this.inputHasFocus = false; this.stopLoadingMessage(); if(this.inputHasFocus) { $(this.inputId).blur(); } $(this.sBoxName).style.display = 'none'; if(this.documentClickObserver) { Event.stopObserving(document, 'click',  this.documentClickObserver, false); this.documentClickObserver = false; } this.listCaches = new Array(); this.listHTMLCaches = new Array(); if(this.onLoseFocus) { this.onLoseFocus(); } }, getParentListItem: function(evt) { var elem = Event.element(evt); while(elem && elem.id.indexOf('gjsel') != 0) { elem = elem.parentNode; } if(! elem) alert('Could not find parent list element'); return elem; }, isSBoxOpen: function(){ return $(this.sBoxName).style.display == 'block' ? true : false; }};