X-Git-Url: https://git.mdrn.pl/emels.git/blobdiff_plain/228c34b6fb564b8f5444a72ceaec83448594c5a5..1b2d6e07836c08be40d19fcf35aa8b3080db7c7e:/emels/static/django_extensions/js/jquery.autocomplete.js diff --git a/emels/static/django_extensions/js/jquery.autocomplete.js b/emels/static/django_extensions/js/jquery.autocomplete.js deleted file mode 100644 index 77c1db6..0000000 --- a/emels/static/django_extensions/js/jquery.autocomplete.js +++ /dev/null @@ -1,1152 +0,0 @@ -/** - * @fileOverview jquery-autocomplete, the jQuery Autocompleter - * @author Dylan Verheul - * @version 2.4.4 - * @requires jQuery 1.6+ - * @license MIT | GPL | Apache 2.0, see LICENSE.txt - * @see https://github.com/dyve/jquery-autocomplete - */ -(function($) { - "use strict"; - - /** - * jQuery autocomplete plugin - * @param {object|string} options - * @returns (object} jQuery object - */ - $.fn.autocomplete = function(options) { - var url; - if (arguments.length > 1) { - url = options; - options = arguments[1]; - options.url = url; - } else if (typeof options === 'string') { - url = options; - options = { url: url }; - } - var opts = $.extend({}, $.fn.autocomplete.defaults, options); - return this.each(function() { - var $this = $(this); - $this.data('autocompleter', new $.Autocompleter( - $this, - $.meta ? $.extend({}, opts, $this.data()) : opts - )); - }); - }; - - /** - * Store default options - * @type {object} - */ - $.fn.autocomplete.defaults = { - inputClass: 'acInput', - loadingClass: 'acLoading', - resultsClass: 'acResults', - selectClass: 'acSelect', - queryParamName: 'q', - extraParams: {}, - remoteDataType: false, - lineSeparator: '\n', - cellSeparator: '|', - minChars: 2, - maxItemsToShow: 10, - delay: 400, - useCache: true, - maxCacheLength: 10, - matchSubset: true, - matchCase: false, - matchInside: true, - mustMatch: false, - selectFirst: false, - selectOnly: false, - showResult: null, - preventDefaultReturn: 1, - preventDefaultTab: 0, - autoFill: false, - filterResults: true, - filter: true, - sortResults: true, - sortFunction: null, - onItemSelect: null, - onNoMatch: null, - onFinish: null, - matchStringConverter: null, - beforeUseConverter: null, - autoWidth: 'min-width', - useDelimiter: false, - delimiterChar: ',', - delimiterKeyCode: 188, - processData: null, - onError: null, - enabled: true - }; - - /** - * Sanitize result - * @param {Object} result - * @returns {Object} object with members value (String) and data (Object) - * @private - */ - var sanitizeResult = function(result) { - var value, data; - var type = typeof result; - if (type === 'string') { - value = result; - data = {}; - } else if ($.isArray(result)) { - value = result[0]; - data = result.slice(1); - } else if (type === 'object') { - value = result.value; - data = result.data; - } - value = String(value); - if (typeof data !== 'object') { - data = {}; - } - return { - value: value, - data: data - }; - }; - - /** - * Sanitize integer - * @param {mixed} value - * @param {Object} options - * @returns {Number} integer - * @private - */ - var sanitizeInteger = function(value, stdValue, options) { - var num = parseInt(value, 10); - options = options || {}; - if (isNaN(num) || (options.min && num < options.min)) { - num = stdValue; - } - return num; - }; - - /** - * Create partial url for a name/value pair - */ - var makeUrlParam = function(name, value) { - return [name, encodeURIComponent(value)].join('='); - }; - - /** - * Build an url - * @param {string} url Base url - * @param {object} [params] Dictionary of parameters - */ - var makeUrl = function(url, params) { - var urlAppend = []; - $.each(params, function(index, value) { - urlAppend.push(makeUrlParam(index, value)); - }); - if (urlAppend.length) { - url += url.indexOf('?') === -1 ? '?' : '&'; - url += urlAppend.join('&'); - } - return url; - }; - - /** - * Default sort filter - * @param {object} a - * @param {object} b - * @param {boolean} matchCase - * @returns {number} - */ - var sortValueAlpha = function(a, b, matchCase) { - a = String(a.value); - b = String(b.value); - if (!matchCase) { - a = a.toLowerCase(); - b = b.toLowerCase(); - } - if (a > b) { - return 1; - } - if (a < b) { - return -1; - } - return 0; - }; - - /** - * Parse data received in text format - * @param {string} text Plain text input - * @param {string} lineSeparator String that separates lines - * @param {string} cellSeparator String that separates cells - * @returns {array} Array of autocomplete data objects - */ - var plainTextParser = function(text, lineSeparator, cellSeparator) { - var results = []; - var i, j, data, line, value, lines; - // Be nice, fix linebreaks before splitting on lineSeparator - lines = String(text).replace('\r\n', '\n').split(lineSeparator); - for (i = 0; i < lines.length; i++) { - line = lines[i].split(cellSeparator); - data = []; - for (j = 0; j < line.length; j++) { - data.push(decodeURIComponent(line[j])); - } - value = data.shift(); - results.push({ value: value, data: data }); - } - return results; - }; - - /** - * Autocompleter class - * @param {object} $elem jQuery object with one input tag - * @param {object} options Settings - * @constructor - */ - $.Autocompleter = function($elem, options) { - - /** - * Assert parameters - */ - if (!$elem || !($elem instanceof $) || $elem.length !== 1 || $elem.get(0).tagName.toUpperCase() !== 'INPUT') { - throw new Error('Invalid parameter for jquery.Autocompleter, jQuery object with one element with INPUT tag expected.'); - } - - /** - * @constant Link to this instance - * @type object - * @private - */ - var self = this; - - /** - * @property {object} Options for this instance - * @public - */ - this.options = options; - - /** - * @property object Cached data for this instance - * @private - */ - this.cacheData_ = {}; - - /** - * @property {number} Number of cached data items - * @private - */ - this.cacheLength_ = 0; - - /** - * @property {string} Class name to mark selected item - * @private - */ - this.selectClass_ = 'jquery-autocomplete-selected-item'; - - /** - * @property {number} Handler to activation timeout - * @private - */ - this.keyTimeout_ = null; - - /** - * @property {number} Handler to finish timeout - * @private - */ - this.finishTimeout_ = null; - - /** - * @property {number} Last key pressed in the input field (store for behavior) - * @private - */ - this.lastKeyPressed_ = null; - - /** - * @property {string} Last value processed by the autocompleter - * @private - */ - this.lastProcessedValue_ = null; - - /** - * @property {string} Last value selected by the user - * @private - */ - this.lastSelectedValue_ = null; - - /** - * @property {boolean} Is this autocompleter active (showing results)? - * @see showResults - * @private - */ - this.active_ = false; - - /** - * @property {boolean} Is this autocompleter allowed to finish on blur? - * @private - */ - this.finishOnBlur_ = true; - - /** - * Sanitize options - */ - this.options.minChars = sanitizeInteger(this.options.minChars, $.fn.autocomplete.defaults.minChars, { min: 0 }); - this.options.maxItemsToShow = sanitizeInteger(this.options.maxItemsToShow, $.fn.autocomplete.defaults.maxItemsToShow, { min: 0 }); - this.options.maxCacheLength = sanitizeInteger(this.options.maxCacheLength, $.fn.autocomplete.defaults.maxCacheLength, { min: 1 }); - this.options.delay = sanitizeInteger(this.options.delay, $.fn.autocomplete.defaults.delay, { min: 0 }); - if (this.options.preventDefaultReturn != 2) { - this.options.preventDefaultReturn = this.options.preventDefaultReturn ? 1 : 0; - } - if (this.options.preventDefaultTab != 2) { - this.options.preventDefaultTab = this.options.preventDefaultTab ? 1 : 0; - } - - /** - * Init DOM elements repository - */ - this.dom = {}; - - /** - * Store the input element we're attached to in the repository - */ - this.dom.$elem = $elem; - - /** - * Switch off the native autocomplete and add the input class - */ - this.dom.$elem.attr('autocomplete', 'off').addClass(this.options.inputClass); - - /** - * Create DOM element to hold results, and force absolute position - */ - this.dom.$results = $('
').hide().addClass(this.options.resultsClass).css({ - position: 'absolute' - }); - $('body').append(this.dom.$results); - - /** - * Attach keyboard monitoring to $elem - */ - $elem.keydown(function(e) { - self.lastKeyPressed_ = e.keyCode; - switch(self.lastKeyPressed_) { - - case self.options.delimiterKeyCode: // comma = 188 - if (self.options.useDelimiter && self.active_) { - self.selectCurrent(); - } - break; - - // ignore navigational & special keys - case 35: // end - case 36: // home - case 16: // shift - case 17: // ctrl - case 18: // alt - case 37: // left - case 39: // right - break; - - case 38: // up - e.preventDefault(); - if (self.active_) { - self.focusPrev(); - } else { - self.activate(); - } - return false; - - case 40: // down - e.preventDefault(); - if (self.active_) { - self.focusNext(); - } else { - self.activate(); - } - return false; - - case 9: // tab - if (self.active_) { - self.selectCurrent(); - if (self.options.preventDefaultTab) { - e.preventDefault(); - return false; - } - } - if (self.options.preventDefaultTab === 2) { - e.preventDefault(); - return false; - } - break; - - case 13: // return - if (self.active_) { - self.selectCurrent(); - if (self.options.preventDefaultReturn) { - e.preventDefault(); - return false; - } - } - if (self.options.preventDefaultReturn === 2) { - e.preventDefault(); - return false; - } - break; - - case 27: // escape - if (self.active_) { - e.preventDefault(); - self.deactivate(true); - return false; - } - break; - - default: - self.activate(); - - } - }); - - /** - * Attach paste event listener because paste may occur much later then keydown or even without a keydown at all - */ - $elem.on('paste', function() { - self.activate(); - }); - - /** - * Finish on blur event - * Use a timeout because instant blur gives race conditions - */ - var onBlurFunction = function() { - self.deactivate(true); - } - $elem.blur(function() { - if (self.finishOnBlur_) { - self.finishTimeout_ = setTimeout(onBlurFunction, 200); - } - }); - /** - * Catch a race condition on form submit - */ - $elem.parents('form').on('submit', onBlurFunction); - - }; - - /** - * Position output DOM elements - * @private - */ - $.Autocompleter.prototype.position = function() { - var offset = this.dom.$elem.offset(); - var height = this.dom.$results.outerHeight(); - var totalHeight = $(window).outerHeight(); - var inputBottom = offset.top + this.dom.$elem.outerHeight(); - var bottomIfDown = inputBottom + height; - // Set autocomplete results at the bottom of input - var position = {top: inputBottom, left: offset.left}; - if (bottomIfDown > totalHeight) { - // Try to set autocomplete results at the top of input - var topIfUp = offset.top - height; - if (topIfUp >= 0) { - position.top = topIfUp; - } - } - this.dom.$results.css(position); - }; - - /** - * Read from cache - * @private - */ - $.Autocompleter.prototype.cacheRead = function(filter) { - var filterLength, searchLength, search, maxPos, pos; - if (this.options.useCache) { - filter = String(filter); - filterLength = filter.length; - if (this.options.matchSubset) { - searchLength = 1; - } else { - searchLength = filterLength; - } - while (searchLength <= filterLength) { - if (this.options.matchInside) { - maxPos = filterLength - searchLength; - } else { - maxPos = 0; - } - pos = 0; - while (pos <= maxPos) { - search = filter.substr(0, searchLength); - if (this.cacheData_[search] !== undefined) { - return this.cacheData_[search]; - } - pos++; - } - searchLength++; - } - } - return false; - }; - - /** - * Write to cache - * @private - */ - $.Autocompleter.prototype.cacheWrite = function(filter, data) { - if (this.options.useCache) { - if (this.cacheLength_ >= this.options.maxCacheLength) { - this.cacheFlush(); - } - filter = String(filter); - if (this.cacheData_[filter] !== undefined) { - this.cacheLength_++; - } - this.cacheData_[filter] = data; - return this.cacheData_[filter]; - } - return false; - }; - - /** - * Flush cache - * @public - */ - $.Autocompleter.prototype.cacheFlush = function() { - this.cacheData_ = {}; - this.cacheLength_ = 0; - }; - - /** - * Call hook - * Note that all called hooks are passed the autocompleter object - * @param {string} hook - * @param data - * @returns Result of called hook, false if hook is undefined - */ - $.Autocompleter.prototype.callHook = function(hook, data) { - var f = this.options[hook]; - if (f && $.isFunction(f)) { - return f(data, this); - } - return false; - }; - - /** - * Set timeout to activate autocompleter - */ - $.Autocompleter.prototype.activate = function() { - if (!this.options.enabled) return; - var self = this; - if (this.keyTimeout_) { - clearTimeout(this.keyTimeout_); - } - this.keyTimeout_ = setTimeout(function() { - self.activateNow(); - }, this.options.delay); - }; - - /** - * Activate autocompleter immediately - */ - $.Autocompleter.prototype.activateNow = function() { - var value = this.beforeUseConverter(this.dom.$elem.val()); - if (value !== this.lastProcessedValue_ && value !== this.lastSelectedValue_) { - this.fetchData(value); - } - }; - - /** - * Get autocomplete data for a given value - * @param {string} value Value to base autocompletion on - * @private - */ - $.Autocompleter.prototype.fetchData = function(value) { - var self = this; - var processResults = function(results, filter) { - if (self.options.processData) { - results = self.options.processData(results); - } - self.showResults(self.filterResults(results, filter), filter); - }; - this.lastProcessedValue_ = value; - if (value.length < this.options.minChars) { - processResults([], value); - } else if (this.options.data) { - processResults(this.options.data, value); - } else { - this.fetchRemoteData(value, function(remoteData) { - processResults(remoteData, value); - }); - } - }; - - /** - * Get remote autocomplete data for a given value - * @param {string} filter The filter to base remote data on - * @param {function} callback The function to call after data retrieval - * @private - */ - $.Autocompleter.prototype.fetchRemoteData = function(filter, callback) { - var data = this.cacheRead(filter); - if (data) { - callback(data); - } else { - var self = this; - var dataType = self.options.remoteDataType === 'json' ? 'json' : 'text'; - var ajaxCallback = function(data) { - var parsed = false; - if (data !== false) { - parsed = self.parseRemoteData(data); - self.cacheWrite(filter, parsed); - } - self.dom.$elem.removeClass(self.options.loadingClass); - callback(parsed); - }; - this.dom.$elem.addClass(this.options.loadingClass); - $.ajax({ - url: this.makeUrl(filter), - success: ajaxCallback, - error: function(jqXHR, textStatus, errorThrown) { - if($.isFunction(self.options.onError)) { - self.options.onError(jqXHR, textStatus, errorThrown); - } else { - ajaxCallback(false); - } - }, - dataType: dataType - }); - } - }; - - /** - * Create or update an extra parameter for the remote request - * @param {string} name Parameter name - * @param {string} value Parameter value - * @public - */ - $.Autocompleter.prototype.setExtraParam = function(name, value) { - var index = $.trim(String(name)); - if (index) { - if (!this.options.extraParams) { - this.options.extraParams = {}; - } - if (this.options.extraParams[index] !== value) { - this.options.extraParams[index] = value; - this.cacheFlush(); - } - } - - return this; - }; - - /** - * Build the url for a remote request - * If options.queryParamName === false, append query to url instead of using a GET parameter - * @param {string} param The value parameter to pass to the backend - * @returns {string} The finished url with parameters - */ - $.Autocompleter.prototype.makeUrl = function(param) { - var self = this; - var url = this.options.url; - var params = $.extend({}, this.options.extraParams); - - if (this.options.queryParamName === false) { - url += encodeURIComponent(param); - } else { - params[this.options.queryParamName] = param; - } - - return makeUrl(url, params); - }; - - /** - * Parse data received from server - * @param remoteData Data received from remote server - * @returns {array} Parsed data - */ - $.Autocompleter.prototype.parseRemoteData = function(remoteData) { - var remoteDataType; - var data = remoteData; - if (this.options.remoteDataType === 'json') { - remoteDataType = typeof(remoteData); - switch (remoteDataType) { - case 'object': - data = remoteData; - break; - case 'string': - data = $.parseJSON(remoteData); - break; - default: - throw new Error("Unexpected remote data type: " + remoteDataType); - } - return data; - } - return plainTextParser(data, this.options.lineSeparator, this.options.cellSeparator); - }; - - /** - * Default filter for results - * @param {Object} result - * @param {String} filter - * @returns {boolean} Include this result - * @private - */ - $.Autocompleter.prototype.defaultFilter = function(result, filter) { - if (!result.value) { - return false; - } - if (this.options.filterResults) { - var pattern = this.matchStringConverter(filter); - var testValue = this.matchStringConverter(result.value); - if (!this.options.matchCase) { - pattern = pattern.toLowerCase(); - testValue = testValue.toLowerCase(); - } - var patternIndex = testValue.indexOf(pattern); - if (this.options.matchInside) { - return patternIndex > -1; - } else { - return patternIndex === 0; - } - } - return true; - }; - - /** - * Filter result - * @param {Object} result - * @param {String} filter - * @returns {boolean} Include this result - * @private - */ - $.Autocompleter.prototype.filterResult = function(result, filter) { - // No filter - if (this.options.filter === false) { - return true; - } - // Custom filter - if ($.isFunction(this.options.filter)) { - return this.options.filter(result, filter); - } - // Default filter - return this.defaultFilter(result, filter); - }; - - /** - * Filter results - * @param results - * @param filter - */ - $.Autocompleter.prototype.filterResults = function(results, filter) { - var filtered = []; - var i, result; - - for (i = 0; i < results.length; i++) { - result = sanitizeResult(results[i]); - if (this.filterResult(result, filter)) { - filtered.push(result); - } - } - if (this.options.sortResults) { - filtered = this.sortResults(filtered, filter); - } - if (this.options.maxItemsToShow > 0 && this.options.maxItemsToShow < filtered.length) { - filtered.length = this.options.maxItemsToShow; - } - return filtered; - }; - - /** - * Sort results - * @param results - * @param filter - */ - $.Autocompleter.prototype.sortResults = function(results, filter) { - var self = this; - var sortFunction = this.options.sortFunction; - if (!$.isFunction(sortFunction)) { - sortFunction = function(a, b, f) { - return sortValueAlpha(a, b, self.options.matchCase); - }; - } - results.sort(function(a, b) { - return sortFunction(a, b, filter, self.options); - }); - return results; - }; - - /** - * Convert string before matching - * @param s - * @param a - * @param b - */ - $.Autocompleter.prototype.matchStringConverter = function(s, a, b) { - var converter = this.options.matchStringConverter; - if ($.isFunction(converter)) { - s = converter(s, a, b); - } - return s; - }; - - /** - * Convert string before use - * @param {String} s - */ - $.Autocompleter.prototype.beforeUseConverter = function(s) { - s = this.getValue(s); - var converter = this.options.beforeUseConverter; - if ($.isFunction(converter)) { - s = converter(s); - } - return s; - }; - - /** - * Enable finish on blur event - */ - $.Autocompleter.prototype.enableFinishOnBlur = function() { - this.finishOnBlur_ = true; - }; - - /** - * Disable finish on blur event - */ - $.Autocompleter.prototype.disableFinishOnBlur = function() { - this.finishOnBlur_ = false; - }; - - /** - * Create a results item (LI element) from a result - * @param result - */ - $.Autocompleter.prototype.createItemFromResult = function(result) { - var self = this; - var $li = $('
  • '); - $li.html(this.showResult(result.value, result.data)); - $li.data({value: result.value, data: result.data}) - .click(function() { - self.selectItem($li); - }) - .mousedown(self.disableFinishOnBlur) - .mouseup(self.enableFinishOnBlur) - ; - return $li; - }; - - /** - * Get all items from the results list - * @param result - */ - $.Autocompleter.prototype.getItems = function() { - return $('>ul>li', this.dom.$results); - }; - - /** - * Show all results - * @param results - * @param filter - */ - $.Autocompleter.prototype.showResults = function(results, filter) { - var numResults = results.length; - var self = this; - var $ul = $(''); - var i, result, $li, autoWidth, first = false, $first = false; - - if (numResults) { - for (i = 0; i < numResults; i++) { - result = results[i]; - $li = this.createItemFromResult(result); - $ul.append($li); - if (first === false) { - first = String(result.value); - $first = $li; - $li.addClass(this.options.firstItemClass); - } - if (i === numResults - 1) { - $li.addClass(this.options.lastItemClass); - } - } - - this.dom.$results.html($ul).show(); - - // Always recalculate position since window size or - // input element location may have changed. - this.position(); - if (this.options.autoWidth) { - autoWidth = this.dom.$elem.outerWidth() - this.dom.$results.outerWidth() + this.dom.$results.width(); - this.dom.$results.css(this.options.autoWidth, autoWidth); - } - this.getItems().hover( - function() { self.focusItem(this); }, - function() { /* void */ } - ); - if (this.autoFill(first, filter) || this.options.selectFirst || (this.options.selectOnly && numResults === 1)) { - this.focusItem($first); - } - this.active_ = true; - } else { - this.hideResults(); - this.active_ = false; - } - }; - - $.Autocompleter.prototype.showResult = function(value, data) { - if ($.isFunction(this.options.showResult)) { - return this.options.showResult(value, data); - } else { - return $('

    ').text(value).html(); - } - }; - - $.Autocompleter.prototype.autoFill = function(value, filter) { - var lcValue, lcFilter, valueLength, filterLength; - if (this.options.autoFill && this.lastKeyPressed_ !== 8) { - lcValue = String(value).toLowerCase(); - lcFilter = String(filter).toLowerCase(); - valueLength = value.length; - filterLength = filter.length; - if (lcValue.substr(0, filterLength) === lcFilter) { - var d = this.getDelimiterOffsets(); - var pad = d.start ? ' ' : ''; // if there is a preceding delimiter - this.setValue( pad + value ); - var start = filterLength + d.start + pad.length; - var end = valueLength + d.start + pad.length; - this.selectRange(start, end); - return true; - } - } - return false; - }; - - $.Autocompleter.prototype.focusNext = function() { - this.focusMove(+1); - }; - - $.Autocompleter.prototype.focusPrev = function() { - this.focusMove(-1); - }; - - $.Autocompleter.prototype.focusMove = function(modifier) { - var $items = this.getItems(); - modifier = sanitizeInteger(modifier, 0); - if (modifier) { - for (var i = 0; i < $items.length; i++) { - if ($($items[i]).hasClass(this.selectClass_)) { - this.focusItem(i + modifier); - return; - } - } - } - this.focusItem(0); - }; - - $.Autocompleter.prototype.focusItem = function(item) { - var $item, $items = this.getItems(); - if ($items.length) { - $items.removeClass(this.selectClass_).removeClass(this.options.selectClass); - if (typeof item === 'number') { - if (item < 0) { - item = 0; - } else if (item >= $items.length) { - item = $items.length - 1; - } - $item = $($items[item]); - } else { - $item = $(item); - } - if ($item) { - $item.addClass(this.selectClass_).addClass(this.options.selectClass); - } - } - }; - - $.Autocompleter.prototype.selectCurrent = function() { - var $item = $('li.' + this.selectClass_, this.dom.$results); - if ($item.length === 1) { - this.selectItem($item); - } else { - this.deactivate(false); - } - }; - - $.Autocompleter.prototype.selectItem = function($li) { - var value = $li.data('value'); - var data = $li.data('data'); - var displayValue = this.displayValue(value, data); - var processedDisplayValue = this.beforeUseConverter(displayValue); - this.lastProcessedValue_ = processedDisplayValue; - this.lastSelectedValue_ = processedDisplayValue; - var d = this.getDelimiterOffsets(); - var delimiter = this.options.delimiterChar; - var elem = this.dom.$elem; - var extraCaretPos = 0; - if ( this.options.useDelimiter ) { - // if there is a preceding delimiter, add a space after the delimiter - if ( elem.val().substring(d.start-1, d.start) == delimiter && delimiter != ' ' ) { - displayValue = ' ' + displayValue; - } - // if there is not already a delimiter trailing this value, add it - if ( elem.val().substring(d.end, d.end+1) != delimiter && this.lastKeyPressed_ != this.options.delimiterKeyCode ) { - displayValue = displayValue + delimiter; - } else { - // move the cursor after the existing trailing delimiter - extraCaretPos = 1; - } - } - this.setValue(displayValue); - this.setCaret(d.start + displayValue.length + extraCaretPos); - this.callHook('onItemSelect', { value: value, data: data }); - this.deactivate(true); - elem.focus(); - }; - - $.Autocompleter.prototype.displayValue = function(value, data) { - if ($.isFunction(this.options.displayValue)) { - return this.options.displayValue(value, data); - } - return value; - }; - - $.Autocompleter.prototype.hideResults = function() { - this.dom.$results.hide(); - }; - - $.Autocompleter.prototype.deactivate = function(finish) { - if (this.finishTimeout_) { - clearTimeout(this.finishTimeout_); - } - if (this.keyTimeout_) { - clearTimeout(this.keyTimeout_); - } - if (finish) { - if (this.lastProcessedValue_ !== this.lastSelectedValue_) { - if (this.options.mustMatch) { - this.setValue(''); - } - this.callHook('onNoMatch'); - } - if (this.active_) { - this.callHook('onFinish'); - } - this.lastKeyPressed_ = null; - this.lastProcessedValue_ = null; - this.lastSelectedValue_ = null; - this.active_ = false; - } - this.hideResults(); - }; - - $.Autocompleter.prototype.selectRange = function(start, end) { - var input = this.dom.$elem.get(0); - if (input.setSelectionRange) { - input.focus(); - input.setSelectionRange(start, end); - } else if (input.createTextRange) { - var range = input.createTextRange(); - range.collapse(true); - range.moveEnd('character', end); - range.moveStart('character', start); - range.select(); - } - }; - - /** - * Move caret to position - * @param {Number} pos - */ - $.Autocompleter.prototype.setCaret = function(pos) { - this.selectRange(pos, pos); - }; - - /** - * Get caret position - */ - $.Autocompleter.prototype.getCaret = function() { - var $elem = this.dom.$elem; - var elem = $elem[0]; - var val, selection, range, start, end, stored_range; - if (elem.createTextRange) { // IE - selection = document.selection; - if (elem.tagName.toLowerCase() != 'textarea') { - val = $elem.val(); - range = selection.createRange().duplicate(); - range.moveEnd('character', val.length); - if (range.text === '') { - start = val.length; - } else { - start = val.lastIndexOf(range.text); - } - range = selection.createRange().duplicate(); - range.moveStart('character', -val.length); - end = range.text.length; - } else { - range = selection.createRange(); - stored_range = range.duplicate(); - stored_range.moveToElementText(elem); - stored_range.setEndPoint('EndToEnd', range); - start = stored_range.text.length - range.text.length; - end = start + range.text.length; - } - } else { - start = $elem[0].selectionStart; - end = $elem[0].selectionEnd; - } - return { - start: start, - end: end - }; - }; - - /** - * Set the value that is currently being autocompleted - * @param {String} value - */ - $.Autocompleter.prototype.setValue = function(value) { - if ( this.options.useDelimiter ) { - // set the substring between the current delimiters - var val = this.dom.$elem.val(); - var d = this.getDelimiterOffsets(); - var preVal = val.substring(0, d.start); - var postVal = val.substring(d.end); - value = preVal + value + postVal; - } - this.dom.$elem.val(value); - }; - - /** - * Get the value currently being autocompleted - * @param {String} value - */ - $.Autocompleter.prototype.getValue = function(value) { - if ( this.options.useDelimiter ) { - var d = this.getDelimiterOffsets(); - return value.substring(d.start, d.end).trim(); - } else { - return value; - } - }; - - /** - * Get the offsets of the value currently being autocompleted - */ - $.Autocompleter.prototype.getDelimiterOffsets = function() { - var val = this.dom.$elem.val(); - if ( this.options.useDelimiter ) { - var preCaretVal = val.substring(0, this.getCaret().start); - var start = preCaretVal.lastIndexOf(this.options.delimiterChar) + 1; - var postCaretVal = val.substring(this.getCaret().start); - var end = postCaretVal.indexOf(this.options.delimiterChar); - if ( end == -1 ) end = val.length; - end += this.getCaret().start; - } else { - start = 0; - end = val.length; - } - return { - start: start, - end: end - }; - }; - -})((typeof window.jQuery == 'undefined' && typeof window.django != 'undefined')? django.jQuery : jQuery);