Issues (1686)

themes/default/scripts/suggest.js (5 issues)

1
/*!
2
 * @package   ElkArte Forum
3
 * @copyright ElkArte Forum contributors
4
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
5
 *
6
 * This file contains code covered by:
7
 * copyright: 2011 Simple Machines (http://www.simplemachines.org)
8
 *
9
 * @version 2.0 dev
10
 */
11
12
/** global: elk_session_var, elk_session_id, elk_scripturl */
13
14
/**
15
 * This file contains javascript associated with an auto suggest control.
16
 */
17
18
/**
19
 * The auto suggest class, used to display a selection list of members
20
 *
21
 * @param {object} oOptions
22
 */
23
function elk_AutoSuggest (oOptions)
24
{
25
	this.opt = oOptions;
26
27
	// Store the handle to the text box.
28
	this.oTextHandle = document.getElementById(this.opt.sControlId);
29
	this.oRealTextHandle = null;
30
	this.oSuggestDivHandle = null;
31
32
	this.sLastSearch = '';
33
	this.sLastDirtySearch = '';
34
	this.oSelectedDiv = null;
35
	this.aCache = [];
36
	this.aDisplayData = [];
37
	this.sRetrieveURL = this.opt.sRetrieveURL || '%scripturl%action=suggest;api=xml';
38
39
	// How many objects can we show at once?
40
	this.iMaxDisplayQuantity = this.opt.iMaxDisplayQuantity || 12;
41
42
	// How many characters shall we start searching on?
43
	this.iMinimumSearchChars = this.opt.iMinimumSearchChars || 2;
44
45
	// Should selected items be added to a list?
46
	this.bItemList = this.opt.bItemList || false;
47
48
	// Are there any items that should be added in advance?
49
	this.aListItems = this.opt.aListItems || [];
50
51
	this.sItemTemplate = this.opt.sItemTemplate || '<input type="hidden" name="%post_name%[]" value="%item_id%" /><a href="%item_href%" class="extern" onclick="window.open(this.href, \'_blank\'); return false;">%item_name%</a><span class="breaking_space"></span><i class="icon icon-small i-remove" title="%delete_text%"><s>%delete_text%</s></i>';
52
	this.sTextDeleteItem = this.opt.sTextDeleteItem || '';
53
	this.oCallback = {};
54
	this.bDoAutoAdd = false;
55
	this.iItemCount = 0;
56
	this.oHideTimer = null;
57
	this.bPositionComplete = false;
58
59
	this.oXmlRequestHandle = null;
60
61
	// Just make sure the page is loaded before calling the init.
62
	window.addEventListener('load', this.init.bind(this));
63
}
64
65
/**
66
 * Initialize our auto suggest object, adds events and containers to the element we monitor
67
 */
68
elk_AutoSuggest.prototype.init = function() {
69
	// Create a div that'll contain the results later on.
70
	this.oSuggestDivHandle = document.createElement('div');
71
	this.oSuggestDivHandle.className = 'auto_suggest_div';
72
	document.body.appendChild(this.oSuggestDivHandle);
73
74
	// Create a backup text input.
75
	this.oRealTextHandle = document.createElement('input');
76
	this.oRealTextHandle.type = 'hidden';
77
	this.oRealTextHandle.name = this.oTextHandle.name;
78
	this.oRealTextHandle.value = this.oTextHandle.value;
79
	this.oTextHandle.form.appendChild(this.oRealTextHandle);
80
81
	// Disable autocomplete in any browser by obfuscating the name.
82
	this.oTextHandle.name = 'dummy_' + Math.floor(Math.random() * 1000000);
83
	this.oTextHandle.autocomplete = 'off';
84
85
	// Set up all the event monitoring
86
	this.oTextHandle.onkeydown = this.handleKey.bind(this);
87
	this.oTextHandle.onkeyup = debounce((function () {this.autoSuggestUpdate();}).bind(this), 150);
88
	this.oTextHandle.onchange = debounce((function () {this.autoSuggestUpdate();}).bind(this), 150);
89
	this.oTextHandle.onblur = this.autoSuggestHide.bind(this);
90
	this.oTextHandle.onfocus = this.autoSuggestUpdate.bind(this);
91
92
	// Adding items to a list, then we need a place to insert them
93
	if (this.bItemList)
94
	{
95
		if ('sItemListContainerId' in this.opt)
96
		{
97
			this.oItemList = document.getElementById(this.opt.sItemListContainerId);
98
		}
99
		else
100
		{
101
			this.oItemList = document.createElement('div');
102
			this.oTextHandle.parentNode.insertBefore(this.oItemList, this.oTextHandle.nextSibling);
103
		}
104
	}
105
106
	// Items provided to add to the top of the selection list?
107
	if (this.aListItems.length > 0)
108
	{
109
		for (let i = 0, n = this.aListItems.length; i < n; i++)
110
		{
111
			this.addItemLink(this.aListItems[i].sItemId, this.aListItems[i].sItemName, false);
112
		}
113
	}
114
115
	return true;
116
};
117
118
/**
119
 * Handle keypress events for the suggest controller
120
 */
121
elk_AutoSuggest.prototype.handleKey = function(oEvent) {
122
	let iKeyPress = this.getKeyPress(oEvent);
123
124
	switch (iKeyPress)
125
	{
126
		case 9: // Tab
127
			return this.handleTabKey();
128
		case 13: // Enter
129
			return this.handleEnterKey();
130
		case 38: // Up arrow
131
		case 40: // Down arrow
132
			return this.handleArrowKey(iKeyPress);
133
	}
134
135
	return true;
136
};
137
138
/**
139
 * Gets the key pressed from the event handler.
140
 */
141
elk_AutoSuggest.prototype.getKeyPress = function(oEvent) {
142
	return 'which' in oEvent ? oEvent.which : oEvent.keyCode;
143
};
144
145
/**
146
 * Handles the tab key press event for the AutoSuggest component.
147
 */
148
elk_AutoSuggest.prototype.handleTabKey = function() {
149
	if (this.aDisplayData.length > 0)
150
	{
151
		if (this.oSelectedDiv !== null)
152
		{
153
			this.itemClicked(this.oSelectedDiv);
154
		}
155
		else
156
		{
157
			this.handleSubmit();
158
		}
159
	}
160
161
	return true;
162
};
163
164
/**
165
 * Handles the enter key press event for the auto-suggest feature.
166
 * Triggers the selectItem() method to select the highlighted item
167
 * when the enter key is pressed.
168
 */
169
elk_AutoSuggest.prototype.handleEnterKey = function() {
170
	if (this.aDisplayData.length > 0 && this.oSelectedDiv !== null)
171
	{
172
		this.itemClicked(this.oSelectedDiv);
173
174
		// Do our best to stop it submitting the form!
175
		return false;
176
	}
177
178
	return true;
179
};
180
181
/**
182
 * Handles the up/down arrow key events for the AutoSuggest component.
183
 */
184
elk_AutoSuggest.prototype.handleArrowKey = function(iKeyPress) {
185
	if (this.aDisplayData.length && this.oSuggestDivHandle.style.visibility !== 'hidden')
186
	{
187
		// Loop through the display data trying to find our entry.
188
		let bPrevHandle = false,
189
			oToHighlight = null;
190
191
		for (let i = 0; i < this.aDisplayData.length; i++)
192
		{
193
			// If we're going up and yet the top one was already selected don't go around.
194
			if (this.oSelectedDiv !== null && this.oSelectedDiv === this.aDisplayData[i] && i === 0 && iKeyPress === 38)
195
			{
196
				oToHighlight = this.oSelectedDiv;
197
				break;
198
			}
199
200
			// If nothing is selected, and we are going down then we select the first one.
201
			if (this.oSelectedDiv === null && iKeyPress === 40)
202
			{
203
				oToHighlight = this.aDisplayData[i];
204
				break;
205
			}
206
207
			// If the previous handle was the actual previously selected one, and we're hitting down then this is the one we want.
208
			if (bPrevHandle !== false && bPrevHandle === this.oSelectedDiv && iKeyPress === 40)
209
			{
210
				oToHighlight = this.aDisplayData[i];
211
				break;
212
			}
213
214
			// If we're going up and this is the previously selected one then we want the one before, if there was one.
215
			if (bPrevHandle !== false && this.aDisplayData[i] === this.oSelectedDiv && iKeyPress === 38)
216
			{
217
				oToHighlight = bPrevHandle;
218
				break;
219
			}
220
221
			// Make the previous handle this!
222
			bPrevHandle = this.aDisplayData[i];
223
		}
224
225
		// If we don't have one to highlight by now then it must be the last one that we're after.
226
		if (oToHighlight === null)
227
		{
228
			oToHighlight = bPrevHandle;
229
		}
230
231
		// Remove any old highlighting.
232
		if (this.oSelectedDiv !== null)
233
		{
234
			this.itemMouseOut(this.oSelectedDiv);
235
		}
236
237
		// Mark what the selected div now is.
238
		this.oSelectedDiv = oToHighlight;
239
		this.itemMouseOver(this.oSelectedDiv);
240
	}
241
242
	return true;
243
};
244
245
/**
246
 * Handles the mouse over event for an item in the auto suggest menu.
247
 */
248
elk_AutoSuggest.prototype.itemMouseOver = function(oCurElement) {
249
	this.oSelectedDiv = oCurElement;
250
	oCurElement.className = 'auto_suggest_item_hover';
251
};
252
253
/**
254
 * Handle the mouse out event on an item in the auto suggest dropdown.
255
 */
256
elk_AutoSuggest.prototype.itemMouseOut = function(oCurElement) {
257
	oCurElement.className = 'auto_suggest_item';
258
};
259
260
/**
261
 * Registers a callback function to be called when the auto-suggest results are available.
262
 */
263
elk_AutoSuggest.prototype.registerCallback = function(sCallbackType, sCallback) {
264
	switch (sCallbackType)
265
	{
266
		case 'onBeforeAddItem':
267
			this.oCallback.onBeforeAddItem = sCallback;
268
			break;
269
270
		case 'onAfterAddItem':
271
			this.oCallback.onAfterAddItem = sCallback;
272
			break;
273
274
		case 'onAfterDeleteItem':
275
			this.oCallback.onAfterDeleteItem = sCallback;
276
			break;
277
278
		case 'onBeforeUpdate':
279
			this.oCallback.onBeforeUpdate = sCallback;
280
			break;
281
	}
282
};
283
284
/**
285
 * Handle form submission for the AutoSuggest component.
286
 *
287
 * @returns {boolean} - Returns false to prevent the default form submission behavior.
288
 */
289
elk_AutoSuggest.prototype.handleSubmit = function() {
290
	let bReturnValue = true,
291
		oFoundEntry = null;
292
293
	// Do we have something that matches the current text?
294
	for (let i = 0; i < this.aCache.length; i++)
295
	{
296
		if (this.sLastSearch.toLowerCase() === this.aCache[i].sItemName.toLowerCase().substring(0, this.sLastSearch.length))
297
		{
298
			// Exact match?
299
			if (this.sLastSearch.length === this.aCache[i].sItemName.length)
300
			{
301
				// This is the one!
302
				oFoundEntry = {
303
					sItemId: this.aCache[i].sItemId,
304
					sItemName: this.aCache[i].sItemName
305
				};
306
307
				break;
308
			}
309
			// Not an exact match, but it'll do for now.
310
			else
311
			{
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
312
				// If we have two matches don't find anything.
313
				if (oFoundEntry !== null)
314
				{
315
					bReturnValue = false;
316
				}
317
				else
318
				{
319
					oFoundEntry = {
320
						sItemId: this.aCache[i].sItemId,
321
						sItemName: this.aCache[i].sItemName
322
					};
323
				}
324
			}
325
		}
326
	}
327
328
	if (oFoundEntry === null || bReturnValue === false)
329
	{
330
		return bReturnValue;
331
	}
332
333
	this.addItemLink(oFoundEntry.sItemId, oFoundEntry.sItemName, true);
334
	return false;
335
};
336
337
/**
338
 * Positions the suggestion dropdown div based on the input element's position.
339
 */
340
elk_AutoSuggest.prototype.positionDiv = function() {
341
	// Only do it once.
342
	if (this.bPositionComplete)
343
	{
344
		return true;
345
	}
346
347
	this.bPositionComplete = true;
348
349
	// Put the div under the text box.
350
	let aParentPos = elk_itemPos(this.oTextHandle);
351
352
	this.oSuggestDivHandle.style.left = aParentPos[0] + 'px';
353
	this.oSuggestDivHandle.style.top = (aParentPos[1] + this.oTextHandle.offsetHeight) + 'px';
354
	this.oSuggestDivHandle.style.width = this.oTextHandle.clientWidth + 'px';
355
356
	return true;
357
};
358
359
/**
360
 * Called when an item in the auto suggest list is clicked.
361
 */
362
elk_AutoSuggest.prototype.itemClicked = function(oEvent) {
363
	let target = 'target' in oEvent ? oEvent.target : oEvent;
364
365
	// Is there a div that we are populating?
366
	if (this.bItemList)
367
	{
368
		this.addItemLink(target.sItemId, target.innerHTML, false);
369
	}
370
	// Otherwise clear things down.
371
	else
372
	{
373
		this.oTextHandle.value = target.innerHTML.php_unhtmlspecialchars();
374
	}
375
376
	this.oRealTextHandle.value = this.oTextHandle.value;
377
	this.autoSuggestActualHide();
378
	this.oSelectedDiv = null;
379
};
380
381
/**
382
 * Removes the last entered search string from the auto-suggest component.
383
 */
384
elk_AutoSuggest.prototype.removeLastSearchString = function() {
385
	// Remove the text we searched for from the div.
386
	let sTempText = this.oTextHandle.value.toLowerCase(),
387
		iStartString = sTempText.indexOf(this.sLastSearch.toLowerCase());
388
389
	// Just attempt to remove the bits we just searched for.
390
	if (iStartString !== -1)
391
	{
392
		while (iStartString > 0)
393
		{
394
			if (sTempText.charAt(iStartString - 1) === '"' || sTempText.charAt(iStartString - 1) === ',' || sTempText.charAt(iStartString - 1) === ' ')
395
			{
396
				iStartString--;
397
				if (sTempText.charAt(iStartString - 1) === ',')
398
				{
399
					break;
400
				}
401
			}
402
			else
403
			{
404
				break;
405
			}
406
		}
407
408
		// Now remove anything from iStartString upwards.
409
		this.oTextHandle.value = this.oTextHandle.value.substring(0, iStartString);
410
	}
411
	// Just take it all.
412
	else
413
	{
414
		this.oTextHandle.value = '';
415
	}
416
};
417
418
/**
419
 * Adds an item link to the item list.
420
 *
421
 * @param {string} sItemId - The ID of the item.
422
 * @param {string} sItemName - The name of the item.
423
 * @param {boolean} bFromSubmit - Specifies whether the call is from a submit action.
424
 */
425
elk_AutoSuggest.prototype.addItemLink = function(sItemId, sItemName, bFromSubmit) {
426
	// Increase the internal item count.
427
	this.iItemCount++;
428
429
	// If there's a callback then call it.
430
	if (typeof this.oCallback.onBeforeAddItem === 'function')
431
	{
432
		// If it returns false the item must not be added.
433
		if (!this.oCallback.onBeforeAddItem.call(this, sItemId))
434
		{
435
			return;
436
		}
437
	}
438
439
	let oNewDiv = document.createElement('div');
440
	oNewDiv.id = 'suggest_' + this.opt.sSuggestId + '_' + sItemId;
441
	oNewDiv.innerHTML = this.sItemTemplate
442
		.replace(/%post_name%/g, this.opt.sPostName)
443
		.replace(/%item_id%/g, sItemId)
444
		.replace(/%item_href%/g, elk_prepareScriptUrl(elk_scripturl) + this.opt.sURLMask.replace(/%item_id%/g, sItemId))
445
		.replace(/%item_name%/g, sItemName)
446
		.replace(/%images_url%/g, elk_images_url).replace(/%delete_text%/g, this.sTextDeleteItem);
0 ignored issues
show
The variable elk_images_url seems to be never declared. If this is a global, consider adding a /** global: elk_images_url */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
447
	oNewDiv.getElementsByClassName('icon-small')[0].addEventListener('click', this.deleteAddedItem.bind(this));
448
	this.oItemList.appendChild(oNewDiv);
449
450
	// If there's a registered callback, call it.
451
	if (typeof this.oCallback.onAfterAddItem === 'function')
452
	{
453
		this.oCallback.onAfterAddItem.call(this, oNewDiv.id);
454
	}
455
456
	// Clear the div a bit.
457
	this.removeLastSearchString();
458
459
	// If we came from a submit, and there's still more to go, turn on auto add for all the other things.
460
	this.bDoAutoAdd = this.oTextHandle.value !== '' && bFromSubmit;
461
462
	// Update the fellow.
463
	this.autoSuggestUpdate();
464
};
465
466
/**
467
 * Deletes the added item from the auto-suggest component.
468
 */
469
elk_AutoSuggest.prototype.deleteAddedItem = function(oEvent) {
470
	let oDiv;
471
472
	// A registerCallback, e.g. PM preventing duplicate entries
473
	if (typeof oEvent === 'string')
474
	{
475
		oDiv = document.getElementById('suggest_' + this.opt.sSuggestId + '_' + oEvent);
476
	}
477
478
	// Or the remove button
479
	if (typeof oEvent === 'object')
480
	{
481
		oDiv = oEvent.target.parentNode;
482
	}
483
484
	// Remove the div if it exists.
485
	if (oDiv !== null)
0 ignored issues
show
The variable oDiv does not seem to be initialized in case typeof oEvent === "string" on line 473 is false. Are you sure this can never be the case?
Loading history...
486
	{
487
		this.oItemList.removeChild(oDiv);
488
489
		// Decrease the internal item count.
490
		this.iItemCount--;
491
492
		// If there's a registered callback, call it.
493
		if (typeof this.oCallback.onAfterDeleteItem === 'function')
494
		{
495
			this.oCallback.onAfterDeleteItem.call(this);
496
		}
497
	}
498
499
	return false;
500
};
501
502
/**
503
 * Hide the auto suggest suggestions.
504
 */
505
elk_AutoSuggest.prototype.autoSuggestHide = function() {
506
	// Delay to allow events to propagate through....
507
	this.oHideTimer = setTimeout(this.autoSuggestActualHide.bind(this), 350);
508
};
509
510
/**
511
 * Hides the actual auto-suggest dropdown after a timeout
512
 */
513
elk_AutoSuggest.prototype.autoSuggestActualHide = function() {
514
	this.oSuggestDivHandle.style.display = 'none';
515
	this.oSuggestDivHandle.style.visibility = 'hidden';
516
	this.oSelectedDiv = null;
517
};
518
519
/**
520
 * Shows the auto suggest dropdown when triggered by the user.
521
 */
522
elk_AutoSuggest.prototype.autoSuggestShow = function() {
523
	if (this.oHideTimer)
524
	{
525
		clearTimeout(this.oHideTimer);
526
		this.oHideTimer = false;
527
	}
528
529
	this.positionDiv();
530
	this.oSuggestDivHandle.style.visibility = 'visible';
531
	this.oSuggestDivHandle.style.display = '';
532
};
533
534
/**
535
 * Populates the auto-suggest dropdown div with suggestions based on the provided data.
536
 */
537
elk_AutoSuggest.prototype.populateDiv = function(aResults) {
538
	// Cannot have any children yet.
539
	while (this.oSuggestDivHandle.childNodes.length > 0)
540
	{
541
		// Tidy up the events etc. too.
542
		this.oSuggestDivHandle.childNodes[0].onmouseover = null;
543
		this.oSuggestDivHandle.childNodes[0].onmouseout = null;
544
		this.oSuggestDivHandle.childNodes[0].onclick = null;
545
546
		this.oSuggestDivHandle.removeChild(this.oSuggestDivHandle.childNodes[0]);
547
	}
548
549
	// Something to display?
550
	if (typeof aResults === 'undefined')
551
	{
552
		this.aDisplayData = [];
553
		return false;
554
	}
555
556
	let aNewDisplayData = [];
557
	for (let i = 0; i < (aResults.length > this.iMaxDisplayQuantity ? this.iMaxDisplayQuantity : aResults.length); i++)
558
	{
559
		// Create the sub element
560
		let oNewDivHandle = document.createElement('div');
561
562
		oNewDivHandle.sItemId = aResults[i].sItemId;
563
		oNewDivHandle.className = 'auto_suggest_item';
564
		oNewDivHandle.innerHTML = aResults[i].sItemName;
565
		//oNewDivHandle.style.width = this.oTextHandle.style.width;
566
567
		this.oSuggestDivHandle.appendChild(oNewDivHandle);
568
569
		// Attach some events to it, so we can do stuff.
570
		oNewDivHandle.onmouseover = function() {
571
			this.className = 'auto_suggest_item_hover';
572
		};
573
		oNewDivHandle.onmouseout = function() {
574
			this.className = 'auto_suggest_item';
575
		};
576
		oNewDivHandle.onclick = this.itemClicked.bind(this);
577
578
		aNewDisplayData[i] = oNewDivHandle;
579
	}
580
581
	this.aDisplayData = aNewDisplayData;
582
583
	return true;
584
};
585
586
/**
587
 * Callback function for the XML request, should contain the list of users that match
588
 */
589
elk_AutoSuggest.prototype.onSuggestionReceived = function(oXMLDoc) {
590
	if (oXMLDoc === false)
591
	{
592
		return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
593
	}
594
595
	let aItems = oXMLDoc.getElementsByTagName('item');
596
597
	// Go through each item received
598
	this.aCache = [];
599
	for (let i = 0; i < aItems.length; i++)
600
	{
601
		this.aCache[i] = {
602
			sItemId: aItems[i].getAttribute('id'),
603
			sItemName: aItems[i].childNodes[0].nodeValue
604
		};
605
606
		// If we're doing auto add, and we found the exact person, then add them!
607
		if (this.bDoAutoAdd && this.sLastSearch === this.aCache[i].sItemName)
608
		{
609
			let oReturnValue = {
610
				sItemId: this.aCache[i].sItemId,
611
				sItemName: this.aCache[i].sItemName
612
			};
613
614
			this.aCache = [];
615
			return this.addItemLink(oReturnValue.sItemId, oReturnValue.sItemName, true);
616
		}
617
	}
618
619
	// Check we don't try to keep auto updating!
620
	this.bDoAutoAdd = false;
621
622
	// Populate the div.
623
	this.populateDiv(this.aCache);
624
625
	// Make sure we can see it - if we can.
626
	if (aItems.length === 0)
627
	{
628
		this.autoSuggestHide();
629
	}
630
	else
631
	{
632
		this.autoSuggestShow();
633
	}
634
635
	return true;
636
};
637
638
/**
639
 * Update the suggestions in the auto suggest dropdown based on the user input
640
 */
641
elk_AutoSuggest.prototype.autoSuggestUpdate = function() {
642
	// If there's a callback then call it.
643
	if (typeof this.oCallback.onBeforeUpdate === 'function')
644
	{
645
		// If it returns false the item must not be added.
646
		if (!this.oCallback.onBeforeUpdate.call(this))
647
		{
648
			return false;
649
		}
650
	}
651
652
	this.oRealTextHandle.value = this.oTextHandle.value;
653
654
	if (isEmptyText(this.oTextHandle))
655
	{
656
		this.aCache = [];
657
		this.populateDiv();
658
		this.autoSuggestHide();
659
660
		return true;
661
	}
662
663
	// Nothing changed?
664
	if (this.oTextHandle.value === this.sLastDirtySearch)
665
	{
666
		return true;
667
	}
668
	this.sLastDirtySearch = this.oTextHandle.value;
669
670
	// We're only actually interested in the last string.
671
	let sSearchString = this.oTextHandle.value.replace(/^("[^"]+",[ ]*)+/, '').replace(/^([^,]+,[ ]*)+/, '');
672
	if (sSearchString.substring(0, 1) === '"')
673
	{
674
		sSearchString = sSearchString.substring(1);
675
	}
676
677
	// Stop replication ASAP.
678
	let sRealLastSearch = this.sLastSearch;
679
	this.sLastSearch = sSearchString;
680
681
	// Either nothing or we've completed a sentence.
682
	if (sSearchString === '' || sSearchString.substring(sSearchString.length - 1) === '"')
683
	{
684
		this.populateDiv();
685
		return true;
686
	}
687
688
	// Nothing?
689
	if (sRealLastSearch === sSearchString)
690
	{
691
		return true;
692
	}
693
694
	// Too small?
695
	if (sSearchString.length < this.iMinimumSearchChars)
696
	{
697
		this.aCache = [];
698
		this.autoSuggestHide();
699
		return true;
700
	}
701
702
	if (sSearchString.substring(0, sRealLastSearch.length) === sRealLastSearch)
703
	{
704
		// Instead of hitting the server again, just narrow down the results...
705
		let aNewCache = [],
706
			j = 0,
707
			sLowercaseSearch = sSearchString.toLowerCase();
708
709
		for (let k = 0; k < this.aCache.length; k++)
710
		{
711
			if (this.aCache[k].sItemName.slice(0, sSearchString.length).toLowerCase() === sLowercaseSearch)
712
			{
713
				aNewCache[j++] = this.aCache[k];
714
			}
715
		}
716
717
		this.aCache = [];
718
		if (aNewCache.length !== 0)
719
		{
720
			this.aCache = aNewCache;
721
722
			// Repopulate.
723
			this.populateDiv(this.aCache);
724
725
			// Check it can be seen.
726
			this.autoSuggestShow();
727
728
			return true;
729
		}
730
	}
731
732
	// In progress means destroy!
733
	if (typeof this.oXmlRequestHandle === 'object' && this.oXmlRequestHandle !== null)
734
	{
735
		this.oXmlRequestHandle.abort();
736
	}
737
738
	// Clean the text handle.
739
	sSearchString = sSearchString.php_urlencode();
740
741
	// Get the document.
742
	let obj = {
743
			'suggest_type': this.opt.sSearchType,
744
			'search': sSearchString,
745
			'time': new Date().getTime()
746
		},
747
		postString;
748
749
	// Post values plus session
750
	postString = serialize(obj) + '&' + this.opt.sSessionVar + '=' + this.opt.sSessionId;
751
752
	sendXMLDocument.call(this, this.sRetrieveURL.replace(/%scripturl%/g, elk_prepareScriptUrl(elk_scripturl)), postString, this.onSuggestionReceived);
0 ignored issues
show
The variable sendXMLDocument seems to be never declared. If this is a global, consider adding a /** global: sendXMLDocument */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
753
754
	return true;
755
};
756