PageSourceSearch

https://abest.ru/bitrix/components/bitrix/search.title/script.js

js abest.ru collected 2026-09-24 09:44:29 UTC 10,573 bytes, 456 lines download raw bytes

1function JCTitleSearch(arParams)
2{
3	var _this = this;
4
5	this.arParams = {
6		'AJAX_PAGE': BX.util.htmlspecialcharsback(arParams.AJAX_PAGE),
7		'CONTAINER_ID': arParams.CONTAINER_ID,
8		'INPUT_ID': arParams.INPUT_ID,
9		'MIN_QUERY_LEN': parseInt(arParams.MIN_QUERY_LEN, 10),
10	};
11
12	if (arParams.WAIT_IMAGE)
13	{
14		this.arParams.WAIT_IMAGE = arParams.WAIT_IMAGE;
15	}
16
17	if (this.arParams.MIN_QUERY_LEN <= 0)
18	{
19		this.arParams.MIN_QUERY_LEN = 1;
20	}
21
22	this.cache = [];
23	this.cache_key = null;
24
25	this.startText = '';
26	this.running = false;
27	this.runningCall = false;
28	this.currentRow = -1;
29	this.RESULT = null;
30	this.CONTAINER = null;
31	this.INPUT = null;
32	this.WAIT = null;
33
34	this.ShowResult = function(result)
35	{
36		if (BX.type.isString(result))
37		{
38			_this.RESULT.innerHTML = result;
39		}
40
41		_this.RESULT.style.display = _this.RESULT.innerHTML === '' ? 'none' : 'block';
42		var pos = _this.adjustResultNode();
43
44		// adjust left column to be an outline
45		var resultPosition = null;
46		var th = null;
47		var tbl = BX.findChild(_this.RESULT, { 'tag': 'table', 'class': 'title-search-result' }, true);
48		if (tbl)
49		{
50			th = BX.findChild(tbl, { 'tag': 'th' }, true);
51		}
52
53		if (th)
54		{
55			var tablePosition = BX.pos(tbl);
56			tablePosition.width = tablePosition.right - tablePosition.left;
57
58			var tableHeaderPosition = BX.pos(th);
59			tableHeaderPosition.width = tableHeaderPosition.right - tableHeaderPosition.left;
60			th.style.width = tableHeaderPosition.width + 'px';
61
62			_this.RESULT.style.width = (pos.width + tableHeaderPosition.width) + 'px';
63
64			// Move table to left by width of the first column
65			_this.RESULT.style.left = (pos.left - tableHeaderPosition.width - 1) + 'px';
66
67			// Shrink table when it's too wide
68			if ((tablePosition.width - tableHeaderPosition.width) > pos.width)
69			{
70				_this.RESULT.style.width = (pos.width + tableHeaderPosition.width - 1) + 'px';
71			}
72
73			// Check if table is too wide and shrink result div to it's width
74			tablePosition = BX.pos(tbl);
75			resultPosition = BX.pos(_this.RESULT);
76			if (resultPosition.right > tablePosition.right)
77			{
78				_this.RESULT.style.width = (tablePosition.right - tablePosition.left) + 'px';
79			}
80		}
81
82		var fade = false;
83		if (tbl)
84		{
85			fade = BX.findChild(_this.RESULT, { 'class': 'title-search-fader' }, true);
86		}
87
88		if (fade && th)
89		{
90			resultPosition = BX.pos(_this.RESULT);
91			fade.style.left = (resultPosition.right - resultPosition.left - 18) + 'px';
92			fade.style.width = 18 + 'px';
93			fade.style.top = 0 + 'px';
94			fade.style.height = (resultPosition.bottom - resultPosition.top) + 'px';
95			fade.style.display = 'block';
96		}
97	};
98
99	this.onKeyPress = function(keyCode)
100	{
101		var tbl = BX.findChild(_this.RESULT, { 'tag': 'table', 'class': 'title-search-result' }, true);
102		if (!tbl)
103		{
104			return false;
105		}
106
107		var i = 0;
108		var cnt = tbl.rows.length;
109
110		switch (keyCode)
111		{
112			case 27: // escape key - close search div
113				_this.RESULT.style.display = 'none';
114				_this.currentRow = -1;
115				_this.UnSelectAll();
116
117				return true;
118			case 40: // down key - navigate down on search results
119				if (_this.RESULT.style.display == 'none')
120				{
121					_this.RESULT.style.display = 'block';
122				}
123
124				var first = -1;
125				for (i = 0; i < cnt; i++)
126				{
127					if (!BX.findChild(tbl.rows[i], { 'class': 'title-search-separator' }, true))
128					{
129						if (first == -1)
130						{
131							first = i;
132						}
133
134						if (_this.currentRow < i)
135						{
136							_this.currentRow = i;
137							break;
138						}
139						else if (tbl.rows[i].className == 'title-search-selected')
140						{
141							tbl.rows[i].className = '';
142						}
143					}
144				}
145
146				if (i == cnt && _this.currentRow != i)
147				{
148					_this.currentRow = first;
149				}
150
151				tbl.rows[_this.currentRow].className = 'title-search-selected';
152
153				return true;
154			case 38: // up key - navigate up on search results
155				if (_this.RESULT.style.display == 'none')
156				{
157					_this.RESULT.style.display = 'block';
158				}
159
160				var last = -1;
161				for (i = cnt - 1; i >= 0; i--)
162				{
163					if (!BX.findChild(tbl.rows[i], { 'class': 'title-search-separator' }, true))
164					{
165						if (last == -1)
166						{
167							last = i;
168						}
169
170						if (_this.currentRow > i)
171						{
172							_this.currentRow = i;
173							break;
174						}
175						else if (tbl.rows[i].className == 'title-search-selected')
176						{
177							tbl.rows[i].className = '';
178						}
179					}
180				}
181
182				if (i < 0 && _this.currentRow != i)
183				{
184					_this.currentRow = last;
185				}
186
187				tbl.rows[_this.currentRow].className = 'title-search-selected';
188
189				return true;
190			case 13: // enter key - choose current search result
191				if (_this.RESULT.style.display == 'block')
192				{
193					for (i = 0; i < cnt; i++)
194					{
195						if (
196							_this.currentRow == i
197							&& !BX.findChild(tbl.rows[i], { 'class': 'title-search-separator' }, true)
198						)
199						{
200							var a = BX.findChild(tbl.rows[i], { 'tag': 'a' }, true);
201							if (a)
202							{
203								window.location = a.href;
204
205								return true;
206							}
207						}
208					}
209				}
210
211				return false;
212			default:
213				break;
214		}
215
216		return false;
217	};
218
219	this.onTimeout = function()
220	{
221		_this.onChange(function() {
222			setTimeout(_this.onTimeout, 500);
223		});
224	};
225
226	this.onChange = function(callback)
227	{
228		if (_this.running)
229		{
230			_this.runningCall = true;
231
232			return;
233		}
234		_this.running = true;
235
236		if (_this.INPUT.value != _this.oldValue && _this.INPUT.value != _this.startText)
237		{
238			_this.oldValue = _this.INPUT.value;
239			if (_this.INPUT.value.length >= _this.arParams.MIN_QUERY_LEN)
240			{
241				_this.cache_key = _this.arParams.INPUT_ID + '|' + _this.INPUT.value;
242				if (_this.cache[_this.cache_key] == null)
243				{
244					if (_this.WAIT)
245					{
246						var pos = BX.pos(_this.INPUT);
247						var height = (pos.bottom - pos.top) - 2;
248						_this.WAIT.style.top = (pos.top + 1) + 'px';
249						_this.WAIT.style.height = height + 'px';
250						_this.WAIT.style.width = height + 'px';
251						_this.WAIT.style.left = (pos.right - height + 2) + 'px';
252						_this.WAIT.style.display = 'block';
253					}
254
255					BX.ajax.post(
256						_this.arParams.AJAX_PAGE,
257						{
258							'ajax_call': 'y',
259							'INPUT_ID': _this.arParams.INPUT_ID,
260							'q': _this.INPUT.value,
261							'l': _this.arParams.MIN_QUERY_LEN,
262						},
263						function(result)
264						{
265							_this.cache[_this.cache_key] = result;
266							_this.ShowResult(result);
267							_this.currentRow = -1;
268							_this.EnableMouseEvents();
269							if (_this.WAIT)
270							{
271								_this.WAIT.style.display = 'none';
272							}
273
274							if (!!callback)
275							{
276								callback();
277							}
278
279							_this.running = false;
280							if (_this.runningCall)
281							{
282								_this.runningCall = false;
283								_this.onChange();
284							}
285						}
286					);
287
288					return;
289				}
290
291				_this.ShowResult(_this.cache[_this.cache_key]);
292				_this.currentRow = -1;
293				_this.EnableMouseEvents();
294			}
295			else
296			{
297				_this.RESULT.style.display = 'none';
298				_this.currentRow = -1;
299				_this.UnSelectAll();
300			}
301		}
302
303		if (!!callback)
304		{
305			callback();
306		}
307		_this.running = false;
308	};
309
310	this.onScroll = function ()
311	{
312		if (BX.type.isElementNode(_this.RESULT)
313			&& _this.RESULT.style.display !== 'none'
314			&& _this.RESULT.innerHTML !== ''
315		)
316		{
317			_this.adjustResultNode();
318		}
319	};
320
321	this.UnSelectAll = function()
322	{
323		var tbl = BX.findChild(_this.RESULT, { 'tag': 'table', 'class': 'title-search-result' }, true);
324		if (tbl)
325		{
326			var cnt = tbl.rows.length;
327			for (var i = 0; i < cnt; i++)
328			{
329				tbl.rows[i].className = '';
330			}
331		}
332	};
333
334	this.EnableMouseEvents = function()
335	{
336		var tbl = BX.findChild(_this.RESULT, { 'tag': 'table', 'class': 'title-search-result' }, true);
337		if (tbl)
338		{
339			var cnt = tbl.rows.length;
340			for (var i = 0; i < cnt; i++)
341			{
342				if (!BX.findChild(tbl.rows[i], { 'class': 'title-search-separator' }, true))
343				{
344					tbl.rows[i].id = 'row_' + i;
345					tbl.rows[i].onmouseover = function (e) {
346						if (_this.currentRow != this.id.substr(4))
347						{
348							_this.UnSelectAll();
349							this.className = 'title-search-selected';
350							_this.currentRow = this.id.substr(4);
351						}
352					};
353
354					tbl.rows[i].onmouseout = function (e) {
355						this.className = '';
356						_this.currentRow = -1;
357					};
358				}
359			}
360		}
361	};
362
363	this.onFocusLost = function(hide)
364	{
365		setTimeout(function() { _this.RESULT.style.display = 'none'; }, 250);
366	};
367
368	this.onFocusGain = function()
369	{
370		if (_this.RESULT.innerHTML.length > 0)
371		{
372			_this.ShowResult();
373		}
374	};
375
376	this.onKeyDown = function(e)
377	{
378		if (!e)
379		{
380			e = window.event;
381		}
382
383		if (_this.RESULT.style.display == 'block' && _this.onKeyPress(e.keyCode))
384		{
385			return BX.PreventDefault(e);
386		}
387	};
388
389	this.adjustResultNode = function()
390	{
391		if (!(BX.type.isElementNode(_this.RESULT)
392			&& BX.type.isElementNode(_this.CONTAINER))
393		)
394		{
395			return { top: 0, right: 0, bottom: 0, left: 0, width: 0, height: 0 };
396		}
397
398		var pos = BX.pos(_this.CONTAINER);
399
400		_this.RESULT.style.position = 'absolute';
401		_this.RESULT.style.top = (pos.bottom + 2) + 'px';
402		_this.RESULT.style.left = pos.left + 'px';
403		_this.RESULT.style.width = pos.width + 'px';
404
405		return pos;
406	};
407
408	this.onContainerLayoutChange = function()
409	{
410		if (BX.type.isElementNode(_this.RESULT)
411			&& _this.RESULT.style.display !== 'none'
412			&& _this.RESULT.innerHTML !== ''
413		)
414		{
415			_this.adjustResultNode();
416		}
417	};
418
419	this.Init = function()
420	{
421		this.CONTAINER = document.getElementById(this.arParams.CONTAINER_ID);
422		BX.addCustomEvent(this.CONTAINER, 'OnNodeLayoutChange', this.onContainerLayoutChange);
423
424		this.RESULT = document.body.appendChild(document.createElement("DIV"));
425		this.RESULT.className = 'title-search-result';
426		this.INPUT = document.getElementById(this.arParams.INPUT_ID);
427		this.startText = this.INPUT.value;
428		this.oldValue = this.INPUT.value;
429		BX.bind(this.INPUT, 'focus', function() { _this.onFocusGain(); });
430		BX.bind(this.INPUT, 'blur', function() { _this.onFocusLost(); });
431		this.INPUT.onkeydown = this.onKeyDown;
432
433		if (this.arParams.WAIT_IMAGE)
434		{
435			this.WAIT = document.body.appendChild(document.createElement('DIV'));
436			this.WAIT.style.backgroundImage = "url('" + this.arParams.WAIT_IMAGE + "')";
437			if (!BX.browser.IsIE())
438			{
439				this.WAIT.style.backgroundRepeat = 'none';
440			}
441			this.WAIT.style.display = 'none';
442			this.WAIT.style.position = 'absolute';
443			this.WAIT.style.zIndex = '1100';
444		}
445
446		BX.bind(this.INPUT, 'bxchange', function() {_this.onChange()});
447
448		var fixedParent = BX.findParent(this.CONTAINER, BX.is_fixed);
449		if (BX.type.isElementNode(fixedParent))
450		{
451			BX.bind(window, 'scroll', BX.throttle(this.onScroll, 100, this));
452		}
453	};
454
455	BX.ready(function() { _this.Init(arParams); });
456}

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.