chosen-rails 1.5.2 → 1.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 53ab8c7f957d30317d0e6081b2c1e2e7fd67846a
4
- data.tar.gz: dc31f364d75238af5225017fb87bf85d91273930
3
+ metadata.gz: 84d37ed2825106c6c400858bff7497d7d9319335
4
+ data.tar.gz: 6f5a6bbbdf12cf07e6830d3c4ed9f834b6409f5b
5
5
  SHA512:
6
- metadata.gz: 6dee8a53fa50bba34f37ff6888aa8680854d826e1c63623fdf7d2d2d7becab356460d35912194ac5f4db9377b9d65dc1eb56a01a715b36223b93cbb85e6be418
7
- data.tar.gz: f950fbcf9c474463b712defbd0c28319bc24634631f5cd4612b414d53e6b4371a14347366d21d5dc8f523869154cfaf9457f4be6e5aa2181b0f334ce038ea5a6
6
+ metadata.gz: 6e61368b655875ed16a8b99080fb0a2344e249e3ae96121bee97f40f7bda9c060f4d0e6078b8a2bc41fbfe3847e55c456020b4a6fd0150ccdcaf14e76b75aa28
7
+ data.tar.gz: c092ae8213173a6e1d357dea55fbb6cdad215a72e09efbcbd628864a48e7aa2d30217b0871f4c2515eb58593c52916940cad55d7641987576a9984c691c51913
data/README.md CHANGED
@@ -8,17 +8,14 @@ The `chosen-rails` gem integrates the `Chosen` with the Rails asset pipeline.
8
8
 
9
9
  ### Install chosen-rails gem
10
10
 
11
- Include `chosen-rails` in Gemefile
11
+ Include `chosen-rails` in Gemfile
12
12
 
13
13
  ```rb
14
- gem 'compass-rails'
15
14
  gem 'chosen-rails'
16
15
  ```
17
16
 
18
17
  Then run `bundle install`
19
18
 
20
- You need to add `compass-rails` manually since it is not a dependency from version 1.5.1.
21
-
22
19
  Please consider [jquery-turbolinks](https://github.com/kossnocorp/jquery.turbolinks) if you have turbolinks issues for Rails 4 +.
23
20
 
24
21
  ### Include chosen javascript assets
@@ -39,12 +36,6 @@ Or with Prototype
39
36
 
40
37
  Add to your `app/assets/stylesheets/application.css`
41
38
 
42
- ```scss
43
- *= require chosen-compass
44
- ```
45
-
46
- or without `compass-rails`
47
-
48
39
  ```scss
49
40
  *= require chosen
50
41
  ```
@@ -63,7 +63,7 @@ module Chosen
63
63
  input.click
64
64
 
65
65
  within "##{input[:id]} .chosen-drop .chosen-results" do
66
- result = find('.active-result', text: item)
66
+ result = find('.active-result', text: item, match: :prefer_exact)
67
67
 
68
68
  result.click if result.visible?
69
69
  end
@@ -1,6 +1,6 @@
1
1
  module Chosen
2
2
  module Rails
3
- VERSION = '1.5.2'
4
- CHOSEN_VERSION = '1.5.1'
3
+ VERSION = '1.8.2'
4
+ CHOSEN_VERSION = '1.8.2'
5
5
  end
6
6
  end
@@ -24,7 +24,6 @@ class Chosen extends AbstractChosen
24
24
  setup: ->
25
25
  @form_field_jq = $ @form_field
26
26
  @current_selectedIndex = @form_field.selectedIndex
27
- @is_rtl = @form_field_jq.hasClass "chosen-rtl"
28
27
 
29
28
  set_up_html: ->
30
29
  container_classes = ["chosen-container"]
@@ -34,17 +33,19 @@ class Chosen extends AbstractChosen
34
33
 
35
34
  container_props =
36
35
  'class': container_classes.join ' '
37
- 'style': "width: #{this.container_width()};"
38
36
  'title': @form_field.title
39
37
 
40
38
  container_props.id = @form_field.id.replace(/[^\w]/g, '_') + "_chosen" if @form_field.id.length
41
39
 
42
40
  @container = ($ "<div />", container_props)
43
41
 
42
+ # CSP without 'unsafe-inline' doesn't allow setting the style attribute directly
43
+ @container.width this.container_width()
44
+
44
45
  if @is_multiple
45
- @container.html '<ul class="chosen-choices"><li class="search-field"><input type="text" value="' + @default_text + '" class="default" autocomplete="off" style="width:25px;" /></li></ul><div class="chosen-drop"><ul class="chosen-results"></ul></div>'
46
+ @container.html this.get_multi_html()
46
47
  else
47
- @container.html '<a class="chosen-single chosen-default"><span>' + @default_text + '</span><div><b></b></div></a><div class="chosen-drop"><div class="chosen-search"><input type="text" autocomplete="off" /></div><ul class="chosen-results"></ul></div>'
48
+ @container.html this.get_single_html()
48
49
 
49
50
  @form_field_jq.hide().after @container
50
51
  @dropdown = @container.find('div.chosen-drop').first()
@@ -70,42 +71,44 @@ class Chosen extends AbstractChosen
70
71
  @form_field_jq.trigger("chosen:ready", {chosen: this})
71
72
 
72
73
  register_observers: ->
73
- @container.bind 'touchstart.chosen', (evt) => this.container_mousedown(evt); evt.preventDefault()
74
- @container.bind 'touchend.chosen', (evt) => this.container_mouseup(evt); evt.preventDefault()
75
-
76
- @container.bind 'mousedown.chosen', (evt) => this.container_mousedown(evt); return
77
- @container.bind 'mouseup.chosen', (evt) => this.container_mouseup(evt); return
78
- @container.bind 'mouseenter.chosen', (evt) => this.mouse_enter(evt); return
79
- @container.bind 'mouseleave.chosen', (evt) => this.mouse_leave(evt); return
80
-
81
- @search_results.bind 'mouseup.chosen', (evt) => this.search_results_mouseup(evt); return
82
- @search_results.bind 'mouseover.chosen', (evt) => this.search_results_mouseover(evt); return
83
- @search_results.bind 'mouseout.chosen', (evt) => this.search_results_mouseout(evt); return
84
- @search_results.bind 'mousewheel.chosen DOMMouseScroll.chosen', (evt) => this.search_results_mousewheel(evt); return
85
-
86
- @search_results.bind 'touchstart.chosen', (evt) => this.search_results_touchstart(evt); return
87
- @search_results.bind 'touchmove.chosen', (evt) => this.search_results_touchmove(evt); return
88
- @search_results.bind 'touchend.chosen', (evt) => this.search_results_touchend(evt); return
89
-
90
- @form_field_jq.bind "chosen:updated.chosen", (evt) => this.results_update_field(evt); return
91
- @form_field_jq.bind "chosen:activate.chosen", (evt) => this.activate_field(evt); return
92
- @form_field_jq.bind "chosen:open.chosen", (evt) => this.container_mousedown(evt); return
93
- @form_field_jq.bind "chosen:close.chosen", (evt) => this.input_blur(evt); return
94
-
95
- @search_field.bind 'blur.chosen', (evt) => this.input_blur(evt); return
96
- @search_field.bind 'keyup.chosen', (evt) => this.keyup_checker(evt); return
97
- @search_field.bind 'keydown.chosen', (evt) => this.keydown_checker(evt); return
98
- @search_field.bind 'focus.chosen', (evt) => this.input_focus(evt); return
99
- @search_field.bind 'cut.chosen', (evt) => this.clipboard_event_checker(evt); return
100
- @search_field.bind 'paste.chosen', (evt) => this.clipboard_event_checker(evt); return
74
+ @container.on 'touchstart.chosen', (evt) => this.container_mousedown(evt); return
75
+ @container.on 'touchend.chosen', (evt) => this.container_mouseup(evt); return
76
+
77
+ @container.on 'mousedown.chosen', (evt) => this.container_mousedown(evt); return
78
+ @container.on 'mouseup.chosen', (evt) => this.container_mouseup(evt); return
79
+ @container.on 'mouseenter.chosen', (evt) => this.mouse_enter(evt); return
80
+ @container.on 'mouseleave.chosen', (evt) => this.mouse_leave(evt); return
81
+
82
+ @search_results.on 'mouseup.chosen', (evt) => this.search_results_mouseup(evt); return
83
+ @search_results.on 'mouseover.chosen', (evt) => this.search_results_mouseover(evt); return
84
+ @search_results.on 'mouseout.chosen', (evt) => this.search_results_mouseout(evt); return
85
+ @search_results.on 'mousewheel.chosen DOMMouseScroll.chosen', (evt) => this.search_results_mousewheel(evt); return
86
+
87
+ @search_results.on 'touchstart.chosen', (evt) => this.search_results_touchstart(evt); return
88
+ @search_results.on 'touchmove.chosen', (evt) => this.search_results_touchmove(evt); return
89
+ @search_results.on 'touchend.chosen', (evt) => this.search_results_touchend(evt); return
90
+
91
+ @form_field_jq.on "chosen:updated.chosen", (evt) => this.results_update_field(evt); return
92
+ @form_field_jq.on "chosen:activate.chosen", (evt) => this.activate_field(evt); return
93
+ @form_field_jq.on "chosen:open.chosen", (evt) => this.container_mousedown(evt); return
94
+ @form_field_jq.on "chosen:close.chosen", (evt) => this.close_field(evt); return
95
+
96
+ @search_field.on 'blur.chosen', (evt) => this.input_blur(evt); return
97
+ @search_field.on 'keyup.chosen', (evt) => this.keyup_checker(evt); return
98
+ @search_field.on 'keydown.chosen', (evt) => this.keydown_checker(evt); return
99
+ @search_field.on 'focus.chosen', (evt) => this.input_focus(evt); return
100
+ @search_field.on 'cut.chosen', (evt) => this.clipboard_event_checker(evt); return
101
+ @search_field.on 'paste.chosen', (evt) => this.clipboard_event_checker(evt); return
101
102
 
102
103
  if @is_multiple
103
- @search_choices.bind 'click.chosen', (evt) => this.choices_click(evt); return
104
+ @search_choices.on 'click.chosen', (evt) => this.choices_click(evt); return
104
105
  else
105
- @container.bind 'click.chosen', (evt) -> evt.preventDefault(); return # gobble click of anchor
106
+ @container.on 'click.chosen', (evt) -> evt.preventDefault(); return # gobble click of anchor
106
107
 
107
108
  destroy: ->
108
- $(@container[0].ownerDocument).unbind "click.chosen", @click_test_action
109
+ $(@container[0].ownerDocument).off 'click.chosen', @click_test_action
110
+ @form_field_label.off 'click.chosen' if @form_field_label.length > 0
111
+
109
112
  if @search_field[0].tabIndex
110
113
  @form_field_jq[0].tabIndex = @search_field[0].tabIndex
111
114
 
@@ -114,32 +117,35 @@ class Chosen extends AbstractChosen
114
117
  @form_field_jq.show()
115
118
 
116
119
  search_field_disabled: ->
117
- @is_disabled = @form_field_jq[0].disabled
118
- if(@is_disabled)
119
- @container.addClass 'chosen-disabled'
120
- @search_field[0].disabled = true
121
- @selected_item.unbind "focus.chosen", @activate_action if !@is_multiple
120
+ @is_disabled = @form_field.disabled || @form_field_jq.parents('fieldset').is(':disabled')
121
+
122
+ @container.toggleClass 'chosen-disabled', @is_disabled
123
+ @search_field[0].disabled = @is_disabled
124
+
125
+ unless @is_multiple
126
+ @selected_item.off 'focus.chosen', this.activate_field
127
+
128
+ if @is_disabled
122
129
  this.close_field()
123
- else
124
- @container.removeClass 'chosen-disabled'
125
- @search_field[0].disabled = false
126
- @selected_item.bind "focus.chosen", @activate_action if !@is_multiple
130
+ else unless @is_multiple
131
+ @selected_item.on 'focus.chosen', this.activate_field
127
132
 
128
133
  container_mousedown: (evt) ->
129
- if !@is_disabled
130
- if evt and evt.type is "mousedown" and not @results_showing
131
- evt.preventDefault()
134
+ return if @is_disabled
135
+
136
+ if evt and evt.type in ['mousedown', 'touchstart'] and not @results_showing
137
+ evt.preventDefault()
132
138
 
133
- if not (evt? and ($ evt.target).hasClass "search-choice-close")
134
- if not @active_field
135
- @search_field.val "" if @is_multiple
136
- $(@container[0].ownerDocument).bind 'click.chosen', @click_test_action
137
- this.results_show()
138
- else if not @is_multiple and evt and (($(evt.target)[0] == @selected_item[0]) || $(evt.target).parents("a.chosen-single").length)
139
- evt.preventDefault()
140
- this.results_toggle()
139
+ if not (evt? and ($ evt.target).hasClass "search-choice-close")
140
+ if not @active_field
141
+ @search_field.val "" if @is_multiple
142
+ $(@container[0].ownerDocument).on 'click.chosen', @click_test_action
143
+ this.results_show()
144
+ else if not @is_multiple and evt and (($(evt.target)[0] == @selected_item[0]) || $(evt.target).parents("a.chosen-single").length)
145
+ evt.preventDefault()
146
+ this.results_toggle()
141
147
 
142
- this.activate_field()
148
+ this.activate_field()
143
149
 
144
150
  container_mouseup: (evt) ->
145
151
  this.results_reset(evt) if evt.target.nodeName is "ABBR" and not @is_disabled
@@ -155,7 +161,7 @@ class Chosen extends AbstractChosen
155
161
  this.close_field() if not @active_field and @container.hasClass "chosen-container-active"
156
162
 
157
163
  close_field: ->
158
- $(@container[0].ownerDocument).unbind "click.chosen", @click_test_action
164
+ $(@container[0].ownerDocument).off "click.chosen", @click_test_action
159
165
 
160
166
  @active_field = false
161
167
  this.results_hide()
@@ -165,8 +171,11 @@ class Chosen extends AbstractChosen
165
171
 
166
172
  this.show_search_field_default()
167
173
  this.search_field_scale()
174
+ @search_field.blur()
168
175
 
169
176
  activate_field: ->
177
+ return if @is_disabled
178
+
170
179
  @container.addClass "chosen-container-active"
171
180
  @active_field = true
172
181
 
@@ -238,7 +247,7 @@ class Chosen extends AbstractChosen
238
247
  @results_showing = true
239
248
 
240
249
  @search_field.focus()
241
- @search_field.val @search_field.val()
250
+ @search_field.val this.get_search_field_value()
242
251
 
243
252
  this.winnow_results()
244
253
  @form_field_jq.trigger("chosen:showing_dropdown", {chosen: this})
@@ -268,7 +277,7 @@ class Chosen extends AbstractChosen
268
277
  @form_field_label = $("label[for='#{@form_field.id}']") #next check for a for=#{id}
269
278
 
270
279
  if @form_field_label.length > 0
271
- @form_field_label.bind 'click.chosen', (evt) => if @is_multiple then this.container_mousedown(evt) else this.activate_field()
280
+ @form_field_label.on 'click.chosen', this.label_click_handler
272
281
 
273
282
  show_search_field_default: ->
274
283
  if @is_multiple and this.choices_count() < 1 and not @active_field
@@ -290,7 +299,7 @@ class Chosen extends AbstractChosen
290
299
  this.result_do_highlight( target ) if target
291
300
 
292
301
  search_results_mouseout: (evt) ->
293
- this.result_clear_highlight() if $(evt.target).hasClass "active-result" or $(evt.target).parents('.active-result').first()
302
+ this.result_clear_highlight() if $(evt.target).hasClass("active-result") or $(evt.target).parents('.active-result').first()
294
303
 
295
304
  choice_build: (item) ->
296
305
  choice = $('<li />', { class: "search-choice" }).html("<span>#{this.choice_label(item)}</span>")
@@ -299,7 +308,7 @@ class Chosen extends AbstractChosen
299
308
  choice.addClass 'search-choice-disabled'
300
309
  else
301
310
  close_link = $('<a />', { class: 'search-choice-close', 'data-option-array-index': item.array_index })
302
- close_link.bind 'click.chosen', (evt) => this.choice_destroy_link_click(evt)
311
+ close_link.on 'click.chosen', (evt) => this.choice_destroy_link_click(evt)
303
312
  choice.append close_link
304
313
 
305
314
  @search_container.before choice
@@ -311,9 +320,12 @@ class Chosen extends AbstractChosen
311
320
 
312
321
  choice_destroy: (link) ->
313
322
  if this.result_deselect( link[0].getAttribute("data-option-array-index") )
314
- this.show_search_field_default()
323
+ if @active_field
324
+ @search_field.focus()
325
+ else
326
+ this.show_search_field_default()
315
327
 
316
- this.results_hide() if @is_multiple and this.choices_count() > 0 and @search_field.val().length < 1
328
+ this.results_hide() if @is_multiple and this.choices_count() > 0 and this.get_search_field_value().length < 1
317
329
 
318
330
  link.parents('li').first().remove()
319
331
 
@@ -325,7 +337,7 @@ class Chosen extends AbstractChosen
325
337
  this.single_set_selected_text()
326
338
  this.show_search_field_default()
327
339
  this.results_reset_cleanup()
328
- @form_field_jq.trigger "change"
340
+ this.trigger_form_field_change()
329
341
  this.results_hide() if @active_field
330
342
 
331
343
  results_reset_cleanup: ->
@@ -354,16 +366,20 @@ class Chosen extends AbstractChosen
354
366
 
355
367
  @form_field.options[item.options_index].selected = true
356
368
  @selected_option_count = null
369
+ @search_field.val("")
357
370
 
358
371
  if @is_multiple
359
372
  this.choice_build item
360
373
  else
361
374
  this.single_set_selected_text(this.choice_label(item))
362
375
 
363
- this.results_hide() unless (evt.metaKey or evt.ctrlKey) and @is_multiple
364
- this.show_search_field_default()
376
+ if @is_multiple && (!@hide_results_on_select || (evt.metaKey or evt.ctrlKey))
377
+ this.winnow_results()
378
+ else
379
+ this.results_hide()
380
+ this.show_search_field_default()
365
381
 
366
- @form_field_jq.trigger "change", {'selected': @form_field.options[item.options_index].value} if @is_multiple || @form_field.selectedIndex != @current_selectedIndex
382
+ this.trigger_form_field_change selected: @form_field.options[item.options_index].value if @is_multiple || @form_field.selectedIndex != @current_selectedIndex
367
383
  @current_selectedIndex = @form_field.selectedIndex
368
384
 
369
385
  evt.preventDefault()
@@ -391,7 +407,7 @@ class Chosen extends AbstractChosen
391
407
  this.result_clear_highlight()
392
408
  this.winnow_results() if @results_showing
393
409
 
394
- @form_field_jq.trigger "change", {deselected: @form_field.options[result_data.options_index].value}
410
+ this.trigger_form_field_change deselected: @form_field.options[result_data.options_index].value
395
411
  this.search_field_scale()
396
412
 
397
413
  return true
@@ -403,8 +419,14 @@ class Chosen extends AbstractChosen
403
419
  @selected_item.find("span").first().after "<abbr class=\"search-choice-close\"></abbr>" unless @selected_item.find("abbr").length
404
420
  @selected_item.addClass("chosen-single-with-deselect")
405
421
 
422
+ get_search_field_value: ->
423
+ @search_field.val()
424
+
406
425
  get_search_text: ->
407
- $('<div/>').text($.trim(@search_field.val())).html()
426
+ $.trim this.get_search_field_value()
427
+
428
+ escape_html: (text) ->
429
+ $('<div/>').text(text).html()
408
430
 
409
431
  winnow_results_set_highlight: ->
410
432
  selected_results = if not @is_multiple then @search_results.find(".result-selected.active-result") else []
@@ -413,9 +435,7 @@ class Chosen extends AbstractChosen
413
435
  this.result_do_highlight do_high if do_high?
414
436
 
415
437
  no_results: (terms) ->
416
- no_results_html = $('<li class="no-results">' + @results_none_found + ' "<span></span>"</li>')
417
- no_results_html.find("span").first().html(terms)
418
-
438
+ no_results_html = this.get_no_results_html(terms)
419
439
  @search_results.append no_results_html
420
440
  @form_field_jq.trigger("chosen:no_results", {chosen:this})
421
441
 
@@ -458,56 +478,33 @@ class Chosen extends AbstractChosen
458
478
  @pending_backstroke.removeClass "search-choice-focus" if @pending_backstroke
459
479
  @pending_backstroke = null
460
480
 
461
- keydown_checker: (evt) ->
462
- stroke = evt.which ? evt.keyCode
463
- this.search_field_scale()
464
-
465
- this.clear_backstroke() if stroke != 8 and this.pending_backstroke
466
-
467
- switch stroke
468
- when 8
469
- @backstroke_length = this.search_field.val().length
470
- break
471
- when 9
472
- this.result_select(evt) if this.results_showing and not @is_multiple
473
- @mouse_on_container = false
474
- break
475
- when 13
476
- evt.preventDefault() if this.results_showing
477
- break
478
- when 32
479
- evt.preventDefault() if @disable_search
480
- break
481
- when 38
482
- evt.preventDefault()
483
- this.keyup_arrow()
484
- break
485
- when 40
486
- evt.preventDefault()
487
- this.keydown_arrow()
488
- break
489
-
490
481
  search_field_scale: ->
491
- if @is_multiple
492
- h = 0
493
- w = 0
482
+ return unless @is_multiple
483
+
484
+ style_block =
485
+ position: 'absolute'
486
+ left: '-1000px'
487
+ top: '-1000px'
488
+ display: 'none'
489
+ whiteSpace: 'pre'
494
490
 
495
- style_block = "position:absolute; left: -1000px; top: -1000px; display:none;"
496
- styles = ['font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing']
491
+ styles = ['fontSize', 'fontStyle', 'fontWeight', 'fontFamily', 'lineHeight', 'textTransform', 'letterSpacing']
497
492
 
498
- for style in styles
499
- style_block += style + ":" + @search_field.css(style) + ";"
493
+ for style in styles
494
+ style_block[style] = @search_field.css(style)
500
495
 
501
- div = $('<div />', { 'style' : style_block })
502
- div.text @search_field.val()
503
- $('body').append div
496
+ div = $('<div />').css(style_block)
497
+ div.text this.get_search_field_value()
498
+ $('body').append div
504
499
 
505
- w = div.width() + 25
506
- div.remove()
500
+ width = div.width() + 25
501
+ div.remove()
507
502
 
508
- f_width = @container.outerWidth()
503
+ if @container.is(':visible')
504
+ width = Math.min(@container.outerWidth() - 10, width)
509
505
 
510
- if( w > f_width - 10 )
511
- w = f_width - 10
506
+ @search_field.width(width)
512
507
 
513
- @search_field.css({'width': w + 'px'})
508
+ trigger_form_field_change: (extra) ->
509
+ @form_field_jq.trigger "input", extra
510
+ @form_field_jq.trigger "change", extra
@@ -2,15 +2,6 @@ class @Chosen extends AbstractChosen
2
2
 
3
3
  setup: ->
4
4
  @current_selectedIndex = @form_field.selectedIndex
5
- @is_rtl = @form_field.hasClassName "chosen-rtl"
6
-
7
- set_default_values: ->
8
- super()
9
-
10
- # HTML Templates
11
- @single_temp = new Template('<a class="chosen-single chosen-default"><span>#{default}</span><div><b></b></div></a><div class="chosen-drop"><div class="chosen-search"><input type="text" autocomplete="off" /></div><ul class="chosen-results"></ul></div>')
12
- @multi_temp = new Template('<ul class="chosen-choices"><li class="search-field"><input type="text" value="#{default}" class="default" autocomplete="off" style="width:25px;" /></li></ul><div class="chosen-drop"><ul class="chosen-results"></ul></div>')
13
- @no_results_temp = new Template('<li class="no-results">' + @results_none_found + ' "<span>#{terms}</span>"</li>')
14
5
 
15
6
  set_up_html: ->
16
7
  container_classes = ["chosen-container"]
@@ -20,12 +11,19 @@ class @Chosen extends AbstractChosen
20
11
 
21
12
  container_props =
22
13
  'class': container_classes.join ' '
23
- 'style': "width: #{this.container_width()};"
24
14
  'title': @form_field.title
25
15
 
26
16
  container_props.id = @form_field.id.replace(/[^\w]/g, '_') + "_chosen" if @form_field.id.length
27
17
 
28
- @container = if @is_multiple then new Element('div', container_props).update( @multi_temp.evaluate({ "default": @default_text}) ) else new Element('div', container_props).update( @single_temp.evaluate({ "default":@default_text }) )
18
+ @container = new Element('div', container_props)
19
+
20
+ # CSP without 'unsafe-inline' doesn't allow setting the style attribute directly
21
+ @container.setStyle(width: this.container_width())
22
+
23
+ if @is_multiple
24
+ @container.update this.get_multi_html()
25
+ else
26
+ @container.update this.get_single_html()
29
27
 
30
28
  @form_field.hide().insert({ after: @container })
31
29
  @dropdown = @container.down('div.chosen-drop')
@@ -51,8 +49,8 @@ class @Chosen extends AbstractChosen
51
49
  @form_field.fire("chosen:ready", {chosen: this})
52
50
 
53
51
  register_observers: ->
54
- @container.observe "touchstart", (evt) => this.container_mousedown(evt); evt.preventDefault()
55
- @container.observe "touchend", (evt) => this.container_mouseup(evt); evt.preventDefault()
52
+ @container.observe "touchstart", (evt) => this.container_mousedown(evt)
53
+ @container.observe "touchend", (evt) => this.container_mouseup(evt)
56
54
 
57
55
  @container.observe "mousedown", (evt) => this.container_mousedown(evt)
58
56
  @container.observe "mouseup", (evt) => this.container_mouseup(evt)
@@ -72,7 +70,7 @@ class @Chosen extends AbstractChosen
72
70
  @form_field.observe "chosen:updated", (evt) => this.results_update_field(evt)
73
71
  @form_field.observe "chosen:activate", (evt) => this.activate_field(evt)
74
72
  @form_field.observe "chosen:open", (evt) => this.container_mousedown(evt)
75
- @form_field.observe "chosen:close", (evt) => this.input_blur(evt)
73
+ @form_field.observe "chosen:close", (evt) => this.close_field(evt)
76
74
 
77
75
  @search_field.observe "blur", (evt) => this.input_blur(evt)
78
76
  @search_field.observe "keyup", (evt) => this.keyup_checker(evt)
@@ -89,7 +87,9 @@ class @Chosen extends AbstractChosen
89
87
  destroy: ->
90
88
  @container.ownerDocument.stopObserving "click", @click_test_action
91
89
 
92
- @form_field.stopObserving()
90
+ for event in ['chosen:updated', 'chosen:activate', 'chosen:open', 'chosen:close']
91
+ @form_field.stopObserving(event)
92
+
93
93
  @container.stopObserving()
94
94
  @search_results.stopObserving()
95
95
  @search_field.stopObserving()
@@ -109,31 +109,38 @@ class @Chosen extends AbstractChosen
109
109
  @form_field.show()
110
110
 
111
111
  search_field_disabled: ->
112
- @is_disabled = @form_field.disabled
113
- if(@is_disabled)
112
+ @is_disabled = @form_field.disabled || @form_field.up('fieldset')?.disabled || false
113
+
114
+ if @is_disabled
114
115
  @container.addClassName 'chosen-disabled'
115
- @search_field.disabled = true
116
- @selected_item.stopObserving "focus", @activate_action if !@is_multiple
117
- this.close_field()
118
116
  else
119
117
  @container.removeClassName 'chosen-disabled'
120
- @search_field.disabled = false
121
- @selected_item.observe "focus", @activate_action if !@is_multiple
118
+
119
+ @search_field.disabled = @is_disabled
120
+
121
+ unless @is_multiple
122
+ @selected_item.stopObserving 'focus', this.activate_field
123
+
124
+ if @is_disabled
125
+ this.close_field()
126
+ else unless @is_multiple
127
+ @selected_item.observe 'focus', this.activate_field
122
128
 
123
129
  container_mousedown: (evt) ->
124
- if !@is_disabled
125
- if evt and evt.type is "mousedown" and not @results_showing
126
- evt.stop()
130
+ return if @is_disabled
131
+
132
+ if evt and evt.type in ['mousedown', 'touchstart'] and not @results_showing
133
+ evt.preventDefault()
127
134
 
128
- if not (evt? and evt.target.hasClassName "search-choice-close")
129
- if not @active_field
130
- @search_field.clear() if @is_multiple
131
- @container.ownerDocument.observe "click", @click_test_action
132
- this.results_show()
133
- else if not @is_multiple and evt and (evt.target is @selected_item || evt.target.up("a.chosen-single"))
134
- this.results_toggle()
135
+ if not (evt? and evt.target.hasClassName "search-choice-close")
136
+ if not @active_field
137
+ @search_field.clear() if @is_multiple
138
+ @container.ownerDocument.observe "click", @click_test_action
139
+ this.results_show()
140
+ else if not @is_multiple and evt and (evt.target is @selected_item || evt.target.up("a.chosen-single"))
141
+ this.results_toggle()
135
142
 
136
- this.activate_field()
143
+ this.activate_field()
137
144
 
138
145
  container_mouseup: (evt) ->
139
146
  this.results_reset(evt) if evt.target.nodeName is "ABBR" and not @is_disabled
@@ -159,12 +166,15 @@ class @Chosen extends AbstractChosen
159
166
 
160
167
  this.show_search_field_default()
161
168
  this.search_field_scale()
169
+ @search_field.blur()
162
170
 
163
171
  activate_field: ->
172
+ return if @is_disabled
173
+
164
174
  @container.addClassName "chosen-container-active"
165
175
  @active_field = true
166
176
 
167
- @search_field.value = @search_field.value
177
+ @search_field.value = this.get_search_field_value()
168
178
  @search_field.focus()
169
179
 
170
180
  test_active_click: (evt) ->
@@ -229,7 +239,7 @@ class @Chosen extends AbstractChosen
229
239
  @results_showing = true
230
240
 
231
241
  @search_field.focus()
232
- @search_field.value = @search_field.value
242
+ @search_field.value = this.get_search_field_value()
233
243
 
234
244
  this.winnow_results()
235
245
  @form_field.fire("chosen:showing_dropdown", {chosen: this})
@@ -259,7 +269,7 @@ class @Chosen extends AbstractChosen
259
269
  @form_field_label = $$("label[for='#{@form_field.id}']").first() #next check for a for=#{id}
260
270
 
261
271
  if @form_field_label?
262
- @form_field_label.observe "click", (evt) => if @is_multiple then this.container_mousedown(evt) else this.activate_field()
272
+ @form_field_label.observe "click", this.label_click_handler
263
273
 
264
274
  show_search_field_default: ->
265
275
  if @is_multiple and this.choices_count() < 1 and not @active_field
@@ -302,9 +312,12 @@ class @Chosen extends AbstractChosen
302
312
 
303
313
  choice_destroy: (link) ->
304
314
  if this.result_deselect link.readAttribute("rel")
305
- this.show_search_field_default()
315
+ if @active_field
316
+ @search_field.focus()
317
+ else
318
+ this.show_search_field_default()
306
319
 
307
- this.results_hide() if @is_multiple and this.choices_count() > 0 and @search_field.value.length < 1
320
+ this.results_hide() if @is_multiple and this.choices_count() > 0 and this.get_search_field_value().length < 1
308
321
 
309
322
  link.up('li').remove()
310
323
 
@@ -316,7 +329,7 @@ class @Chosen extends AbstractChosen
316
329
  this.single_set_selected_text()
317
330
  this.show_search_field_default()
318
331
  this.results_reset_cleanup()
319
- @form_field.simulate("change") if typeof Event.simulate is 'function'
332
+ this.trigger_form_field_change()
320
333
  this.results_hide() if @active_field
321
334
 
322
335
  results_reset_cleanup: ->
@@ -345,16 +358,20 @@ class @Chosen extends AbstractChosen
345
358
 
346
359
  @form_field.options[item.options_index].selected = true
347
360
  @selected_option_count = null
361
+ @search_field.value = ""
348
362
 
349
363
  if @is_multiple
350
364
  this.choice_build item
351
365
  else
352
366
  this.single_set_selected_text(this.choice_label(item))
353
367
 
354
- this.results_hide() unless (evt.metaKey or evt.ctrlKey) and @is_multiple
355
- this.show_search_field_default()
368
+ if @is_multiple && (!@hide_results_on_select || (evt.metaKey or evt.ctrlKey))
369
+ this.winnow_results()
370
+ else
371
+ this.results_hide()
372
+ this.show_search_field_default()
356
373
 
357
- @form_field.simulate("change") if typeof Event.simulate is 'function' && (@is_multiple || @form_field.selectedIndex != @current_selectedIndex)
374
+ this.trigger_form_field_change() if @is_multiple || @form_field.selectedIndex != @current_selectedIndex
358
375
  @current_selectedIndex = @form_field.selectedIndex
359
376
 
360
377
  evt.preventDefault()
@@ -382,7 +399,7 @@ class @Chosen extends AbstractChosen
382
399
  this.result_clear_highlight()
383
400
  this.winnow_results() if @results_showing
384
401
 
385
- @form_field.simulate("change") if typeof Event.simulate is 'function'
402
+ this.trigger_form_field_change()
386
403
  this.search_field_scale()
387
404
  return true
388
405
  else
@@ -393,8 +410,14 @@ class @Chosen extends AbstractChosen
393
410
  @selected_item.down("span").insert { after: "<abbr class=\"search-choice-close\"></abbr>" } unless @selected_item.down("abbr")
394
411
  @selected_item.addClassName("chosen-single-with-deselect")
395
412
 
413
+ get_search_field_value: ->
414
+ @search_field.value
415
+
396
416
  get_search_text: ->
397
- @search_field.value.strip().escapeHTML()
417
+ this.get_search_field_value().strip()
418
+
419
+ escape_html: (text) ->
420
+ text.escapeHTML()
398
421
 
399
422
  winnow_results_set_highlight: ->
400
423
  if not @is_multiple
@@ -406,7 +429,7 @@ class @Chosen extends AbstractChosen
406
429
  this.result_do_highlight do_high if do_high?
407
430
 
408
431
  no_results: (terms) ->
409
- @search_results.insert @no_results_temp.evaluate( terms: terms )
432
+ @search_results.insert this.get_no_results_html(terms)
410
433
  @form_field.fire("chosen:no_results", {chosen: this})
411
434
 
412
435
  no_results_clear: ->
@@ -453,55 +476,45 @@ class @Chosen extends AbstractChosen
453
476
  @pending_backstroke.removeClassName("search-choice-focus") if @pending_backstroke
454
477
  @pending_backstroke = null
455
478
 
456
- keydown_checker: (evt) ->
457
- stroke = evt.which ? evt.keyCode
458
- this.search_field_scale()
459
-
460
- this.clear_backstroke() if stroke != 8 and this.pending_backstroke
461
-
462
- switch stroke
463
- when 8
464
- @backstroke_length = this.search_field.value.length
465
- break
466
- when 9
467
- this.result_select(evt) if this.results_showing and not @is_multiple
468
- @mouse_on_container = false
469
- break
470
- when 13
471
- evt.preventDefault() if this.results_showing
472
- break
473
- when 32
474
- evt.preventDefault() if @disable_search
475
- break
476
- when 38
477
- evt.preventDefault()
478
- this.keyup_arrow()
479
- break
480
- when 40
481
- evt.preventDefault()
482
- this.keydown_arrow()
483
- break
484
-
485
479
  search_field_scale: ->
486
- if @is_multiple
487
- h = 0
488
- w = 0
489
-
490
- style_block = "position:absolute; left: -1000px; top: -1000px; display:none;"
491
- styles = ['font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing']
492
-
493
- for style in styles
494
- style_block += style + ":" + @search_field.getStyle(style) + ";"
495
-
496
- div = new Element('div', { 'style' : style_block }).update(@search_field.value.escapeHTML())
497
- document.body.appendChild(div)
498
-
499
- w = Element.measure(div, 'width') + 25
500
- div.remove()
501
-
502
- f_width = @container.getWidth()
503
-
504
- if( w > f_width-10 )
505
- w = f_width - 10
506
-
507
- @search_field.setStyle({'width': w + 'px'})
480
+ return unless @is_multiple
481
+
482
+ style_block =
483
+ position: 'absolute'
484
+ left: '-1000px'
485
+ top: '-1000px'
486
+ display: 'none'
487
+ whiteSpace: 'pre'
488
+
489
+ styles = ['fontSize', 'fontStyle', 'fontWeight', 'fontFamily', 'lineHeight', 'textTransform', 'letterSpacing']
490
+
491
+ for style in styles
492
+ style_block[style] = @search_field.getStyle(style)
493
+
494
+ div = new Element('div').update(this.escape_html(this.get_search_field_value()))
495
+ # CSP without 'unsafe-inline' doesn't allow setting the style attribute directly
496
+ div.setStyle(style_block)
497
+ document.body.appendChild(div)
498
+
499
+ width = div.measure('width') + 25
500
+ div.remove()
501
+
502
+ if container_width = @container.getWidth()
503
+ width = Math.min(container_width - 10, width)
504
+
505
+ @search_field.setStyle(width: width + 'px')
506
+
507
+ trigger_form_field_change: ->
508
+ triggerHtmlEvent @form_field, 'input'
509
+ triggerHtmlEvent @form_field, 'change'
510
+
511
+ triggerHtmlEvent = (element, eventType) ->
512
+ if element.dispatchEvent # Modern way:
513
+ try
514
+ evt = new Event(eventType, bubbles: true, cancelable: true)
515
+ catch
516
+ evt = document.createEvent('HTMLEvents')
517
+ evt.initEvent(eventType, true, true);
518
+ element.dispatchEvent(evt)
519
+ else # Old IE:
520
+ element.fireEvent("on#{eventType}", document.createEventObject());
@@ -20,6 +20,7 @@ class AbstractChosen
20
20
  @mouse_on_container = false
21
21
  @results_showing = false
22
22
  @result_highlighted = null
23
+ @is_rtl = @options.rtl || /\bchosen-rtl\b/.test(@form_field.className)
23
24
  @allow_single_deselect = if @options.allow_single_deselect? and @form_field.options[0]? and @form_field.options[0].text is "" then @options.allow_single_deselect else false
24
25
  @disable_search_threshold = @options.disable_search_threshold || 0
25
26
  @disable_search = @options.disable_search || false
@@ -34,6 +35,7 @@ class AbstractChosen
34
35
  @include_group_label_in_selected = @options.include_group_label_in_selected || false
35
36
  @max_shown_results = @options.max_shown_results || Number.POSITIVE_INFINITY
36
37
  @case_sensitive_search = @options.case_sensitive_search || false
38
+ @hide_results_on_select = if @options.hide_results_on_select? then @options.hide_results_on_select else true
37
39
 
38
40
  set_default_text: ->
39
41
  if @form_field.getAttribute("data-placeholder")
@@ -43,6 +45,8 @@ class AbstractChosen
43
45
  else
44
46
  @default_text = @options.placeholder_text_single || @options.placeholder_text || AbstractChosen.default_single_text
45
47
 
48
+ @default_text = this.escape_html(@default_text)
49
+
46
50
  @results_none_found = @form_field.getAttribute("data-no_results_text") || @options.no_results_text || AbstractChosen.default_no_result_text
47
51
 
48
52
  choice_label: (item) ->
@@ -65,6 +69,12 @@ class AbstractChosen
65
69
  @active_field = false
66
70
  setTimeout (=> this.blur_test()), 100
67
71
 
72
+ label_click_handler: (evt) =>
73
+ if @is_multiple
74
+ this.container_mousedown(evt)
75
+ else
76
+ this.activate_field()
77
+
68
78
  results_option_build: (options) ->
69
79
  content = ''
70
80
  shown_results = 0
@@ -106,7 +116,7 @@ class AbstractChosen
106
116
  option_el.className = classes.join(" ")
107
117
  option_el.style.cssText = option.style
108
118
  option_el.setAttribute("data-option-array-index", option.array_index)
109
- option_el.innerHTML = option.search_text
119
+ option_el.innerHTML = option.highlighted_html or option.html
110
120
  option_el.title = option.title if option.title
111
121
 
112
122
  this.outerHTML(option_el)
@@ -121,7 +131,7 @@ class AbstractChosen
121
131
 
122
132
  group_el = document.createElement("li")
123
133
  group_el.className = classes.join(" ")
124
- group_el.innerHTML = group.search_text
134
+ group_el.innerHTML = group.highlighted_html or this.escape_html(group.label)
125
135
  group_el.title = group.title if group.title
126
136
 
127
137
  this.outerHTML(group_el)
@@ -154,15 +164,16 @@ class AbstractChosen
154
164
 
155
165
  results = 0
156
166
 
157
- searchText = this.get_search_text()
158
- escapedSearchText = searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&")
159
- zregex = new RegExp(escapedSearchText, 'i')
160
- regex = this.get_search_regex(escapedSearchText)
167
+ query = this.get_search_text()
168
+ escapedQuery = query.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&")
169
+ regex = this.get_search_regex(escapedQuery)
161
170
 
162
171
  for option in @results_data
163
172
 
164
173
  option.search_match = false
165
174
  results_group = null
175
+ search_match = null
176
+ option.highlighted_html = ''
166
177
 
167
178
  if this.include_option_in_results(option)
168
179
 
@@ -175,17 +186,21 @@ class AbstractChosen
175
186
  results += 1 if results_group.active_options is 0 and results_group.search_match
176
187
  results_group.active_options += 1
177
188
 
178
- option.search_text = if option.group then option.label else option.html
189
+ text = if option.group then option.label else option.text
179
190
 
180
191
  unless option.group and not @group_search
181
- option.search_match = this.search_string_match(option.search_text, regex)
192
+ search_match = this.search_string_match(text, regex)
193
+ option.search_match = search_match?
194
+
182
195
  results += 1 if option.search_match and not option.group
183
196
 
184
197
  if option.search_match
185
- if searchText.length
186
- startpos = option.search_text.search zregex
187
- text = option.search_text.substr(0, startpos + searchText.length) + '</em>' + option.search_text.substr(startpos + searchText.length)
188
- option.search_text = text.substr(0, startpos) + '<em>' + text.substr(startpos)
198
+ if query.length
199
+ startpos = search_match.index
200
+ prefix = text.slice(0, startpos)
201
+ fix = text.slice(startpos, startpos + query.length)
202
+ suffix = text.slice(startpos + query.length)
203
+ option.highlighted_html = "#{this.escape_html(prefix)}<em>#{this.escape_html(fix)}</em>#{this.escape_html(suffix)}"
189
204
 
190
205
  results_group.group_match = true if results_group?
191
206
 
@@ -194,28 +209,23 @@ class AbstractChosen
194
209
 
195
210
  this.result_clear_highlight()
196
211
 
197
- if results < 1 and searchText.length
212
+ if results < 1 and query.length
198
213
  this.update_results_content ""
199
- this.no_results searchText
214
+ this.no_results query
200
215
  else
201
216
  this.update_results_content this.results_option_build()
202
217
  this.winnow_results_set_highlight()
203
218
 
204
219
  get_search_regex: (escaped_search_string) ->
205
- regex_anchor = if @search_contains then "" else "^"
220
+ regex_string = if @search_contains then escaped_search_string else "(^|\\s|\\b)#{escaped_search_string}[^\\s]*"
221
+ regex_string = "^#{regex_string}" unless @enable_split_word_search or @search_contains
206
222
  regex_flag = if @case_sensitive_search then "" else "i"
207
- new RegExp(regex_anchor + escaped_search_string, regex_flag)
223
+ new RegExp(regex_string, regex_flag)
208
224
 
209
225
  search_string_match: (search_string, regex) ->
210
- if regex.test search_string
211
- return true
212
- else if @enable_split_word_search and (search_string.indexOf(" ") >= 0 or search_string.indexOf("[") == 0)
213
- #TODO: replace this substitution of /\[\]/ with a list of characters to skip.
214
- parts = search_string.replace(/\[|\]/g, "").split(" ")
215
- if parts.length
216
- for part in parts
217
- if regex.test part
218
- return true
226
+ match = regex.exec(search_string)
227
+ match.index += 1 if !@search_contains && match?[1] # make up for lack of lookbehind operator in regex
228
+ match
219
229
 
220
230
  choices_count: ->
221
231
  return @selected_option_count if @selected_option_count?
@@ -228,30 +238,68 @@ class AbstractChosen
228
238
 
229
239
  choices_click: (evt) ->
230
240
  evt.preventDefault()
241
+ this.activate_field()
231
242
  this.results_show() unless @results_showing or @is_disabled
232
243
 
244
+ keydown_checker: (evt) ->
245
+ stroke = evt.which ? evt.keyCode
246
+ this.search_field_scale()
247
+
248
+ this.clear_backstroke() if stroke != 8 and @pending_backstroke
249
+
250
+ switch stroke
251
+ when 8 # backspace
252
+ @backstroke_length = this.get_search_field_value().length
253
+ break
254
+ when 9 # tab
255
+ this.result_select(evt) if @results_showing and not @is_multiple
256
+ @mouse_on_container = false
257
+ break
258
+ when 13 # enter
259
+ evt.preventDefault() if @results_showing
260
+ break
261
+ when 27 # escape
262
+ evt.preventDefault() if @results_showing
263
+ break
264
+ when 32 # space
265
+ evt.preventDefault() if @disable_search
266
+ break
267
+ when 38 # up arrow
268
+ evt.preventDefault()
269
+ this.keyup_arrow()
270
+ break
271
+ when 40 # down arrow
272
+ evt.preventDefault()
273
+ this.keydown_arrow()
274
+ break
275
+
233
276
  keyup_checker: (evt) ->
234
277
  stroke = evt.which ? evt.keyCode
235
278
  this.search_field_scale()
236
279
 
237
280
  switch stroke
238
- when 8
281
+ when 8 # backspace
239
282
  if @is_multiple and @backstroke_length < 1 and this.choices_count() > 0
240
283
  this.keydown_backstroke()
241
284
  else if not @pending_backstroke
242
285
  this.result_clear_highlight()
243
286
  this.results_search()
244
- when 13
287
+ break
288
+ when 13 # enter
245
289
  evt.preventDefault()
246
290
  this.result_select(evt) if this.results_showing
247
- when 27
291
+ break
292
+ when 27 # escape
248
293
  this.results_hide() if @results_showing
249
- return true
250
- when 9, 38, 40, 16, 91, 17, 18
294
+ break
295
+ when 9, 16, 17, 18, 38, 40, 91
251
296
  # don't do anything on these keys
252
- else this.results_search()
297
+ else
298
+ this.results_search()
299
+ break
253
300
 
254
301
  clipboard_event_checker: (evt) ->
302
+ return if @is_disabled
255
303
  setTimeout (=> this.results_search()), 50
256
304
 
257
305
  container_width: ->
@@ -281,6 +329,39 @@ class AbstractChosen
281
329
  tmp.appendChild(element)
282
330
  tmp.innerHTML
283
331
 
332
+ get_single_html: ->
333
+ """
334
+ <a class="chosen-single chosen-default">
335
+ <span>#{@default_text}</span>
336
+ <div><b></b></div>
337
+ </a>
338
+ <div class="chosen-drop">
339
+ <div class="chosen-search">
340
+ <input class="chosen-search-input" type="text" autocomplete="off" />
341
+ </div>
342
+ <ul class="chosen-results"></ul>
343
+ </div>
344
+ """
345
+
346
+ get_multi_html: ->
347
+ """
348
+ <ul class="chosen-choices">
349
+ <li class="search-field">
350
+ <input class="chosen-search-input" type="text" autocomplete="off" value="#{@default_text}" />
351
+ </li>
352
+ </ul>
353
+ <div class="chosen-drop">
354
+ <ul class="chosen-results"></ul>
355
+ </div>
356
+ """
357
+
358
+ get_no_results_html: (terms) ->
359
+ """
360
+ <li class="no-results">
361
+ #{@results_none_found} <span>#{this.escape_html(terms)}</span>
362
+ </li>
363
+ """
364
+
284
365
  # class methods and variables ============================================================
285
366
 
286
367
  @browser_is_supported: ->
@@ -15,7 +15,7 @@ class SelectParser
15
15
  @parsed.push
16
16
  array_index: group_position
17
17
  group: true
18
- label: this.escapeExpression(group.label)
18
+ label: group.label
19
19
  title: group.title if group.title
20
20
  children: 0
21
21
  disabled: group.disabled,
@@ -47,21 +47,6 @@ class SelectParser
47
47
  empty: true
48
48
  @options_index += 1
49
49
 
50
- escapeExpression: (text) ->
51
- if not text? or text is false
52
- return ""
53
- unless /[\&\<\>\"\'\`]/.test(text)
54
- return text
55
- map =
56
- "<": "&lt;"
57
- ">": "&gt;"
58
- '"': "&quot;"
59
- "'": "&#x27;"
60
- "`": "&#x60;"
61
- unsafe_chars = /&(?!\w+;)|[\<\>\"\'\`]/g
62
- text.replace unsafe_chars, (chr) ->
63
- map[chr] || "&amp;"
64
-
65
50
  SelectParser.select_to_array = (select) ->
66
51
  parser = new SelectParser()
67
52
  parser.add_node( child ) for child in select.childNodes
@@ -1,8 +1,7 @@
1
1
  //= depend_on_asset "chosen-sprite.png"
2
2
  //= depend_on_asset "chosen-sprite@2x.png"
3
-
4
- $chosen-sprite: image-url('chosen-sprite.png') !default;
5
- $chosen-sprite-retina: image-url('chosen-sprite@2x.png') !default;
3
+ $chosen-sprite: url('chosen-sprite.png') !default;
4
+ $chosen-sprite-retina: url('chosen-sprite@2x.png') !default;
6
5
 
7
6
  /* @group Base */
8
7
  .chosen-container {
@@ -10,21 +9,23 @@ $chosen-sprite-retina: image-url('chosen-sprite@2x.png') !default;
10
9
  display: inline-block;
11
10
  vertical-align: middle;
12
11
  font-size: 13px;
12
+ user-select: none;
13
13
  * {
14
+ box-sizing: border-box;
14
15
  }
15
16
  .chosen-drop {
16
17
  position: absolute;
17
18
  top: 100%;
18
- left: -9999px;
19
19
  z-index: 1010;
20
20
  width: 100%;
21
21
  border: 1px solid #aaa;
22
22
  border-top: 0;
23
23
  background: #fff;
24
24
  box-shadow: 0 4px 5px rgba(#000,.15);
25
+ clip: rect(0,0,0,0);
25
26
  }
26
27
  &.chosen-with-drop .chosen-drop {
27
- left: 0;
28
+ clip: auto;
28
29
  }
29
30
  a{
30
31
  cursor: pointer;
@@ -59,6 +60,7 @@ $chosen-sprite-retina: image-url('chosen-sprite@2x.png') !default;
59
60
  border: 1px solid #aaa;
60
61
  border-radius: 5px;
61
62
  background-color: #fff;
63
+ background: linear-gradient(#fff 20%, #f6f6f6 50%, #eee 52%, #f4f4f4 100%);
62
64
  background-clip: padding-box;
63
65
  box-shadow: 0 0 3px #fff inset, 0 1px 1px rgba(#000,.1);
64
66
  color: #444;
@@ -115,6 +117,7 @@ $chosen-sprite-retina: image-url('chosen-sprite@2x.png') !default;
115
117
  margin: 0;
116
118
  padding: 3px 4px;
117
119
  white-space: nowrap;
120
+
118
121
  input[type="text"] {
119
122
  margin: 1px 0;
120
123
  padding: 4px 20px 4px 5px;
@@ -122,7 +125,7 @@ $chosen-sprite-retina: image-url('chosen-sprite@2x.png') !default;
122
125
  height: auto;
123
126
  outline: 0;
124
127
  border: 1px solid #aaa;
125
- background: #fff $chosen-sprite no-repeat 100% -20px;
128
+ background: $chosen-sprite no-repeat 100% -20px;
126
129
  font-size: 1em;
127
130
  font-family: sans-serif;
128
131
  line-height: normal;
@@ -136,7 +139,7 @@ $chosen-sprite-retina: image-url('chosen-sprite@2x.png') !default;
136
139
  }
137
140
  &.chosen-container-single-nosearch .chosen-search {
138
141
  position: absolute;
139
- left: -9999px;
142
+ clip: rect(0,0,0,0);
140
143
  }
141
144
  }
142
145
  /* @end */
@@ -170,6 +173,7 @@ $chosen-sprite-retina: image-url('chosen-sprite@2x.png') !default;
170
173
  }
171
174
  &.highlighted {
172
175
  background-color: #3875d7;
176
+ background-image: linear-gradient(#3875d7 20%, #2a62bc 90%);
173
177
  color: #fff;
174
178
  }
175
179
  &.no-results {
@@ -204,6 +208,7 @@ $chosen-sprite-retina: image-url('chosen-sprite@2x.png') !default;
204
208
  height: auto;
205
209
  border: 1px solid #aaa;
206
210
  background-color: #fff;
211
+ background-image: linear-gradient(#eee 1%, #fff 15%);
207
212
  cursor: text;
208
213
  }
209
214
  .chosen-choices li {
@@ -226,6 +231,7 @@ $chosen-sprite-retina: image-url('chosen-sprite@2x.png') !default;
226
231
  font-family: sans-serif;
227
232
  line-height: normal;
228
233
  border-radius: 0;
234
+ width: 25px;
229
235
  }
230
236
  }
231
237
  &.search-choice {
@@ -236,6 +242,7 @@ $chosen-sprite-retina: image-url('chosen-sprite@2x.png') !default;
236
242
  max-width: 100%;
237
243
  border-radius: 3px;
238
244
  background-color: #eeeeee;
245
+ background-image: linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
239
246
  background-size: 100% 19px;
240
247
  background-repeat: repeat-x;
241
248
  background-clip: padding-box;
@@ -264,6 +271,7 @@ $chosen-sprite-retina: image-url('chosen-sprite@2x.png') !default;
264
271
  padding-right: 5px;
265
272
  border: 1px solid #ccc;
266
273
  background-color: #e4e4e4;
274
+ background-image: linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
267
275
  color: #666;
268
276
  }
269
277
  &.search-choice-focus {
@@ -298,6 +306,7 @@ $chosen-sprite-retina: image-url('chosen-sprite@2x.png') !default;
298
306
  border-bottom-right-radius: 0;
299
307
  -moz-border-radius-bottomleft: 0;
300
308
  border-bottom-left-radius: 0;
309
+ background-image: linear-gradient(#eee 20%, #fff 80%);
301
310
  box-shadow: 0 1px 0 #fff inset;
302
311
  }
303
312
  .chosen-single div {
@@ -368,10 +377,6 @@ $chosen-sprite-retina: image-url('chosen-sprite@2x.png') !default;
368
377
  }
369
378
  }
370
379
  }
371
- &.chosen-container-single-nosearch .chosen-search,
372
- .chosen-drop {
373
- left: 9999px;
374
- }
375
380
  &.chosen-container-single .chosen-results {
376
381
  margin: 0 0 4px 4px;
377
382
  padding: 0 4px 0 0;
@@ -385,7 +390,7 @@ $chosen-sprite-retina: image-url('chosen-sprite@2x.png') !default;
385
390
  }
386
391
  .chosen-search input[type="text"] {
387
392
  padding: 4px 5px 4px 20px;
388
- background: #fff $chosen-sprite no-repeat -30px -20px;
393
+ background: $chosen-sprite no-repeat -30px -20px;
389
394
  direction: rtl;
390
395
  }
391
396
  &.chosen-container-single{
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chosen-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.2
4
+ version: 1.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tse-Ching Ho
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-19 00:00:00.000000000 Z
11
+ date: 2017-12-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -147,7 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
147
147
  version: '0'
148
148
  requirements: []
149
149
  rubyforge_project:
150
- rubygems_version: 2.5.1
150
+ rubygems_version: 2.6.13
151
151
  signing_key:
152
152
  specification_version: 4
153
153
  summary: Integrate Chosen javascript library with Rails asset pipeline