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