@@ -52,6 +52,7 @@ class Chosen extends AbstractChosen
52
52
53
53
@search_field = @container .find (' input' ).first ()
54
54
@search_results = @container .find (' ul.chosen-results' ).first ()
55
+ @search_results .attr (' id' , " #{ @form_field .id } -chosen-search-results" )
55
56
this .search_field_scale ()
56
57
57
58
@search_no_results = @container .find (' li.no-results' ).first ()
@@ -63,6 +64,7 @@ class Chosen extends AbstractChosen
63
64
@search_container = @container .find (' div.chosen-search' ).first ()
64
65
@selected_item = @container .find (' .chosen-single' ).first ()
65
66
67
+ this .set_aria_labels ()
66
68
this .results_build ()
67
69
this .set_tab_index ()
68
70
this .set_label_behavior ()
@@ -106,7 +108,7 @@ class Chosen extends AbstractChosen
106
108
@container .on ' click.chosen' , (evt ) -> evt .preventDefault (); return # gobble click of anchor
107
109
108
110
destroy : ->
109
- $ (@container [0 ].ownerDocument ).off ' click.chosen' , @click_test_action
111
+ $ (if @container [ 0 ]. getRootNode ? then @container [ 0 ]. getRootNode () else @container [0 ].ownerDocument ).off ' click.chosen' , @click_test_action
110
112
@form_field_label .off ' click.chosen' if @form_field_label .length > 0
111
113
112
114
if @search_field [0 ].tabIndex
@@ -116,6 +118,20 @@ class Chosen extends AbstractChosen
116
118
@form_field_jq .removeData (' chosen' )
117
119
@form_field_jq .show ()
118
120
121
+ set_aria_labels : ->
122
+ @search_field .attr " aria-owns" , @search_results .attr " id"
123
+ if @form_field .attributes [" aria-label" ]
124
+ @search_field .attr " aria-label" , @form_field .attributes [" aria-label" ]
125
+ if @form_field .attributes [" aria-labelledby" ]
126
+ @search_field .attr " aria-labelledby" , @form_field .attributes [" aria-labelledby" ]
127
+ else if Object .prototype .hasOwnProperty .call (@form_field ,' labels' ) && @form_field .labels .length
128
+ labelledbyList = " "
129
+ for label, i in @form_field .labels
130
+ if label .id is " "
131
+ label .id = " #{ @form_field .id } -chosen-label-#{ i} "
132
+ labelledbyList += @form_field .labels [i].id + " "
133
+ @search_field .attr " aria-labelledby" , labelledbyList
134
+
119
135
search_field_disabled : ->
120
136
@is_disabled = @form_field .disabled || @form_field_jq .parents (' fieldset' ).is (' :disabled' )
121
137
@@ -139,7 +155,7 @@ class Chosen extends AbstractChosen
139
155
if not (evt? and ($ evt .target ).hasClass " search-choice-close" )
140
156
if not @active_field
141
157
@search_field .val " " if @is_multiple
142
- $ (@container [0 ].ownerDocument ).on ' click.chosen' , @click_test_action
158
+ $ (if @container [ 0 ]. getRootNode ? then @container [ 0 ]. getRootNode () else @container [0 ].ownerDocument ).on ' click.chosen' , @click_test_action
143
159
this .results_show ()
144
160
else if not @is_multiple and evt and (($ (evt .target )[0 ] == @selected_item [0 ]) || $ (evt .target ).parents (" a.chosen-single" ).length )
145
161
evt .preventDefault ()
@@ -161,17 +177,18 @@ class Chosen extends AbstractChosen
161
177
this .close_field () if not @active_field and @container .hasClass " chosen-container-active"
162
178
163
179
close_field : ->
164
- $ (@container [0 ].ownerDocument ).off " click.chosen" , @click_test_action
180
+ $ (if @container [ 0 ]. getRootNode ? then @container [ 0 ]. getRootNode () else @container [0 ].ownerDocument ).off " click.chosen" , @click_test_action
165
181
166
182
@active_field = false
167
183
this .results_hide ()
184
+ @search_field .attr (" aria-expanded" ,false );
168
185
169
186
@container .removeClass " chosen-container-active"
170
187
this .clear_backstroke ()
171
188
172
189
this .show_search_field_default ()
173
190
this .search_field_scale ()
174
- @search_field .blur ()
191
+ @search_field .trigger " blur"
175
192
176
193
activate_field : ->
177
194
return if @is_disabled
@@ -180,7 +197,9 @@ class Chosen extends AbstractChosen
180
197
@active_field = true
181
198
182
199
@search_field .val (@search_field .val ())
183
- @search_field .focus ()
200
+ @search_field .attr (" aria-expanded" ,true );
201
+ this .search_results .attr (" aria-busy" , false );
202
+ @search_field .trigger " focus"
184
203
185
204
186
205
test_active_click : (evt ) ->
@@ -198,7 +217,7 @@ class Chosen extends AbstractChosen
198
217
199
218
if @is_multiple
200
219
@search_choices .find (" li.search-choice" ).remove ()
201
- else if not @is_multiple
220
+ else
202
221
this .single_set_selected_text ()
203
222
if @disable_search or @form_field .options .length <= @disable_search_threshold
204
223
@search_field [0 ].readOnly = true
@@ -222,6 +241,8 @@ class Chosen extends AbstractChosen
222
241
@result_highlight = el
223
242
@result_highlight .addClass " highlighted"
224
243
244
+ @search_field .attr (" aria-activedescendant" , @result_highlight .attr (" id" ))
245
+
225
246
maxHeight = parseInt @search_results .css (" maxHeight" ), 10
226
247
visible_top = @search_results .scrollTop ()
227
248
visible_bottom = maxHeight + visible_top
@@ -246,7 +267,7 @@ class Chosen extends AbstractChosen
246
267
@container .addClass " chosen-with-drop"
247
268
@results_showing = true
248
269
249
- @search_field .focus ()
270
+ @search_field .trigger " focus"
250
271
@search_field .val this .get_search_field_value ()
251
272
252
273
this .winnow_results ()
@@ -255,6 +276,9 @@ class Chosen extends AbstractChosen
255
276
update_results_content : (content ) ->
256
277
@search_results .html content
257
278
279
+ fire_search_updated : (search_term ) ->
280
+ @form_field_jq .trigger (" chosen:search_updated" , {chosen : this , search_term : search_term})
281
+
258
282
results_hide : ->
259
283
if @results_showing
260
284
this .result_clear_highlight ()
@@ -279,20 +303,26 @@ class Chosen extends AbstractChosen
279
303
if @form_field_label .length > 0
280
304
@form_field_label .on ' click.chosen' , this .label_click_handler
281
305
306
+ set_search_field_placeholder : ->
307
+ if @is_multiple and this .choices_count () < 1
308
+ @search_field .attr (' placeholder' , @default_text )
309
+ else
310
+ @search_field .attr (' placeholder' , ' ' )
311
+
282
312
show_search_field_default : ->
313
+ @search_field .val (' ' )
314
+ do @set_search_field_placeholder
283
315
if @is_multiple and this .choices_count () < 1 and not @active_field
284
- @search_field .val (@default_text )
285
316
@search_field .addClass " default"
286
317
else
287
- @search_field .val (" " )
288
318
@search_field .removeClass " default"
289
319
290
320
search_results_mouseup : (evt ) ->
291
321
target = if $ (evt .target ).hasClass " active-result" then $ (evt .target ) else $ (evt .target ).parents (" .active-result" ).first ()
292
322
if target .length
293
323
@result_highlight = target
294
324
this .result_select (evt)
295
- @search_field .focus ()
325
+ @search_field .trigger " focus"
296
326
297
327
search_results_mouseover : (evt ) ->
298
328
target = if $ (evt .target ).hasClass " active-result" then $ (evt .target ) else $ (evt .target ).parents (" .active-result" ).first ()
@@ -302,14 +332,16 @@ class Chosen extends AbstractChosen
302
332
this .result_clear_highlight () if $ (evt .target ).hasClass (" active-result" ) or $ (evt .target ).parents (' .active-result' ).first ()
303
333
304
334
choice_build : (item ) ->
305
- choice = $ (' <li />' , { class : " search-choice" }).html (" <span>#{ this .choice_label (item)} </span>" )
335
+ choice = $ (' <li />' , { class : " search-choice" , " data-value " : item . value }).html (" <span>#{ this .choice_label (item)} </span>" )
306
336
307
337
if item .disabled
308
338
choice .addClass ' search-choice-disabled'
309
339
else
310
340
close_link = $ (' <a />' , { class : ' search-choice-close' , ' data-option-array-index' : item .array_index })
311
341
close_link .on ' click.chosen' , (evt ) => this .choice_destroy_link_click (evt)
312
342
choice .append close_link
343
+ if @inherit_option_classes && item .classes
344
+ choice[0 ].classList .add item .classes
313
345
314
346
@search_container .before choice
315
347
@@ -321,14 +353,15 @@ class Chosen extends AbstractChosen
321
353
choice_destroy : (link ) ->
322
354
if this .result_deselect ( link[0 ].getAttribute (" data-option-array-index" ) )
323
355
if @active_field
324
- @search_field .focus ()
356
+ @search_field .trigger " focus"
325
357
else
326
358
this .show_search_field_default ()
327
359
328
- this .results_hide () if @is_multiple and this .choices_count () > 0 and this .get_search_field_value ().length < 1
360
+ this .results_hide () if @is_multiple and this .hide_results_on_select and this . choices_count () > 0 and this .get_search_field_value ().length < 1
329
361
330
362
link .parents (' li' ).first ().remove ()
331
363
364
+ do @set_search_field_placeholder
332
365
this .search_field_scale ()
333
366
334
367
results_reset : ->
@@ -366,15 +399,18 @@ class Chosen extends AbstractChosen
366
399
367
400
@form_field .options [item .options_index ].selected = true
368
401
@selected_option_count = null
369
- @search_field .val (" " )
370
402
371
403
if @is_multiple
372
404
this .choice_build item
373
405
else
374
406
this .single_set_selected_text (this .choice_label (item))
375
407
376
408
if @is_multiple && (! @hide_results_on_select || (evt .metaKey or evt .ctrlKey ))
377
- this .winnow_results ()
409
+ if evt .metaKey or evt .ctrlKey
410
+ this .winnow_results (skip_highlight : true )
411
+ else
412
+ @search_field .val (" " )
413
+ this .winnow_results ()
378
414
else
379
415
this .results_hide ()
380
416
this .show_search_field_default ()
@@ -494,7 +530,7 @@ class Chosen extends AbstractChosen
494
530
style_block[style] = @search_field .css (style)
495
531
496
532
div = $ (' <div />' ).css (style_block)
497
- div .text this . get_search_field_value ()
533
+ div .text @ get_search_field_value () || @search_field . attr ( ' placeholder ' )
498
534
$ (' body' ).append div
499
535
500
536
width = div .width () + 25
0 commit comments