Mercurial > hg > vamp-website
comparison forum/Themes/Vamp/scripts/suggest.js @ 76:e3e11437ecea website
Add forum code
author | Chris Cannam |
---|---|
date | Sun, 07 Jul 2013 11:25:48 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
75:72f59aa7e503 | 76:e3e11437ecea |
---|---|
1 // This file contains javascript associated with a autosuggest control | |
2 function smc_AutoSuggest(oOptions) | |
3 { | |
4 this.opt = oOptions; | |
5 | |
6 // Store the handle to the text box. | |
7 this.oTextHandle = document.getElementById(this.opt.sControlId); | |
8 this.oRealTextHandle = null; | |
9 | |
10 this.oSuggestDivHandle = null; | |
11 this.sLastSearch = ''; | |
12 this.sLastDirtySearch = ''; | |
13 this.oSelectedDiv = null; | |
14 this.aCache = []; | |
15 this.aDisplayData = []; | |
16 | |
17 this.sRetrieveURL = 'sRetrieveURL' in this.opt ? this.opt.sRetrieveURL : '%scripturl%action=suggest;suggest_type=%suggest_type%;search=%search%;%sessionVar%=%sessionID%;xml;time=%time%'; | |
18 | |
19 // How many objects can we show at once? | |
20 this.iMaxDisplayQuantity = 'iMaxDisplayQuantity' in this.opt ? this.opt.iMaxDisplayQuantity : 15; | |
21 | |
22 // How many characters shall we start searching on? | |
23 this.iMinimumSearchChars = 'iMinimumSearchChars' in this.opt ? this.opt.iMinimumSearchChars : 3; | |
24 | |
25 // Should selected items be added to a list? | |
26 this.bItemList = 'bItemList' in this.opt ? this.opt.bItemList : false; | |
27 | |
28 // Are there any items that should be added in advance? | |
29 this.aListItems = 'aListItems' in this.opt ? this.opt.aListItems : []; | |
30 | |
31 this.sItemTemplate = 'sItemTemplate' in this.opt ? 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> <img src="%images_url%/pm_recipient_delete.gif" alt="%delete_text%" title="%delete_text%" onclick="return %self%.deleteAddedItem(%item_id%);" />'; | |
32 | |
33 this.sTextDeleteItem = 'sTextDeleteItem' in this.opt ? this.opt.sTextDeleteItem : ''; | |
34 | |
35 this.oCallback = {}; | |
36 this.bDoAutoAdd = false; | |
37 this.iItemCount = 0; | |
38 | |
39 this.oHideTimer = null; | |
40 this.bPositionComplete = false; | |
41 | |
42 this.oXmlRequestHandle = null; | |
43 | |
44 // Just make sure the page is loaded before calling the init. | |
45 addLoadEvent(this.opt.sSelf + '.init();'); | |
46 } | |
47 | |
48 smc_AutoSuggest.prototype.init = function() | |
49 { | |
50 if (!window.XMLHttpRequest) | |
51 return false; | |
52 | |
53 // Create a div that'll contain the results later on. | |
54 this.oSuggestDivHandle = document.createElement('div'); | |
55 this.oSuggestDivHandle.className = 'auto_suggest_div'; | |
56 document.body.appendChild(this.oSuggestDivHandle); | |
57 | |
58 // Create a backup text input. | |
59 this.oRealTextHandle = document.createElement('input'); | |
60 this.oRealTextHandle.type = 'hidden'; | |
61 this.oRealTextHandle.name = this.oTextHandle.name; | |
62 this.oRealTextHandle.value = this.oTextHandle.value; | |
63 this.oTextHandle.form.appendChild(this.oRealTextHandle); | |
64 | |
65 // Disable autocomplete in any browser by obfuscating the name. | |
66 this.oTextHandle.name = 'dummy_' + Math.floor(Math.random() * 1000000); | |
67 this.oTextHandle.autocomplete = 'off'; | |
68 | |
69 this.oTextHandle.instanceRef = this; | |
70 | |
71 var fOnKeyDown = function (oEvent) { | |
72 return this.instanceRef.handleKey(oEvent); | |
73 }; | |
74 is_opera ? this.oTextHandle.onkeypress = fOnKeyDown : this.oTextHandle.onkeydown = fOnKeyDown; | |
75 | |
76 this.oTextHandle.onkeyup = function (oEvent) { | |
77 return this.instanceRef.autoSuggestUpdate(oEvent); | |
78 }; | |
79 | |
80 this.oTextHandle.onchange = function (oEvent) { | |
81 return this.instanceRef.autoSuggestUpdate(oEvent); | |
82 }; | |
83 | |
84 this.oTextHandle.onblur = function (oEvent) { | |
85 return this.instanceRef.autoSuggestHide(oEvent); | |
86 }; | |
87 | |
88 this.oTextHandle.onfocus = function (oEvent) { | |
89 return this.instanceRef.autoSuggestUpdate(oEvent); | |
90 }; | |
91 | |
92 if (this.bItemList) | |
93 { | |
94 if ('sItemListContainerId' in this.opt) | |
95 this.oItemList = document.getElementById(this.opt.sItemListContainerId); | |
96 else | |
97 { | |
98 this.oItemList = document.createElement('div'); | |
99 this.oTextHandle.parentNode.insertBefore(this.oItemList, this.oTextHandle.nextSibling); | |
100 } | |
101 } | |
102 | |
103 if (this.aListItems.length > 0) | |
104 for (var i = 0, n = this.aListItems.length; i < n; i++) | |
105 this.addItemLink(this.aListItems[i].sItemId, this.aListItems[i].sItemName); | |
106 | |
107 return true; | |
108 } | |
109 | |
110 // Was it an enter key - if so assume they are trying to select something. | |
111 smc_AutoSuggest.prototype.handleKey = function(oEvent) | |
112 { | |
113 // Grab the event object, one way or the other | |
114 if (!oEvent) | |
115 oEvent = window.event; | |
116 | |
117 // Get the keycode of the key that was pressed. | |
118 var iKeyPress = 0; | |
119 if ('keyCode' in oEvent) | |
120 iKeyPress = oEvent.keyCode; | |
121 else if ('which' in oEvent) | |
122 iKeyPress = oEvent.which; | |
123 | |
124 switch (iKeyPress) | |
125 { | |
126 // Tab. | |
127 case 9: | |
128 if (this.aDisplayData.length > 0) | |
129 { | |
130 if (this.oSelectedDiv != null) | |
131 this.itemClicked(this.oSelectedDiv); | |
132 else | |
133 this.handleSubmit(); | |
134 } | |
135 | |
136 // Continue to the next control. | |
137 return true; | |
138 break; | |
139 | |
140 // Enter. | |
141 case 13: | |
142 if (this.aDisplayData.length > 0 && this.oSelectedDiv != null) | |
143 { | |
144 this.itemClicked(this.oSelectedDiv); | |
145 | |
146 // Do our best to stop it submitting the form! | |
147 return false; | |
148 } | |
149 else | |
150 return true; | |
151 | |
152 break; | |
153 | |
154 // Up/Down arrow? | |
155 case 38: | |
156 case 40: | |
157 if (this.aDisplayData.length && this.oSuggestDivHandle.style.visibility != 'hidden') | |
158 { | |
159 // Loop through the display data trying to find our entry. | |
160 var bPrevHandle = false; | |
161 var oToHighlight = null; | |
162 for (var i = 0; i < this.aDisplayData.length; i++) | |
163 { | |
164 // If we're going up and yet the top one was already selected don't go around. | |
165 if (this.oSelectedDiv != null && this.oSelectedDiv == this.aDisplayData[i] && i == 0 && iKeyPress == 38) | |
166 { | |
167 oToHighlight = this.oSelectedDiv; | |
168 break; | |
169 } | |
170 // If nothing is selected and we are going down then we select the first one. | |
171 if (this.oSelectedDiv == null && iKeyPress == 40) | |
172 { | |
173 oToHighlight = this.aDisplayData[i]; | |
174 break; | |
175 } | |
176 | |
177 // If the previous handle was the actual previously selected one and we're hitting down then this is the one we want. | |
178 if (bPrevHandle != false && bPrevHandle == this.oSelectedDiv && iKeyPress == 40) | |
179 { | |
180 oToHighlight = this.aDisplayData[i]; | |
181 break; | |
182 } | |
183 // If we're going up and this is the previously selected one then we want the one before, if there was one. | |
184 if (bPrevHandle != false && this.aDisplayData[i] == this.oSelectedDiv && iKeyPress == 38) | |
185 { | |
186 oToHighlight = bPrevHandle; | |
187 break; | |
188 } | |
189 // Make the previous handle this! | |
190 bPrevHandle = this.aDisplayData[i]; | |
191 } | |
192 | |
193 // If we don't have one to highlight by now then it must be the last one that we're after. | |
194 if (oToHighlight == null) | |
195 oToHighlight = bPrevHandle; | |
196 | |
197 // Remove any old highlighting. | |
198 if (this.oSelectedDiv != null) | |
199 this.itemMouseOut(this.oSelectedDiv); | |
200 // Mark what the selected div now is. | |
201 this.oSelectedDiv = oToHighlight; | |
202 this.itemMouseOver(this.oSelectedDiv); | |
203 } | |
204 break; | |
205 } | |
206 return true; | |
207 } | |
208 | |
209 // Functions for integration. | |
210 smc_AutoSuggest.prototype.registerCallback = function(sCallbackType, sCallback) | |
211 { | |
212 switch (sCallbackType) | |
213 { | |
214 case 'onBeforeAddItem': | |
215 this.oCallback.onBeforeAddItem = sCallback; | |
216 break; | |
217 | |
218 case 'onAfterAddItem': | |
219 this.oCallback.onAfterAddItem = sCallback; | |
220 break; | |
221 | |
222 case 'onAfterDeleteItem': | |
223 this.oCallback.onAfterDeleteItem = sCallback; | |
224 break; | |
225 | |
226 case 'onBeforeUpdate': | |
227 this.oCallback.onBeforeUpdate = sCallback; | |
228 break; | |
229 } | |
230 } | |
231 | |
232 // User hit submit? | |
233 smc_AutoSuggest.prototype.handleSubmit = function() | |
234 { | |
235 var bReturnValue = true; | |
236 var oFoundEntry = null; | |
237 | |
238 // Do we have something that matches the current text? | |
239 for (var i = 0; i < this.aCache.length; i++) | |
240 { | |
241 if (this.sLastSearch.toLowerCase() == this.aCache[i].sItemName.toLowerCase().substr(0, this.sLastSearch.length)) | |
242 { | |
243 // Exact match? | |
244 if (this.sLastSearch.length == this.aCache[i].sItemName.length) | |
245 { | |
246 // This is the one! | |
247 oFoundEntry = { | |
248 sItemId: this.aCache[i].sItemId, | |
249 sItemName: this.aCache[i].sItemName | |
250 }; | |
251 break; | |
252 } | |
253 | |
254 // Not an exact match, but it'll do for now. | |
255 else | |
256 { | |
257 // If we have two matches don't find anything. | |
258 if (oFoundEntry != null) | |
259 bReturnValue = false; | |
260 else | |
261 oFoundEntry = { | |
262 sItemId: this.aCache[i].sItemId, | |
263 sItemName: this.aCache[i].sItemName | |
264 }; | |
265 } | |
266 } | |
267 } | |
268 | |
269 if (oFoundEntry == null || bReturnValue == false) | |
270 return bReturnValue; | |
271 else | |
272 { | |
273 this.addItemLink(oFoundEntry.sItemId, oFoundEntry.sItemName, true); | |
274 return false; | |
275 } | |
276 } | |
277 | |
278 // Positions the box correctly on the window. | |
279 smc_AutoSuggest.prototype.positionDiv = function() | |
280 { | |
281 // Only do it once. | |
282 if (this.bPositionComplete) | |
283 return true; | |
284 | |
285 this.bPositionComplete = true; | |
286 | |
287 // Put the div under the text box. | |
288 var aParentPos = smf_itemPos(this.oTextHandle); | |
289 | |
290 this.oSuggestDivHandle.style.left = aParentPos[0] + 'px'; | |
291 this.oSuggestDivHandle.style.top = (aParentPos[1] + this.oTextHandle.offsetHeight) + 'px'; | |
292 this.oSuggestDivHandle.style.width = this.oTextHandle.style.width; | |
293 | |
294 return true; | |
295 } | |
296 | |
297 // Do something after clicking an item. | |
298 smc_AutoSuggest.prototype.itemClicked = function(oCurElement) | |
299 { | |
300 // Is there a div that we are populating? | |
301 if (this.bItemList) | |
302 this.addItemLink(oCurElement.sItemId, oCurElement.innerHTML); | |
303 | |
304 // Otherwise clear things down. | |
305 else | |
306 this.oTextHandle.value = oCurElement.innerHTML.php_unhtmlspecialchars(); | |
307 | |
308 this.oRealTextHandle.value = this.oTextHandle.value; | |
309 this.autoSuggestActualHide(); | |
310 this.oSelectedDiv = null; | |
311 } | |
312 | |
313 // Remove the last searched for name from the search box. | |
314 smc_AutoSuggest.prototype.removeLastSearchString = function () | |
315 { | |
316 // Remove the text we searched for from the div. | |
317 var sTempText = this.oTextHandle.value.toLowerCase(); | |
318 var iStartString = sTempText.indexOf(this.sLastSearch.toLowerCase()); | |
319 // Just attempt to remove the bits we just searched for. | |
320 if (iStartString != -1) | |
321 { | |
322 while (iStartString > 0) | |
323 { | |
324 if (sTempText.charAt(iStartString - 1) == '"' || sTempText.charAt(iStartString - 1) == ',' || sTempText.charAt(iStartString - 1) == ' ') | |
325 { | |
326 iStartString--; | |
327 if (sTempText.charAt(iStartString - 1) == ',') | |
328 break; | |
329 } | |
330 else | |
331 break; | |
332 } | |
333 | |
334 // Now remove anything from iStartString upwards. | |
335 this.oTextHandle.value = this.oTextHandle.value.substr(0, iStartString); | |
336 } | |
337 // Just take it all. | |
338 else | |
339 this.oTextHandle.value = ''; | |
340 } | |
341 | |
342 // Add a result if not already done. | |
343 smc_AutoSuggest.prototype.addItemLink = function (sItemId, sItemName, bFromSubmit) | |
344 { | |
345 // Increase the internal item count. | |
346 this.iItemCount ++; | |
347 | |
348 // If there's a callback then call it. | |
349 if ('oCallback' in this && 'onBeforeAddItem' in this.oCallback && typeof(this.oCallback.onBeforeAddItem) == 'string') | |
350 { | |
351 // If it returns false the item must not be added. | |
352 if (!eval(this.oCallback.onBeforeAddItem + '(' + this.opt.sSelf + ', \'' + sItemId + '\');')) | |
353 return; | |
354 } | |
355 | |
356 var oNewDiv = document.createElement('div'); | |
357 oNewDiv.id = 'suggest_' + this.opt.sSuggestId + '_' + sItemId; | |
358 setInnerHTML(oNewDiv, this.sItemTemplate.replace(/%post_name%/g, this.opt.sPostName).replace(/%item_id%/g, sItemId).replace(/%item_href%/g, smf_prepareScriptUrl(smf_scripturl) + this.opt.sURLMask.replace(/%item_id%/g, sItemId)).replace(/%item_name%/g, sItemName).replace(/%images_url%/g, smf_images_url).replace(/%self%/g, this.opt.sSelf).replace(/%delete_text%/g, this.sTextDeleteItem)); | |
359 this.oItemList.appendChild(oNewDiv); | |
360 | |
361 // If there's a registered callback, call it. | |
362 if ('oCallback' in this && 'onAfterAddItem' in this.oCallback && typeof(this.oCallback.onAfterAddItem) == 'string') | |
363 eval(this.oCallback.onAfterAddItem + '(' + this.opt.sSelf + ', \'' + oNewDiv.id + '\', ' + this.iItemCount + ');'); | |
364 | |
365 // Clear the div a bit. | |
366 this.removeLastSearchString(); | |
367 | |
368 // If we came from a submit, and there's still more to go, turn on auto add for all the other things. | |
369 this.bDoAutoAdd = this.oTextHandle.value != '' && bFromSubmit; | |
370 | |
371 // Update the fellow.. | |
372 this.autoSuggestUpdate(); | |
373 } | |
374 | |
375 // Delete an item that has been added, if at all? | |
376 smc_AutoSuggest.prototype.deleteAddedItem = function (sItemId) | |
377 { | |
378 var oDiv = document.getElementById('suggest_' + this.opt.sSuggestId + '_' + sItemId); | |
379 | |
380 // Remove the div if it exists. | |
381 if (typeof(oDiv) == 'object' && oDiv != null) | |
382 { | |
383 oDiv.parentNode.removeChild(document.getElementById('suggest_' + this.opt.sSuggestId + '_' + sItemId)); | |
384 | |
385 // Decrease the internal item count. | |
386 this.iItemCount --; | |
387 | |
388 // If there's a registered callback, call it. | |
389 if ('oCallback' in this && 'onAfterDeleteItem' in this.oCallback && typeof(this.oCallback.onAfterDeleteItem) == 'string') | |
390 eval(this.oCallback.onAfterDeleteItem + '(' + this.opt.sSelf + ', ' + this.iItemCount + ');'); | |
391 } | |
392 | |
393 return false; | |
394 } | |
395 | |
396 // Hide the box. | |
397 smc_AutoSuggest.prototype.autoSuggestHide = function () | |
398 { | |
399 // Delay to allow events to propogate through.... | |
400 this.oHideTimer = setTimeout(this.opt.sSelf + '.autoSuggestActualHide();', 250); | |
401 } | |
402 | |
403 // Do the actual hiding after a timeout. | |
404 smc_AutoSuggest.prototype.autoSuggestActualHide = function() | |
405 { | |
406 this.oSuggestDivHandle.style.display = 'none'; | |
407 this.oSuggestDivHandle.style.visibility = 'hidden'; | |
408 this.oSelectedDiv = null; | |
409 } | |
410 | |
411 // Show the box. | |
412 smc_AutoSuggest.prototype.autoSuggestShow = function() | |
413 { | |
414 if (this.oHideTimer) | |
415 { | |
416 clearTimeout(this.oHideTimer); | |
417 this.oHideTimer = false; | |
418 } | |
419 | |
420 this.positionDiv(); | |
421 | |
422 this.oSuggestDivHandle.style.visibility = 'visible'; | |
423 this.oSuggestDivHandle.style.display = ''; | |
424 } | |
425 | |
426 // Populate the actual div. | |
427 smc_AutoSuggest.prototype.populateDiv = function(aResults) | |
428 { | |
429 // Cannot have any children yet. | |
430 while (this.oSuggestDivHandle.childNodes.length > 0) | |
431 { | |
432 // Tidy up the events etc too. | |
433 this.oSuggestDivHandle.childNodes[0].onmouseover = null; | |
434 this.oSuggestDivHandle.childNodes[0].onmouseout = null; | |
435 this.oSuggestDivHandle.childNodes[0].onclick = null; | |
436 | |
437 this.oSuggestDivHandle.removeChild(this.oSuggestDivHandle.childNodes[0]); | |
438 } | |
439 | |
440 // Something to display? | |
441 if (typeof(aResults) == 'undefined') | |
442 { | |
443 this.aDisplayData = []; | |
444 return false; | |
445 } | |
446 | |
447 var aNewDisplayData = []; | |
448 for (var i = 0; i < (aResults.length > this.iMaxDisplayQuantity ? this.iMaxDisplayQuantity : aResults.length); i++) | |
449 { | |
450 // Create the sub element | |
451 var oNewDivHandle = document.createElement('div'); | |
452 oNewDivHandle.sItemId = aResults[i].sItemId; | |
453 oNewDivHandle.className = 'auto_suggest_item'; | |
454 oNewDivHandle.innerHTML = aResults[i].sItemName; | |
455 //oNewDivHandle.style.width = this.oTextHandle.style.width; | |
456 | |
457 this.oSuggestDivHandle.appendChild(oNewDivHandle); | |
458 | |
459 // Attach some events to it so we can do stuff. | |
460 oNewDivHandle.instanceRef = this; | |
461 oNewDivHandle.onmouseover = function (oEvent) | |
462 { | |
463 this.instanceRef.itemMouseOver(this); | |
464 } | |
465 oNewDivHandle.onmouseout = function (oEvent) | |
466 { | |
467 this.instanceRef.itemMouseOut(this); | |
468 } | |
469 oNewDivHandle.onclick = function (oEvent) | |
470 { | |
471 this.instanceRef.itemClicked(this); | |
472 } | |
473 | |
474 | |
475 aNewDisplayData[i] = oNewDivHandle; | |
476 } | |
477 | |
478 this.aDisplayData = aNewDisplayData; | |
479 | |
480 return true; | |
481 } | |
482 | |
483 // Refocus the element. | |
484 smc_AutoSuggest.prototype.itemMouseOver = function (oCurElement) | |
485 { | |
486 this.oSelectedDiv = oCurElement; | |
487 oCurElement.className = 'auto_suggest_item_hover'; | |
488 } | |
489 | |
490 // Onfocus the element | |
491 smc_AutoSuggest.prototype.itemMouseOut = function (oCurElement) | |
492 { | |
493 oCurElement.className = 'auto_suggest_item'; | |
494 } | |
495 | |
496 smc_AutoSuggest.prototype.onSuggestionReceived = function (oXMLDoc) | |
497 { | |
498 var sQuoteText = ''; | |
499 var aItems = oXMLDoc.getElementsByTagName('item'); | |
500 this.aCache = []; | |
501 for (var i = 0; i < aItems.length; i++) | |
502 { | |
503 this.aCache[i] = { | |
504 sItemId: aItems[i].getAttribute('id'), | |
505 sItemName: aItems[i].childNodes[0].nodeValue | |
506 }; | |
507 | |
508 // If we're doing auto add and we find the exact person, then add them! | |
509 if (this.bDoAutoAdd && this.sLastSearch == this.aCache[i].sItemName) | |
510 { | |
511 var oReturnValue = { | |
512 sItemId: this.aCache[i].sItemId, | |
513 sItemName: this.aCache[i].sItemName | |
514 }; | |
515 this.aCache = []; | |
516 return this.addItemLink(oReturnValue.sItemId, oReturnValue.sItemName, true); | |
517 } | |
518 } | |
519 | |
520 // Check we don't try to keep auto updating! | |
521 this.bDoAutoAdd = false; | |
522 | |
523 // Populate the div. | |
524 this.populateDiv(this.aCache); | |
525 | |
526 // Make sure we can see it - if we can. | |
527 if (aItems.length == 0) | |
528 this.autoSuggestHide(); | |
529 else | |
530 this.autoSuggestShow(); | |
531 | |
532 return true; | |
533 } | |
534 | |
535 // Get a new suggestion. | |
536 smc_AutoSuggest.prototype.autoSuggestUpdate = function () | |
537 { | |
538 // If there's a callback then call it. | |
539 if ('onBeforeUpdate' in this.oCallback && typeof(this.oCallback.onBeforeUpdate) == 'string') | |
540 { | |
541 // If it returns false the item must not be added. | |
542 if (!eval(this.oCallback.onBeforeUpdate + '(' + this.opt.sSelf + ');')) | |
543 return false; | |
544 } | |
545 | |
546 this.oRealTextHandle.value = this.oTextHandle.value; | |
547 | |
548 if (isEmptyText(this.oTextHandle)) | |
549 { | |
550 this.aCache = []; | |
551 | |
552 this.populateDiv(); | |
553 | |
554 this.autoSuggestHide(); | |
555 | |
556 return true; | |
557 } | |
558 | |
559 // Nothing changed? | |
560 if (this.oTextHandle.value == this.sLastDirtySearch) | |
561 return true; | |
562 this.sLastDirtySearch = this.oTextHandle.value; | |
563 | |
564 // We're only actually interested in the last string. | |
565 var sSearchString = this.oTextHandle.value.replace(/^("[^"]+",[ ]*)+/, '').replace(/^([^,]+,[ ]*)+/, ''); | |
566 if (sSearchString.substr(0, 1) == '"') | |
567 sSearchString = sSearchString.substr(1); | |
568 | |
569 // Stop replication ASAP. | |
570 var sRealLastSearch = this.sLastSearch; | |
571 this.sLastSearch = sSearchString; | |
572 | |
573 // Either nothing or we've completed a sentance. | |
574 if (sSearchString == '' || sSearchString.substr(sSearchString.length - 1) == '"') | |
575 { | |
576 this.populateDiv(); | |
577 return true; | |
578 } | |
579 | |
580 // Nothing? | |
581 if (sRealLastSearch == sSearchString) | |
582 return true; | |
583 | |
584 // Too small? | |
585 else if (sSearchString.length < this.iMinimumSearchChars) | |
586 { | |
587 this.aCache = []; | |
588 this.autoSuggestHide(); | |
589 return true; | |
590 } | |
591 else if (sSearchString.substr(0, sRealLastSearch.length) == sRealLastSearch) | |
592 { | |
593 // Instead of hitting the server again, just narrow down the results... | |
594 var aNewCache = []; | |
595 var j = 0; | |
596 var sLowercaseSearch = sSearchString.toLowerCase(); | |
597 for (var k = 0; k < this.aCache.length; k++) | |
598 { | |
599 if (this.aCache[k].sItemName.substr(0, sSearchString.length).toLowerCase() == sLowercaseSearch) | |
600 aNewCache[j++] = this.aCache[k]; | |
601 } | |
602 | |
603 this.aCache = []; | |
604 if (aNewCache.length != 0) | |
605 { | |
606 this.aCache = aNewCache; | |
607 // Repopulate. | |
608 this.populateDiv(this.aCache); | |
609 | |
610 // Check it can be seen. | |
611 this.autoSuggestShow(); | |
612 | |
613 return true; | |
614 } | |
615 } | |
616 | |
617 // In progress means destroy! | |
618 if (typeof(this.oXmlRequestHandle) == 'object' && this.oXmlRequestHandle != null) | |
619 this.oXmlRequestHandle.abort(); | |
620 | |
621 // Clean the text handle. | |
622 sSearchString = sSearchString.php_to8bit().php_urlencode(); | |
623 | |
624 // Get the document. | |
625 this.tmpMethod = getXMLDocument; | |
626 this.oXmlRequestHandle = this.tmpMethod(this.sRetrieveURL.replace(/%scripturl%/g, smf_prepareScriptUrl(smf_scripturl)).replace(/%suggest_type%/g, this.opt.sSearchType).replace(/%search%/g, sSearchString).replace(/%sessionVar%/g, this.opt.sSessionVar).replace(/%sessionID%/g, this.opt.sSessionId).replace(/%time%/g, new Date().getTime()), this.onSuggestionReceived); | |
627 delete this.tmpMethod; | |
628 | |
629 return true; | |
630 } |