PageSourceSearch

https://akb98.ru/bitrix/js/ui/dropdown/dropdown.js?173801063626951

js akb98.ru collected 2026-09-28 13:38:37 UTC 26,951 bytes, 1,072 lines download raw bytes

1(function() {
2
3	"use strict";
4
5	BX.namespace("BX.UI");
6
7	/**
8	 *
9	 * @param {object} options
10	 * @param {Element} options.targetElement
11	 * @param {Element} options.inputElement
12	 * @param {Array} options.items
13	 * @param {String} [options.ajaxUrl]
14	 * @param {object} [options.events<string, function>]
15	 * @constructor
16	 */
17	BX.UI.Dropdown = function(options)
18	{
19		this.popupWindow = null;
20		this.items = [];
21		this.defaultItems = [];
22		this.itemsContainer = null;
23		this.popupConatiner = null;
24		this.footerItems = null;
25		this.targetElement = options.targetElement;
26		this.CurrentItem = null;
27
28		this.id = BX.prop.getString(options, "id", BX.Text.getRandom());
29		this.searchAction = BX.prop.getString(options, "searchAction", "");
30		this.searchOptions = BX.prop.getObject(options, "searchOptions", {});
31		this.previousSearchQuery = null;
32		this.isLastSearchComplete = null;
33
34		this.messages = BX.prop.getObject(options, "messages", {});
35
36		this.isChanged = false;
37		this.isDisabled = BX.prop.getBoolean(options, "isDisabled", false);
38		this.enableCreation = BX.prop.getBoolean(options, "enableCreation", false);
39		this.enableCreationOnBlur = BX.prop.getBoolean(options, "enableCreationOnBlur", true);
40
41		this.isEmbedded = BX.prop.getBoolean(BX.prop.getObject(options, "context", {}), "isEmbedded", false);
42		this.quickForm = document.querySelectorAll('.crm-kanban-quick-form');
43
44		this.ajaxRequestTimer = null;
45		this.autocompleteDelay = BX.prop.getInteger(options, "autocompleteDelay", 0);
46		this.minSearchStringLength = BX.prop.getInteger(options, "minSearchStringLength", 2);
47
48		this.documentClickHandler = BX.delegate(this.onDocumentClick, this);
49
50		this.emptyValueEventHandle = 0;
51
52		this.events = options.events || {};
53		this.bindEvents();
54
55		this.updateItemsList(options.items);
56		this.setDefaultItems(options.items);
57		this.setFooterItems(options.footerItems);
58
59		if (this.targetElement !== 'undefined' && (typeof this.targetElement !== 'undefined'))
60		{
61			this.init();
62		}
63	};
64	BX.UI.Dropdown.prototype =
65		{
66			bindEvents: function()
67			{
68				if (this.events)
69				{
70					for (var eventName in this.events)
71					{
72						if (BX.type.isFunction(this.events[eventName]))
73						{
74							BX.addCustomEvent(this, "BX.UI.Dropdown:" + eventName, this.events[eventName]);
75						}
76					}
77				}
78			},
79			init: function ()
80			{
81				setTimeout(function() {
82					BX.bind(this.targetElement, "input", function()
83					{
84						if (this.isDisabled)
85						{
86							return;
87						}
88
89						if (this.targetElement.value.length === 0)
90						{
91							this.enableTargetElement();
92							return;
93						}
94
95						this.showPopupWindow();
96
97					}.bind(this));
98				}.bind(this), 100);
99
100				this.targetElement.addEventListener("click", function(e)
101				{
102					this.destroyPopupWindow();
103
104                    if (this.isDisabled)
105                    {
106                        return;
107                    }
108
109					if(this.CurrentItem && this.CurrentItem.title.length === this.targetElement.value.length)
110					{
111						this.disableTargetElement();
112					}
113
114					else if(this.targetElement.value.length > 0)
115					{
116						this.disableTargetElement();
117					}
118
119					if(this.popupWindow)
120					{
121						BX.PreventDefault(e);
122					}
123					this.showPopupWindow();
124				}.bind(this), true);
125
126				setTimeout(function() {
127					this.targetElement.addEventListener("focus", function()
128					{
129						if (this.isDisabled)
130						{
131							return;
132						}
133
134						this.showPopupWindow();
135
136						if(!this.popupAlertContainer)
137						{
138							return;
139						}
140					}.bind(this), true);
141				}.bind(this), 100);
142
143				BX.bind(
144					this.targetElement,
145					"keyup",
146					BX.throttle(
147						function(e) {
148                            if (this.isDisabled)
149                            {
150                                return;
151                            }
152
153							if (this.targetElement.value === '')
154							{
155								return;
156							}
157
158							if (e.key === "Escape")
159							{
160                                if (this.isDisabled)
161                                {
162                                    return;
163                                }
164
165								if (this.targetElement.value !== '' && !this.popupWindow)
166								{
167									this.showPopupWindow();
168								}
169								else {
170									BX.PreventDefault(e);
171								}
172							}
173						}.bind(this),
174						1000
175					)
176				);
177
178				this.targetElement.addEventListener("keyup", function(e)
179				{
180                    if (this.isDisabled)
181                    {
182                        return;
183                    }
184
185					if (e.keyCode === 40)
186					{
187						this.handleDownArrow();
188					}
189					else if (e.keyCode === 38)
190					{
191						this.handleUpArrow();
192					}
193					else if (e.keyCode === 13)
194					{
195						if (this.highlightedItem)
196						{
197							this.handleItemClick(this.highlightedItem);
198							this.getPopupWindow().close();
199						}
200
201						if (this.highlightedItem && this.CurrentItem === this.popupAlertContainer)
202						{
203                            this.onEmptyValueEvent();
204                            return;
205						}
206
207                        if ((this.CurrentItem && this.CurrentItem.title.length !== this.targetElement.value.length)
208                            || (!this.CurrentItem && this.targetElement.value.length > 0))
209                        {
210                            this.onEmptyValueEvent();
211                            return;
212                        }
213
214                        if (this.popupWindow && this.enableCreation)
215                        {
216                            this.destroyPopupWindow();
217                        }
218					}
219					else
220					{
221						this.handleTypeInField();
222					}
223
224					if(this.targetElement.value !== '' && !this.popupWindow)
225					{
226						this.showPopupWindow();
227						return;
228					}
229
230					if(e.keyCode === 9 && !this.popupWindow)
231					{
232						this.showPopupWindow();
233						return;
234					}
235
236					if(e.keyCode === 9 && this.targetElement.value === '' && !this.popupWindow)
237					{
238						this.showPopupWindow();
239					}
240
241					if(!this.enableCreation) {
242						this.targetElement.addEventListener("keyup", function(e)
243						{
244							if(e.key === "Escape")
245							{
246								this.resetInputValue();
247							}
248						}.bind(this));
249
250						BX.bind(document, "click", this.documentClickHandler);
251					}
252				}.bind(this));
253
254				this.targetElement.addEventListener('keydown', function(e)
255				{
256                    if (this.isDisabled)
257                    {
258                        return;
259                    }
260
261					if ((e.keyCode === 9 && this.CurrentItem && this.CurrentItem.title.length !== this.targetElement.value.length)
262						|| (e.keyCode === 9 && !this.CurrentItem && this.targetElement.value.length > 0))
263					{
264						this.onEmptyValueEvent();
265						return;
266					}
267
268					if (e.keyCode === 9 && !this.popupWindow)
269					{
270						this.showPopupWindow();
271						return;
272					}
273					if (e.keyCode === 9 && this.targetElement.value === '' && !this.popupWindow)
274					{
275						this.showPopupWindow();
276						return;
277					}
278
279					if (e.keyCode === 9 && this.popupWindow)
280					{
281						this.destroyPopupWindow();
282					}
283				}.bind(this));
284			},
285			onDocumentClick: function()
286			{
287				if(this.isTargetElementChanged())
288				{
289					if(!this.enableCreationOnBlur)
290					{
291						this.resetInputValue();
292						this.setItems(this.getDefaultItems());
293						BX.cleanNode(this.popupAlertContainer);
294						this.newAlertContainer = null;
295					}
296					else
297					{
298						this.onEmptyValueEvent();
299					}
300				}
301			},
302			isTargetElementChanged: function()
303			{
304				return (this.CurrentItem && this.CurrentItem.title.length !== this.targetElement.value.length)
305					|| (!this.CurrentItem && this.targetElement.value.length > 0);
306			},
307			getDefaultItems: function()
308			{
309				return this.defaultItems;
310			},
311			setDefaultItems: function(defaultItems)
312			{
313				this.defaultItems = defaultItems;
314			},
315			getItems: function()
316			{
317				return this.items;
318			},
319			updateItemsList: function (items)
320			{
321				this.setDefaultItems(items);
322				this.setItems(items);
323			},
324			setItems: function(items)
325			{
326				this.items = items;
327				if (this.popupWindow)
328				{
329					this.renderItemsToInnerContainer();
330
331					this.popupWindow.adjustPosition({
332						forceBindPosition: true
333					});
334				}
335			},
336			handleTypeInField: function()
337			{
338				if(!this.isChanged) {
339					this.isChanged = true;
340				}
341
342				var searchQuery = this.targetElement.value.trim();
343				var isRequestsFlowAllowed =
344					this.autocompleteDelay === 0
345						? true
346						: this.isLastSearchComplete !== false
347				;
348				var loader = this.getItemsListContainer();
349
350				if(!searchQuery)
351				{
352					this.setItems(this.getDefaultItems());
353					loader.classList.remove('ui-dropdown-loader-active');
354					BX.cleanNode(this.popupAlertContainer);
355					this.newAlertContainer = null;
356					this.previousSearchQuery = '';
357
358					BX.onCustomEvent(this, "BX.UI.Dropdown:onReset", [this]);
359				}
360				else if(
361					searchQuery.length >= this.minSearchStringLength
362					&& searchQuery !== this.previousSearchQuery
363					&& isRequestsFlowAllowed
364				) {
365					BX.onCustomEvent(this, "BX.UI.Dropdown:onBeforeSearchStart", [this, searchQuery]);
366					clearTimeout(this.ajaxRequestTimer);
367					this.ajaxRequestTimer = setTimeout(this.searchItemsByStrDelayed.bind(this), this.autocompleteDelay);
368
369					loader.classList.add('ui-dropdown-loader-active');
370				}
371			},
372			searchItemsByStrDelayed: function()
373			{
374				this.isLastSearchComplete = false;
375				var loader = this.getItemsListContainer();
376				var searchQuery = this.targetElement.value.trim();
377				var eventData = {
378					searchQuery: searchQuery
379				};
380				BX.onCustomEvent(this, "BX.UI.Dropdown:onSearchStart", [this, eventData]);
381
382				this.searchItemsByStr(eventData.searchQuery)
383					.then(
384						function (items)
385						{
386							BX.onCustomEvent(this, "BX.UI.Dropdown:onSearchComplete", [this, items]);
387
388							return items;
389						}.bind(this))
390					.then(
391						function (items)
392						{
393							if(!this.newAlertContainer && this.enableCreation &&
394								BX.Type.isDomNode(this.popupAlertContainer))
395							{
396								var newAlertContainer = this.getNewAlertContainer(items);
397								if (BX.Type.isDomNode(newAlertContainer))
398								{
399									this.popupAlertContainer.appendChild(newAlertContainer);
400								}
401								BX.bind(document, "click", this.documentClickHandler);
402							}
403							this.setItems(items);
404							loader.classList.remove('ui-dropdown-loader-active');
405
406							this.showPopupWindow();
407
408							this.previousSearchQuery = searchQuery;
409							this.isLastSearchComplete = true;
410							this.handleTypeInField();
411						}.bind(this)
412				);
413			},
414			searchItemsByStr: function(target)
415			{
416				return BX.ajax.runAction(
417					this.searchAction,
418					{ data: { searchQuery: target, options: this.searchOptions } }
419				).then(this.onSearchRequestSuccess.bind(this));
420			},
421			onSearchRequestSuccess: function(results)
422			{
423				return BX.prop.getArray(BX.prop.getObject(results, "data", {}), "items", []);
424			},
425			getFooterItems: function()
426			{
427				return this.footerItems;
428			},
429			setFooterItems: function(items)
430			{
431				if (Array.isArray(items))
432				{
433					this.footerItems = items;
434				}
435			},
436			showPopupWindow: function()
437			{
438				var popupAlertContainer = this.getPopupAlertContainer();
439				if (this.getItems().length || this.footerItems || (popupAlertContainer && popupAlertContainer.textContent.trim().length))
440				{
441					this.getPopupWindow().show();
442				}
443			},
444			getPopupWindow: function()
445			{
446				if (!this.popupWindow)
447				{
448					this.popupWindow = new BX.PopupWindow("dropdown_" + this.id, this.targetElement, {
449						autoHide: true,
450						content : this.popupConatiner ? this.popupContainer : this.getPopupContainer(),
451						contentColor : "white",
452						closeByEsc: true,
453						className: "ui-dropdown-window",
454						events: {
455							onPopupClose: function()
456							{
457								this.popupWindow.destroy();
458								this.popupWindow = null;
459								this.itemListContainer = null;
460								this.itemListInnerContainer = null;
461								this.newAlertContainer = null;
462								this.popupAlertContainer = null;
463							}.bind(this)
464						}
465					});
466
467					if(this.isEmbedded && this.quickForm)
468					{
469						this.popupWindow.setOffset({
470							offsetLeft: this.getQuickFormOffsetWidth(),
471						});
472					}
473				}
474
475				this.setWidthPopup();
476				BX.bind(window, "resize", this.setWidthPopup.bind(this));
477
478				return this.popupWindow;
479			},
480			getQuickFormOffsetWidth: function()
481			{
482				var currentElement = BX.findParent(this.getPopupWindow().bindElement, {className: 'crm-kanban-quick-form'});
483
484				if (!currentElement)
485				{
486					return 0;
487				}
488				this.popupWindow.popupContainer.style.width = currentElement.offsetWidth + "px";
489				var equalWidth = - (this.targetElement.getBoundingClientRect().left - currentElement.getBoundingClientRect().left);
490
491				return equalWidth;
492			},
493			setWidthPopup: function()
494			{
495				if(!this.isEmbedded && this.quickForm)
496				{
497					if(this.popupWindow && this.targetElement)
498					{
499						this.popupWindow.popupContainer.style.width = this.targetElement.offsetWidth + "px"
500					}
501				}
502			},
503			onEmptyValueEvent: function()
504			{
505				this.emptyValueEventHandle = window.setTimeout(
506					function()
507					{
508						this.emptyValueEventHandle = 0;
509						if(this.enableCreation)
510						{
511							BX.onCustomEvent(this, "BX.UI.Dropdown:onAdd", [this, { title: this.targetElement.value }]);
512
513							this.setItems(this.getDefaultItems());
514							BX.cleanNode(this.popupAlertContainer);
515							this.newAlertContainer = null;
516						}
517						else
518						{
519							this.resetInputValue();
520						}
521					}.bind(this),
522					0
523				);
524			},
525			resetInputValue: function() {
526				this.targetElement.value = "";
527
528				BX.onCustomEvent(this, "BX.UI.Dropdown:onReset", [this]);
529			},
530			destroyPopupWindow: function()
531			{
532				BX.unbind(document, "click", this.documentClickHandler);
533
534				if(!this.popupWindow)
535				{
536					return;
537				}
538
539				this.popupWindow.close();
540			},
541			getPopupContainer: function()
542			{
543				this.popupContainer = this.getItemsListContainer();
544
545				this.popupContainer.appendChild(this.getItemsListInnerContainer());
546				this.popupContainer.appendChild(this.getPopupAlertContainer());
547
548				this.renderItemsToInnerContainer();
549				if (this.footerItems)
550				{
551					this.popupContainer.appendChild(this.getLoaderContainer());
552					this.popupContainer.appendChild(this.getFooterContent());
553				}
554
555				return this.popupContainer;
556			},
557			getPopupAlertContainer: function()
558			{
559				if(!this.popupAlertContainer)
560				{
561					this.popupAlertContainer = BX.create("div", {
562						attrs: { className: 'ui-dropdown-alert-container' }
563					});
564				}
565
566				return this.popupAlertContainer;
567			},
568			getNewAlertContainer: function(items)
569			{
570				if(!this.newAlertContainer)
571				{
572					this.newAlertContainer = BX.create('div', {
573						props: {
574							className: 'ui-dropdown-alert'
575						},
576						children: [
577							this.alertContainerValue = BX.create('div', {
578								attrs: { className: 'ui-dropdown-alert-name' },
579								text: this.targetElement.value
580							}),
581							BX.create('div', {
582								attrs: { className: 'ui-dropdown-alert-text' },
583								text: BX.prop.getString(this.messages, this.enableCreation ? "creationLegend" : "notFound", ""),
584								events: {
585									click: this.onEmptyValueEvent.bind(this)
586								}
587							})
588						]
589					});
590					BX.onCustomEvent(this, "BX.UI.Dropdown:onGetNewAlertContainer", [this, this.newAlertContainer]);
591					this.targetElement.addEventListener("input", function()
592					{
593						this.alertContainerValue.textContent = this.targetElement.value;
594					}.bind(this));
595
596					if(!this.enableCreation)
597					{
598						this.targetElement.addEventListener("input", function()
599						{
600							this.alertContainerValue.style.display = "none";
601						}.bind(this));
602					}
603				}
604
605				if(items.length > 0 && !this.enableCreation)
606				{
607					this.newAlertContainer.style.display = "none";
608				}
609				else
610				{
611					this.newAlertContainer.style.display = "";
612				}
613
614				return this.newAlertContainer;
615			},
616			getItemsListContainer: function()
617			{
618				if(!this.itemListContainer)
619				{
620					this.itemListContainer = BX.create('div', {
621						attrs: {
622							className: 'ui-dropdown-container'
623						}
624					});
625				}
626				return this.itemListContainer;
627			},
628			getItemsListInnerContainer: function()
629			{
630				if(!this.itemListInnerContainer)
631				{
632					this.itemListInnerContainer = BX.create('div', {
633						attrs: {
634							className: 'ui-dropdown-inner'
635						}
636					});
637				}
638				return this.itemListInnerContainer;
639			},
640			getItemNodeList: function()
641			{
642				var result = [];
643
644				this.getItems().forEach(function(item)
645				{
646					var attrs = BX.prop.getObject(item, "attributes", {});
647
648					var icon = BX.prop.getObject(attrs, "icon", null);
649					var phones = BX.prop.getArray(attrs, "phone", []);
650					var emails = BX.prop.getArray(attrs, "email", []);
651					var webs = BX.prop.getArray(attrs, "web", []);
652
653					var iconSrc = (icon !== null && BX.type.isNotEmptyString(icon.src) ? icon.src : '');
654					var phone = phones.length > 0 ? phones[0].value : "";
655					var email = emails.length > 0 ? emails[0].value : "";
656					var web = (webs.length > 0 ? webs[0].value : '');
657
658					item.node = BX.create('div', {
659						attrs: {
660							className: 'ui-dropdown-item' + (iconSrc !== '' ? ' ui-dropdown-item-node-with-icon' : '')
661						},
662						events: { click: this.handleItemClick.bind(this, item) },
663						children: [
664							iconSrc !== '' ? BX.create('span', {
665								attrs: {
666									className: 'ui-dropdown-item-icon',
667									style: 'background-image: url(\'' + BX.util.htmlspecialchars(iconSrc) + '\')'
668								},
669								text: ''
670							}) : null,
671							BX.create('div', {
672								attrs: {
673									className: 'ui-dropdown-item-name'
674								},
675								text: item.title
676							}),
677							BX.create('div', {
678								attrs: {
679									className: 'ui-dropdown-item-subname'
680								},
681								text: item.subTitle || ''
682							}),
683							BX.create('div', {
684								attrs: {
685									className: 'ui-dropdown-contact-info'
686								},
687								children: [
688									phone !== "" ? BX.create('div', {
689										attrs: {
690											className: 'ui-dropdown-contact-info-item ui-dropdown-item-phone'
691										},
692										text: phone
693									}) : null,
694									email !== "" ? BX.create('div', {
695										attrs: {
696											className: 'ui-dropdown-contact-info-item ui-dropdown-item-email'
697										},
698										text: email
699									}) : null,
700									web !== "" ? BX.create('div', {
701										attrs: {
702											className: 'ui-dropdown-contact-info-item ui-dropdown-item-web'
703										},
704										text: web
705									}) : null
706								]
707							})
708						]
709					});
710					result.push(item.node);
711				}, this);
712
713				return result;
714			},
715			renderItemsToInnerContainer: function()
716			{
717				var innerContainer = this.getItemsListInnerContainer();
718				BX.cleanNode(innerContainer);
719
720				var itemsNodeList = this.getItemNodeList();
721				// var itemAlertNode = this.getPopupAlertContainer();
722
723				for (var i = 0; i < itemsNodeList.length; i++)
724				{
725					innerContainer.appendChild(itemsNodeList[i]);
726				}
727
728				// innerContainer.appendChild(itemAlertNode);
729
730				return innerContainer;
731			},
732			getLoaderContainer: function()
733			{
734				return BX.create('div', {
735					props: {
736						className: 'ui-dropdown-loader-container'
737					},
738					html: '<svg class="ui-dropdown-loader" viewBox="25 25 50 50"><circle class="ui-dropdown-loader-path" cx="50" cy="50" r="20" fill="none" stroke-miterlimit="10"></circle><circle class="ui-dropdown-loader-inner-path" cx="50" cy="50" r="20" fill="none" stroke-miterlimit="10"></circle></svg>'
739				})
740			},
741			getFooterContent: function()
742			{
743				var footerContainer = BX.create('div', {
744
745				});
746
747				this.getFooterItems().forEach(function(footerItem)
748				{
749
750					var footer = BX.create('div', {
751						attrs: {
752							className: 'ui-dropdown-footer'
753						},
754						children: [
755							BX.create('div', {
756								attrs: {
757									className: 'ui-dropdown-caption-box'
758								},
759								children: [
760									BX.create('div', {
761										attrs: {
762											className: 'ui-dropdown-caption'
763										},
764										text: footerItem.caption
765									})
766								]
767							})
768						]
769					});
770					footerItem.buttons.forEach(function(button)
771					{
772						footer.appendChild(
773							BX.create('div', {
774								attrs: {
775									className: 'ui-dropdown-button-add'
776								},
777								text: button.caption,
778								events: button.events
779							})
780						);
781					});
782					footerContainer.appendChild(footer);
783
784				});
785
786				return footerContainer;
787			},
788			handleUpArrow: function()
789			{
790				if(this.newAlertContainer && this.popupAlertContainer.classList.contains('ui-dropdown-item-highlight'))
791				{
792					if (this.items && this.items.length > 0)
793					{
794						itemToHighlight = this.getItemByIndex(this.items.length - 1);
795						this.popupAlertContainer.classList.remove('ui-dropdown-item-highlight');
796						this.cleanHighlightingItem();
797						this.highlightItem(itemToHighlight);
798					}
799					return;
800				}
801
802				if (!this.items)
803				{
804					return;
805				}
806
807				var highlightElementIndex = this.getHighlightItemIndex();
808				var itemToHighlight = null;
809				if (highlightElementIndex === null)
810				{
811					itemToHighlight = this.getLastItem();
812				}
813				else
814				{
815					if (this.items.length >= highlightElementIndex + 1)
816					{
817						itemToHighlight = this.getItemByIndex(highlightElementIndex-1);
818					}
819				}
820				if (itemToHighlight)
821				{
822					this.cleanHighlightingItem();
823					this.highlightItem(itemToHighlight);
824				}
825			},
826			handleDownArrow: function()
827			{
828				var highlightElementIndex = this.getHighlightItemIndex();
829
830				if(this.newAlertContainer && this.popupAlertContainer.classList.contains('ui-dropdown-item-highlight'))
831				{
832					return;
833				}
834
835				if (!this.items || this.items.length === 0)
836				{
837					if(this.newAlertContainer && !this.popupAlertContainer.classList.contains('ui-dropdown-item-highlight'))
838					{
839						this.popupAlertContainer.classList.add('ui-dropdown-item-highlight');
840					}
841
842					return;
843				}
844
845				if(highlightElementIndex === this.items.length - 1)
846				{
847					if(this.newAlertContainer && !this.popupAlertContainer.classList.contains('ui-dropdown-item-highlight'))
848					{
849						this.cleanHighlightingItem();
850						this.popupAlertContainer.classList.add('ui-dropdown-item-highlight');
851					}
852
853					return;
854				}
855
856				var itemToHighlight = null;
857				if (highlightElementIndex === null)
858				{
859					itemToHighlight = this.getFirstItem();
860				}
861				else
862				{
863					itemToHighlight = this.getItemByIndex(highlightElementIndex + 1);
864				}
865				if (itemToHighlight)
866				{
867					this.cleanHighlightingItem();
868					this.highlightItem(itemToHighlight);
869				}
870
871			},
872			scrollToItem: function()
873			{
874				var parent = this.getItemsListInnerContainer();
875				var parentBounding = parent.getBoundingClientRect();
876				var elemBounding = this.highlightedItem.node.getBoundingClientRect();
877				var deltaBottom = parentBounding.bottom - elemBounding.bottom;
878				var deltaTop = parentBounding.top - elemBounding.top;
879
880				if(deltaBottom < 0)
881				{
882					parent.scrollTop = parent.scrollTop + Math.abs(deltaBottom)
883				}
884				else if(deltaTop > 0)
885				{
886					parent.scrollTop = parent.scrollTop - deltaTop
887				}
888			},
889			highlightItem: function(item)
890			{
891				item.node.classList.add('ui-dropdown-item-highlight');
892				// this.getItemsListInnerContainer().scrollTop = item.node.offsetTop;
893				this.highlightedItem = item;
894
895				this.scrollToItem();
896			},
897			cleanHighlightingItem: function()
898			{
899				if (this.highlightedItem)
900				{
901					this.highlightedItem.node.classList.remove('ui-dropdown-item-highlight');
902				}
903
904				this.highlightedItem = null;
905			},
906			getHighlightItemIndex: function()
907			{
908				var result = null;
909				var items = this.getItems();
910				for (var i = 0; i < items.length; i++) {
911					if (items[i].node.classList.contains('ui-dropdown-item-highlight'))
912					{
913						return i
914					}
915				}
916				return result;
917			},
918			getItemIndex: function(item)
919			{
920				var items = this.getItems();
921				for (var i = 0; i < items.length; i++)
922				{
923					if (items[i] === item)
924					{
925						return i;
926					}
927				}
928				return false;
929			},
930			getFirstItem: function()
931			{
932				if (!this.items || this.items.length === 0)
933				{
934					return null;
935				}
936
937				return this.items[0];
938			},
939			getLastItem: function()
940			{
941				var items = this.getItems();
942				if (!items)
943				{
944					return;
945				}
946
947				return items[items.length - 1];
948			},
949
950			getItemByIndex: function(index)
951			{
952				var items = this.getItems();
953				if (items[index])
954				{
955					return items[index];
956				}
957				return null;
958			},
959
960			handleItemClick: function(item, event)
961			{
962				if(this.emptyValueEventHandle > 0)
963				{
964					window.clearTimeout(this.emptyValueEventHandle);
965					this.emptyValueEventHandle = 0;
966				}
967				this.CurrentItem = item;
968				BX.onCustomEvent(this, "BX.UI.Dropdown:onSelect", [this, item]);
969			},
970
971			selectTargetElementValue: function()
972			{
973				this.targetElement.select();
974				this.targetElement.focus();
975			},
976
977			disableTargetElement: function()
978			{
979				this.targetElement.select();
980				this.targetElement.focus();
981
982				this.targetElement.addEventListener("keyup", function(e)
983				{
984					var key = e.charCode || e.keyCode;
985
986					if(this.targetElement === document.activeElement)
987					{
988						if(key === 8) {
989							return true;
990						}
991						else if(key === 37 || key === 39)
992						{
993							if(this.targetElement.value.length > 0 && this.targetElement === document.activeElement)
994							{
995								this.selectTargetElementValue();
996							}
997						}
998						else if(this.targetElement.value.length > 0 && this.targetElement === document.activeElement)
999						{
1000							return true;
1001						}
1002						else
1003						{
1004							BX.PreventDefault(e);
1005						}
1006					}
1007
1008				}.bind(this));
1009			},
1010			enableTargetElement: function()
1011			{
1012				this.targetElement.addEventListener("keyup", function() {return true;}.bind(this));
1013			}
1014		};
1015
1016
1017	BX.UI.DropdownUser = function(options)
1018	{
1019		BX.UI.Dropdown.call(this, options);
1020	};
1021
1022
1023	BX.UI.DropdownUser.prototype =
1024		{
1025			__proto__: BX.UI.Dropdown.prototype,
1026
1027			renderItem: function(item)
1028			{
1029
1030				itemsContainer.appendChild(BX.create('div', {
1031					attrs: {
1032						className: 'ui-dropdown-item ui-dropdown-item-user'
1033					},
1034					children: [
1035						BX.create('div', {
1036							attrs: {
1037								className: 'ui-dropdown-item-icon'
1038							},
1039							text: item.user
1040						}),
1041						BX.create('div', {
1042							attrs: {
1043								className: 'ui-dropdown-info-box'
1044							},
1045							children: [
1046								BX.create('div', {
1047									attrs: {
1048										className: 'ui-dropdown-item-name'
1049									},
1050									text: item.title
1051								}),
1052								BX.create('div', {
1053									attrs: {
1054										className: 'ui-dropdown-item-subname'
1055									},
1056									text: item.subtitle
1057								}),
1058								BX.create('div', {
1059									attrs: {
1060										className: 'ui-dropdown-item-value'
1061									},
1062									text: item.value
1063								})
1064							]
1065						})
1066					]
1067				}))
1068
1069			}
1070		};
1071
1072})();

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.