X-Git-Url: https://git.mdrn.pl/wolnelektury.git/blobdiff_plain/362ea2e7f8ac4254398791139cc060090199f400..8236368dcf8d49214946e291300e29622fd26aaf:/wolnelektury/static/js/jquery.autocomplete.js diff --git a/wolnelektury/static/js/jquery.autocomplete.js b/wolnelektury/static/js/jquery.autocomplete.js index 5ad9178f8..4e425e8bd 100644 --- a/wolnelektury/static/js/jquery.autocomplete.js +++ b/wolnelektury/static/js/jquery.autocomplete.js @@ -1,14 +1,18 @@ /* - * Autocomplete - jQuery plugin 1.0.2 + * jQuery Autocomplete plugin 1.1 * - * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer + * Copyright (c) 2009 Jörn Zaefferer * * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html * - * Revision: $Id: jquery.autocomplete.js 5747 2008-06-25 18:30:55Z joern.zaefferer $ - * + * Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $ + */ + +/* + * Modified by Radek Czajka, Fundacja Nowoczesna Polska, 2010-05-10: + * escape regex for word start checking in matchSubset */ ;(function($) { @@ -90,6 +94,9 @@ $.Autocompleter = function(input, options) { // only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all $input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) { + // a keypress means the input has focus + // avoids issue where input had focus before the autocomplete was applied + hasFocus = 1; // track last key pressed lastKeyPressCode = event.keyCode; switch(event.keyCode) { @@ -209,7 +216,21 @@ $.Autocompleter = function(input, options) { if ( options.multiple ) { var words = trimWords($input.val()); if ( words.length > 1 ) { - v = words.slice(0, words.length - 1).join( options.multipleSeparator ) + options.multipleSeparator + v; + var seperator = options.multipleSeparator.length; + var cursorAt = $(input).selection().start; + var wordAt, progress = 0; + $.each(words, function(i, word) { + progress += word.length; + if (cursorAt <= progress) { + wordAt = i; + return false; + } + progress += seperator; + }); + words[wordAt] = v; + // TODO this should set the cursor to the right position, but it gets overriden somewhere + //$.Autocompleter.Selection(input, progress + seperator, progress + seperator); + v = words.join( options.multipleSeparator ); } v += options.multipleSeparator; } @@ -246,22 +267,27 @@ $.Autocompleter = function(input, options) { }; function trimWords(value) { - if ( !value ) { + if (!value) return [""]; - } - var words = value.split( options.multipleSeparator ); - var result = []; - $.each(words, function(i, value) { - if ( $.trim(value) ) - result[i] = $.trim(value); + if (!options.multiple) + return [$.trim(value)]; + return $.map(value.split(options.multipleSeparator), function(word) { + return $.trim(value).length ? $.trim(word) : null; }); - return result; } function lastWord(value) { if ( !options.multiple ) return value; var words = trimWords(value); + if (words.length == 1) + return words[0]; + var cursorAt = $(input).selection().start; + if (cursorAt == value.length) { + words = trimWords(value) + } else { + words = trimWords(value.replace(value.substring(cursorAt), "")); + } return words[words.length - 1]; } @@ -275,7 +301,7 @@ $.Autocompleter = function(input, options) { // fill in the value (keep the case the user has typed) $input.val($input.val() + sValue.substring(lastWord(previousValue).length)); // select the portion of the value not typed by the user (so the next character will erase) - $.Autocompleter.Selection(input, previousValue.length, previousValue.length + sValue.length); + $(input).selection(previousValue.length, previousValue.length + sValue.length); } }; @@ -299,15 +325,14 @@ $.Autocompleter = function(input, options) { var words = trimWords($input.val()).slice(0, -1); $input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") ); } - else + else { $input.val( "" ); + $input.trigger("result", null); + } } } ); } - if (wasVisible) - // position cursor at end of input field - $.Autocompleter.Selection(input, input.value.length, input.value.length); }; function receiveData(q, data) { @@ -405,8 +430,22 @@ $.Autocompleter.defaults = { width: 0, multiple: false, multipleSeparator: ", ", + regex_escape: function(term) { + term = term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1"); + /* no polish diacritics; should be more locale-aware */ + term = term.replace(/a/g, '[aą]') + .replace(/c/g, '[cć]') + .replace(/e/g, '[eę]') + .replace(/l/g, '[lł]') + .replace(/n/g, '[nń]') + .replace(/o/g, '[oó]') + .replace(/s/g, '[sś]') + .replace(/z/g, '[zźż]'); + return term; + }, highlight: function(value, term) { - return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "$1"); + term = $.Autocompleter.defaults.regex_escape(term); + return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "$1"); }, scroll: true, scrollHeight: 180 @@ -421,6 +460,10 @@ $.Autocompleter.Cache = function(options) { if (!options.matchCase) s = s.toLowerCase(); var i = s.indexOf(sub); + if (options.matchContains == "word"){ + query = $.Autocompleter.defaults.regex_escape(sub.toLowerCase()); + i = s.toLowerCase().search("\\b" + query); + } if (i == -1) return false; return i == 0 || options.matchContains; }; @@ -738,22 +781,48 @@ $.Autocompleter.Select = function (options, input, select, config) { }; }; -$.Autocompleter.Selection = function(field, start, end) { - if( field.createTextRange ){ - var selRange = field.createTextRange(); - selRange.collapse(true); - selRange.moveStart("character", start); - selRange.moveEnd("character", end); - selRange.select(); - } else if( field.setSelectionRange ){ - field.setSelectionRange(start, end); - } else { - if( field.selectionStart ){ - field.selectionStart = start; - field.selectionEnd = end; +$.fn.selection = function(start, end) { + if (start !== undefined) { + return this.each(function() { + if( this.createTextRange ){ + var selRange = this.createTextRange(); + if (end === undefined || start == end) { + selRange.move("character", start); + selRange.select(); + } else { + selRange.collapse(true); + selRange.moveStart("character", start); + selRange.moveEnd("character", end); + selRange.select(); + } + } else if( this.setSelectionRange ){ + this.setSelectionRange(start, end); + } else if( this.selectionStart ){ + this.selectionStart = start; + this.selectionEnd = end; + } + }); + } + var field = this[0]; + if ( field.createTextRange ) { + var range = document.selection.createRange(), + orig = field.value, + teststring = "<->", + textLength = range.text.length; + range.text = teststring; + var caretAt = field.value.indexOf(teststring); + field.value = orig; + this.selection(caretAt, caretAt + textLength); + return { + start: caretAt, + end: caretAt + textLength + } + } else if( field.selectionStart !== undefined ){ + return { + start: field.selectionStart, + end: field.selectionEnd } } - field.focus(); }; })(jQuery); \ No newline at end of file