Modifications, to fix a bug I found

Neolite's Avatar

Neolite

06 Jun, 2011 01:56 PM

Hello,

I'm a french programmer and I found a bug in this plugin.
So, I found that the first value can't be deleted!
This is due to the use of the "replace function" which only replaces values which are between commas. However, the first value just has only one comma at right.

Here's the new code (modifications starting at line 334):
` / * AutoSuggest * Copyright 2009-2010 Drew Wilson * www.drewwilson.com * code.drewwilson.com/entry/autosuggest-jquery-plugin * * Version 1.4 - Updated: Mar. 23, 2010 * * This Plug-In will auto-complete or auto-suggest completed search queries * for you as you type. You can add multiple selections and remove them on * the fly. It supports keybord navigation (UP + DOWN + RETURN), as well * as multiple AutoSuggest fields on the same page. * * Inspied by the Autocomplete plugin by: Jšrn Zaefferer * and the Facelist plugin by: Ian Tearle (iantearle.com) * * This AutoSuggest jQuery plug-in is dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html /

(function($){

$.fn.autoSuggest = function(data, options) {
    var defaults = { 
        asHtmlID: false,
        startText: "Enter Name Here",
        emptyText: "No Results Found",
        preFill: {},
        limitText: "No More Selections Are Allowed",
        selectedItemProp: "value", //name of object property
        selectedValuesProp: "value", //name of object property
        searchObjProps: "value", //comma separated list of object property names
        queryParam: "q",
        retrieveLimit: false, //number for 'limit' param on ajax request
        extraParams: "",
        matchCase: false,
        minChars: 1,
        keyDelay: 400,
        resultsHighlight: true,
        neverSubmit: false,
        selectionLimit: false,
        showResultList: true,
        start: function(){},
        selectionClick: function(elem){},
        selectionAdded: function(elem){},
        selectionRemoved: function(elem){ elem.remove(); },
        formatList: false, //callback function
        beforeRetrieve: function(string){ return string; },
        retrieveComplete: function(data){ return data; },
        resultClick: function(data){},
        resultsComplete: function(){}
    };  
    var opts = $.extend(defaults, options);     

    var d_type = "object";
    var d_count = 0;
    if(typeof data == "string") {
        d_type = "string";
        var req_string = data;
    } else {
        var org_data = data;
        for (k in data) if (data.hasOwnProperty(k)) d_count++;
    }
    if((d_type == "object" && d_count > 0) || d_type == "string"){
        return this.each(function(x){
            if(!opts.asHtmlID){
                x = x+""+Math.floor(Math.random()*100); //this ensures there will be unique IDs on the page if autoSuggest() is called multiple times
                var x_id = "as-input-"+x;
            } else {
                x = opts.asHtmlID;
                var x_id = x;
            }
            opts.start.call(this);
            var input = $(this);
            input.attr("autocomplete","off").addClass("as-input").attr("id",x_id).val(opts.startText);
            var input_focus = false;

            // Setup basic elements and render them to the DOM
            input.wrap('<ul class="as-selections" id="as-selections-'+x+'"></ul>').wrap('<li class="as-original" id="as-original-'+x+'"></li>');
            var selections_holder = $("#as-selections-"+x);
            var org_li = $("#as-original-"+x);              
            var results_holder = $('<div class="as-results" id="as-results-'+x+'"></div>').hide();
            var results_ul =  $('<ul class="as-list"></ul>');
            var values_input = $('<input type="hidden" class="as-values" name="as_values_'+x+'" id="as-values-'+x+'" />');
            var prefill_value = "";
            if(typeof opts.preFill == "string"){
                var vals = opts.preFill.split(",");                 
                for(var i=0; i < vals.length; i++){
                    var v_data = {};
                    v_data[opts.selectedValuesProp] = vals[i];
                    if(vals[i] != ""){
                        add_selected_item(v_data, "000"+i); 
                    }       
                }
                prefill_value = opts.preFill;
            } else {
                prefill_value = "";
                var prefill_count = 0;
                for (k in opts.preFill) if (opts.preFill.hasOwnProperty(k)) prefill_count++;
                if(prefill_count > 0){
                    for(var i=0; i < prefill_count; i++){
                        var new_v = opts.preFill[i][opts.selectedValuesProp];
                        if(new_v == undefined){ new_v = ""; }
                        prefill_value = prefill_value+new_v+",";
                        if(new_v != ""){
                            add_selected_item(opts.preFill[i], "000"+i);    
                        }       
                    }
                }
            }
            if(prefill_value != ""){
                input.val("");
                var lastChar = prefill_value.substring(prefill_value.length-1);
                if(lastChar != ","){ prefill_value = prefill_value+","; }
                values_input.val(","+prefill_value);
                $("li.as-selection-item", selections_holder).addClass("blur").removeClass("selected");
            }
            input.after(values_input);
            selections_holder.click(function(){
                input_focus = true;
                input.focus();
            }).mousedown(function(){ input_focus = false; }).after(results_holder); 

            var timeout = null;
            var prev = "";
            var totalSelections = 0;
            var tab_press = false;

            // Handle input field events
            input.focus(function(){         
                if($(this).val() == opts.startText && values_input.val() == ""){
                    $(this).val("");
                } else if(input_focus){
                    $("li.as-selection-item", selections_holder).removeClass("blur");
                    if($(this).val() != ""){
                        results_ul.css("width",selections_holder.outerWidth());
                        results_holder.show();
                    }
                }
                input_focus = true;
                return true;
            }).blur(function(){
                if($(this).val() == "" && values_input.val() == "" && prefill_value == ""){
                    $(this).val(opts.startText);
                } else if(input_focus){
                    $("li.as-selection-item", selections_holder).addClass("blur").removeClass("selected");
                    results_holder.hide();
                }               
            }).keydown(function(e) {
                // track last key pressed
                lastKeyPressCode = e.keyCode;
                first_focus = false;
                switch(e.keyCode) {
                    case 38: // up
                        e.preventDefault();
                        moveSelection("up");
                        break;
                    case 40: // down
                        e.preventDefault();
                        moveSelection("down");
                        break;
                    case 8:  // delete
                        if(input.val() == ""){                          
                            var last = values_input.val().split(",");
                            last = last[last.length - 2];
                            selections_holder.children().not(org_li.prev()).removeClass("selected");
                            if(org_li.prev().hasClass("selected")){
                                values_input.val(values_input.val().replace(","+last+",",","));
                                opts.selectionRemoved.call(this, org_li.prev());
                            } else {
                                opts.selectionClick.call(this, org_li.prev());
                                org_li.prev().addClass("selected");     
                            }
                        }
                        if(input.val().length == 1){
                            results_holder.hide();
                             prev = "";
                        }
                        if($(":visible",results_holder).length > 0){
                            if (timeout){ clearTimeout(timeout); }
                            timeout = setTimeout(function(){ keyChange(); }, opts.keyDelay);
                        }
                        break;
                    case 9: case 188:  // tab or comma
                        tab_press = true;
                        var i_input = input.val().replace(/(,)/g, "");
                        if(i_input != "" && values_input.val().search(","+i_input+",") < 0 && i_input.length >= opts.minChars){ 
                            e.preventDefault();
                            var n_data = {};
                            n_data[opts.selectedItemProp] = i_input;
                            n_data[opts.selectedValuesProp] = i_input;                                                                              
                            var lis = $("li", selections_holder).length;
                            add_selected_item(n_data, "00"+(lis+1));
                            input.val("");
                        }
                    case 13: // return
                        tab_press = false;
                        var active = $("li.active:first", results_holder);
                        if(active.length > 0){
                            active.click();
                            results_holder.hide();
                        }
                        if(opts.neverSubmit || active.length > 0){
                            e.preventDefault();
                        }
                        break;
                    default:
                        if(opts.showResultList){
                            if(opts.selectionLimit && $("li.as-selection-item", selections_holder).length >= opts.selectionLimit){
                                results_ul.html('<li class="as-message">'+opts.limitText+'</li>');
                                results_holder.show();
                            } else {
                                if (timeout){ clearTimeout(timeout); }
                                timeout = setTimeout(function(){ keyChange(); }, opts.keyDelay);
                            }
                        }
                        break;
                }
            });

            function keyChange() {
                // ignore if the following keys are pressed: [del] [shift] [capslock]
                if( lastKeyPressCode == 46 || (lastKeyPressCode > 8 && lastKeyPressCode < 32) ){ return results_holder.hide(); }
                var string = input.val().replace(/[\\]+|[\/]+/g,"");
                if (string == prev) return;
                prev = string;
                if (string.length >= opts.minChars) {
                    selections_holder.addClass("loading");
                    if(d_type == "string"){
                        var limit = "";
                        if(opts.retrieveLimit){
                            limit = "&limit="+encodeURIComponent(opts.retrieveLimit);
                        }
                        if(opts.beforeRetrieve){
                            string = opts.beforeRetrieve.call(this, string);
                        }
                        $.getJSON(req_string+"?"+opts.queryParam+"="+encodeURIComponent(string)+limit+opts.extraParams, function(data){ 
                            d_count = 0;
                            var new_data = opts.retrieveComplete.call(this, data);
                            for (k in new_data) if (new_data.hasOwnProperty(k)) d_count++;
                            processData(new_data, string); 
                        });
                    } else {
                        if(opts.beforeRetrieve){
                            string = opts.beforeRetrieve.call(this, string);
                        }
                        processData(org_data, string);
                    }
                } else {
                    selections_holder.removeClass("loading");
                    results_holder.hide();
                }
            }
            var num_count = 0;
            function processData(data, query){
                if (!opts.matchCase){ query = query.toLowerCase(); }
                var matchCount = 0;
                results_holder.html(results_ul.html("")).hide();
                for(var i=0;i<d_count;i++){             
                    var num = i;
                    num_count++;
                    var forward = false;
                    if(opts.searchObjProps == "value") {
                        var str = data[num].value;
                    } else {    
                        var str = "";
                        var names = opts.searchObjProps.split(",");
                        for(var y=0;y<names.length;y++){
                            var name = $.trim(names[y]);
                            str = str+data[num][name]+" ";
                        }
                    }
                    if(str){
                        if (!opts.matchCase){ str = str.toLowerCase(); }                
                        if(str.search(query) != -1 && values_input.val().search(","+data[num][opts.selectedValuesProp]+",") == -1){
                            forward = true;
                        }   
                    }
                    if(forward){
                        var formatted = $('<li class="as-result-item" id="as-result-item-'+num+'"></li>').click(function(){
                                var raw_data = $(this).data("data");
                                var number = raw_data.num;
                                if($("#as-selection-"+number, selections_holder).length <= 0 && !tab_press){
                                    var data = raw_data.attributes;
                                    input.val("").focus();
                                    prev = "";
                                    add_selected_item(data, number);
                                    opts.resultClick.call(this, raw_data);
                                    results_holder.hide();
                                }
                                tab_press = false;
                            }).mousedown(function(){ input_focus = false; }).mouseover(function(){
                                $("li", results_ul).removeClass("active");
                                $(this).addClass("active");
                            }).data("data",{attributes: data[num], num: num_count});
                        var this_data = $.extend({},data[num]);
                        if (!opts.matchCase){ 
                            var regx = new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + query + ")(?![^<>]*>)(?![^&;]+;)", "gi");
                        } else {
                            var regx = new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + query + ")(?![^<>]*>)(?![^&;]+;)", "g");
                        }

                        if(opts.resultsHighlight){
                            this_data[opts.selectedItemProp] = this_data[opts.selectedItemProp].replace(regx,"<em>$1</em>");
                        }
                        if(!opts.formatList){
                            formatted = formatted.html(this_data[opts.selectedItemProp]);
                        } else {
                            formatted = opts.formatList.call(this, this_data, formatted);   
                        }
                        results_ul.append(formatted);
                        delete this_data;
                        matchCount++;
                        if(opts.retrieveLimit && opts.retrieveLimit == matchCount ){ break; }
                    }
                }
                selections_holder.removeClass("loading");
                if(matchCount <= 0){
                    results_ul.html('<li class="as-message">'+opts.emptyText+'</li>');
                }
                results_ul.css("width", selections_holder.outerWidth());
                results_holder.show();
                opts.resultsComplete.call(this);
            }

            function add_selected_item(data, num){
                values_input.val(values_input.val()+data[opts.selectedValuesProp]+",");
                var item = $('<li class="as-selection-item" id="as-selection-'+num+'"></li>').click(function(){
                        opts.selectionClick.call(this, $(this));
                        selections_holder.children().removeClass("selected");
                        $(this).addClass("selected");
                    }).mousedown(function(){ input_focus = false; });
                var close = $('<a class="as-close">&times;</a>').click(function(){
                        /* //orignal code
                        values_input.val(values_input.val().replace(","+data[opts.selectedValuesProp]+",",","));
                        opts.selectionRemoved.call(this, item);
                        input_focus = true;
                        input.focus();
                        return false;
                        */
                        /* modifications by Neolite (to correctly delete the first value)*/
                        var val = values_input.val();

                        if (val.split(",").length == 2) { // if there is only one value
                            values_input.val('');
                        } else { // else we do the previous code line which uses a regex to delete the value
                            values_input.val(val.replace(","+data[opts.selectedValuesProp]+",",","));
                        }
                        opts.selectionRemoved.call(this, item);
                        input_focus = true;
                        input.focus();
                        return false;
                    });
                org_li.before(item.html(data[opts.selectedItemProp]).prepend(close));
                opts.selectionAdded.call(this, org_li.prev());  
            }

            function moveSelection(direction){
                if($(":visible",results_holder).length > 0){
                    var lis = $("li", results_holder);
                    if(direction == "down"){
                        var start = lis.eq(0);
                    } else {
                        var start = lis.filter(":last");
                    }                   
                    var active = $("li.active:first", results_holder);
                    if(active.length > 0){
                        if(direction == "down"){
                        start = active.next();
                        } else {
                            start = active.prev();
                        }   
                    }
                    lis.removeClass("active");
                    start.addClass("active");
                }
            }

        });
    }
}

})(jQuery);

`

  1. 1 Posted by Neolite on 06 Jun, 2011 02:01 PM

    Neolite's Avatar

    Well...
    Require the same changes when pressing "return"...
    Why can't call click event when pressing return?

    Bye

Reply to this discussion

Internal reply

Formatting help / Preview (switch to plain text) No formatting (switch to Markdown)

Attaching KB article:

»

Attached Files

You can attach files up to 10MB

If you don't have an account yet, we need to confirm you're human and not a machine trying to post spam.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac