1function JsSuggest(oHandler, sParams, sParser) 2{ 3 var t = this; 4 5 t.oObj = oHandler; 6 t.sParams = sParams; 7 // Arrays for data 8 if (sParser) 9 { 10 t.sExp = new RegExp("["+sParser+"]+", "i"); 11 } 12 else 13 { 14 t.sExp = new RegExp(","); 15 } 16 t.oLast = {"str":false, "arr":false}; 17 t.oThis = {"str":false, "arr":false}; 18 t.oEl = {"start":false, "end":false}; 19 t.oUnfinedWords = {}; 20 // Flags 21 t.bReady = true; 22 t.eFocus = true; 23 // Array with results & it`s showing 24 t.aDiv = null; 25 t.oDiv = null; 26 // Pointers 27 t.oActive = null; 28 t.oPointer = []; 29 t.oPointer_default = []; 30 t.oPointer_this = 'input_field'; 31 32 t.oObj.onblur = function() 33 { 34 t.eFocus = false; 35 }; 36 37 t.oObj.onfocus = function() 38 { 39 if (!t.eFocus) 40 { 41 t.eFocus = true; 42 setTimeout(function(){t.CheckModif('focus')}, 500); 43 } 44 }; 45 46 t.oLast["arr"] = t.oObj.value.split(t.sExp); 47 t.oLast["str"] = t.oLast["arr"].join(":"); 48 49 setTimeout(function(){t.CheckModif('this')}, 500); 50 51 this.CheckModif = function(__data) 52 { 53 var 54 sThis = false, tmp = 0, 55 bUnfined = false, word = "", 56 cursor = {}; 57 58 if (!t.eFocus) 59 return; 60 61 if (t.bReady && t.oObj.value.length > 0) 62 { 63 // Preparing input data 64 t.oThis["arr"] = t.oObj.value.split(t.sExp); 65 t.oThis["str"] = t.oThis["arr"].join(":"); 66 67 // Getting modificated element 68 if (t.oThis["str"] && (t.oThis["str"] != t.oLast["str"])) 69 { 70 cursor['position'] = TCJsUtils.getCursorPosition(t.oObj); 71 if (cursor['position']['end'] > 0 && !t.sExp.test(t.oObj.value.substr(cursor['position']['end']-1, 1))) 72 { 73 cursor['arr'] = t.oObj.value.substr(0, cursor['position']['end']).split(t.sExp); 74 sThis = t.oThis["arr"][cursor['arr'].length - 1]; 75 76 t.oEl['start'] = cursor['position']['end'] - cursor['arr'][cursor['arr'].length - 1].length; 77 t.oEl['end'] = t.oEl['start'] + sThis.length; 78 t.oEl['content'] = sThis; 79 80 t.oLast["arr"] = t.oThis["arr"]; 81 t.oLast["str"] = t.oThis["str"]; 82 } 83 } 84 if (sThis) 85 { 86 // Checking for UnfinedWords 87 for (tmp = 2; tmp <= sThis.length; tmp++) 88 { 89 word = sThis.substr(0, tmp); 90 if (t.oUnfinedWords[word] == '!fined') 91 { 92 bUnfined = true; 93 break; 94 } 95 } 96 if (!bUnfined) 97 t.Send(sThis); 98 } 99 } 100 setTimeout(function(){t.CheckModif('this')}, 500); 101 }; 102 103 t.Send = function(sSearch) 104 { 105 if (!sSearch) 106 return false; 107 108 var oError = []; 109 t.bReady = false; 110 if (BX('wait_container')) 111 { 112 BX('wait_container').innerHTML = BX.message('JS_CORE_LOADING'); 113 BX.show(BX('wait_container')); 114 } 115 BX.ajax.post( 116 '/bitrix/components/bitrix/search.suggest.input/search.php', 117 {"search":sSearch, "params":t.sParams}, 118 function(data) 119 { 120 var result = {}; 121 t.bReady = true; 122 123 try 124 { 125 eval("result = " + data + ";"); 126 } 127 catch(e) 128 { 129 oError['result_unval'] = e; 130 } 131 132 if (TCJsUtils.empty(result)) 133 oError['result_empty'] = 'Empty result'; 134 135 try 136 { 137 if (TCJsUtils.empty(oError) && (typeof result == 'object')) 138 { 139 if (!(result.length == 1 && result[0]['NAME'] == t.oEl['content'])) 140 { 141 t.Show(result); 142 return; 143 } 144 } 145 else 146 { 147 t.oUnfinedWords[t.oEl['content']] = '!fined'; 148 } 149 } 150 catch(e) 151 { 152 oError['unknown_error'] = e; 153 } 154 155 if(BX('wait_container')) 156 BX.hide(BX('wait_container')); 157 } 158 ); 159 }; 160 161 t.Show = function(result) 162 { 163 t.Destroy(); 164 t.oDiv = document.body.appendChild(document.createElement("DIV")); 165 t.oDiv.id = t.oObj.id+'_div'; 166 167 t.oDiv.className = "search-popup"; 168 t.oDiv.style.position = 'absolute'; 169 170 t.aDiv = t.Print(result); 171 var pos = TCJsUtils.GetRealPos(t.oObj); 172 t.oDiv.style.width = parseInt(pos["width"]) + "px"; 173 TCJsUtils.show(t.oDiv, pos["left"], pos["bottom"]); 174 TCJsUtils.addEvent(document, "click", t.CheckMouse); 175 TCJsUtils.addEvent(document, "keydown", t.CheckKeyword); 176 }; 177 178 t.Print = function(aArr) 179 { 180 var aEl = null; 181 var aResult = {}; 182 var iCnt = 0; 183 var oDiv = null; 184 var oSpan = null; 185 var sPrefix = t.oDiv.id; 186 187 for (var tmp_ in aArr) 188 { 189 if (aArr.hasOwnProperty(tmp_)) 190 { 191 // Math 192 aEl = aArr[tmp_]; 193 194 var aRes = {}; 195 aRes['ID'] = (aEl['ID'] && aEl['ID'].length > 0) ? aEl['ID'] : iCnt++; 196 aRes['GID'] = sPrefix + '_' + aRes['ID']; 197 aRes['NAME'] = TCJsUtils.htmlspecialcharsEx(aEl['NAME']); 198 aRes['CNT'] = aEl['CNT']; 199 200 aResult[aRes['GID']] = aRes; 201 t.oPointer.push(aRes['GID']); 202 // Graph 203 oDiv = t.oDiv.appendChild(document.createElement("DIV")); 204 oDiv.id = aRes['GID']; 205 oDiv.name = sPrefix + '_div'; 206 207 oDiv.className = 'search-popup-row'; 208 209 oDiv.onmouseover = function(){t.Init(); this.className='search-popup-row-active';}; 210 oDiv.onmouseout = function(){t.Init(); this.className='search-popup-row';};
211 oDiv.onclick = function(){t.oActive = this.id}; 212 213 oSpan = oDiv.appendChild(document.createElement("DIV")); 214 oSpan.id = oDiv.id + '_NAME'; 215 oSpan.className = "search-popup-el search-popup-el-cnt"; 216 oSpan.innerHTML = aRes['CNT']; 217 218 oSpan = oDiv.appendChild(document.createElement("DIV")); 219 oSpan.id = oDiv.id + '_NAME'; 220 oSpan.className = "search-popup-el search-popup-el-name"; 221 oSpan.innerHTML = aRes['NAME']; 222 } 223 } 224 t.oPointer.push('input_field'); 225 t.oPointer_default = t.oPointer; 226 return aResult; 227 }; 228 229 t.Destroy = function() 230 { 231 try 232 { 233 TCJsUtils.hide(t.oDiv); 234 t.oDiv.parentNode.removeChild(t.oDiv); 235 } 236 catch(e) 237 {} 238 239 t.aDiv = []; 240 t.oPointer = []; 241 t.oPointer_default = []; 242 t.oPointer_this = 'input_field'; 243 t.bReady = true; 244 t.eFocus = true; 245 t.oActive = null; 246 247 TCJsUtils.removeEvent(document, "click", t.CheckMouse); 248 TCJsUtils.removeEvent(document, "keydown", t.CheckKeyword); 249 }; 250 251 t.Replace = function() 252 { 253 if (typeof t.oActive == 'string') 254 { 255 var tmp = t.aDiv[t.oActive]; 256 var tmp1 = ''; 257 if (typeof tmp == 'object') 258 { 259 var elEntities = document.createElement("span"); 260 elEntities.innerHTML = tmp['NAME'].replace(/"/g, '"').replace(/&/g, '&'); 261 tmp1 = elEntities.innerHTML; 262 } 263 //this preserves leading spaces 264 var start = t.oEl['start']; 265 while(start < t.oObj.value.length && t.oObj.value.substring(start, start+1) == " ") 266 start++; 267 268 t.oObj.value = t.oObj.value.substring(0, start) + tmp1.replace(/</g, '<').replace(/>/g, '>') + t.oObj.value.substr(t.oEl['end']); 269 TCJsUtils.setCursorPosition(t.oObj, start + tmp1.length); 270 } 271 }; 272 273 t.Init = function() 274 { 275 t.oActive = false; 276 t.oPointer = t.oPointer_default; 277 t.Clear(); 278 t.oPointer_this = 'input_pointer'; 279 }; 280 281 t.Clear = function() 282 { 283 var oEl = t.oDiv.getElementsByTagName("div"); 284 if (oEl.length > 0 && typeof oEl == 'object') 285 { 286 for (var ii in oEl) 287 { 288 if (oEl.hasOwnProperty(ii)) 289 { 290 var oE = oEl[ii]; 291 if (oE && (typeof oE == 'object') && (oE.name == t.oDiv.id + '_div')) 292 { 293 oE.className = "search-popup-row"; 294 } 295 } 296 } 297 } 298 }; 299 300 t.CheckMouse = function() 301 { 302 t.Replace(); 303 t.Destroy(); 304 }; 305 306 t.CheckKeyword = function(e) 307 { 308 if (!e) 309 e = window.event; 310 311 var oP = null; 312 var oEl = null; 313 314 if ((37 < e.keyCode && e.keyCode <41) || (e.keyCode == 13)) 315 { 316 t.Clear(); 317 318 switch (e.keyCode) 319 { 320 case 38: 321 oP = t.oPointer.pop(); 322 if (t.oPointer_this == oP) 323 { 324 t.oPointer.unshift(oP); 325 oP = t.oPointer.pop(); 326 } 327 328 if (oP != 'input_field') 329 { 330 t.oActive = oP; 331 oEl = document.getElementById(oP); 332 if (typeof oEl == 'object') 333 { 334 oEl.className = "search-popup-row-active"; 335 } 336 } 337 t.oPointer.unshift(oP); 338 break; 339 case 40: 340 oP = t.oPointer.shift(); 341 if (t.oPointer_this == oP) 342 { 343 t.oPointer.push(oP); 344 oP = t.oPointer.shift(); 345 } 346 if (oP != 'input_field') 347 { 348 t.oActive = oP; 349 oEl = document.getElementById(oP); 350 if (typeof oEl == 'object') 351 { 352 oEl.className = "search-popup-row-active"; 353 } 354 } 355 t.oPointer.push(oP); 356 break; 357 case 39: 358 t.Replace(); 359 t.Destroy(); 360 break; 361 case 13: 362 t.Replace(); 363 t.Destroy(); 364 break; 365 } 366 t.oPointer_this = oP; 367 } 368 else 369 { 370 t.Destroy(); 371 } 372 }; 373} 374 375var TCJsUtils = 376{ 377 arEvents: [], 378 379 addEvent: function(el, evname, func) 380 { 381 if(el.attachEvent) // IE 382 el.attachEvent("on" + evname, func); 383 else if(el.addEventListener) // Gecko / W3C 384 el.addEventListener(evname, func, false); 385 else 386 el["on" + evname] = func; 387 this.arEvents[this.arEvents.length] = {'element': el, 'event': evname, 'fn': func}; 388 }, 389 390 removeEvent: function(el, evname, func) 391 { 392 if(el.detachEvent) // IE 393 el.detachEvent("on" + evname, func); 394 else if(el.removeEventListener) // Gecko / W3C 395 el.removeEventListener(evname, func, false); 396 else 397 el["on" + evname] = null; 398 }, 399 400 getCursorPosition: function(oObj) 401 { 402 var result = {'start': 0, 'end': 0}; 403 if (!oObj || (typeof oObj != 'object')) 404 return result; 405 try 406 { 407 if (document.selection != null && oObj.selectionStart == null) 408 { 409 oObj.focus(); 410 var oRange = document.selection.createRange(); 411 var oParent = oRange.parentElement(); 412 var sBookmark = oRange.getBookmark(); 413 var sContents = oObj.value; 414 var sContents_ = oObj.value; 415 var sMarker = '__' + Math.random() + '__'; 416 417 while(sContents.indexOf(sMarker) != -1) 418 { 419 sMarker = '__' + Math.random() + '__'; 420 } 421 422 if (!oParent || oParent == null || (oParent.type != "textarea" && oParent.type != "text")) 423 { 424 return result; 425 } 426 427 oRange.text = sMarker + oRange.text + sMarker; 428 sContents = oObj.value; 429 result['start'] = sContents.indexOf(sMarker); 430 sContents = sContents.replace(sMarker, ""); 431 result['end'] = sContents.indexOf(sMarker); 432 oObj.value = sContents_; 433 oRange.moveToBookmark(sBookmark); 434 oRange.select(); 435 return result; 436 } 437 else 438 {
439 return { 440 'start': oObj.selectionStart, 441 'end': oObj.selectionEnd 442 }; 443 } 444 } 445 catch(e){} 446 return result; 447 }, 448 449 setCursorPosition: function(oObj, iPosition) 450 { 451 if (typeof oObj != 'object') 452 return false; 453 454 oObj.focus(); 455 456 try 457 { 458 if (document.selection != null && oObj.selectionStart == null) 459 { 460 var oRange = document.selection.createRange(); 461 oRange.select(); 462 } 463 else 464 { 465 oObj.selectionStart = iPosition; 466 oObj.selectionEnd = iPosition; 467 } 468 return true; 469 } 470 catch(e) 471 { 472 return false; 473 } 474 475 }, 476 477 printArray: function (oObj, sParser, iLevel) 478 { 479 try 480 { 481 var result = ''; 482 var space = ''; 483 484 if (iLevel==undefined) 485 iLevel = 0; 486 if (!sParser) 487 sParser = "\n"; 488 489 for (var j = 0; j <= iLevel; j++) 490 space += ' '; 491 492 for (var i in oObj) 493 { 494 if (oObj.hasOwnProperty(i)) 495 { 496 if (typeof oObj[i] == 'object') 497 result += space+i + " = {"+ sParser + TCJsUtils.printArray(oObj[i], sParser, iLevel+1) + ", " + sParser + "}" + sParser; 498 else 499 result += space+i + " = " + oObj[i] + "; " + sParser; 500 } 501 } 502 503 return result; 504 } 505 catch(e) 506 { 507 } 508 }, 509 510 empty: function(oObj) 511 { 512 var result = true; 513 if (oObj) 514 { 515 for (var i in oObj) 516 { 517 if (oObj.hasOwnProperty(i)) 518 { 519 result = false;
520 break; 521 } 522 } 523 } 524 return result; 525 }, 526 527 show: function(oDiv, iLeft, iTop) 528 { 529 if (typeof oDiv != 'object') 530 return; 531 var zIndex = parseInt(oDiv.style.zIndex); 532 if(zIndex <= 0 || isNaN(zIndex)) 533 zIndex = 100; 534 oDiv.style.zIndex = zIndex; 535 oDiv.style.left = iLeft + "px"; 536 oDiv.style.top = iTop + "px"; 537 538 return oDiv; 539 }, 540 541 hide: function(oDiv) 542 { 543 if(oDiv) 544 oDiv.style.display = 'none'; 545 }, 546 547 GetRealPos: function(el) 548 { 549 if(!el || !el.offsetParent) 550 return false; 551 552 var res = {}; 553 var objParent = el.offsetParent; 554 res["left"] = el.offsetLeft; 555 res["top"] = el.offsetTop; 556 while(objParent && objParent.tagName != "BODY") 557 { 558 res["left"] += objParent.offsetLeft; 559 res["top"] += objParent.offsetTop; 560 objParent = objParent.offsetParent; 561 } 562 res["right"]=res["left"] + el.offsetWidth; 563 res["bottom"]=res["top"] + el.offsetHeight; 564 res["width"]=el.offsetWidth; 565 res["height"]=el.offsetHeight; 566 567 return res; 568 }, 569 570 htmlspecialcharsEx: function(str) 571 { 572 return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); 573 }, 574 575 htmlspecialcharsback: function(str) 576 { 577 return str.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/&/g, '&'); 578 } 579};
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.