Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chosen.prototype.winnow_results when searchText is empty #1139

Closed
meghuizen opened this issue Apr 17, 2013 · 3 comments
Closed

Chosen.prototype.winnow_results when searchText is empty #1139

meghuizen opened this issue Apr 17, 2013 · 3 comments

Comments

@meghuizen
Copy link

The function Chosen.prototype.winnow_results does even search for matches when searchText is empty. Why even bother the regex matches when it's empty?

@meghuizen
Copy link
Author

This function also rebuilds the whole result structure when the searchText is the same as the former time (if you for example expand it the next time with the same searchText as the current state). This gives a slow user experience.

This function is rather slow because of the DOM manipulation in result.html(). Also the regex matching is a bit slow. Usage of both could be minimized so the user experience of the component is a lot better.

@meghuizen
Copy link
Author

This is example code of what I have made from the jQuery part.

This reduced the average time of the function from: 125 ms to 1 ms (on 4019 items, using Chrome and current chosen master version)

Chosen.prototype.winnow_results = function(){
    var found, option, part, parts, regex, regexAnchor, result, result_id, results, searchText, startpos, text, zregex, _i, _j, _len, _len1, _ref1;

    console.time('Chosen.prototype.winnow_result');

    this.no_results_clear();
    results = 0;
    searchText = this.search_field.val() === this.default_text ? "" : $('<div/>').text($.trim(this.search_field.val())).html();

    var sameSearchterm = (typeof(this.oldSearchText) != 'undefined' && this.oldSearchText === searchText);
    regexAnchor = this.search_contains ? "" : "^";
    regex = sameSearchterm ? null : new RegExp(regexAnchor + searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i');
    zregex = sameSearchterm ? null : new RegExp(searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i');
    _ref1 = this.results_data;

    if (!sameSearchterm)
    for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
        option = _ref1[_i];
        if (!option.disabled && !option.empty) {
            if (option.group) {
                $('#' + option.dom_id).css('display', 'none');
            }
            else 
                if (!(this.is_multiple && option.selected)) {
                    found = false;
                    result_id = option.dom_id;
                    result = $("#" + result_id);

                    if (searchText.length) {
                        if (regex.test(option.html)) {
                            found = true;
                            results += 1;
                        }
                        else 
                            if (this.enable_split_word_search && (option.html.indexOf(" ") >= 0 || option.html.indexOf("[") === 0)) {
                                parts = option.html.replace(/\[|\]/g, "").split(" ");
                                if (parts.length) {
                                    for (_j = 0, _len1 = parts.length; _j < _len1; _j++) {
                                        part = parts[_j];
                                        if (regex.test(part)) {
                                            found = true;
                                            results += 1;
                                        }
                                    }
                                }
                            }
                    } else {
                        found = true;
                        results += 1;
                    }


                    if (found) {
                        if (searchText.length) {
                            startpos = option.html.search(zregex);
                            text = option.html.substr(0, startpos + searchText.length) + '</em>' + option.html.substr(startpos + searchText.length);
                            text = text.substr(0, startpos) + '<em>' + text.substr(startpos);
                        }
                        else {
                            text = option.html;
                        }
                        result.html(text);
                        this.result_activate(result);

                        if (option.group_array_index != null) {
                            $("#" + this.results_data[option.group_array_index].dom_id).css('display', 'list-item');
                        }
                    }
                    else {
                        if (this.result_highlight && result_id === this.result_highlight.attr('id')) {
                            this.result_clear_highlight();
                        }
                        this.result_deactivate(result);
                    }
                }
        }
    }

    this.oldSearchText = searchText;

    console.timeEnd('Chosen.prototype.winnow_result');
    if (results < 1 && searchText.length) {
        return this.no_results(searchText);
    }
    else {
        return this.winnow_results_set_highlight();
    }
};

@pfiller
Copy link
Contributor

pfiller commented Jul 10, 2013

The winnow_results method has been totally rewritten ro reduce the amount of dom manipulation it was doing. The net result is a much, much faster Chosen. See #1339 for details.

@pfiller pfiller closed this as completed Jul 10, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants