chosen-rails 1.5.2 → 1.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +14 -10
- data/Rakefile +1 -1
- data/chosen-rails.gemspec +1 -1
- data/lib/chosen-rails/rspec.rb +7 -6
- data/lib/chosen-rails/source_file.rb +6 -8
- data/lib/chosen-rails/version.rb +2 -2
- data/lib/chosen-rails.rb +1 -1
- data/vendor/assets/javascripts/chosen.jquery.coffee +118 -118
- data/vendor/assets/javascripts/chosen.proto.coffee +113 -97
- data/vendor/assets/javascripts/lib/abstract-chosen.coffee +116 -35
- data/vendor/assets/javascripts/lib/select-parser.coffee +1 -16
- data/vendor/assets/stylesheets/chosen-base.scss +18 -10
- data/vendor/assets/stylesheets/chosen.scss +375 -9
- metadata +9 -11
- data/vendor/assets/stylesheets/chosen-compass.scss +0 -63
@@ -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 =
|
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)
|
55
|
-
@container.observe "touchend", (evt) => this.container_mouseup(evt)
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
|
121
|
-
|
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
|
125
|
-
if evt and evt.type is "mousedown" and not @results_showing
|
126
|
-
evt.stop()
|
130
|
+
return if @is_disabled
|
127
131
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
132
|
+
if evt and evt.type in ['mousedown', 'touchstart'] and not @results_showing
|
133
|
+
evt.preventDefault()
|
134
|
+
|
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
|
-
|
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 =
|
177
|
+
@search_field.value = this.get_search_field_value()
|
168
178
|
@search_field.focus()
|
169
179
|
|
170
180
|
test_active_click: (evt) ->
|
@@ -181,7 +191,7 @@ class @Chosen extends AbstractChosen
|
|
181
191
|
|
182
192
|
if @is_multiple
|
183
193
|
@search_choices.select("li.search-choice").invoke("remove")
|
184
|
-
else
|
194
|
+
else
|
185
195
|
this.single_set_selected_text()
|
186
196
|
if @disable_search or @form_field.options.length <= @disable_search_threshold
|
187
197
|
@search_field.readOnly = true
|
@@ -229,7 +239,7 @@ class @Chosen extends AbstractChosen
|
|
229
239
|
@results_showing = true
|
230
240
|
|
231
241
|
@search_field.focus()
|
232
|
-
@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",
|
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
|
-
|
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
|
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
|
-
|
332
|
+
this.trigger_form_field_change()
|
320
333
|
this.results_hide() if @active_field
|
321
334
|
|
322
335
|
results_reset_cleanup: ->
|
@@ -351,10 +364,17 @@ class @Chosen extends AbstractChosen
|
|
351
364
|
else
|
352
365
|
this.single_set_selected_text(this.choice_label(item))
|
353
366
|
|
354
|
-
|
355
|
-
|
367
|
+
if @is_multiple && (!@hide_results_on_select || (evt.metaKey or evt.ctrlKey))
|
368
|
+
if evt.metaKey or evt.ctrlKey
|
369
|
+
this.winnow_results(skip_highlight: true)
|
370
|
+
else
|
371
|
+
@search_field.value = ""
|
372
|
+
this.winnow_results()
|
373
|
+
else
|
374
|
+
this.results_hide()
|
375
|
+
this.show_search_field_default()
|
356
376
|
|
357
|
-
|
377
|
+
this.trigger_form_field_change() if @is_multiple || @form_field.selectedIndex != @current_selectedIndex
|
358
378
|
@current_selectedIndex = @form_field.selectedIndex
|
359
379
|
|
360
380
|
evt.preventDefault()
|
@@ -382,7 +402,7 @@ class @Chosen extends AbstractChosen
|
|
382
402
|
this.result_clear_highlight()
|
383
403
|
this.winnow_results() if @results_showing
|
384
404
|
|
385
|
-
|
405
|
+
this.trigger_form_field_change()
|
386
406
|
this.search_field_scale()
|
387
407
|
return true
|
388
408
|
else
|
@@ -393,8 +413,14 @@ class @Chosen extends AbstractChosen
|
|
393
413
|
@selected_item.down("span").insert { after: "<abbr class=\"search-choice-close\"></abbr>" } unless @selected_item.down("abbr")
|
394
414
|
@selected_item.addClassName("chosen-single-with-deselect")
|
395
415
|
|
416
|
+
get_search_field_value: ->
|
417
|
+
@search_field.value
|
418
|
+
|
396
419
|
get_search_text: ->
|
397
|
-
|
420
|
+
this.get_search_field_value().strip()
|
421
|
+
|
422
|
+
escape_html: (text) ->
|
423
|
+
text.escapeHTML()
|
398
424
|
|
399
425
|
winnow_results_set_highlight: ->
|
400
426
|
if not @is_multiple
|
@@ -406,7 +432,7 @@ class @Chosen extends AbstractChosen
|
|
406
432
|
this.result_do_highlight do_high if do_high?
|
407
433
|
|
408
434
|
no_results: (terms) ->
|
409
|
-
@search_results.insert
|
435
|
+
@search_results.insert this.get_no_results_html(terms)
|
410
436
|
@form_field.fire("chosen:no_results", {chosen: this})
|
411
437
|
|
412
438
|
no_results_clear: ->
|
@@ -453,55 +479,45 @@ class @Chosen extends AbstractChosen
|
|
453
479
|
@pending_backstroke.removeClassName("search-choice-focus") if @pending_backstroke
|
454
480
|
@pending_backstroke = null
|
455
481
|
|
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
482
|
search_field_scale: ->
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
483
|
+
return unless @is_multiple
|
484
|
+
|
485
|
+
style_block =
|
486
|
+
position: 'absolute'
|
487
|
+
left: '-1000px'
|
488
|
+
top: '-1000px'
|
489
|
+
display: 'none'
|
490
|
+
whiteSpace: 'pre'
|
491
|
+
|
492
|
+
styles = ['fontSize', 'fontStyle', 'fontWeight', 'fontFamily', 'lineHeight', 'textTransform', 'letterSpacing']
|
493
|
+
|
494
|
+
for style in styles
|
495
|
+
style_block[style] = @search_field.getStyle(style)
|
496
|
+
|
497
|
+
div = new Element('div').update(this.escape_html(this.get_search_field_value()))
|
498
|
+
# CSP without 'unsafe-inline' doesn't allow setting the style attribute directly
|
499
|
+
div.setStyle(style_block)
|
500
|
+
document.body.appendChild(div)
|
501
|
+
|
502
|
+
width = div.measure('width') + 25
|
503
|
+
div.remove()
|
504
|
+
|
505
|
+
if container_width = @container.getWidth()
|
506
|
+
width = Math.min(container_width - 10, width)
|
507
|
+
|
508
|
+
@search_field.setStyle(width: width + 'px')
|
509
|
+
|
510
|
+
trigger_form_field_change: ->
|
511
|
+
triggerHtmlEvent @form_field, 'input'
|
512
|
+
triggerHtmlEvent @form_field, 'change'
|
513
|
+
|
514
|
+
triggerHtmlEvent = (element, eventType) ->
|
515
|
+
if element.dispatchEvent # Modern way:
|
516
|
+
try
|
517
|
+
evt = new Event(eventType, bubbles: true, cancelable: true)
|
518
|
+
catch
|
519
|
+
evt = document.createEvent('HTMLEvents')
|
520
|
+
evt.initEvent(eventType, true, true);
|
521
|
+
element.dispatchEvent(evt)
|
522
|
+
else # Old IE:
|
523
|
+
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,11 +45,13 @@ 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) ->
|
49
53
|
if @include_group_label_in_selected and item.group_label?
|
50
|
-
"<b class='group-name'>#{item.group_label}</b>#{item.html}"
|
54
|
+
"<b class='group-name'>#{this.escape_html(item.group_label)}</b>#{item.html}"
|
51
55
|
else
|
52
56
|
item.html
|
53
57
|
|
@@ -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
|
@@ -104,9 +114,9 @@ class AbstractChosen
|
|
104
114
|
|
105
115
|
option_el = document.createElement("li")
|
106
116
|
option_el.className = classes.join(" ")
|
107
|
-
option_el.style.cssText = option.style
|
117
|
+
option_el.style.cssText = option.style if option.style
|
108
118
|
option_el.setAttribute("data-option-array-index", option.array_index)
|
109
|
-
option_el.innerHTML = option.
|
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.
|
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)
|
@@ -149,20 +159,21 @@ class AbstractChosen
|
|
149
159
|
else
|
150
160
|
this.results_show()
|
151
161
|
|
152
|
-
winnow_results: ->
|
162
|
+
winnow_results: (options) ->
|
153
163
|
this.no_results_clear()
|
154
164
|
|
155
165
|
results = 0
|
156
166
|
|
157
|
-
|
158
|
-
|
159
|
-
|
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
|
-
|
189
|
+
text = if option.group then option.label else option.text
|
179
190
|
|
180
191
|
unless option.group and not @group_search
|
181
|
-
|
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
|
186
|
-
startpos =
|
187
|
-
|
188
|
-
|
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
|
212
|
+
if results < 1 and query.length
|
198
213
|
this.update_results_content ""
|
199
|
-
this.no_results
|
214
|
+
this.no_results query
|
200
215
|
else
|
201
216
|
this.update_results_content this.results_option_build()
|
202
|
-
this.winnow_results_set_highlight()
|
217
|
+
this.winnow_results_set_highlight() unless options?.skip_highlight
|
203
218
|
|
204
219
|
get_search_regex: (escaped_search_string) ->
|
205
|
-
|
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(
|
223
|
+
new RegExp(regex_string, regex_flag)
|
208
224
|
|
209
225
|
search_string_match: (search_string, regex) ->
|
210
|
-
|
211
|
-
|
212
|
-
|
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
|
-
|
287
|
+
break
|
288
|
+
when 13 # enter
|
245
289
|
evt.preventDefault()
|
246
290
|
this.result_select(evt) if this.results_showing
|
247
|
-
|
291
|
+
break
|
292
|
+
when 27 # escape
|
248
293
|
this.results_hide() if @results_showing
|
249
|
-
|
250
|
-
when 9,
|
294
|
+
break
|
295
|
+
when 9, 16, 17, 18, 38, 40, 91
|
251
296
|
# don't do anything on these keys
|
252
|
-
else
|
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:
|
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
|
-
"<": "<"
|
57
|
-
">": ">"
|
58
|
-
'"': """
|
59
|
-
"'": "'"
|
60
|
-
"`": "`"
|
61
|
-
unsafe_chars = /&(?!\w+;)|[\<\>\"\'\`]/g
|
62
|
-
text.replace unsafe_chars, (chr) ->
|
63
|
-
map[chr] || "&"
|
64
|
-
|
65
50
|
SelectParser.select_to_array = (select) ->
|
66
51
|
parser = new SelectParser()
|
67
52
|
parser.add_node( child ) for child in select.childNodes
|