chosen-rails 1.5.2 → 1.8.2

Sign up to get free protection for your applications and to get access to all the features.
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