1/************ Main control object class ****************/ 2function JCMainLookupSelector(arParams) 3{ 4 var _this = this; 5 6 this.timerId = null; 7 this._currentSearchStr = ''; 8 9 this.LAYOUT = null; 10 this.VALUE_CONTAINER = null; 11 12 this.VISUAL = null; 13 this.SEARCH = null; 14 15 this.__search_current_row = null; 16 17 arParams.VISUAL.CONTROL_ID = arParams.CONTROL_ID; 18 19 this.arParams = { 20 'AJAX_PAGE': arParams.AJAX_PAGE, 21 'CONTROL_ID': arParams.CONTROL_ID, 22 'LAYOUT_ID': arParams.LAYOUT_ID, 23 'INPUT_NAME': arParams.INPUT_NAME, 24 'VISUAL': arParams.VISUAL 25 }; 26 27 this.arParams.PROACTIVE = 'NONE'; 28 if (!!arParams.PROACTIVE) 29 this.arParams.PROACTIVE = arParams.PROACTIVE; 30 this.arParams.PROACTIVE = this.arParams.PROACTIVE.toUpperCase(); 31 32 if (!!arParams.AJAX_PARAMS) 33 { 34 this.arParams.AJAX_PARAMS = arParams.AJAX_PARAMS; 35 } 36 37 if (!!arParams.VALUE) 38 { 39 //this.arParams.VISUAL.START_TEXT = ''; 40 this.arParams.VALUE = arParams.VALUE; 41 } 42 43 if (!!arParams.INPUT_NAME_SUSPICIOUS) 44 { 45 this.INPUT_SUSPICIOUS = null; 46 this.arParams.INPUT_NAME_SUSPICIOUS = arParams.INPUT_NAME_SUSPICIOUS; 47 } 48 49 this.processSearchStr = function() 50 { 51 var url = _this.arParams.AJAX_PAGE+'?MODE=SEARCH'; 52 53 url += '&search=' + encodeURIComponent(_this._currentSearchStr); 54 if (_this.arParams.AJAX_PARAMS) 55 { 56 for(var param_name in _this.arParams.AJAX_PARAMS) 57 url += '&' + param_name + '=' + encodeURIComponent(_this.arParams.AJAX_PARAMS[param_name]); 58 } 59 BX.ajax.get(url, _this.ShowSearchResults); 60 }; 61 62 this.ShowSearchResults = function(data) 63 { 64 if (null != _this.__search_current_row) 65 _this.__search_current_row = null; 66 67 if (null != _this.SEARCH) 68 _this.SEARCH.innerHTML = ''; 69 70 var DATA = []; 71 72 if (BX.type.isNotEmptyString(data)) 73 { 74 var data_test = BX.parseJSON(data); 75 if (data_test) 76 { 77 eval('DATA = ' + data); 78 } 79 else 80 { 81 if ("''" != data) 82 { 83 if ('MESSAGE' == _this.arParams.PROACTIVE || 'BXWINDOW' == _this.arParams.PROACTIVE) 84 { 85 if ('MESSAGE' == _this.arParams.PROACTIVE) 86 { 87 alert(data); // this alert show proactive message 88 } 89 else 90 { 91 var obDialog = new BX.CDialog({ 92 'content': data, 93 'draggable': true, 94 'resizable': false, 95 'buttons': [BX.CDialog.btnClose] 96 }); 97 obDialog.Show(); 98 } 99 100 _this.VISUAL.TEXT.value = _this.VISUAL.TEXT.value.replace(_this._currentSearchStr,''); 101 _this._currentSearchStr = ''; 102 } 103 } 104 } 105 } 106 107 if (DATA.length > 0) 108 { 109 if (DATA.length == 1 && null != DATA[0].READY) 110 { 111 _this.VISUAL.SetTokenData(_this._currentSearchStr, DATA[0], false); 112 return; 113 } 114 115 if (null == _this.SEARCH) 116 { 117 if (!!_this.arParams.VISUAL.SEARCH_POSITION && 'absolute' == _this.arParams.VISUAL.SEARCH_POSITION) 118 { 119 _this.SEARCH = BX.GetDocElement().appendChild(document.createElement('DIV')); 120 _this.SEARCH.className = 'mli-search-results'; 121 _this.SEARCH.style.position = 'absolute'; 122 if (!!_this.arParams.VISUAL.SEARCH_ZINDEX) 123 { 124 _this.arParams.VISUAL.SEARCH_ZINDEX = parseInt(_this.arParams.VISUAL.SEARCH_ZINDEX); 125 if (!isNaN(_this.arParams.VISUAL.SEARCH_ZINDEX) && 0 < _this.arParams.VISUAL.SEARCH_ZINDEX) 126 { 127 _this.SEARCH.style.zIndex = _this.arParams.VISUAL.SEARCH_ZINDEX; 128 } 129 } 130 } 131 else 132 { 133 _this.SEARCH = _this.LAYOUT.appendChild(document.createElement('DIV')); 134 _this.SEARCH.className = 'mli-search-results'; 135 _this.SEARCH.style.position = 'absolute'; 136 } 137 } 138 139 var pos; 140 if (!!_this.arParams.VISUAL.SEARCH_POSITION && 'absolute' == _this.arParams.VISUAL.SEARCH_POSITION) 141 { 142 pos = BX.pos(_this.VISUAL.TEXT, false); 143 } 144 else 145 { 146 pos = BX.pos(_this.VISUAL.TEXT, true); 147 } 148 _this.SEARCH.style.top = pos.bottom + 'px'; 149 _this.SEARCH.style.left = pos.left + 'px'; 150 _this.SEARCH.style.width = (pos.right - pos.left - 2) + 'px'; 151 152 for (var i = 0; i < DATA.length; i++) 153 { 154 var obSearchResult = _this.SEARCH.appendChild(document.createElement('DIV')); 155 obSearchResult.className = 'mli-search-result'; 156 obSearchResult.appendChild(document.createTextNode(DATA[i].NAME + ' [' + DATA[i].ID + ']')); 157 158 obSearchResult.BX_ROW_DATA = DATA[i]; 159 obSearchResult.onclick = _this.__search_result_click; 160 obSearchResult.onmouseover = _this.__search_result_over; 161 BX.bind(obSearchResult, "mousedown", function(event) { 162 event.stopPropagation(); 163 }); 164 } 165 166 _this.SEARCH.style.display = 'block'; 167 } 168 else 169 { 170 _this.__hideSearch(); 171 } 172 }; 173 174 this.__search_result_click = function() 175 { 176 _this.VISUAL.SetTokenData(_this._currentSearchStr, this.BX_ROW_DATA); 177 _this.__hideSearch(); 178 }; 179 180 this.__search_result_over = function() 181 { 182 if (null != _this.__search_current_row) 183 _this.__search_current_row.className = 'mli-search-result'; 184 185 _this.__search_current_row = this; 186 this.className = 'mli-search-result mli-search-current'; 187 }; 188 189 jsUtils.addCustomEvent('onEmpUserSelectorChangeTokenActivity', this.SetTokenInput, null, this); 190 BX.addCustomEvent('onGridClearFilter', BX.delegate(this.ClearValues, this)); 191 BX.ready(function() {_this.Init(); }); 192} 193 194JCMainLookupSelector.prototype.Init = function() 195{ 196 if (!!this.bInit) return; 197 this.bInit = true; 198 199 var _this = this; 200 201 this.LAYOUT = document.getElementById(this.arParams.LAYOUT_ID); 202 this.VISUAL = new JCMainLookupSelectorText(this.arParams.VISUAL); 203 this.VISUAL.parent = this; 204
205 this.VISUAL.onCurrentStringExists = function(str) 206 { 207 if (_this._currentSearchStr == str) 208 { 209 if (null != _this.SEARCH && _this.SEARCH.innerHTML.length > 0) 210 _this.SEARCH.style.display = 'block'; 211 } 212 else 213 { 214 if (null != _this.timerId) 215 clearTimeout(_this.timerId); 216 217 _this._currentSearchStr = str; 218 // timeout moved to keys processing inside the textarea 219 //_this.timerId = setTimeout(_this.processSearchStr, 100); 220 _this.processSearchStr(); 221 } 222 }; 223 224 this.VISUAL.onCurrentStringChange = function() 225 { 226 if (null != _this.timerId) 227 clearTimeout(_this.timerId); 228 229 _this.__hideSearch(); 230 }; 231 232 this.VISUAL.onUnidentifiedTokenFound = function(str) 233 { 234 var url = _this.arParams.AJAX_PAGE+'?MODE=SEARCH'; 235 236 url += '&search=' + encodeURIComponent(str); 237 if (_this.arParams.AJAX_PARAMS) 238 { 239 for(var param_name in _this.arParams.AJAX_PARAMS) 240 url += '&' + param_name + '=' + encodeURIComponent(_this.arParams.AJAX_PARAMS[param_name]); 241 } 242 BX.ajax.get(url, function(data) { 243 if (data.length <= 0) 244 return; 245 246 var DATA = []; 247 eval('DATA = ' + data); 248 if (DATA.length == 1 && DATA[0].READY == 'Y') 249 _this.VISUAL.SetTokenData(str, DATA[0], false); 250 }); 251 }; 252 253 this.VISUAL.onControlKeyPressed = function(keyCode) 254 { 255 if (null != _this.SEARCH && _this.SEARCH.style.display == 'block') 256 { 257 switch (keyCode) 258 { 259 case 27: // escape key - close search div 260 _this.SEARCH.style.display = 'none'; 261 return false; 262 break; 263 264 case 40: // down key - navigate down on search results 265 if (null == _this.__search_current_row) 266 _this.SEARCH.firstChild.onmouseover(); 267 else if (null != _this.__search_current_row.nextSibling) 268 _this.__search_current_row.nextSibling.onmouseover(); 269 return false; 270 break; 271 272 case 38: // up key - navigate up on search results 273 if (null == _this.__search_current_row) 274 _this.SEARCH.lastChild.onmouseover(); 275 else if (null != _this.__search_current_row.previousSibling) 276 _this.__search_current_row.previousSibling.onmouseover(); 277 return false; 278 break; 279 280 case 13: // enter key - choose current search result 281 if (null != _this.__search_current_row) 282 _this.__search_current_row.onclick(); 283 return false; 284 break; 285 } 286 } 287 288 return true; 289 }; 290 291 if (null != this.arParams.INPUT_NAME_SUSPICIOUS) 292 { 293 this.VISUAL.onSuspiciousTokensFound = function(arWords) 294 { 295 if (null == _this.INPUT_SUSPICIOUS) 296 { 297 _this.INPUT_SUSPICIOUS = document.createElement('INPUT'); 298 _this.INPUT_SUSPICIOUS.type = 'hidden'; 299 _this.INPUT_SUSPICIOUS.name = _this.arParams.INPUT_NAME_SUSPICIOUS; 300 301 _this.VALUE_CONTAINER.appendChild(_this.INPUT_SUSPICIOUS); 302 } 303 304 _this.INPUT_SUSPICIOUS.value = arWords.join(';'); 305 }; 306 } 307 308 this.__hideSearch = function() {if (null != _this.SEARCH) _this.SEARCH.style.display = 'none';}; 309 this.__delayedHideSearch = function() {if (null != _this.SEARCH) setTimeout(_this.__hideSearch, 500);}; 310 311 jsUtils.addEvent(this.VISUAL.TEXT, 'blur', this.__delayedHideSearch); 312 313 if (BX('value_container_' + this.arParams['CONTROL_ID'])) 314 this.VALUE_CONTAINER = BX('value_container_' + this.arParams['CONTROL_ID']); 315 else 316 this.VALUE_CONTAINER = this.LAYOUT.appendChild(document.createElement('DIV')); 317 318 this.VALUE_CONTAINER.style.display = 'none'; 319 320 if (null != this.arParams.VALUE) 321 this.SetValue(this.arParams.VALUE); 322}; 323 324// object destructor 325JCMainLookupSelector.prototype.Clear = function() 326{ 327 // remove global event handler 328 jsUtils.removeCustomEvent('onEmpUserSelectorChangeTokenActivity', this.SetTokenInput); 329 330 // clear textarea object internal event handlers 331 this.VISUAL.onCurrentStringChange = null; 332 this.VISUAL.onCurrentStringExists = null; 333 this.VISUAL.onCurrentTokenExists = null; 334 this.VISUAL.onUnidentifiedTokenFound = null; 335 this.VISUAL.onControlKeyPressed = null; 336 this.VISUAL.onSuspiciousTokensFound = null; 337 338 jsUtils.removeEvent(this.VISUAL.TEXT, 'blur', this.__delayedHideSearch); 339 340 // reset and kill textarea processing object 341 this.VISUAL.Reset(false, true); 342 this.VISUAL = null; 343 344 // collect garbage 345 if (null != this.timerId) 346 clearTimeout(this.timerId); 347 348 if (null != this.SEARCH) 349 { 350 this.SEARCH.parentNode.removeChild(this.SEARCH); 351 this.SEARCH = null; 352 } 353 354 this._currentSearchStr = ''; 355 BX.cleanNode(this.LAYOUT, true); 356}; 357 358JCMainLookupSelector.prototype.SetTokenInput = function(arParams, arEventParam
358s) 359{ 360 if (arEventParams.CONTROL_ID != this.arParams.CONTROL_ID) 361 return; 362 363 if (null == this.VALUE_CONTAINER) return; 364 if (null == arEventParams.TOKEN.DATA || null == arEventParams.TOKEN.DATA.ID) return; 365 366 if (null == arEventParams.TOKEN.INPUT) 367 { 368 arEventParams.TOKEN.INPUT = document.createElement('INPUT'); 369 arEventParams.TOKEN.INPUT.type = 'hidden'; 370 arEventParams.TOKEN.INPUT.name = this.arParams.INPUT_NAME + '[]'; 371 arEventParams.TOKEN.INPUT.value = arEventParams.TOKEN.DATA.ID; 372 } 373 374 if (arEventParams.TOKEN.ACTIVE && null == arEventParams.TOKEN.INPUT.parentNode) 375 { 376 this.AddInput(arEventParams.TOKEN.INPUT); 377 jsUtils.onCustomEvent('onLookupInputChange', {'CONTROL_ID': this.arParams.CONTROL_ID, 'ACTION': 'add', 'DATA': arEventParams.TOKEN.DATA}); 378 } 379 else if (!arEventParams.TOKEN.ACTIVE && null != arEventParams.TOKEN.INPUT.parentNode) 380 { 381 this.DeleteInput(arEventParams.TOKEN.INPUT); 382 jsUtils.onCustomEvent('onLookupInputChange', {'CONTROL_ID': this.arParams.CONTROL_ID, 'ACTION': 'remove', 'DATA': arEventParams.TOKEN.DATA}); 383 } 384}; 385 386 387JCMainLookupSelector.prototype.AddValue = function(arValue) 388{ 389 if (typeof arValue != 'object' || null == arValue.length || null == arValue[0]) 390 arValue = [arValue]; 391 392 var _this = this; 393 for (var i = 0; i < arValue.length; i++) 394 { 395 if (typeof arValue[i] == 'object') 396 { 397 if (null != arValue[i].ID && null != arValue[i].NAME) 398 { 399 this.VISUAL.AddTokenData(arValue[i], false); 400 } 401 } 402 else 403 { 404 var val = parseInt(arValue[i]); 405 if (!isNaN(val)) 406 { 407 var str = 'q <q@q> [' + val + ']'; // hack 408 var url = this.arParams.AJAX_PAGE+'?MODE=SEARCH'; 409 410 url += '&search=' + encodeURIComponent(str); 411 if (this.arParams.AJAX_PARAMS) 412 { 413 for(var param_name in this.arParams.AJAX_PARAMS) 414 url += '&' + param_name + '=' + encodeURIComponent(this.arParams.AJAX_PARAMS[param_name]); 415 } 416 BX.ajax.get(url, function(data) { 417 if (data.length <= 0) 418 return; 419 420 var DATA = []; 421 eval('DATA = ' + data); 422 if (DATA.length == 1 && DATA[0].READY == 'Y') 423 { 424 _this.VISUAL.AddTokenData(DATA[0], false); 425 } 426 }); 427 } 428 } 429 } 430}; 431 432JCMainLookupSelector.prototype.SetValue = function(arValue) 433{ 434 this.VISUAL.Reset(true, false); 435 this.ClearValues(); 436 this.AddValue(arValue); 437}; 438 439JCMainLookupSelector.prototype.ClearValues = function() 440{ 441 if (this.VALUE_CONTAINER && this.VALUE_CONTAINER.childNodes) 442 { 443 var children = this.VALUE_CONTAINER.childNodes; 444 for (var i = 0; i < children.length; i++) 445 { 446 var child = children[i]; 447 child.value = ''; 448 } 449 this.CleanUpValues(); 450 } 451}; 452 453JCMainLookupSelector.prototype.AddInput = function(input) 454{ 455 if (this.VALUE_CONTAINER) 456 { 457 this.VALUE_CONTAINER.appendChild(input); 458 this.CleanUpValues(); 459 } 460}; 461 462JCMainLookupSelector.prototype.DeleteInput = function(input) 463{ 464 if (this.VALUE_CONTAINER) 465 { 466 input.value = ''; 467 this.CleanUpValues(); 468 } 469}; 470 471JCMainLookupSelector.prototype.CleanUpValues = function(input) 472{ 473 if (this.VALUE_CONTAINER && this.VALUE_CONTAINER.childNodes) 474 { 475 var i; 476 var found = false; 477 var children = this.VALUE_CONTAINER.childNodes; 478 for (i = 0; i < children.length; i++) 479 { 480 var child = children[i]; 481 if (child.value.length > 0) 482 found++; 483 } 484 485 i = 0; 486 while (i < children.length) 487 { 488 var child = children[i]; 489 if (child.value.length == 0) 490 { 491 if (found > 0) 492 { 493 this.VALUE_CONTAINER.removeChild(child); 494 } 495 else 496 { 497 i++; 498 found++; 499 } 500 } 501 else 502 { 503 i++; 504 } 505 } 506 } 507}; 508 509/**************** Visual textarea **********************/ 510function JCMainLookupSelectorText(arParams) 511{ 512 var _this = this; 513 514 this.__split_reg = /([,;\n])/; 515 this.__check_reg = /^(.*?) \[\d+\]/m; 516 this.__check_suspicious = [/^[a-z0-9.\-_]+@[a-z0-9.\-]+$/i, /^(.*?)<[a-z0-9.\-_]+@[a-z0-9.\-]+>$/i, /^(.*?)\[[a-z0-9.\-_]+@[a-z0-9.\-]+\]$/i]; 517 518 this.arParams = arParams; 519 520 this.__token_index = 0; 521 522 this.previousCurrentHash = ''; 523 this.previousCurrentIndex = -1; 524 525 this.timerId = null; 526 527 this.isMainUiFilter = (this.arParams['MAIN_UI_FILTER'] === 'Y'); 528 this.isMultiple = (this.arParams['MULTIPLE'] === 'Y'); 529 530 this.TEXT = document.getElementById(this.arParams.ID); 531 this.TEXT.bx_last_position = 0; 532 this.TEXT.bx_focused = false;
533 534 this.TEXT.style.width = '95%'; 535 if (this.arParams.MAX_WIDTH) this.TEXT.style.width = this.arParams.MAX_WIDTH + 'px'; 536 if(this.TEXT.type.toLowerCase() == "textarea") 537 this.TEXT.style.height = this.arParams.MIN_HEIGHT + 'px'; 538 539 this.__text_focus = function() 540 { 541 _this.TEXT.bx_focused = true; 542 if (_this.TEXT.value == _this.arParams.START_TEXT) 543 { 544 _this.TEXT.value = ''; 545 } 546 }; 547 this.__text_blur = function() 548 { 549 _this.TEXT.bx_focused = false; 550 if (_this.TEXT.value == '') 551 { 552 _this.TEXT.value = _this.arParams.START_TEXT; 553 } 554 }; 555 this.__text_additional_check = function() 556 { 557 _this.TEXT.bx_focused = false; 558 _this.__process(); 559 }; 560 561 if (this.TEXT.value == '') 562 { 563 this.TEXT.value = this.arParams.START_TEXT; 564 } 565 566 jsUtils.addEvent(this.TEXT, 'focus', this.__text_focus); 567 jsUtils.addEvent(this.TEXT, 'blur', this.__text_blur); 568 jsUtils.addEvent(this.TEXT, 'blur', this.__text_additional_check); 569 570 if (null != this.TEXT.form) 571 { 572 jsUtils.addEvent(this.TEXT.form, 'submit', this.__text_focus); 573 } 574 575 this.arTokens = []; 576 this.arTokensMap = {}; 577 578 /*** internal event handlers ****/ 579 this.onCurrentStringExists = null; // caret in textarea is on the unidentified string 580 this.onCurrentStringChange = null; // caret in textarea changes to unidentified string 581 this.onCurrentTokenExists = null; // caret in textarea is on the identified token 582 this.onUnidentifiedTokenFound = null; // found a string in required format, which hasn't a token object 583 this.onControlKeyPressed = null; // arrow or escape key was pressed while textarea editing; return false to prevent default key action 584 this.onSuspiciousTokensFound = null; // found some suspicious tokens found. array of them is passing as parameter (empty one if none found) 585 586 /*** tokens parsing ****/ 587 this.__ignore_key = false; 588 589 this.__pre_process = function() {_this.__process(); }; 590 591 this.TEXT.onkeydown = function(e) 592 { 593 if (null == e) e = window.event; 594 595 if (null != _this.onControlKeyPressed && ((e.keyCode >= 37 && e.keyCode <= 40) || e.keyCode == 27 || e.keyCode == 13)) 596 { 597 if (!_this.onControlKeyPressed(e.keyCode)) 598 { 599 _this.__ignore_key = true; 600 return jsUtils.PreventDefault(e); 601 } 602 } 603 604 }; 605 606 this.TEXT.onclick = this.TEXT.onkeyup = function(e) { 607 if (null == e) e = window.event; 608 609 if (e.type == 'keyup' && e.keyCode >= 16 && e.keyCode <= 18) // shift, alt & ctrl keys for avoing of event doubling while copy-pasting 610 return; 611 612 if (e.type == 'keyup' && _this.__ignore_key) 613 { 614 _this.__ignore_key = false; 615 return false; 616 } 617 618 if (null != _this.timerId) 619 clearTimeout(_this.timerId); 620 621 _this.timerId = setTimeout(_this.__pre_process, 500); 622 }; 623 624 if (this.TEXT.value.length > 0) 625 { 626 this.timerId = setTimeout(this.__pre_process, 200); 627 } 628 629 _this.AdjustHeight(); 630} 631 632 633//This function splits string with respect to __check_reg pattern 634JCMainLookupSelectorText.prototype.__split = function (str, separator, limit) { 635 636 if (Object.prototype.toString.call(separator) !== "[object RegExp]") { 637 return str.split(separator, limit); 638 } 639 640 var _compliantExecNpcg = /()??/.exec("")[1] === undefined; 641 642 var output = []; 643 var lastLastIndex = 0; 644 var flags = (separator.ignoreCase ? "i" : "") + (separator.multiline ? "m" : "") + (separator.sticky ? "y" : ""); 645 separator = RegExp(separator.source, flags + "g"); 646 var separator2, match, lastIndex, lastLength; 647 648 str = str + ""; // type conversion 649 if (!_compliantExecNpcg) 650 separator2 = RegExp("^" + separator.source + "$(?!\\s)", flags); // doesn't need /g or /y, but they don't hurt 651 652 /* behavior for `limit`: if it's... 653 - `undefined`: no limit. 654 - `NaN` or zero: return an empty array. 655 - a positive number: use `Math.floor(limit)`. 656 - a negative number: no limit. 657 - other: type-convert, then use the above rules. */ 658 if (limit === undefined || +limit < 0) 659 { 660 limit = Infinity; 661 } 662 else 663 { 664 limit = Math.floor(+limit); 665 if (!limit) 666 return []; 667 } 668 669 while (match = separator.exec(str)) 670 { 671 lastIndex = match.index + match[0].length; // `separator.lastIndex` is not reliable cross-browser 672 673 if (lastIndex > lastLastIndex) 674 { 675 output.push(str.slice(lastLastIndex, match.index)); 676 677 // fix browsers whose `exec` methods don't consistently return `undefined` for nonparticipating capturing groups 678 if (!_compliantExecNpcg && match.length > 1) 679 { 680 match[0].replace(separator2, function () { 681 for (var i = 1; i < arguments.length - 2; i++) 682 if (arguments[i] === undefined) 683 match[i] = undefined; 684 }); 685 } 686 687 if (match.length > 1 && match.index < str.length) 688 Array.prototype.push.apply(output, match.slice(1)); 689 690 lastLength = match[0].length; 691 lastLastIndex = lastIndex; 692 693 if (output.length >= limit) 694 break; 695 696 } 697 698 if (separator.lastIndex === match.index) 699 separator.lastIndex++; // avoid an infinite loop 700 } 701 702 if (lastLastIndex === str.length) 703 { 704 if (lastLength || !separator.test("")) 705 { 706 output.push(""); 707 } 708 } 709 else 710 { 711 output.push(str.slice(lastLastIndex)); 712 } 713 714 return output.length > limit ? output.slice(0, limit) : output; 715}; 716 717//This function splits string with respect to __check_reg pattern 718JCMainLookupSelectorText.prototype.__parse = function(str, split_reg, check_reg, arTokens, newStr) 719{ 720 var arResult = []; 721 722 var arToks = []; 723 var tok = ''; 724 725 if(arTokens && arTokens.length > 0) 726 { 727 for(var j = 0; j < arTokens.length; j++) 728 { 729 if(arTokens[j]) 730 { 731 tok = jsUtils.trim(arTokens[j].TOKEN); 732 if(tok.length) 733 { 734 arToks[arToks.length] = tok; 735 var start = -1; 736 while( (start = str.indexOf(tok, start+1)) > -1 ) 737 { 738 arResult[arResult.length] = { 739 'start' : start, 740 'end' : start + tok.length, 741 'tok' : tok, 742 'trimmed': jsUtils.trim(tok), 743 'delim' : '' 744 }; 745 } 746 } 747 } 748 } 749 } 750 if(newStr && newStr.length > 0) 751 { 752 tok = jsUtils.trim(newStr); 753 if(tok.length) 754 { 755 arToks[arToks.length] = tok; 756 start = -1; 757 while( (start = str.indexOf(tok, start+1)) > -1 ) 758 { 759 var found = false;
760 for(var i =0; i < arResult.length; i++) 761 { 762 if(start >= arResult[i].start && start < arResult[i].end) 763 { 764 start = arResult[i].end; 765 found = true; 766 break; 767 } 768 } 769 770 if(!found) 771 { 772 arResult[arResult.length] = { 773 'start' : start, 774 'end' : start + tok.length, 775 'tok' : tok, 776 'trimmed': jsUtils.trim(tok), 777 'delim' : '' 778 }; 779 break; 780 } 781 } 782 } 783 } 784 785 var arTmp = this.__split(str, split_reg); 786 787 tok = ''; 788 var delim = ''; 789 var cur_pos = 0; 790 for(i = 0; i < arTmp.length; i++) 791 { 792 tok = arTmp[i]; 793 794 i++; 795 if(i < arTmp.length) 796 delim = arTmp[i]; 797 else 798 delim = ''; 799 800 var skip = false; 801 if(tok.length) 802 { 803 for(var ii = 0; ii < arResult.length && !skip; ii++) 804 { 805 if ( cur_pos >= arResult[ii].start && cur_pos < arResult[ii].end ) 806 { 807 arResult[ii].delim = delim; 808 skip = true; 809 } 810 } 811 //if ( cur_pos >= strNew_start && cur_pos < strNew_end ) 812 // skip = true; 813 } 814 815 if(tok.length && !skip) 816 { 817 //Additional check if this is string followed known token 818 if(check_reg.test(tok) && arToks.length > 0) 819 { 820 for(j = 0; j < arToks.length; j++) 821 { 822 if( 823 tok.length > arToks[j].length 824 && arToks[j] == tok.substr(tok.length - arToks[j].length) 825 ) 826 { 827 828 var pre_tok = tok.substr(0, tok.length - arToks[j].length); 829 tok = tok.substr(pre_tok.length); 830 831 while(pre_tok && pre_tok.length > 0 && pre_tok.substr(0, 1) == ' ') 832 { 833 cur_pos++; 834 pre_tok = pre_tok.substr(1); 835 } 836 837 if(pre_tok && pre_tok.length > 0) 838 { 839 arResult[arResult.length] = { 840 'start' : cur_pos, 841 'end' : cur_pos + pre_tok.length, 842 'tok' : pre_tok, 843 'trimmed': jsUtils.trim(pre_tok), 844 'delim' : '' 845 }; 846 cur_pos += pre_tok.length; 847 } 848 } 849 } 850 } 851 852 while(tok.length && tok.substr(0, 1) == ' ') 853 { 854 cur_pos++; 855 tok = tok.substr(1); 856 } 857 arResult[arResult.length] = { 858 'start' : cur_pos, 859 'end' : cur_pos + tok.length, 860 'tok' : tok, 861 'trimmed': jsUtils.trim(tok), 862 'delim' : delim 863 }; 864 } 865 866 cur_pos += tok.length + delim.length; 867 } 868 869// if(tok.length) 870// arResult[arResult.length] = { 871// 'start' : cur_pos, 872// 'end' : cur_pos + tok.length, 873// 'tok' : tok, 874// 'delim' : '' 875// }; 876 877 return arResult; 878}; 879 880JCMainLookupSelectorText.prototype.__process = function() 881{ 882 this.__current_token = null; 883 884 if ( 885 ( 886 this.arParams.START_TEXT.length > 0 887 && this.TEXT.value == this.arParams.START_TEXT 888 ) || ( 889 this.TEXT.value == '' 890 ) 891 ) 892 { 893 this.parent.ClearValues(); 894 return; 895 } 896 897 var arToks = this.__parse(this.TEXT.value, this.__split_reg, this.__check_reg, this.arTokens); 898 899 var cur_pos = this.GetCursorPos(); 900 var bCurrent; 901 902 var arSuspiciousTokens = []; 903 904 for (var i = 0; i < arToks.length; i++) 905 { 906 bCurrent = (cur_pos > arToks[i].start && cur_pos <= arToks[i].end); 907 908 var str = jsUtils.trim(arToks[i].tok); 909 if (str.length > 0) 910 { 911 if (null != this.onUnidentifiedTokenFound && this.__check_reg.test(str)) 912 { 913 if (null == this.arTokensMap[this.GetHash(str)]) 914 this.onUnidentifiedTokenFound(str); 915 } 916 else 917 { 918 if (bCurrent) 919 { 920 var currentHash = this.GetHash(str); 921 var currentIndex = i; 922 923 if ( 924 null != this.arTokensMap[this.previousCurrentHash] 925 && currentHash != this.previousCurrentHash 926 && currentIndex == this.previousCurrentIndex 927 ) 928 this.arTokensMap[this.previousCurrentHash] = null; 929 930 /**** external events block *****/ 931 if ( 932 null != this.onCurrentStringChange 933 && null != this.previousCurrentIndex 934 && this.previousCurrentIndex != currentIndex 935 ) 936 this.onCurrentStringChange(); 937 938 939 if ( 940 null != this.onCurrentStringExists 941 && null == this.arTokensMap[currentHash] 942 ) 943 this.onCurrentStringExists(str); 944 945 if ( 946 null != this.onCurrentTokenExists 947 && null != this.arTokensMap[currentHash] 948 ) 949 this.onCurrentTokenExists(this.arTokensMap[currentHash]); 950 951 this.previousCurrentHash = currentHash; 952 this.previousCurrentIndex = currentIndex; 953 } 954 955 if (null != this.onSuspiciousTokensFound) 956 { 957 for (var j = 0; j < this.__check_suspicious.length; j++) 958 { 959 if (this.__check_suspicious[j].test(str)) 960 { 961 arSuspiciousTokens[arSuspiciousTokens.length] = str; 962 break; 963 } 964 } 965 } 966 } 967 } 968 } 969 970 if (null != this.onSuspiciousTokensFound) 971 this.onSuspiciousTokensFound(arSuspiciousTokens); 972 973 this.CheckTokens(arToks); 974 this.AdjustHeight(); 975}; 976 977JCMainLookupSelectorText.prototype.Reset = function(bClearText, bClearEvents) 978{ 979 if (null == bClearText) bClearEvents = false;
980 if (null == bClearEvents) bClearEvents = false; 981 982 for (var i = 0; i < this.arTokens.length; i++) 983 { 984 if (null == this.arTokens[i]) 985 continue; 986 this.arTokensMap[this.arTokens[i].TEXT_HASH] = null; 987 this.arTokens[i] = null; 988 } 989 990 this.arTokens = []; 991 this.arTokensMap = {}; 992 993 this.__token_index = 0; 994 995 this.previousCurrentHash = ''; 996 this.previousCurrentIndex = -1; 997 998 if (bClearText) 999 { 1000 this.TEXT.value = this.arParams.START_TEXT; 1001 } 1002 1003 if (bClearEvents) 1004 { 1005 this.TEXT.onkeydown = this.TEXT.onkeyup = this.TEXT.onclick = null; 1006 jsUtils.removeEvent(this.TEXT, 'focus', this.__text_focus); 1007 jsUtils.removeEvent(this.TEXT, 'blur', this.__text_blur); 1008 jsUtils.removeEvent(this.TEXT, 'blur', this.__text_additional_check); 1009 if (null != this.TEXT.form) 1010 jsUtils.removeEvent(this.TEXT.form, 'submit', this.__text_focus); 1011 1012 } 1013}; 1014 1015JCMainLookupSelectorText.prototype.CheckTokens = function(arToks) 1016{ 1017 if (!arToks) 1018 { 1019 arToks = this.__parse(this.TEXT.value, this.__split_reg, this.__check_reg, this.arTokens); 1020 } 1021 1022 var index = []; 1023 for (var j = 0; j < arToks.length; j++) 1024 { 1025 if (arToks[j].trimmed.length <= 0) 1026 continue; 1027 if (index[arToks[j].trimmed] !== undefined) 1028 continue; 1029 index[arToks[j].trimmed] = j; 1030 } 1031 1032 for (var i = 0; i < this.arTokens.length; i++) 1033 { 1034 if (null == this.arTokens[i]) 1035 continue; 1036 1037 var tok = jsUtils.trim(this.arTokens[i].TOKEN); 1038 1039 this.arTokens[i].SetActive(index[tok] !== undefined); 1040 } 1041}; 1042 1043JCMainLookupSelectorText.prototype.AdjustHeight = function() 1044{ 1045 if (this.TEXT.scrollHeight > this.TEXT.clientHeight) 1046 { 1047 var dy = this.TEXT.offsetHeight - this.TEXT.clientHeight; 1048 var newHeight = this.TEXT.scrollHeight + dy; 1049 1050 if (newHeight > this.arParams.MAX_HEIGHT) 1051 newHeight = this.arParams.MAX_HEIGHT; 1052 1053 if(this.TEXT.type.toLowerCase() == "textarea") 1054 this.TEXT.style.height = newHeight + 'px'; 1055 } 1056}; 1057 1058JCMainLookupSelectorText.prototype.AddTokenData = function(data, bSelect) 1059{ 1060 if (this.TEXT.value == this.arParams.START_TEXT) 1061 this.TEXT.value = ''; 1062 1063 // IE bug: focus on hidden input 1064 //try{this.TEXT.focus();}catch(e){}; 1065 var scrollTop = this.TEXT.scrollTop; 1066 1067 if(this.TEXT.type.toLowerCase() == "textarea") 1068 { 1069 var str = jsUtils.trim(data.NAME + ' [' + data.ID + ']'); 1070 if(this.TEXT.value.indexOf(str) < 0) 1071 { 1072 if (this.TEXT.value.length > 0 && this.TEXT.value.substr(this.TEXT.value.length-1, 1) != "\n") 1073 this.TEXT.value += "\n"; 1074 1075 this.TEXT.value += str + "\n"; 1076 this.TEXT.scrollTop = scrollTop; 1077 this.SetTokenData(str, data, bSelect); 1078 } 1079 } 1080 else 1081 { 1082 str = jsUtils.trim(data.NAME + ' [' + data.ID + ']'); 1083 if (this.isMultiple && this.isMainUiFilter) 1084 { 1085 if(this.TEXT.value.indexOf(str) < 0) 1086 { 1087 this.TEXT.value += str + "\u00A0"; 1088 this.SetTokenData(str, data, bSelect); 1089 } 1090 } 1091 else 1092 { 1093 if(this.TEXT.value.indexOf(str) < 0) 1094 { 1095 this.TEXT.value = str; 1096 this.SetTokenData(str, data, bSelect); 1097 } 1098 } 1099 } 1100 1101}; 1102 1103JCMainLookupSelectorText.prototype.SetTokenData = function(str, data, bSelect) 1104{ 1105 if (null == bSelect) bSelect = true; 1106 1107 var arToks = this.__parse(this.TEXT.value, this.__split_reg, this.__check_reg, this.arTokens, str); 1108 1109 var delim = ''; 1110 for (var i = 0; i < arToks.length; i++) 1111 { 1112 if(delim == '')//take first delim 1113 delim = arToks[i].delim; 1114 if(delim.length) 1115 break; 1116 } 1117 if(delim == '')//fall to default 1118 delim = "\n"; 1119 1120 for (i = 0; i < arToks.length; i++) 1121 { 1122 var s = jsUtils.trim(arToks[i].tok); 1123 1124 if (s.length <= 0) 1125 continue; 1126 1127 if (str == s) 1128 { 1129 var newText = jsUtils.trim(data.NAME + ' [' + data.ID + ']'); 1130 1131 //delimiter is needed only at the end of input 1132 //at when replaced text has no delimiter just before next token 1133 var actual_delim = ''; 1134 if(i == arToks.length || arToks[i].delim == '') 1135 actual_delim = delim; 1136 1137 // IE bug: focus on hidden input 1138 //try{this.TEXT.focus();}catch(e){}; 1139 1140 var scrollTop = this.TEXT.scrollTop; 1141 1142 var prefix = this.TEXT.value.substr(0, arToks[i].start); 1143 var posfix = this.TEXT.value.substr(arToks[i].end); 1144 1145 this.TEXT.value = prefix + newText + actual_delim + posfix; 1146 1147 this.TEXT.scrollTop = scrollTop; 1148 1149 var obToken = new JCMainLookupSelectorToken({ 1150 'CONTROL_ID': this.arParams.CONTROL_ID, 1151 'TOKEN': newText, 1152 'INDEX': this.__token_index++, 1153 'START': arToks[i].start, 1154 'FINISH': arToks[i].start + newText.length + actual_delim.length, 1155 'ACTIVE': true, 1156 'DATA': data 1157 }); 1158 1159 if (null != this.arTokensMap[obToken.TEXT_HASH]) 1160 this.arTokens[this.arTokensMap[obToken.TEXT_HASH].INDEX] = null; 1161 1162 var change = newText.length + actual_delim.length - arToks[i].tok.length; 1163 this.AdjustTokensPos(arToks[i].end, change); 1164 1165 this.arTokensMap[obToken.TEXT_HASH] = this.arTokens[obToken.INDEX] = obToken; 1166 1167 if (bSelect) 1168 this.SetCursorPos(obToken.FINISH); 1169 1170 if (null != this.onCurrentTokenExists)
1171 this.onCurrentStringExists(obToken); 1172 1173 this.AdjustHeight(); 1174 this.__pre_process(); 1175 return; 1176 } 1177 } 1178 1179 this.AddTokenData(data, bSelect); 1180}; 1181 1182JCMainLookupSelectorText.prototype.AdjustTokensPos = function(start_pos, change) 1183{ 1184 for (var i = 0; i < this.arTokens.length; i++) 1185 { 1186 if (null != this.arTokens[i] && this.arTokens[i].ACTIVE && this.arTokens[i].START >= start_pos) 1187 { 1188 this.arTokens[i].START += change; 1189 this.arTokens[i].FINISH += change; 1190 } 1191 } 1192}; 1193 1194JCMainLookupSelectorText.prototype.SetCursorPos = function(pos) 1195{ 1196 if (null != this.TEXT.selectionStart)// Gecko 1197 this.TEXT.setSelectionRange(pos, pos); 1198 else if (document.selection)//IE 1199 { 1200 try { 1201 var r = this.TEXT.createTextRange(); 1202 r.collapse(true); 1203 r.moveEnd('character', pos); 1204 r.moveStart('character', pos); 1205 r.select(); 1206 } catch (e) {} 1207 } 1208}; 1209 1210JCMainLookupSelectorText.prototype.GetCursorPos = function() 1211{ 1212 try { 1213 if (null != this.TEXT.selectionStart)// Gecko 1214 return this.TEXT.selectionStart; 1215 else if (document.selection && this.TEXT.bx_focused)//IE 1216 { 1217 if(this.TEXT.type.toLowerCase() == "textarea") 1218 { 1219 var sel = document.selection.createRange(); 1220 var clone = sel.duplicate(); 1221 clone.moveToElementText(this.TEXT); 1222 clone.setEndPoint('EndToEnd', sel); 1223 this.TEXT.bx_last_position = clone.text.length; 1224 } 1225 else 1226 this.TEXT.bx_last_position = 1; 1227 } 1228 1229 return this.TEXT.bx_last_position; 1230 } catch (e) {return 0; } 1231}; 1232 1233JCMainLookupSelectorText.prototype.GetHash = function(text) 1234{ 1235 var hash = ''; 1236 for (var i = 0; i < text.length; i++) 1237 { 1238 hash += text.charCodeAt(i).toString(16); 1239 } 1240 return hash; 1241}; 1242 1243/**************** Visual textarea token ******************/ 1244function JCMainLookupSelectorToken(arParams) 1245{ 1246 var _this = this; 1247 1248 this.CONTROL_ID = arParams.CONTROL_ID; 1249 1250 this.TOKEN = arParams.TOKEN; 1251 this.INDEX = arParams.INDEX; 1252 this.START = arParams.START; 1253 this.FINISH = arParams.FINISH; 1254 1255 this.DATA = arParams.DATA; 1256
1257 this.SetActive(null == arParams.ACTIVE ? false : arParams.ACTIVE); 1258 1259 this.HASH = this.GetHash(this.INDEX + '$$' + jsUtils.trim(this.TOKEN)); 1260 this.TEXT_HASH = this.GetHash(jsUtils.trim(this.TOKEN)); 1261} 1262 1263JCMainLookupSelectorToken.prototype.SetActive = function(flag) 1264{ 1265 this.ACTIVE = !!flag; 1266 jsUtils.onCustomEvent('onEmpUserSelectorChangeTokenActivity', {'CONTROL_ID': this.CONTROL_ID, 'TOKEN': this}); 1267}; 1268 1269JCMainLookupSelectorToken.prototype.SetPos = function(start, finish) 1270{ 1271 if (null == finish) finish = start+this.TOKEN.length; 1272 1273 this.START = start; this.FINISH = finish; 1274}; 1275 1276JCMainLookupSelectorToken.prototype.GetHash = JCMainLookupSelectorText.prototype.GetHash; 1277
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.