chosen-rails-adding 1.0.2.1

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.
@@ -0,0 +1,529 @@
1
+ class @Chosen extends AbstractChosen
2
+
3
+ setup: ->
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" tabindex="-1"><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
+ @new_option_temp = new Template('<option value="#{value}">#{text}</option>')
15
+ @create_option_temp = new Template('<li class="create-option active-result"><a>#{text}</a>: "#{terms}"</li>')
16
+
17
+ set_up_html: ->
18
+ container_classes = ["chosen-container"]
19
+ container_classes.push "chosen-container-" + (if @is_multiple then "multi" else "single")
20
+ container_classes.push @form_field.className if @inherit_select_classes && @form_field.className
21
+ container_classes.push "chosen-rtl" if @is_rtl
22
+
23
+ container_props =
24
+ 'class': container_classes.join ' '
25
+ 'style': "width: #{this.container_width()};"
26
+ 'title': @form_field.title
27
+
28
+ container_props.id = @form_field.id.replace(/[^\w]/g, '_') + "_chosen" if @form_field.id.length
29
+
30
+ @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 }) )
31
+
32
+ @form_field.hide().insert({ after: @container })
33
+ @dropdown = @container.down('div.chosen-drop')
34
+
35
+ @search_field = @container.down('input')
36
+ @search_results = @container.down('ul.chosen-results')
37
+ this.search_field_scale()
38
+
39
+ @search_no_results = @container.down('li.no-results')
40
+
41
+ if @is_multiple
42
+ @search_choices = @container.down('ul.chosen-choices')
43
+ @search_container = @container.down('li.search-field')
44
+ else
45
+ @search_container = @container.down('div.chosen-search')
46
+ @selected_item = @container.down('.chosen-single')
47
+
48
+ this.results_build()
49
+ this.set_tab_index()
50
+ this.set_label_behavior()
51
+ @form_field.fire("chosen:ready", {chosen: this})
52
+
53
+ register_observers: ->
54
+ @container.observe "mousedown", (evt) => this.container_mousedown(evt)
55
+ @container.observe "mouseup", (evt) => this.container_mouseup(evt)
56
+ @container.observe "mouseenter", (evt) => this.mouse_enter(evt)
57
+ @container.observe "mouseleave", (evt) => this.mouse_leave(evt)
58
+
59
+ @search_results.observe "mouseup", (evt) => this.search_results_mouseup(evt)
60
+ @search_results.observe "mouseover", (evt) => this.search_results_mouseover(evt)
61
+ @search_results.observe "mouseout", (evt) => this.search_results_mouseout(evt)
62
+ @search_results.observe "mousewheel", (evt) => this.search_results_mousewheel(evt)
63
+ @search_results.observe "DOMMouseScroll", (evt) => this.search_results_mousewheel(evt)
64
+
65
+ @search_results.observe "touchstart", (evt) => this.search_results_touchstart(evt)
66
+ @search_results.observe "touchmove", (evt) => this.search_results_touchmove(evt)
67
+ @search_results.observe "touchend", (evt) => this.search_results_touchend(evt)
68
+
69
+ @form_field.observe "chosen:updated", (evt) => this.results_update_field(evt)
70
+ @form_field.observe "chosen:activate", (evt) => this.activate_field(evt)
71
+ @form_field.observe "chosen:open", (evt) => this.container_mousedown(evt)
72
+ @form_field.observe "chosen:close", (evt) => this.input_blur(evt)
73
+
74
+ @search_field.observe "blur", (evt) => this.input_blur(evt)
75
+ @search_field.observe "keyup", (evt) => this.keyup_checker(evt)
76
+ @search_field.observe "keydown", (evt) => this.keydown_checker(evt)
77
+ @search_field.observe "focus", (evt) => this.input_focus(evt)
78
+
79
+ if @is_multiple
80
+ @search_choices.observe "click", (evt) => this.choices_click(evt)
81
+ else
82
+ @container.observe "click", (evt) => evt.preventDefault() # gobble click of anchor
83
+
84
+ destroy: ->
85
+ document.stopObserving "click", @click_test_action
86
+
87
+ @form_field.stopObserving()
88
+ @container.stopObserving()
89
+ @search_results.stopObserving()
90
+ @search_field.stopObserving()
91
+ @form_field_label.stopObserving() if @form_field_label?
92
+
93
+ if @is_multiple
94
+ @search_choices.stopObserving()
95
+ @container.select(".search-choice-close").each (choice) ->
96
+ choice.stopObserving()
97
+ else
98
+ @selected_item.stopObserving()
99
+
100
+ if @search_field.tabIndex
101
+ @form_field.tabIndex = @search_field.tabIndex
102
+
103
+ @container.remove()
104
+ @form_field.show()
105
+
106
+ search_field_disabled: ->
107
+ @is_disabled = @form_field.disabled
108
+ if(@is_disabled)
109
+ @container.addClassName 'chosen-disabled'
110
+ @search_field.disabled = true
111
+ @selected_item.stopObserving "focus", @activate_action if !@is_multiple
112
+ this.close_field()
113
+ else
114
+ @container.removeClassName 'chosen-disabled'
115
+ @search_field.disabled = false
116
+ @selected_item.observe "focus", @activate_action if !@is_multiple
117
+
118
+ container_mousedown: (evt) ->
119
+ if !@is_disabled
120
+ if evt and evt.type is "mousedown" and not @results_showing
121
+ evt.stop()
122
+
123
+ if not (evt? and evt.target.hasClassName "search-choice-close")
124
+ if not @active_field
125
+ @search_field.clear() if @is_multiple
126
+ document.observe "click", @click_test_action
127
+ this.results_show()
128
+ else if not @is_multiple and evt and (evt.target is @selected_item || evt.target.up("a.chosen-single"))
129
+ this.results_toggle()
130
+
131
+ this.activate_field()
132
+
133
+ container_mouseup: (evt) ->
134
+ this.results_reset(evt) if evt.target.nodeName is "ABBR" and not @is_disabled
135
+
136
+ search_results_mousewheel: (evt) ->
137
+ delta = -evt.wheelDelta or evt.detail
138
+ if delta?
139
+ evt.preventDefault()
140
+ delta = delta * 40 if evt.type is 'DOMMouseScroll'
141
+ @search_results.scrollTop = delta + @search_results.scrollTop
142
+
143
+ blur_test: (evt) ->
144
+ this.close_field() if not @active_field and @container.hasClassName("chosen-container-active")
145
+
146
+ close_field: ->
147
+ document.stopObserving "click", @click_test_action
148
+
149
+ @active_field = false
150
+ this.results_hide()
151
+
152
+ @container.removeClassName "chosen-container-active"
153
+ this.clear_backstroke()
154
+
155
+ this.show_search_field_default()
156
+ this.search_field_scale()
157
+
158
+ activate_field: ->
159
+ @container.addClassName "chosen-container-active"
160
+ @active_field = true
161
+
162
+ @search_field.value = @search_field.value
163
+ @search_field.focus()
164
+
165
+ test_active_click: (evt) ->
166
+ if evt.target.up('.chosen-container') is @container
167
+ @active_field = true
168
+ else
169
+ this.close_field()
170
+
171
+ results_build: ->
172
+ @parsing = true
173
+ @selected_option_count = null
174
+
175
+ @results_data = SelectParser.select_to_array @form_field
176
+
177
+ if @is_multiple
178
+ @search_choices.select("li.search-choice").invoke("remove")
179
+ else if not @is_multiple
180
+ this.single_set_selected_text()
181
+ if @disable_search or @form_field.options.length <= @disable_search_threshold and not @create_option
182
+ @search_field.readOnly = true
183
+ @container.addClassName "chosen-container-single-nosearch"
184
+ else
185
+ @search_field.readOnly = false
186
+ @container.removeClassName "chosen-container-single-nosearch"
187
+
188
+ this.update_results_content this.results_option_build({first:true})
189
+
190
+ this.search_field_disabled()
191
+ this.show_search_field_default()
192
+ this.search_field_scale()
193
+
194
+ @parsing = false
195
+
196
+ result_do_highlight: (el) ->
197
+ this.result_clear_highlight()
198
+
199
+ @result_highlight = el
200
+ @result_highlight.addClassName "highlighted"
201
+
202
+ maxHeight = parseInt @search_results.getStyle('maxHeight'), 10
203
+ visible_top = @search_results.scrollTop
204
+ visible_bottom = maxHeight + visible_top
205
+
206
+ high_top = @result_highlight.positionedOffset().top
207
+ high_bottom = high_top + @result_highlight.getHeight()
208
+
209
+ if high_bottom >= visible_bottom
210
+ @search_results.scrollTop = if (high_bottom - maxHeight) > 0 then (high_bottom - maxHeight) else 0
211
+ else if high_top < visible_top
212
+ @search_results.scrollTop = high_top
213
+
214
+ result_clear_highlight: ->
215
+ @result_highlight.removeClassName('highlighted') if @result_highlight
216
+ @result_highlight = null
217
+
218
+ results_show: ->
219
+ if @is_multiple and @max_selected_options <= this.choices_count()
220
+ @form_field.fire("chosen:maxselected", {chosen: this})
221
+ return false
222
+
223
+ @container.addClassName "chosen-with-drop"
224
+ @form_field.fire("chosen:showing_dropdown", {chosen: this})
225
+
226
+ @results_showing = true
227
+
228
+ @search_field.focus()
229
+ @search_field.value = @search_field.value
230
+
231
+ this.winnow_results()
232
+
233
+ update_results_content: (content) ->
234
+ @search_results.update content
235
+
236
+ results_hide: ->
237
+ if @results_showing
238
+ this.result_clear_highlight()
239
+
240
+ @container.removeClassName "chosen-with-drop"
241
+ @form_field.fire("chosen:hiding_dropdown", {chosen: this})
242
+
243
+ @results_showing = false
244
+
245
+
246
+ set_tab_index: (el) ->
247
+ if @form_field.tabIndex
248
+ ti = @form_field.tabIndex
249
+ @form_field.tabIndex = -1
250
+ @search_field.tabIndex = ti
251
+
252
+ set_label_behavior: ->
253
+ @form_field_label = @form_field.up("label") # first check for a parent label
254
+ if not @form_field_label?
255
+ @form_field_label = $$("label[for='#{@form_field.id}']").first() #next check for a for=#{id}
256
+
257
+ if @form_field_label?
258
+ @form_field_label.observe "click", (evt) => if @is_multiple then this.container_mousedown(evt) else this.activate_field()
259
+
260
+ show_search_field_default: ->
261
+ if @is_multiple and this.choices_count() < 1 and not @active_field
262
+ @search_field.value = @default_text
263
+ @search_field.addClassName "default"
264
+ else
265
+ @search_field.value = ""
266
+ @search_field.removeClassName "default"
267
+
268
+ search_results_mouseup: (evt) ->
269
+ target = if evt.target.hasClassName("active-result") then evt.target else evt.target.up(".active-result")
270
+ if target
271
+ @result_highlight = target
272
+ this.result_select(evt)
273
+ @search_field.focus()
274
+
275
+ search_results_mouseover: (evt) ->
276
+ target = if evt.target.hasClassName("active-result") then evt.target else evt.target.up(".active-result")
277
+ this.result_do_highlight( target ) if target
278
+
279
+ search_results_mouseout: (evt) ->
280
+ this.result_clear_highlight() if evt.target.hasClassName('active-result') or evt.target.up('.active-result')
281
+
282
+ choice_build: (item) ->
283
+ choice = new Element('li', { class: "search-choice" }).update("<span>#{item.html}</span>")
284
+
285
+ if item.disabled
286
+ choice.addClassName 'search-choice-disabled'
287
+ else
288
+ close_link = new Element('a', { href: '#', class: 'search-choice-close', rel: item.array_index })
289
+ close_link.observe "click", (evt) => this.choice_destroy_link_click(evt)
290
+ choice.insert close_link
291
+
292
+ @search_container.insert { before: choice }
293
+
294
+ choice_destroy_link_click: (evt) ->
295
+ evt.preventDefault()
296
+ evt.stopPropagation()
297
+ this.choice_destroy evt.target unless @is_disabled
298
+
299
+ choice_destroy: (link) ->
300
+ if this.result_deselect link.readAttribute("rel")
301
+ this.show_search_field_default()
302
+
303
+ this.results_hide() if @is_multiple and this.choices_count() > 0 and @search_field.value.length < 1
304
+
305
+ link.up('li').remove()
306
+
307
+ this.search_field_scale()
308
+
309
+ results_reset: ->
310
+ this.reset_single_select_options()
311
+ @form_field.options[0].selected = true
312
+ this.single_set_selected_text()
313
+ this.show_search_field_default()
314
+ this.results_reset_cleanup()
315
+ @form_field.simulate("change") if typeof Event.simulate is 'function'
316
+ this.results_hide() if @active_field
317
+
318
+ results_reset_cleanup: ->
319
+ @current_selectedIndex = @form_field.selectedIndex
320
+ deselect_trigger = @selected_item.down("abbr")
321
+ deselect_trigger.remove() if(deselect_trigger)
322
+
323
+ result_select: (evt) ->
324
+ if @result_highlight
325
+ high = @result_highlight
326
+
327
+ if high.hasClassName "create-option"
328
+ this.select_create_option(@search_field.value)
329
+ return this.results_hide()
330
+
331
+ this.result_clear_highlight()
332
+
333
+ if @is_multiple and @max_selected_options <= this.choices_count()
334
+ @form_field.fire("chosen:maxselected", {chosen: this})
335
+ return false
336
+
337
+ if @is_multiple
338
+ high.removeClassName("active-result")
339
+ else
340
+ this.reset_single_select_options()
341
+
342
+ high.addClassName("result-selected")
343
+
344
+ item = @results_data[ high.getAttribute("data-option-array-index") ]
345
+ item.selected = true
346
+
347
+ @form_field.options[item.options_index].selected = true
348
+ @selected_option_count = null
349
+
350
+ if @is_multiple
351
+ this.choice_build item
352
+ else
353
+ this.single_set_selected_text(item.text)
354
+
355
+ this.results_hide() unless (evt.metaKey or evt.ctrlKey) and @is_multiple
356
+
357
+ @search_field.value = ""
358
+
359
+ @form_field.simulate("change") if typeof Event.simulate is 'function' && (@is_multiple || @form_field.selectedIndex != @current_selectedIndex)
360
+ @current_selectedIndex = @form_field.selectedIndex
361
+
362
+ this.search_field_scale()
363
+
364
+ single_set_selected_text: (text=@default_text) ->
365
+ if text is @default_text
366
+ @selected_item.addClassName("chosen-default")
367
+ else
368
+ this.single_deselect_control_build()
369
+ @selected_item.removeClassName("chosen-default")
370
+
371
+ @selected_item.down("span").update(text)
372
+
373
+ result_deselect: (pos) ->
374
+ result_data = @results_data[pos]
375
+
376
+ if not @form_field.options[result_data.options_index].disabled
377
+ result_data.selected = false
378
+
379
+ @form_field.options[result_data.options_index].selected = false
380
+ @selected_option_count = null
381
+
382
+ this.result_clear_highlight()
383
+ this.winnow_results() if @results_showing
384
+
385
+ @form_field.simulate("change") if typeof Event.simulate is 'function'
386
+ this.search_field_scale()
387
+ return true
388
+ else
389
+ return false
390
+
391
+ single_deselect_control_build: ->
392
+ return unless @allow_single_deselect
393
+ @selected_item.down("span").insert { after: "<abbr class=\"search-choice-close\"></abbr>" } unless @selected_item.down("abbr")
394
+ @selected_item.addClassName("chosen-single-with-deselect")
395
+
396
+ get_search_text: ->
397
+ if @search_field.value is @default_text then "" else @search_field.value.strip().escapeHTML()
398
+
399
+ winnow_results_set_highlight: ->
400
+ if not @is_multiple
401
+ do_high = @search_results.down(".result-selected.active-result")
402
+
403
+ if not do_high?
404
+ do_high = @search_results.down(".active-result")
405
+
406
+ this.result_do_highlight do_high if do_high?
407
+
408
+ no_results: (terms) ->
409
+ no_results_html = @no_results_temp.evaluate( terms: terms )
410
+
411
+ @search_results.insert no_results_html
412
+
413
+ show_create_option: (terms) ->
414
+ create_option_html = @create_option_temp.evaluate( terms: terms, text: @create_option_text )
415
+ @search_results.insert create_option_html
416
+ @search_results.down(".create-option").observe "click", (evt) => this.select_create_option(terms)
417
+
418
+ create_option_clear: ->
419
+ co = null
420
+ co.remove() while co = @search_results.down(".create-option")
421
+
422
+ select_create_option: ( terms ) ->
423
+ if Object.isFunction( @create_option )
424
+ @create_option.call this, terms
425
+ else
426
+ this.select_append_option( value: terms, text: terms )
427
+
428
+ select_append_option: ( options ) ->
429
+ option = @new_option_temp.evaluate( options )
430
+ @form_field.insert option
431
+ Event.fire @form_field, "chosen:updated"
432
+ if typeof Event.simulate is 'function'
433
+ @form_field.simulate("change")
434
+ @search_field.simulate("focus")
435
+
436
+ no_results_clear: ->
437
+ nr = null
438
+ nr.remove() while nr = @search_results.down(".no-results")
439
+
440
+ keydown_arrow: ->
441
+ if @results_showing and @result_highlight
442
+ next_sib = @result_highlight.next('.active-result')
443
+ this.result_do_highlight next_sib if next_sib
444
+ else if @results_showing and @create_option
445
+ this.result_do_highlight(@search_results.select('.create-option').first())
446
+ else
447
+ this.results_show()
448
+
449
+ keyup_arrow: ->
450
+ if not @results_showing and not @is_multiple
451
+ this.results_show()
452
+ else if @result_highlight
453
+ sibs = @result_highlight.previousSiblings()
454
+ actives = @search_results.select("li.active-result")
455
+ prevs = sibs.intersect(actives)
456
+
457
+ if prevs.length
458
+ this.result_do_highlight prevs.first()
459
+ else
460
+ this.results_hide() if this.choices_count() > 0
461
+ this.result_clear_highlight()
462
+
463
+ keydown_backstroke: ->
464
+ if @pending_backstroke
465
+ this.choice_destroy @pending_backstroke.down("a")
466
+ this.clear_backstroke()
467
+ else
468
+ next_available_destroy = @search_container.siblings().last()
469
+ if next_available_destroy and next_available_destroy.hasClassName("search-choice") and not next_available_destroy.hasClassName("search-choice-disabled")
470
+ @pending_backstroke = next_available_destroy
471
+ @pending_backstroke.addClassName("search-choice-focus") if @pending_backstroke
472
+ if @single_backstroke_delete
473
+ @keydown_backstroke()
474
+ else
475
+ @pending_backstroke.addClassName("search-choice-focus")
476
+
477
+ clear_backstroke: ->
478
+ @pending_backstroke.removeClassName("search-choice-focus") if @pending_backstroke
479
+ @pending_backstroke = null
480
+
481
+ keydown_checker: (evt) ->
482
+ stroke = evt.which ? evt.keyCode
483
+ this.search_field_scale()
484
+
485
+ this.clear_backstroke() if stroke != 8 and this.pending_backstroke
486
+
487
+ switch stroke
488
+ when 8
489
+ @backstroke_length = this.search_field.value.length
490
+ break
491
+ when 9
492
+ this.result_select(evt) if this.results_showing and not @is_multiple
493
+ @mouse_on_container = false
494
+ break
495
+ when 13
496
+ evt.preventDefault()
497
+ break
498
+ when 38
499
+ evt.preventDefault()
500
+ this.keyup_arrow()
501
+ break
502
+ when 40
503
+ evt.preventDefault()
504
+ this.keydown_arrow()
505
+ break
506
+
507
+ search_field_scale: ->
508
+ if @is_multiple
509
+ h = 0
510
+ w = 0
511
+
512
+ style_block = "position:absolute; left: -1000px; top: -1000px; display:none;"
513
+ styles = ['font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing']
514
+
515
+ for style in styles
516
+ style_block += style + ":" + @search_field.getStyle(style) + ";"
517
+
518
+ div = new Element('div', { 'style' : style_block }).update(@search_field.value.escapeHTML())
519
+ document.body.appendChild(div)
520
+
521
+ w = Element.measure(div, 'width') + 25
522
+ div.remove()
523
+
524
+ f_width = @container.getWidth()
525
+
526
+ if( w > f_width-10 )
527
+ w = f_width - 10
528
+
529
+ @search_field.setStyle({'width': w + 'px'})