Skip to content

Commit 3e7fb81

Browse files
author
Tomas Kirda
committed
Update dist source.
1 parent 74ea7e3 commit 3e7fb81

File tree

1 file changed

+133
-38
lines changed

1 file changed

+133
-38
lines changed

dist/jquery.autocomplete.js

Lines changed: 133 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
that = this,
5555
defaults = {
5656
autoSelectFirst: false,
57-
appendTo: 'body',
57+
appendTo: document.body,
5858
serviceUrl: null,
5959
lookup: null,
6060
onSelect: null,
@@ -76,13 +76,18 @@
7676
dataType: 'text',
7777
currentRequest: null,
7878
triggerSelectOnValidInput: true,
79+
preventBadQueries: true,
7980
lookupFilter: function (suggestion, originalQuery, queryLowerCase) {
8081
return suggestion.value.toLowerCase().indexOf(queryLowerCase) !== -1;
8182
},
8283
paramName: 'query',
8384
transformResult: function (response) {
8485
return typeof response === 'string' ? $.parseJSON(response) : response;
85-
}
86+
},
87+
showNoSuggestionNotice: false,
88+
noSuggestionNotice: 'No results',
89+
orientation: 'bottom',
90+
forceFixPosition: false
8691
};
8792

8893
// Shared variables:
@@ -98,6 +103,7 @@
98103
that.onChange = null;
99104
that.isLocal = false;
100105
that.suggestionsContainer = null;
106+
that.noSuggestionsContainer = null;
101107
that.options = $.extend({}, defaults, options);
102108
that.classes = {
103109
selected: 'autocomplete-selected',
@@ -131,7 +137,8 @@
131137
suggestionSelector = '.' + that.classes.suggestion,
132138
selected = that.classes.selected,
133139
options = that.options,
134-
container;
140+
container,
141+
noSuggestionsContainer;
135142

136143
// Remove autocomplete attribute to prevent native suggestions:
137144
that.element.setAttribute('autocomplete', 'off');
@@ -143,6 +150,10 @@
143150
}
144151
};
145152

153+
// html() deals with many types: htmlString or Element or Array or jQuery
154+
that.noSuggestionsContainer = $('<div class="autocomplete-no-suggestion"></div>')
155+
.html(this.options.noSuggestionNotice).get(0);
156+
146157
that.suggestionsContainer = Autocomplete.utils.createNode(options.containerClass);
147158

148159
container = $(that.suggestionsContainer);
@@ -170,8 +181,6 @@
170181
that.select($(this).data('index'));
171182
});
172183

173-
that.fixPosition();
174-
175184
that.fixPositionCapture = function () {
176185
if (that.visible) {
177186
that.fixPosition();
@@ -211,6 +220,8 @@
211220
options.lookup = that.verifySuggestionsFormat(options.lookup);
212221
}
213222

223+
options.orientation = that.validateOrientation(options.orientation, 'bottom');
224+
214225
// Adjust height, width and z-index:
215226
$(that.suggestionsContainer).css({
216227
'max-height': options.maxHeight + 'px',
@@ -219,6 +230,7 @@
219230
});
220231
},
221232

233+
222234
clearCache: function () {
223235
this.cachedResponse = {};
224236
this.badQueries = [];
@@ -243,27 +255,62 @@
243255
},
244256

245257
fixPosition: function () {
246-
var that = this,
247-
offset,
248-
styles;
258+
// Use only when container has already its content
249259

250-
// Don't adjsut position if custom container has been specified:
251-
if (that.options.appendTo !== 'body') {
260+
var that = this,
261+
$container = $(that.suggestionsContainer),
262+
containerParent = $container.parent().get(0);
263+
// Fix position automatically when appended to body.
264+
// In other cases force parameter must be given.
265+
if (containerParent !== document.body && !that.options.forceFixPosition)
252266
return;
267+
268+
// Choose orientation
269+
var orientation = that.options.orientation,
270+
containerHeight = $container.outerHeight(),
271+
height = that.el.outerHeight(),
272+
offset = that.el.offset(),
273+
styles = { 'top': offset.top, 'left': offset.left };
274+
275+
if (orientation == 'auto') {
276+
var viewPortHeight = $(window).height(),
277+
scrollTop = $(window).scrollTop(),
278+
top_overflow = -scrollTop + offset.top - containerHeight,
279+
bottom_overflow = scrollTop + viewPortHeight - (offset.top + height + containerHeight);
280+
281+
if (Math.max(top_overflow, bottom_overflow) === top_overflow)
282+
orientation = 'top';
283+
else
284+
orientation = 'bottom';
253285
}
254286

255-
offset = that.el.offset();
287+
if (orientation === 'top')
288+
styles.top += -containerHeight;
289+
else
290+
styles.top += height;
256291

257-
styles = {
258-
top: (offset.top + that.el.outerHeight()) + 'px',
259-
left: offset.left + 'px'
260-
};
292+
// If container is not positioned to body,
293+
// correct its position using offset parent offset
294+
if(containerParent !== document.body) {
295+
var opacity = $container.css('opacity'),
296+
parentOffsetDiff;
297+
if (!that.visible)
298+
$container.css('opacity', 0).show();
299+
300+
parentOffsetDiff = $container.offsetParent().offset();
301+
styles.top -= parentOffsetDiff.top;
302+
styles.left -= parentOffsetDiff.left;
303+
304+
if (!that.visible)
305+
$container.css('opacity', opacity).hide();
306+
}
261307

308+
// -2px to account for suggestions border.
262309
if (that.options.width === 'auto') {
263310
styles.width = (that.el.outerWidth() - 2) + 'px';
264311
}
265312

266-
$(that.suggestionsContainer).css(styles);
313+
$container.css(styles);
267314
},
268315

269316
enableKillerFn: function () {
@@ -473,19 +520,19 @@
473520
that = this,
474521
options = that.options,
475522
serviceUrl = options.serviceUrl,
476-
data,
523+
params,
477524
cacheKey;
478525

479526
options.params[options.paramName] = q;
480-
data = options.ignoreParams ? null : options.params;
527+
params = options.ignoreParams ? null : options.params;
481528

482529
if (that.isLocal) {
483530
response = that.getSuggestionsLocal(q);
484531
} else {
485532
if ($.isFunction(serviceUrl)) {
486533
serviceUrl = serviceUrl.call(that.element, q);
487534
}
488-
cacheKey = serviceUrl + '?' + $.param(data || {});
535+
cacheKey = serviceUrl + '?' + $.param(params || {});
489536
response = that.cachedResponse[cacheKey];
490537
}
491538

@@ -501,20 +548,26 @@
501548
}
502549
that.currentRequest = $.ajax({
503550
url: serviceUrl,
504-
data: data,
551+
data: params,
505552
type: options.type,
506553
dataType: options.dataType
507554
}).done(function (data) {
555+
var result;
508556
that.currentRequest = null;
509-
that.processResponse(data, q, cacheKey);
510-
options.onSearchComplete.call(that.element, q);
557+
result = options.transformResult(data);
558+
that.processResponse(result, q, cacheKey);
559+
options.onSearchComplete.call(that.element, q, result.suggestions);
511560
}).fail(function (jqXHR, textStatus, errorThrown) {
512561
options.onSearchError.call(that.element, q, jqXHR, textStatus, errorThrown);
513562
});
514563
}
515564
},
516565

517566
isBadQuery: function (q) {
567+
if (!this.options.preventBadQueries){
568+
return false;
569+
}
570+
518571
var badQueries = this.badQueries,
519572
i = badQueries.length;
520573

@@ -537,7 +590,7 @@
537590

538591
suggest: function () {
539592
if (this.suggestions.length === 0) {
540-
this.hide();
593+
this.options.showNoSuggestionNotice ? this.noSuggestions() : this.hide();
541594
return;
542595
}
543596

@@ -548,6 +601,7 @@
548601
className = that.classes.suggestion,
549602
classSelected = that.classes.selected,
550603
container = $(that.suggestionsContainer),
604+
noSuggestionsContainer = $(that.noSuggestionsContainer),
551605
beforeRender = options.beforeRender,
552606
html = '',
553607
index,
@@ -566,15 +620,9 @@
566620
html += '<div class="' + className + '" data-index="' + i + '">' + formatResult(suggestion, value) + '</div>';
567621
});
568622

569-
// If width is auto, adjust width before displaying suggestions,
570-
// because if instance was created before input had width, it will be zero.
571-
// Also it adjusts if input width has changed.
572-
// -2px to account for suggestions border.
573-
if (options.width === 'auto') {
574-
width = that.el.outerWidth() - 2;
575-
container.width(width > 0 ? width : 300);
576-
}
623+
this.adjustContainerWidth();
577624

625+
noSuggestionsContainer.detach();
578626
container.html(html);
579627

580628
// Select first value by default:
@@ -587,12 +635,49 @@
587635
beforeRender.call(that.element, container);
588636
}
589637

638+
that.fixPosition();
639+
590640
container.show();
591641
that.visible = true;
592642

593643
that.findBestHint();
594644
},
595645

646+
noSuggestions: function() {
647+
var that = this,
648+
container = $(that.suggestionsContainer),
649+
noSuggestionsContainer = $(that.noSuggestionsContainer);
650+
651+
this.adjustContainerWidth();
652+
653+
// Some explicit steps. Be careful here as it easy to get
654+
// noSuggestionsContainer removed from DOM if not detached properly.
655+
noSuggestionsContainer.detach();
656+
container.empty(); // clean suggestions if any
657+
container.append(noSuggestionsContainer);
658+
659+
that.fixPosition();
660+
661+
container.show();
662+
that.visible = true;
663+
},
664+
665+
adjustContainerWidth: function() {
666+
var that = this,
667+
options = that.options,
668+
width,
669+
container = $(that.suggestionsContainer);
670+
671+
// If width is auto, adjust width before displaying suggestions,
672+
// because if instance was created before input had width, it will be zero.
673+
// Also it adjusts if input width has changed.
674+
// -2px to account for suggestions border.
675+
if (options.width === 'auto') {
676+
width = that.el.outerWidth() - 2;
677+
container.width(width > 0 ? width : 300);
678+
}
679+
},
680+
596681
findBestHint: function () {
597682
var that = this,
598683
value = that.el.val().toLowerCase(),
@@ -637,18 +722,24 @@
637722
return suggestions;
638723
},
639724

640-
processResponse: function (response, originalQuery, cacheKey) {
725+
validateOrientation: function(orientation, fallback) {
726+
orientation = orientation.trim().toLowerCase();
727+
if(['auto', 'bottom', 'top'].indexOf(orientation) == '-1')
728+
orientation = fallback;
729+
return orientation
730+
},
731+
732+
processResponse: function (result, originalQuery, cacheKey) {
641733
var that = this,
642-
options = that.options,
643-
result = options.transformResult(response, originalQuery);
734+
options = that.options;
644735

645736
result.suggestions = that.verifySuggestionsFormat(result.suggestions);
646737

647738
// Cache results if cache is not disabled:
648739
if (!options.noCache) {
649740
that.cachedResponse[cacheKey] = result;
650-
if (result.suggestions.length === 0) {
651-
that.badQueries.push(cacheKey);
741+
if (options.preventBadQueries && result.suggestions.length === 0) {
742+
that.badQueries.push(originalQuery);
652743
}
653744
}
654745

@@ -754,7 +845,11 @@
754845
suggestion = that.suggestions[index];
755846

756847
that.currentValue = that.getValue(suggestion.value);
757-
that.el.val(that.currentValue);
848+
849+
if (that.currentValue !== that.el.val()) {
850+
that.el.val(that.currentValue);
851+
}
852+
758853
that.signalHint(null);
759854
that.suggestions = [];
760855
that.selection = suggestion;
@@ -794,7 +889,7 @@
794889
};
795890

796891
// Create chainable jQuery plugin:
797-
$.fn.autocomplete = function (options, args) {
892+
$.fn.autocomplete = function (options, args) {
798893
var dataKey = 'autocomplete';
799894
// If function invoked without argument return
800895
// instance of the first matched element:

0 commit comments

Comments
 (0)