|
1 | 1 | /**
|
2 |
| -* Ajax Autocomplete for jQuery, version 1.2.8 |
| 2 | +* Ajax Autocomplete for jQuery, version 1.2.9 |
3 | 3 | * (c) 2013 Tomas Kirda
|
4 | 4 | *
|
5 | 5 | * Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license.
|
|
75 | 75 | tabDisabled: false,
|
76 | 76 | dataType: 'text',
|
77 | 77 | currentRequest: null,
|
| 78 | + triggerSelectOnValidInput: true, |
78 | 79 | lookupFilter: function (suggestion, originalQuery, queryLowerCase) {
|
79 | 80 | return suggestion.value.toLowerCase().indexOf(queryLowerCase) !== -1;
|
80 | 81 | },
|
|
92 | 93 | that.selectedIndex = -1;
|
93 | 94 | that.currentValue = that.element.value;
|
94 | 95 | that.intervalId = 0;
|
95 |
| - that.cachedResponse = []; |
| 96 | + that.cachedResponse = {}; |
96 | 97 | that.onChangeInterval = null;
|
97 | 98 | that.onChange = null;
|
98 | 99 | that.isLocal = false;
|
|
219 | 220 | },
|
220 | 221 |
|
221 | 222 | clearCache: function () {
|
222 |
| - this.cachedResponse = []; |
| 223 | + this.cachedResponse = {}; |
223 | 224 | this.badQueries = [];
|
224 | 225 | },
|
225 | 226 |
|
|
390 | 391 |
|
391 | 392 | onValueChange: function () {
|
392 | 393 | var that = this,
|
393 |
| - q; |
| 394 | + options = that.options, |
| 395 | + value = that.el.val(), |
| 396 | + query = that.getQuery(value), |
| 397 | + index; |
394 | 398 |
|
395 | 399 | if (that.selection) {
|
396 | 400 | that.selection = null;
|
397 |
| - (that.options.onInvalidateSelection || $.noop)(); |
| 401 | + (options.onInvalidateSelection || $.noop).call(that.element); |
398 | 402 | }
|
399 | 403 |
|
400 | 404 | clearInterval(that.onChangeInterval);
|
401 |
| - that.currentValue = that.el.val(); |
402 |
| - |
403 |
| - q = that.getQuery(that.currentValue); |
| 405 | + that.currentValue = value; |
404 | 406 | that.selectedIndex = -1;
|
405 | 407 |
|
406 |
| - if (q.length < that.options.minChars) { |
| 408 | + // Check existing suggestion for the match before proceeding: |
| 409 | + if (options.triggerSelectOnValidInput) { |
| 410 | + index = that.findSuggestionIndex(query); |
| 411 | + if (index !== -1) { |
| 412 | + that.select(index); |
| 413 | + return; |
| 414 | + } |
| 415 | + } |
| 416 | + |
| 417 | + if (query.length < options.minChars) { |
407 | 418 | that.hide();
|
408 | 419 | } else {
|
409 |
| - that.getSuggestions(q); |
| 420 | + that.getSuggestions(query); |
410 | 421 | }
|
411 | 422 | },
|
412 | 423 |
|
| 424 | + findSuggestionIndex: function (query) { |
| 425 | + var that = this, |
| 426 | + index = -1, |
| 427 | + queryLowerCase = query.toLowerCase(); |
| 428 | + |
| 429 | + $.each(that.suggestions, function (i, suggestion) { |
| 430 | + if (suggestion.value.toLowerCase() === queryLowerCase) { |
| 431 | + index = i; |
| 432 | + return false; |
| 433 | + } |
| 434 | + }); |
| 435 | + |
| 436 | + return index; |
| 437 | + }, |
| 438 | + |
413 | 439 | getQuery: function (value) {
|
414 | 440 | var delimiter = this.options.delimiter,
|
415 | 441 | parts;
|
416 | 442 |
|
417 | 443 | if (!delimiter) {
|
418 |
| - return $.trim(value); |
| 444 | + return value; |
419 | 445 | }
|
420 | 446 | parts = value.split(delimiter);
|
421 | 447 | return $.trim(parts[parts.length - 1]);
|
422 | 448 | },
|
423 | 449 |
|
424 | 450 | getSuggestionsLocal: function (query) {
|
425 | 451 | var that = this,
|
| 452 | + options = that.options, |
426 | 453 | queryLowerCase = query.toLowerCase(),
|
427 |
| - filter = that.options.lookupFilter; |
| 454 | + filter = options.lookupFilter, |
| 455 | + limit = parseInt(options.lookupLimit, 10), |
| 456 | + data; |
428 | 457 |
|
429 |
| - return { |
430 |
| - suggestions: $.grep(that.options.lookup, function (suggestion) { |
| 458 | + data = { |
| 459 | + suggestions: $.grep(options.lookup, function (suggestion) { |
431 | 460 | return filter(suggestion, query, queryLowerCase);
|
432 | 461 | })
|
433 | 462 | };
|
| 463 | + |
| 464 | + if (limit && data.suggestions.length > limit) { |
| 465 | + data.suggestions = data.suggestions.slice(0, limit); |
| 466 | + } |
| 467 | + |
| 468 | + return data; |
434 | 469 | },
|
435 | 470 |
|
436 | 471 | getSuggestions: function (q) {
|
437 | 472 | var response,
|
438 | 473 | that = this,
|
439 | 474 | options = that.options,
|
440 |
| - serviceUrl = options.serviceUrl; |
| 475 | + serviceUrl = options.serviceUrl, |
| 476 | + data, |
| 477 | + cacheKey; |
441 | 478 |
|
442 |
| - response = that.isLocal ? that.getSuggestionsLocal(q) : that.cachedResponse[q]; |
| 479 | + options.params[options.paramName] = q; |
| 480 | + data = options.ignoreParams ? null : options.params; |
| 481 | + |
| 482 | + if (that.isLocal) { |
| 483 | + response = that.getSuggestionsLocal(q); |
| 484 | + } else { |
| 485 | + if ($.isFunction(serviceUrl)) { |
| 486 | + serviceUrl = serviceUrl.call(that.element, q); |
| 487 | + } |
| 488 | + cacheKey = serviceUrl + '?' + $.param(data || {}); |
| 489 | + response = that.cachedResponse[cacheKey]; |
| 490 | + } |
443 | 491 |
|
444 | 492 | if (response && $.isArray(response.suggestions)) {
|
445 | 493 | that.suggestions = response.suggestions;
|
446 | 494 | that.suggest();
|
447 | 495 | } else if (!that.isBadQuery(q)) {
|
448 |
| - options.params[options.paramName] = q; |
449 | 496 | if (options.onSearchStart.call(that.element, options.params) === false) {
|
450 | 497 | return;
|
451 | 498 | }
|
452 |
| - if ($.isFunction(options.serviceUrl)) { |
453 |
| - serviceUrl = options.serviceUrl.call(that.element, q); |
454 |
| - } |
455 | 499 | if (that.currentRequest) {
|
456 | 500 | that.currentRequest.abort();
|
457 | 501 | }
|
458 | 502 | that.currentRequest = $.ajax({
|
459 | 503 | url: serviceUrl,
|
460 |
| - data: options.ignoreParams ? null : options.params, |
| 504 | + data: data, |
461 | 505 | type: options.type,
|
462 | 506 | dataType: options.dataType
|
463 | 507 | }).done(function (data) {
|
464 | 508 | that.currentRequest = null;
|
465 |
| - that.processResponse(data, q); |
466 |
| - options.onSearchComplete.call(that.element, q, data); |
| 509 | + that.processResponse(data, q, cacheKey); |
| 510 | + options.onSearchComplete.call(that.element, q); |
467 | 511 | }).fail(function (jqXHR, textStatus, errorThrown) {
|
468 | 512 | options.onSearchError.call(that.element, q, jqXHR, textStatus, errorThrown);
|
469 | 513 | });
|
|
498 | 542 | }
|
499 | 543 |
|
500 | 544 | var that = this,
|
501 |
| - formatResult = that.options.formatResult, |
| 545 | + options = that.options, |
| 546 | + formatResult = options.formatResult, |
502 | 547 | value = that.getQuery(that.currentValue),
|
503 | 548 | className = that.classes.suggestion,
|
504 | 549 | classSelected = that.classes.selected,
|
505 | 550 | container = $(that.suggestionsContainer),
|
506 |
| - beforeRender = that.options.beforeRender, |
| 551 | + beforeRender = options.beforeRender, |
507 | 552 | html = '',
|
| 553 | + index, |
508 | 554 | width;
|
509 | 555 |
|
| 556 | + if (options.triggerSelectOnValidInput) { |
| 557 | + index = that.findSuggestionIndex(value); |
| 558 | + if (index !== -1) { |
| 559 | + that.select(index); |
| 560 | + return; |
| 561 | + } |
| 562 | + } |
| 563 | + |
510 | 564 | // Build suggestions inner HTML:
|
511 | 565 | $.each(that.suggestions, function (i, suggestion) {
|
512 | 566 | html += '<div class="' + className + '" data-index="' + i + '">' + formatResult(suggestion, value) + '</div>';
|
|
516 | 570 | // because if instance was created before input had width, it will be zero.
|
517 | 571 | // Also it adjusts if input width has changed.
|
518 | 572 | // -2px to account for suggestions border.
|
519 |
| - if (that.options.width === 'auto') { |
| 573 | + if (options.width === 'auto') { |
520 | 574 | width = that.el.outerWidth() - 2;
|
521 | 575 | container.width(width > 0 ? width : 300);
|
522 | 576 | }
|
523 | 577 |
|
524 | 578 | container.html(html);
|
525 | 579 |
|
526 | 580 | // Select first value by default:
|
527 |
| - if (that.options.autoSelectFirst) { |
| 581 | + if (options.autoSelectFirst) { |
528 | 582 | that.selectedIndex = 0;
|
529 | 583 | container.children().first().addClass(classSelected);
|
530 | 584 | }
|
|
583 | 637 | return suggestions;
|
584 | 638 | },
|
585 | 639 |
|
586 |
| - processResponse: function (response, originalQuery) { |
| 640 | + processResponse: function (response, originalQuery, cacheKey) { |
587 | 641 | var that = this,
|
588 | 642 | options = that.options,
|
589 | 643 | result = options.transformResult(response, originalQuery);
|
|
592 | 646 |
|
593 | 647 | // Cache results if cache is not disabled:
|
594 | 648 | if (!options.noCache) {
|
595 |
| - that.cachedResponse[result[options.paramName]] = result; |
| 649 | + that.cachedResponse[cacheKey] = result; |
596 | 650 | if (result.suggestions.length === 0) {
|
597 |
| - that.badQueries.push(result[options.paramName]); |
| 651 | + that.badQueries.push(cacheKey); |
598 | 652 | }
|
599 | 653 | }
|
600 | 654 |
|
601 |
| - // Display suggestions only if returned query matches current value: |
602 |
| - if (originalQuery === that.getQuery(that.currentValue)) { |
603 |
| - that.suggestions = result.suggestions; |
604 |
| - that.suggest(); |
| 655 | + // Return if originalQuery is not matching current query: |
| 656 | + if (originalQuery !== that.getQuery(that.currentValue)) { |
| 657 | + return; |
605 | 658 | }
|
| 659 | + |
| 660 | + that.suggestions = result.suggestions; |
| 661 | + that.suggest(); |
606 | 662 | },
|
607 | 663 |
|
608 | 664 | activate: function (index) {
|
|
0 commit comments