1jQuery.autocomplete = function(input, options) { 2 // Create a link to self 3 var me = this; 4 var isScroll = false; 5 6 // Create jQuery object for input element 7 var $input = $d(input).attr("autocomplete", "off"); 8 var idd = input; 9 // Apply inputClass if necessary 10 if (options.inputClass) $input.addClass(options.inputClass); 11 12 // Create results 13 var results = document.createElement("div"); 14 // Create jQuery object for results 15 var $results = $d(results); 16 $results.hide().addClass(options.resultsClass).css("position", "absolute"); 17 if( options.width > 0 ) $results.css("width", options.width); 18 19 // Add to body element 20 $d("body").append(results); 21 22 input.autocompleter = me; 23 24 var timeout = null; 25 var prev = ""; 26 var active = -1; 27 var cache = {}; 28 var keyb = false; 29 var hasFocus = false; 30 var lastKeyPressCode = null; 31 32 // flush cache 33 function flushCache(){ 34 cache = {}; 35 cache.data = {}; 36 cache.length = 0; 37 }; 38 39 // flush cache 40 flushCache(); 41 42 // if there is a data array supplied 43 if( options.data != null ){ 44 var sFirstChar = "", stMatchSets = {}, row = []; 45 46 // no url was specified, we need to adjust the cache length to make sure it fits the local data store 47 if( typeof options.url != "string" ) options.cacheLength = 1; 48 49 // loop through the array and create a lookup structure 50 for( var i=0; i < options.data.length; i++ ){ 51 // if row is a string, make an array otherwise just reference the array 52 row = ((typeof options.data[i] == "string") ? [options.data[i]] : options.data[i]); 53 54 // if the length is zero, don't add to list 55 if( row[0].length > 0 ){ 56 // get the first character 57 sFirstChar = row[0].substring(0, 1).toLowerCase(); 58 // if no lookup array for this character exists, look it up now 59 if( !stMatchSets[sFirstChar] ) stMatchSets[sFirstChar] = []; 60 // if the match is a string 61 stMatchSets[sFirstChar].push(row); 62 } 63 } 64 65 // add the data items to the cache 66 for( var k in stMatchSets ){ 67 // increase the cache size 68 options.cacheLength++; 69 // add to the cache 70 addToCache(k, stMatchSets[k]); 71 } 72 } 73 74 $input 75 .keydown(function(e) { 76 // track last key pressed 77 lastKeyPressCode = e.keyCode; 78 switch(e.keyCode) { 79 case 38: // up 80 e.preventDefault(); 81 moveSelect(-1); 82 break; 83 case 40: // down 84 e.preventDefault(); 85 moveSelect(1); 86 break; 87 case 9: // tab 88 case 13: // return 89 if( selectCurrent() ){ 90 // make sure to blur off the current field 91 $input.get(0).blur(); 92 e.preventDefault(); 93 } 94 break; 95 default: 96 active = -1; 97 if (timeout) clearTimeout(timeout); 98 timeout = setTimeout(function(){onChange();}, options.delay); 99 break; 100 } 101 }) 102 .focus(function(){ 103 // track whether the field has focus, we shouldn't process any results if the field no longer has focus 104 hasFocus = true; 105 }) 106 .blur(function() { 107 // track whether the field has focus 108 hasFocus = false; 109 //var ua = navigator.userAgent.toLowerCase(); 110 //if (ua.indexOf("chrome") == -1) 111 //if (isScroll == false) 112 hideResults(); // !!! Oleg! 113 }); 114 115 hideResultsNow(); 116 117 //remove starting whitespaces 118 function LTrim( value ) { 119 120 var re = /\s*((\S+\s*)*)/; 121 return value.replace(re, "$1"); 122 123 } 124 125 // Removes ending whitespaces 126 function RTrim( value ) { 127 128 var re = /((\s*\S+)*)\s*/; 129 return value.replace(re, "$1"); 130 131 } 132 133 // Removes leading and ending whitespaces 134 function trim( value ) { 135 136 return LTrim(RTrim(value)); 137 138 } 139 140 function onChange() { 141 // ignore if the following keys are pressed: [del] [shift] [capslock] 142 if( lastKeyPressCode == 46 || (lastKeyPressCode > 8 && lastKeyPressCode < 32) ) return $results.hide(); 143 var v = trim($input.val()); 144 if(options.inputSeperator.length != 0){ 145 var broken = v.split(options.inputSeperator); 146 v = trim(broken[broken.length-1]); 147 } 148 if (v == prev) return; 149 prev = v; 150 if (v.length >= options.minChars) { 151 $input.addClass(options.loadingClass); 152 requestData(v); 153 } else { 154 $input.removeClass(options.loadingClass); 155 $results.hide(); 156 } 157 }; 158 159 function moveSelect(step) { 160 161 var lis = $d("li", results); 162 if (!lis) return; 163 164 active += step; 165 166 if (active < 0) { 167 active = 0; 168 } else if (active >= lis.size()) { 169 active = lis.size() - 1; 170 } 171 172 lis.removeClass("ac_over"); 173 174 $d(lis[active]).addClass("ac_over"); 175 176 // Weird behaviour in IE 177 // if (lis[active] && lis[active].scrollIntoView) { 178 // lis[active].scrollIntoView(false); 179 // } 180 181 }; 182 183 function selectCurrent() { 184 var li = $d("li.ac_over", results)[0]; 185 if (!li) { 186 var $li = $d("li", results); 187 if (options.selectOnly) { 188 if ($li.length == 1) li = $li[0]; 189 } else if (options.selectFirst) { 190 li = $li[0]; 191 } 192 } 193 if (li) { 194 selectItem(li); 195 return true; 196 } else { 197 return false;
198 } 199 }; 200 201 function selectItem(li) { 202 if (!li) { 203 li = document.createElement("li"); 204 li.extra = []; 205 li.selectValue = ""; 206 } 207 var v = $d.trim(li.selectValue ? li.selectValue : li.innerHTML); 208 input.lastSelected = v; 209 prev = v; 210 $results.html(""); 211 if(options.inputSeperator.length != 0){ 212 var broken = $input.val().split(options.inputSeperator); 213 broken.splice(broken.length-1, 1, v); 214 $input.val(broken.join(options.inputSeperator + " ")); 215 }else{ 216 $input.val(v); 217 try { //Silvester: autocomplete hiddenelement 218 $d("#"+idd.name + "Code").val(li.hiddenValue); //<input type="hidden" id="DestinationCode" name="DestinationCode"> 219 } catch(e) {} 220 221 try { //Silvester: autocomplete othes ways 222 cell_change(input.id); // 223 } catch(e) {} // 224 } 225 hideResultsNow(); 226 if (options.onItemSelect) setTimeout(function() { options.onItemSelect(li) }, 1); 227 }; 228 229 // selects a portion of the input string 230 function createSelection(start, end){ 231 // get a reference to the input element 232 var field = $input.get(0); 233 if( field.createTextRange ){ 234 var selRange = field.createTextRange(); 235 selRange.collapse(true); 236 selRange.moveStart("character", start); 237 selRange.moveEnd("character", end); 238 selRange.select(); 239 } else if( field.setSelectionRange ){ 240 field.setSelectionRange(start, end); 241 } else { 242 if( field.selectionStart ){ 243 field.selectionStart = start; 244 field.selectionEnd = end; 245 } 246 } 247 field.focus(); 248 }; 249 250 // fills in the input box w/the first match (assumed to be the best match) 251 function autoFill(sValue){ 252 // if the last user key pressed was backspace, don't autofill 253 if( lastKeyPressCode != 8 ){ 254 // fill in the value (keep the case the user has typed) 255 $input.val($input.val() + sValue.substring(prev.length)); 256 // select the portion of the value not typed by the user (so the next character will erase) 257 createSelection(prev.length, sValue.length); 258 } 259 }; 260 261 function showResults() { 262 // get the position of the input field right now (in case the DOM is shifted) 263 var pos = findPos(input); 264 // either use the specified width, or autocalculate based on form element 265 var iWidth = (options.width > 0) ? options.width : $input.width(); 266 // reposition 267 $results.css({ 268 width: parseInt(iWidth+150) + "px", 269 top: (pos.y + input.offsetHeight) + "px", 270 left: pos.x + "px" 271 }).show(); 272 }; 273 274 function hideResults() { 275 if (isScroll == false) { 276 if (timeout) clearTimeout(timeout); 277 timeout = setTimeout(hideResultsNow, 600); 278 } 279 }; 280 281 function hideResultsNow() { 282 if (isScroll == true) return; 283 284 if (timeout) clearTimeout(timeout); 285 286 $input.removeClass(options.loadingClass); 287 if ($results.is(":visible")) { 288 $results.hide(); 289 } 290 if (options.mustMatch) { 291 var v = $input.val(); 292 if (v != input.lastSelected) { 293 selectItem(null); 294 } 295 } 296 }; 297 298 function receiveData(q, data) { 299 if (data) { 300 $input.removeClass(options.loadingClass); 301 results.innerHTML = ""; 302 303 // if the field no longer has focus or if there are no matches, do not display the drop down 304 if( !hasFocus || data.length == 0 ) return hideResultsNow(); 305 306 if ($d.browser.msie) { 307 // we put a styled iframe behind the calendar so HTML SELECT elements don't show through 308 $results.append(document.createElement('iframe')); 309 } 310 results.appendChild(dataToDom(data)); 311 // autofill in the complete box w/the first match as long as the user hasn't entered in more data 312 if( options.autoFill && ($input.val().toLowerCase() == q.toLowerCase()) ) autoFill(data[0][0]); 313 showResults(); 314 } else { 315 hideResultsNow(); 316 } 317 }; 318 319 function parseData(data) { 320 if (!data) return null; 321 var parsed = []; 322 var rows = data.split(options.lineSeperator); 323 for (var i=0; i < rows.length; i++) { 324 var row = $d.trim(rows[i]); 325 if (row) { 326 parsed[parsed.length] = row.split(options.cellSeperator); 327 } 328 } 329 return parsed; 330 }; 331 332 function dataToDom(data) { 333 var ul = document.createElement("ul"); 334 var num = data.length; 335 336 // limited results to a max number 337 if( (options.maxItemsToShow > 0) && (options.maxItemsToShow < num) ) num = options.maxItemsToShow; 338 339 for (var i=0; i < num; i++) { 340 var row = data[i]; 341 if (!row) continue; 342 var li = document.createElement("li"); 343 if (options.formatItem) { 344 li.innerHTML = options.formatItem(row, i, num); 345 li.selectValue = row[0]; 346 li.hiddenValue = row[1]; 347 } else { 348 li.innerHTML = row[0]; 349 li.selectValue = row[0]; 350 li.hiddenValue = row[1]; 351 } 352 var extra = null; 353 if (row.length > 1) { 354 extra = []; 355 for (var j=1; j < row.length; j++) { 356 extra[extra.length] = row[j]; 357 } 358 } 359 li.extra = extra; 360 ul.appendChild(li); 361 $d(li).hover( 362 function() { $d("li", ul).removeClass("ac_over"); $d(this).addClass("ac_over"); active = $d("li", ul).indexOf($d(this).get(0)); }, 363 function() { $d(this).removeClass("ac_over"); } 364 ).click(function(e) { e.preventDefault(); e.stopPropagation(); selectItem(this); isScroll = false; }); 365 } 366 367 $d(ul).scroll(function() { isScroll = true; } ); 368
369 return ul; 370 }; 371 372 function requestData(q) { 373 if (!options.matchCase) q = q.toLowerCase(); 374 var data = options.cacheLength ? loadFromCache(q) : null; 375 // recieve the cached data 376 if (data) { 377 receiveData(q, data); 378 // if an AJAX url has been supplied, try loading the data now 379 } else if( (typeof options.url == "string") && (options.url.length > 0) ){ 380 $d.get(makeUrl(q), function(data) { 381 data = parseData(data); 382 addToCache(q, data); 383 receiveData(q, data); 384 }); 385 // if there's been no data found, remove the loading class 386 } else { 387 $input.removeClass(options.loadingClass); 388 } 389 }; 390 391 function makeUrl(q) { 392 var url = options.url + "?q=" + encodeURI(q); 393 for (var i in options.extraParams) { 394 url += "&" + i + "=" + encodeURI(options.extraParams[i]); 395 } 396 return url; 397 }; 398 399 function loadFromCache(q) { 400 if (!q) return null; 401 if (cache.data[q]) return cache.data[q]; 402 if (options.matchSubset) { 403 for (var i = q.length - 1; i >= options.minChars; i--) { 404 var qs = q.substr(0, i); 405 var c = cache.data[qs]; 406 if (c) { 407 var csub = []; 408 for (var j = 0; j < c.length; j++) { 409 var x = c[j]; 410 var x0 = x[0]; 411 if (matchSubset(x0, q)) { 412 csub[csub.length] = x; 413 } 414 } 415 return csub; 416 } 417 } 418 } 419 return null; 420 }; 421 422 function matchSubset(s, sub) { 423 if (!options.matchCase) s = s.toLowerCase(); 424 var i = s.indexOf(sub); 425 if (i == -1) return false; 426 return i == 0 || options.matchContains; 427 }; 428 429 this.flushCache = function() { 430 flushCache(); 431 }; 432 433 this.setExtraParams = function(p) { 434 options.extraParams = p; 435 }; 436 437 this.findValue = function(){ 438 var q = $input.val(); 439 440 if (!options.matchCase) q = q.toLowerCase(); 441 var data = options.cacheLength ? loadFromCache(q) : null; 442 if (data) { 443 findValueCallback(q, data); 444 } else if( (typeof options.url == "string") && (options.url.length > 0) ){ 445 $d.get(makeUrl(q), function(data) { 446 data = parseData(data) 447 addToCache(q, data); 448 findValueCallback(q, data); 449 }); 450 } else { 451 // no matches 452 findValueCallback(q, null); 453 } 454 } 455 456 function findValueCallback(q, data){ 457 if (data) $input.removeClass(options.loadingClass); 458 459 var num = (data) ? data.length : 0; 460 var li = null; 461 462 for (var i=0; i < num; i++) { 463 var row = data[i]; 464 465 if( row[0].toLowerCase() == q.toLowerCase() ){ 466 li = document.createElement("li"); 467 if (options.formatItem) { 468 li.innerHTML = options.formatItem(row, i, num); 469 li.selectValue = row[0]; 470 } else { 471 li.innerHTML = row[0]; 472 li.selectValue = row[0]; 473 } 474 var extra = null; 475 if( row.length > 1 ){ 476 extra = []; 477 for (var j=1; j < row.length; j++) { 478 extra[extra.length] = row[j]; 479 } 480 } 481 li.extra = extra; 482 } 483 } 484 485 if( options.onFindValue ) setTimeout(function() { options.onFindValue(li) }, 1); 486 } 487 488 function addToCache(q, data) { 489 if (!data || !q || !options.cacheLength) return; 490 if (!cache.length || cache.length > options.cacheLength) { 491 flushCache(); 492 cache.length++; 493 } else if (!cache[q]) { 494 cache.length++; 495 } 496 cache.data[q] = data; 497 }; 498 499 function findPos(obj) { 500 var curleft = obj.offsetLeft || 0; 501 var curtop = obj.offsetTop || 0; 502 while (obj = obj.offsetParent) { 503 curleft += obj.offsetLeft 504 curtop += obj.offsetTop 505 } 506 return {x:curleft,y:curtop}; 507 } 508} 509 510jQuery.fn.autocomplete = function(url, options, data) { 511 // Make sure options exists 512 options = options || {}; 513 // Set url as option 514 options.url = url; 515 // set some bulk local data 516 options.data = ((typeof data == "object") && (data.constructor == Array)) ? data : null; 517 518 // Set default values for required options 519 options.inputClass = options.inputClass || "ac_input"; 520 options.resultsClass = options.resultsClass || "ac_results"; 521 options.lineSeperator = options.lineSeperator || "\n"; 522 options.cellSeperator = options.cellSeperator || "|"; 523 options.minChars = options.minChars || 1; 524 options.delay = options.delay || 400; 525 options.matchCase = options.matchCase || 0; 526 options.matchSubset = options.matchSubset || 1; 527 options.matchContains = options.matchContains || 0; 528 options.cacheLength = options.cacheLength || 1; 529 options.mustMatch = options.mustMatch || 0; 530 options.extraParams = options.extraParams || {}; 531 options.loadingClass = options.loadingClass || "ac_loading"; 532 options.selectFirst = options.selectFirst || false; 533 options.selectOnly = options.selectOnly || false; 534 options.inputSeperator = options.inputSeperator || ''; 535 options.maxItemsToShow = options.maxItemsToShow || -1; 536 options.autoFill = options.autoFill || false; 537 options.width = parseInt(options.width, 10) || 0; 538 539 this.each(function() { 540 var input = this; 541 new jQuery.autocomplete(input, options); 542 }); 543 544 // Don't break the chain 545 return this; 546} 547 548jQuery.fn.autocompleteArray = function(data, options) { 549 return this.autocomplete(null, options, data); 550} 551 552jQuery.fn.indexOf = function(e){ 553 for( var i=0; i<this.length; i++ ){ 554 if( this[i] == e ) return i; 555 } 556 return -1; 557}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.