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