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

Add new option: search_word_boundary #2898

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion coffee/lib/abstract-chosen.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions public/options.html
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
18 changes: 18 additions & 0 deletions spec/jquery/searching.spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -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')
19 changes: 19 additions & 0 deletions spec/proto/searching.spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -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')