From 5aec6e9a82507f7e674c27ad4da513e31af81d40 Mon Sep 17 00:00:00 2001 From: Mikk3lRo <mikk3lro@gmail.com> Date: Tue, 3 Oct 2017 00:55:47 +0200 Subject: [PATCH] Add new option: search_word_boundary --- coffee/lib/abstract-chosen.coffee | 3 ++- public/options.html | 5 +++++ spec/jquery/searching.spec.coffee | 18 ++++++++++++++++++ spec/proto/searching.spec.coffee | 19 +++++++++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/coffee/lib/abstract-chosen.coffee b/coffee/lib/abstract-chosen.coffee index a83c194f826..3b85fb7b0b5 100644 --- a/coffee/lib/abstract-chosen.coffee +++ b/coffee/lib/abstract-chosen.coffee @@ -27,6 +27,7 @@ class AbstractChosen @enable_split_word_search = if @options.enable_split_word_search? then @options.enable_split_word_search else true @group_search = if @options.group_search? then @options.group_search else true @search_contains = @options.search_contains || false + @search_word_boundary = if @options.search_word_boundary? then @options.search_word_boundary else '^|\\s|\\b' @single_backstroke_delete = if @options.single_backstroke_delete? then @options.single_backstroke_delete else true @max_selected_options = @options.max_selected_options || Infinity @inherit_select_classes = @options.inherit_select_classes || false @@ -217,7 +218,7 @@ class AbstractChosen this.winnow_results_set_highlight() get_search_regex: (escaped_search_string) -> - regex_string = if @search_contains then escaped_search_string else "(^|\\s|\\b)#{escaped_search_string}[^\\s]*" + regex_string = if @search_contains then escaped_search_string else "(#{@search_word_boundary})#{escaped_search_string}[^\\s]*" regex_string = "^#{regex_string}" unless @enable_split_word_search or @search_contains regex_flag = if @case_sensitive_search then "" else "i" new RegExp(regex_string, regex_flag) diff --git a/public/options.html b/public/options.html index 6a92bead277..2f47775511c 100644 --- a/public/options.html +++ b/public/options.html @@ -91,6 +91,11 @@ <h3>Example:</h3> <td>true</td> <td>By default, Chosen will search group labels as well as options, and filter to show all options below matching groups. Set this to <code class="language-javascript">false</code> to search only in the options.</td> </tr> + <tr> + <td>search_word_boundary</td> + <td>^|\\b|\\s</td> + <td>By default, Chosen uses JS RegExp's built-in word boundary to detect word beginnings as well as whitespace or the beginning of the entire label. That works great for ascii-only languages, but <strong>will</strong> erroneously detect word boundaries after letters with umlauts among many, many others.<br>You can pass a string (that will be interpreted as part of a <code class="language-javascript">RegExp</code>) refined for your language and use case to correctly detect word boundaries. A (simplified) example could be <code class="language-javascript">'^|[^A-zæøåÆØÅ]'</code> for Danish.</td> + </tr> <tr> <td>single_backstroke_delete</td> <td>true</td> diff --git a/spec/jquery/searching.spec.coffee b/spec/jquery/searching.spec.coffee index d17f62f85bc..dd4f4f19f74 100644 --- a/spec/jquery/searching.spec.coffee +++ b/spec/jquery/searching.spec.coffee @@ -279,3 +279,21 @@ describe "Searching", -> search_field.trigger("keyup") expect(div.find(".active-result").length).toBe(1) expect(div.find(".active-result")[0].innerText.slice(1)).toBe(boundary_thing) + + it "respects custom search_word_boundary when not using search_contains", -> + div = $("<div>").html(""" + <select> + <option value="Frank Møller">Frank Møller</option> + </select> + """) + div.find("select").chosen({search_word_boundary: '^|[^A-zæøåÆØÅ]'}) + div.find(".chosen-container").trigger("mousedown") # open the drop + + search_field = div.find(".chosen-search-input") + search_field.val('ller') + search_field.trigger("keyup") + expect(div.find(".active-result").length).toBe(0) + search_field.val('Møl') + search_field.trigger("keyup") + expect(div.find(".active-result").length).toBe(1) + expect(div.find(".active-result")[0].innerHTML).toBe('Frank <em>Møl</em>ler') diff --git a/spec/proto/searching.spec.coffee b/spec/proto/searching.spec.coffee index 457396b95d2..7980ac6bd1b 100644 --- a/spec/proto/searching.spec.coffee +++ b/spec/proto/searching.spec.coffee @@ -291,3 +291,22 @@ describe "Searching", -> simulant.fire(search_field, "keyup") expect(div.select(".active-result").length).toBe(1) expect(div.select(".active-result")[0].innerText.slice(1)).toBe(boundary_thing) + + it "respects custom search_word_boundary when not using search_contains", -> + div = new Element("div") + div.update(""" + <select> + <option value="Frank Møller">Frank Møller</option> + </select> + """) + new Chosen(div.down("select"), {search_word_boundary: '^|[^A-zæøåÆØÅ]'}) + simulant.fire(div.down(".chosen-container"), "mousedown") # open the drop + + search_field = div.down(".chosen-search-input") + search_field.value = 'ller' + simulant.fire(search_field, "keyup") + expect(div.select(".active-result").length).toBe(0) + search_field.value = 'Møl' + simulant.fire(search_field, "keyup") + expect(div.select(".active-result").length).toBe(1) + expect(div.select(".active-result")[0].innerHTML).toBe('Frank <em>Møl</em>ler')