2
0
mirror of https://github.com/devbridge/jQuery-Autocomplete.git synced 2024-11-22 12:55:12 +00:00

Merge branch 'develop' into develop_update-jasmine

This commit is contained in:
Tomas Kirda 2014-09-06 15:30:28 -05:00
commit d3e62d904d
10 changed files with 322 additions and 130 deletions

1
.gitignore vendored
View File

@ -4,3 +4,4 @@
/.idea* /.idea*
/*.xml /*.xml
/bower_components /bower_components
/node_modules/*

View File

@ -1,24 +1,24 @@
{ {
"name": "devbridge-autocomplete", "name": "devbridge-autocomplete",
"version": "1.2.9", "version": "1.2.12",
"homepage": "https://github.com/devbridge/jQuery-Autocomplete", "homepage": "https://github.com/devbridge/jQuery-Autocomplete",
"authors": [ "authors": [
"Tomas Kirda" "Tomas Kirda"
], ],
"description": "Autocomplete provides suggestions while you type into the text field.", "description": "Autocomplete provides suggestions while you type into the text field.",
"main": "dist/jquery.autocomplete.js", "main": "dist/jquery.autocomplete.js",
"keywords": [ "keywords": [
"ajax", "ajax",
"autocomplete" "autocomplete"
], ],
"license": "MIT", "license": "MIT",
"ignore": [ "ignore": [
"**/.*", "**/.*",
"node_modules", "node_modules",
"bower_components", "bower_components",
"spec" "spec"
], ],
"dependencies": { "dependencies": {
"jquery": ">=1.7" "jquery": ">=1.7"
} }
} }

View File

@ -6,7 +6,7 @@
"ajax", "ajax",
"autocomplete" "autocomplete"
], ],
"version": "1.2.9", "version": "1.2.12",
"author": { "author": {
"name": "Tomas Kirda", "name": "Tomas Kirda",
"url": "https://github.com/tkirda" "url": "https://github.com/tkirda"
@ -20,7 +20,7 @@
"bugs": "https://github.com/devbridge/jQuery-Autocomplete/issues?state=open", "bugs": "https://github.com/devbridge/jQuery-Autocomplete/issues?state=open",
"homepage": "https://github.com/devbridge/jQuery-Autocomplete", "homepage": "https://github.com/devbridge/jQuery-Autocomplete",
"docs": "https://github.com/devbridge/jQuery-Autocomplete", "docs": "https://github.com/devbridge/jQuery-Autocomplete",
"demo": "http://www.devbridge.com/projects/autocomplete/jquery/", "demo": "http://www.devbridge.com/sourcery/components/jquery-autocomplete/",
"download": "https://github.com/devbridge/jQuery-Autocomplete/tree/master/dist", "download": "https://github.com/devbridge/jQuery-Autocomplete/tree/master/dist",
"dependencies": { "dependencies": {
"jquery": ">=1.7" "jquery": ">=1.7"

View File

@ -1,14 +1,13 @@
/** /**
* Ajax Autocomplete for jQuery, version 1.2.9 * Ajax Autocomplete for jQuery, version 1.2.12
* (c) 2013 Tomas Kirda * (c) 2014 Tomas Kirda
* *
* Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license. * Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license.
* For details, see the web site: https://github.com/devbridge/jQuery-Autocomplete * For details, see the web site: https://github.com/devbridge/jQuery-Autocomplete
*
*/ */
/*jslint browser: true, white: true, plusplus: true */ /*jslint browser: true, white: true, plusplus: true */
/*global define, window, document, jQuery */ /*global define, window, document, jQuery, exports */
// Expose plugin as an AMD module if AMD loader is present: // Expose plugin as an AMD module if AMD loader is present:
(function (factory) { (function (factory) {
@ -16,6 +15,9 @@
if (typeof define === 'function' && define.amd) { if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module. // AMD. Register as an anonymous module.
define(['jquery'], factory); define(['jquery'], factory);
} else if (typeof exports === 'object' && typeof require === 'function') {
// Browserify
factory(require('jquery'));
} else { } else {
// Browser globals // Browser globals
factory(jQuery); factory(jQuery);
@ -53,8 +55,9 @@
var noop = function () { }, var noop = function () { },
that = this, that = this,
defaults = { defaults = {
ajaxSettings: {},
autoSelectFirst: false, autoSelectFirst: false,
appendTo: 'body', appendTo: document.body,
serviceUrl: null, serviceUrl: null,
lookup: null, lookup: null,
onSelect: null, onSelect: null,
@ -76,13 +79,18 @@
dataType: 'text', dataType: 'text',
currentRequest: null, currentRequest: null,
triggerSelectOnValidInput: true, triggerSelectOnValidInput: true,
preventBadQueries: true,
lookupFilter: function (suggestion, originalQuery, queryLowerCase) { lookupFilter: function (suggestion, originalQuery, queryLowerCase) {
return suggestion.value.toLowerCase().indexOf(queryLowerCase) !== -1; return suggestion.value.toLowerCase().indexOf(queryLowerCase) !== -1;
}, },
paramName: 'query', paramName: 'query',
transformResult: function (response) { transformResult: function (response) {
return typeof response === 'string' ? $.parseJSON(response) : response; return typeof response === 'string' ? $.parseJSON(response) : response;
} },
showNoSuggestionNotice: false,
noSuggestionNotice: 'No results',
orientation: 'bottom',
forceFixPosition: false
}; };
// Shared variables: // Shared variables:
@ -98,6 +106,7 @@
that.onChange = null; that.onChange = null;
that.isLocal = false; that.isLocal = false;
that.suggestionsContainer = null; that.suggestionsContainer = null;
that.noSuggestionsContainer = null;
that.options = $.extend({}, defaults, options); that.options = $.extend({}, defaults, options);
that.classes = { that.classes = {
selected: 'autocomplete-selected', selected: 'autocomplete-selected',
@ -143,6 +152,10 @@
} }
}; };
// html() deals with many types: htmlString or Element or Array or jQuery
that.noSuggestionsContainer = $('<div class="autocomplete-no-suggestion"></div>')
.html(this.options.noSuggestionNotice).get(0);
that.suggestionsContainer = Autocomplete.utils.createNode(options.containerClass); that.suggestionsContainer = Autocomplete.utils.createNode(options.containerClass);
container = $(that.suggestionsContainer); container = $(that.suggestionsContainer);
@ -170,8 +183,6 @@
that.select($(this).data('index')); that.select($(this).data('index'));
}); });
that.fixPosition();
that.fixPositionCapture = function () { that.fixPositionCapture = function () {
if (that.visible) { if (that.visible) {
that.fixPosition(); that.fixPosition();
@ -211,6 +222,8 @@
options.lookup = that.verifySuggestionsFormat(options.lookup); options.lookup = that.verifySuggestionsFormat(options.lookup);
} }
options.orientation = that.validateOrientation(options.orientation, 'bottom');
// Adjust height, width and z-index: // Adjust height, width and z-index:
$(that.suggestionsContainer).css({ $(that.suggestionsContainer).css({
'max-height': options.maxHeight + 'px', 'max-height': options.maxHeight + 'px',
@ -219,6 +232,7 @@
}); });
}, },
clearCache: function () { clearCache: function () {
this.cachedResponse = {}; this.cachedResponse = {};
this.badQueries = []; this.badQueries = [];
@ -243,27 +257,65 @@
}, },
fixPosition: function () { fixPosition: function () {
var that = this, // Use only when container has already its content
offset,
styles;
// Don't adjsut position if custom container has been specified: var that = this,
if (that.options.appendTo !== 'body') { $container = $(that.suggestionsContainer),
containerParent = $container.parent().get(0);
// Fix position automatically when appended to body.
// In other cases force parameter must be given.
if (containerParent !== document.body && !that.options.forceFixPosition)
return; return;
// Choose orientation
var orientation = that.options.orientation,
containerHeight = $container.outerHeight(),
height = that.el.outerHeight(),
offset = that.el.offset(),
styles = { 'top': offset.top, 'left': offset.left };
if (orientation == 'auto') {
var viewPortHeight = $(window).height(),
scrollTop = $(window).scrollTop(),
topOverflow = -scrollTop + offset.top - containerHeight,
bottomOverflow = scrollTop + viewPortHeight - (offset.top + height + containerHeight);
orientation = (Math.max(topOverflow, bottomOverflow) === topOverflow)
? 'top'
: 'bottom';
} }
offset = that.el.offset(); if (orientation === 'top') {
styles.top += -containerHeight;
} else {
styles.top += height;
}
styles = { // If container is not positioned to body,
top: (offset.top + that.el.outerHeight()) + 'px', // correct its position using offset parent offset
left: offset.left + 'px' if(containerParent !== document.body) {
}; var opacity = $container.css('opacity'),
parentOffsetDiff;
if (!that.visible){
$container.css('opacity', 0).show();
}
parentOffsetDiff = $container.offsetParent().offset();
styles.top -= parentOffsetDiff.top;
styles.left -= parentOffsetDiff.left;
if (!that.visible){
$container.css('opacity', opacity).hide();
}
}
// -2px to account for suggestions border.
if (that.options.width === 'auto') { if (that.options.width === 'auto') {
styles.width = (that.el.outerWidth() - 2) + 'px'; styles.width = (that.el.outerWidth() - 2) + 'px';
} }
$(that.suggestionsContainer).css(styles); $container.css(styles);
}, },
enableKillerFn: function () { enableKillerFn: function () {
@ -396,7 +448,7 @@
query = that.getQuery(value), query = that.getQuery(value),
index; index;
if (that.selection) { if (that.selection && that.currentValue !== query) {
that.selection = null; that.selection = null;
(options.onInvalidateSelection || $.noop).call(that.element); (options.onInvalidateSelection || $.noop).call(that.element);
} }
@ -473,11 +525,12 @@
that = this, that = this,
options = that.options, options = that.options,
serviceUrl = options.serviceUrl, serviceUrl = options.serviceUrl,
data, params,
cacheKey; cacheKey,
ajaxSettings;
options.params[options.paramName] = q; options.params[options.paramName] = q;
data = options.ignoreParams ? null : options.params; params = options.ignoreParams ? null : options.params;
if (that.isLocal) { if (that.isLocal) {
response = that.getSuggestionsLocal(q); response = that.getSuggestionsLocal(q);
@ -485,7 +538,7 @@
if ($.isFunction(serviceUrl)) { if ($.isFunction(serviceUrl)) {
serviceUrl = serviceUrl.call(that.element, q); serviceUrl = serviceUrl.call(that.element, q);
} }
cacheKey = serviceUrl + '?' + $.param(data || {}); cacheKey = serviceUrl + '?' + $.param(params || {});
response = that.cachedResponse[cacheKey]; response = that.cachedResponse[cacheKey];
} }
@ -499,15 +552,22 @@
if (that.currentRequest) { if (that.currentRequest) {
that.currentRequest.abort(); that.currentRequest.abort();
} }
that.currentRequest = $.ajax({
ajaxSettings = {
url: serviceUrl, url: serviceUrl,
data: data, data: params,
type: options.type, type: options.type,
dataType: options.dataType dataType: options.dataType
}).done(function (data) { };
$.extend(ajaxSettings, options.ajaxSettings);
that.currentRequest = $.ajax(ajaxSettings).done(function (data) {
var result;
that.currentRequest = null; that.currentRequest = null;
that.processResponse(data, q, cacheKey); result = options.transformResult(data);
options.onSearchComplete.call(that.element, q); that.processResponse(result, q, cacheKey);
options.onSearchComplete.call(that.element, q, result.suggestions);
}).fail(function (jqXHR, textStatus, errorThrown) { }).fail(function (jqXHR, textStatus, errorThrown) {
options.onSearchError.call(that.element, q, jqXHR, textStatus, errorThrown); options.onSearchError.call(that.element, q, jqXHR, textStatus, errorThrown);
}); });
@ -515,6 +575,10 @@
}, },
isBadQuery: function (q) { isBadQuery: function (q) {
if (!this.options.preventBadQueries){
return false;
}
var badQueries = this.badQueries, var badQueries = this.badQueries,
i = badQueries.length; i = badQueries.length;
@ -537,7 +601,7 @@
suggest: function () { suggest: function () {
if (this.suggestions.length === 0) { if (this.suggestions.length === 0) {
this.hide(); this.options.showNoSuggestionNotice ? this.noSuggestions() : this.hide();
return; return;
} }
@ -548,10 +612,10 @@
className = that.classes.suggestion, className = that.classes.suggestion,
classSelected = that.classes.selected, classSelected = that.classes.selected,
container = $(that.suggestionsContainer), container = $(that.suggestionsContainer),
noSuggestionsContainer = $(that.noSuggestionsContainer),
beforeRender = options.beforeRender, beforeRender = options.beforeRender,
html = '', html = '',
index, index;
width;
if (options.triggerSelectOnValidInput) { if (options.triggerSelectOnValidInput) {
index = that.findSuggestionIndex(value); index = that.findSuggestionIndex(value);
@ -566,15 +630,9 @@
html += '<div class="' + className + '" data-index="' + i + '">' + formatResult(suggestion, value) + '</div>'; html += '<div class="' + className + '" data-index="' + i + '">' + formatResult(suggestion, value) + '</div>';
}); });
// If width is auto, adjust width before displaying suggestions, this.adjustContainerWidth();
// because if instance was created before input had width, it will be zero.
// Also it adjusts if input width has changed.
// -2px to account for suggestions border.
if (options.width === 'auto') {
width = that.el.outerWidth() - 2;
container.width(width > 0 ? width : 300);
}
noSuggestionsContainer.detach();
container.html(html); container.html(html);
// Select first value by default: // Select first value by default:
@ -587,12 +645,49 @@
beforeRender.call(that.element, container); beforeRender.call(that.element, container);
} }
that.fixPosition();
container.show(); container.show();
that.visible = true; that.visible = true;
that.findBestHint(); that.findBestHint();
}, },
noSuggestions: function() {
var that = this,
container = $(that.suggestionsContainer),
noSuggestionsContainer = $(that.noSuggestionsContainer);
this.adjustContainerWidth();
// Some explicit steps. Be careful here as it easy to get
// noSuggestionsContainer removed from DOM if not detached properly.
noSuggestionsContainer.detach();
container.empty(); // clean suggestions if any
container.append(noSuggestionsContainer);
that.fixPosition();
container.show();
that.visible = true;
},
adjustContainerWidth: function() {
var that = this,
options = that.options,
width,
container = $(that.suggestionsContainer);
// If width is auto, adjust width before displaying suggestions,
// because if instance was created before input had width, it will be zero.
// Also it adjusts if input width has changed.
// -2px to account for suggestions border.
if (options.width === 'auto') {
width = that.el.outerWidth() - 2;
container.width(width > 0 ? width : 300);
}
},
findBestHint: function () { findBestHint: function () {
var that = this, var that = this,
value = that.el.val().toLowerCase(), value = that.el.val().toLowerCase(),
@ -637,18 +732,27 @@
return suggestions; return suggestions;
}, },
processResponse: function (response, originalQuery, cacheKey) { validateOrientation: function(orientation, fallback) {
orientation = $.trim(orientation || '').toLowerCase();
if($.inArray(orientation, ['auto', 'bottom', 'top']) === -1){
orientation = fallback;
}
return orientation;
},
processResponse: function (result, originalQuery, cacheKey) {
var that = this, var that = this,
options = that.options, options = that.options;
result = options.transformResult(response, originalQuery);
result.suggestions = that.verifySuggestionsFormat(result.suggestions); result.suggestions = that.verifySuggestionsFormat(result.suggestions);
// Cache results if cache is not disabled: // Cache results if cache is not disabled:
if (!options.noCache) { if (!options.noCache) {
that.cachedResponse[cacheKey] = result; that.cachedResponse[cacheKey] = result;
if (result.suggestions.length === 0) { if (options.preventBadQueries && result.suggestions.length === 0) {
that.badQueries.push(cacheKey); that.badQueries.push(originalQuery);
} }
} }
@ -666,9 +770,9 @@
activeItem, activeItem,
selected = that.classes.selected, selected = that.classes.selected,
container = $(that.suggestionsContainer), container = $(that.suggestionsContainer),
children = container.children(); children = container.find('.' + that.classes.suggestion);
container.children('.' + selected).removeClass(selected); container.find('.' + selected).removeClass(selected);
that.selectedIndex = index; that.selectedIndex = index;
@ -754,7 +858,11 @@
suggestion = that.suggestions[index]; suggestion = that.suggestions[index];
that.currentValue = that.getValue(suggestion.value); that.currentValue = that.getValue(suggestion.value);
that.el.val(that.currentValue);
if (that.currentValue !== that.el.val()) {
that.el.val(that.currentValue);
}
that.signalHint(null); that.signalHint(null);
that.suggestions = []; that.suggestions = [];
that.selection = suggestion; that.selection = suggestion;
@ -794,7 +902,7 @@
}; };
// Create chainable jQuery plugin: // Create chainable jQuery plugin:
$.fn.autocomplete = function (options, args) { $.fn.autocomplete = $.fn.devbridgeAutocomplete = function (options, args) {
var dataKey = 'autocomplete'; var dataKey = 'autocomplete';
// If function invoked without argument return // If function invoked without argument return
// instance of the first matched element: // instance of the first matched element:

File diff suppressed because one or more lines are too long

69
gruntfile.js Normal file
View File

@ -0,0 +1,69 @@
module.exports = function(grunt) {
var pkg = grunt.file.readJSON('package.json');
var banner = [
'/**',
'* Ajax Autocomplete for jQuery, version ' + pkg.version,
'* (c) 2014 Tomas Kirda',
'*',
'* Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license.',
'* For details, see the web site: https://github.com/devbridge/jQuery-Autocomplete',
'*/'].join('\n') + '\n';
// Project configuration.
grunt.initConfig({
pkg: pkg,
uglify: {
options: {
banner: banner
},
build: {
src: 'src/jquery.autocomplete.js',
dest: 'dist/jquery.autocomplete.min.js'
}
}
});
// Load the plugin that provides the "uglify" task.
grunt.loadNpmTasks('grunt-contrib-uglify');
// Default task(s).
grunt.registerTask('default', ['uglify']);
grunt.task.registerTask('build', 'Create release', function() {
var version = pkg.version
src = grunt.file.read('src/jquery.autocomplete.js').replace('%version%', version),
filePath = 'dist/jquery.autocomplete.js';
// Update not minimized release version:
console.log('Updating: ' + filePath);
grunt.file.write(filePath, src);
// Update plugin version:
filePath = 'devbridge-autocomplete.jquery.json';
src = grunt.file.readJSON(filePath);
if (src.version !== version){
src.version = version;
console.log('Updating: ' + filePath);
grunt.file.write(filePath, JSON.stringify(src, null, 4));
} else {
console.log('No updates for: ' + filePath);
}
// Update bower version:
filePath = 'bower.json';
src = grunt.file.readJSON(filePath);
if (src.version !== version){
src.version = version;
console.log('Updating: ' + filePath);
grunt.file.write(filePath, JSON.stringify(src, null, 4));
} else {
console.log('No updates for: ' + filePath);
}
});
};

16
package.json Normal file
View File

@ -0,0 +1,16 @@
{
"name": "devbridge-autocomplete",
"version": "1.2.12",
"description": "Autocomplete provides suggestions while you type into the text field.",
"homepage": "https://github.com/devbridge/jQuery-Autocomplete",
"author": "Tomas Kirda (https://twitter.com/tkirda)",
"main": "dist/jquery.autocomplete.js",
"license": "MIT",
"dependencies": {
"jquery": ">=1.7"
},
"devDependencies": {
"grunt": "^0.4.5",
"grunt-contrib-uglify": "^0.5.1"
}
}

View File

@ -13,6 +13,7 @@ The standard jquery.autocomplete.js file is around 2.7KB when minified via Closu
* Sets up autocomplete for input field(s). * Sets up autocomplete for input field(s).
* `options`: An object literal which defines the settings to use for the autocomplete plugin. * `options`: An object literal which defines the settings to use for the autocomplete plugin.
* `serviceUrl`: Server side URL or callback function that returns serviceUrl string. Optional if local lookup data is provided. * `serviceUrl`: Server side URL or callback function that returns serviceUrl string. Optional if local lookup data is provided.
* `ajaxSettings`: Any additional [Ajax Settings](http://api.jquery.com/jquery.ajax/#jQuery-ajax-settings) that configure the jQuery Ajax request.
* `lookup`: Lookup array for the suggestions. It may be array of strings or `suggestion` object literals. * `lookup`: Lookup array for the suggestions. It may be array of strings or `suggestion` object literals.
* `suggestion`: An object literal with the following format: `{ value: 'string', data: any }`. * `suggestion`: An object literal with the following format: `{ value: 'string', data: any }`.
* `lookupFilter`: `function (suggestion, query, queryLowerCase) {}` filter function for local lookups. By default it does partial string match (case insensitive). * `lookupFilter`: `function (suggestion, query, queryLowerCase) {}` filter function for local lookups. By default it does partial string match (case insensitive).
@ -158,6 +159,11 @@ you can supply the "paramName" and "transformResult" options:
} }
}) })
##Known Issues
If you use it with jQuery UI library it also has plugin named `autocomplete`. In this case you can use plugin alias `devbridgeAutocomplete`:
$('.autocomplete').devbridgeAutocomplete({ ... });
##License ##License

View File

@ -47,7 +47,7 @@ $(function () {
}); });
// Initialize autocomplete with local lookup: // Initialize autocomplete with local lookup:
$('#autocomplete').autocomplete({ $('#autocomplete').devbridgeAutocomplete({
lookup: countriesArray, lookup: countriesArray,
minChars: 0, minChars: 0,
onSelect: function (suggestion) { onSelect: function (suggestion) {

View File

@ -1,14 +1,13 @@
/** /**
* Ajax Autocomplete for jQuery, version 1.2.9 * Ajax Autocomplete for jQuery, version %version%
* (c) 2013 Tomas Kirda * (c) 2014 Tomas Kirda
* *
* Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license. * Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license.
* For details, see the web site: https://github.com/devbridge/jQuery-Autocomplete * For details, see the web site: https://github.com/devbridge/jQuery-Autocomplete
*
*/ */
/*jslint browser: true, white: true, plusplus: true */ /*jslint browser: true, white: true, plusplus: true */
/*global define, window, document, jQuery */ /*global define, window, document, jQuery, exports */
// Expose plugin as an AMD module if AMD loader is present: // Expose plugin as an AMD module if AMD loader is present:
(function (factory) { (function (factory) {
@ -16,6 +15,9 @@
if (typeof define === 'function' && define.amd) { if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module. // AMD. Register as an anonymous module.
define(['jquery'], factory); define(['jquery'], factory);
} else if (typeof exports === 'object' && typeof require === 'function') {
// Browserify
factory(require('jquery'));
} else { } else {
// Browser globals // Browser globals
factory(jQuery); factory(jQuery);
@ -53,6 +55,7 @@
var noop = function () { }, var noop = function () { },
that = this, that = this,
defaults = { defaults = {
ajaxSettings: {},
autoSelectFirst: false, autoSelectFirst: false,
appendTo: document.body, appendTo: document.body,
serviceUrl: null, serviceUrl: null,
@ -137,8 +140,7 @@
suggestionSelector = '.' + that.classes.suggestion, suggestionSelector = '.' + that.classes.suggestion,
selected = that.classes.selected, selected = that.classes.selected,
options = that.options, options = that.options,
container, container;
noSuggestionsContainer;
// Remove autocomplete attribute to prevent native suggestions: // Remove autocomplete attribute to prevent native suggestions:
that.element.setAttribute('autocomplete', 'off'); that.element.setAttribute('autocomplete', 'off');
@ -275,34 +277,37 @@
if (orientation == 'auto') { if (orientation == 'auto') {
var viewPortHeight = $(window).height(), var viewPortHeight = $(window).height(),
scrollTop = $(window).scrollTop(), scrollTop = $(window).scrollTop(),
top_overflow = -scrollTop + offset.top - containerHeight, topOverflow = -scrollTop + offset.top - containerHeight,
bottom_overflow = scrollTop + viewPortHeight - (offset.top + height + containerHeight); bottomOverflow = scrollTop + viewPortHeight - (offset.top + height + containerHeight);
if (Math.max(top_overflow, bottom_overflow) === top_overflow) orientation = (Math.max(topOverflow, bottomOverflow) === topOverflow)
orientation = 'top'; ? 'top'
else : 'bottom';
orientation = 'bottom';
} }
if (orientation === 'top') if (orientation === 'top') {
styles.top += -containerHeight; styles.top += -containerHeight;
else } else {
styles.top += height; styles.top += height;
}
// If container is not positioned to body, // If container is not positioned to body,
// correct its position using offset parent offset // correct its position using offset parent offset
if(containerParent !== document.body) { if(containerParent !== document.body) {
var opacity = $container.css('opacity'), var opacity = $container.css('opacity'),
parentOffsetDiff; parentOffsetDiff;
if (!that.visible)
$container.css('opacity', 0).show(); if (!that.visible){
$container.css('opacity', 0).show();
}
parentOffsetDiff = $container.offsetParent().offset(); parentOffsetDiff = $container.offsetParent().offset();
styles.top -= parentOffsetDiff.top; styles.top -= parentOffsetDiff.top;
styles.left -= parentOffsetDiff.left; styles.left -= parentOffsetDiff.left;
if (!that.visible) if (!that.visible){
$container.css('opacity', opacity).hide(); $container.css('opacity', opacity).hide();
}
} }
// -2px to account for suggestions border. // -2px to account for suggestions border.
@ -443,7 +448,7 @@
query = that.getQuery(value), query = that.getQuery(value),
index; index;
if (that.selection) { if (that.selection && that.currentValue !== query) {
that.selection = null; that.selection = null;
(options.onInvalidateSelection || $.noop).call(that.element); (options.onInvalidateSelection || $.noop).call(that.element);
} }
@ -521,7 +526,8 @@
options = that.options, options = that.options,
serviceUrl = options.serviceUrl, serviceUrl = options.serviceUrl,
params, params,
cacheKey; cacheKey,
ajaxSettings;
options.params[options.paramName] = q; options.params[options.paramName] = q;
params = options.ignoreParams ? null : options.params; params = options.ignoreParams ? null : options.params;
@ -546,12 +552,17 @@
if (that.currentRequest) { if (that.currentRequest) {
that.currentRequest.abort(); that.currentRequest.abort();
} }
that.currentRequest = $.ajax({
ajaxSettings = {
url: serviceUrl, url: serviceUrl,
data: params, data: params,
type: options.type, type: options.type,
dataType: options.dataType dataType: options.dataType
}).done(function (data) { };
$.extend(ajaxSettings, options.ajaxSettings);
that.currentRequest = $.ajax(ajaxSettings).done(function (data) {
var result; var result;
that.currentRequest = null; that.currentRequest = null;
result = options.transformResult(data); result = options.transformResult(data);
@ -604,8 +615,7 @@
noSuggestionsContainer = $(that.noSuggestionsContainer), noSuggestionsContainer = $(that.noSuggestionsContainer),
beforeRender = options.beforeRender, beforeRender = options.beforeRender,
html = '', html = '',
index, index;
width;
if (options.triggerSelectOnValidInput) { if (options.triggerSelectOnValidInput) {
index = that.findSuggestionIndex(value); index = that.findSuggestionIndex(value);
@ -723,10 +733,13 @@
}, },
validateOrientation: function(orientation, fallback) { validateOrientation: function(orientation, fallback) {
orientation = orientation.trim().toLowerCase(); orientation = $.trim(orientation || '').toLowerCase();
if(['auto', 'bottom', 'top'].indexOf(orientation) == '-1')
if($.inArray(orientation, ['auto', 'bottom', 'top']) === -1){
orientation = fallback; orientation = fallback;
return orientation }
return orientation;
}, },
processResponse: function (result, originalQuery, cacheKey) { processResponse: function (result, originalQuery, cacheKey) {
@ -757,9 +770,9 @@
activeItem, activeItem,
selected = that.classes.selected, selected = that.classes.selected,
container = $(that.suggestionsContainer), container = $(that.suggestionsContainer),
children = container.children(); children = container.find('.' + that.classes.suggestion);
container.children('.' + selected).removeClass(selected); container.find('.' + selected).removeClass(selected);
that.selectedIndex = index; that.selectedIndex = index;
@ -889,7 +902,7 @@
}; };
// Create chainable jQuery plugin: // Create chainable jQuery plugin:
$.fn.autocomplete = function (options, args) { $.fn.autocomplete = $.fn.devbridgeAutocomplete = function (options, args) {
var dataKey = 'autocomplete'; var dataKey = 'autocomplete';
// If function invoked without argument return // If function invoked without argument return
// instance of the first matched element: // instance of the first matched element: