Facebook-like tags for search.
[wolnelektury.git] / wolnelektury / static / js / jquery.autocomplete.js
index 5ad9178..4e425e8 100644 (file)
@@ -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
  *
  *
  * 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($) {
  */
 
 ;(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) {
        
        // 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) {
                // 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 ) {
                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;
                }
                        }
                        v += options.multipleSeparator;
                }
@@ -246,22 +267,27 @@ $.Autocompleter = function(input, options) {
        };
        
        function trimWords(value) {
        };
        
        function trimWords(value) {
-               if ( !value ) {
+               if (!value)
                        return [""];
                        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);
        }
        
        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];
        }
        
                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)
                        // 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 : "") );
                                                }
                                                        var words = trimWords($input.val()).slice(0, -1);
                                                        $input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
                                                }
-                                               else
+                                               else {
                                                        $input.val( "" );
                                                        $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) {
        };
 
        function receiveData(q, data) {
@@ -405,8 +430,22 @@ $.Autocompleter.defaults = {
        width: 0,
        multiple: false,
        multipleSeparator: ", ",
        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) {
        highlight: function(value, term) {
-               return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
+               term = $.Autocompleter.defaults.regex_escape(term);
+               return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
        },
     scroll: true,
     scrollHeight: 180
        },
     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.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;
        };
                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
 };
 
 })(jQuery);
\ No newline at end of file