chosen-awesome-rails 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,104 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ chosen-awesome-rails (1.0.0)
5
+ coffee-rails (>= 3.2)
6
+ railties (>= 3.0)
7
+ sass-rails (>= 3.2)
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ actionmailer (4.0.0)
13
+ actionpack (= 4.0.0)
14
+ mail (~> 2.5.3)
15
+ actionpack (4.0.0)
16
+ activesupport (= 4.0.0)
17
+ builder (~> 3.1.0)
18
+ erubis (~> 2.7.0)
19
+ rack (~> 1.5.2)
20
+ rack-test (~> 0.6.2)
21
+ activemodel (4.0.0)
22
+ activesupport (= 4.0.0)
23
+ builder (~> 3.1.0)
24
+ activerecord (4.0.0)
25
+ activemodel (= 4.0.0)
26
+ activerecord-deprecated_finders (~> 1.0.2)
27
+ activesupport (= 4.0.0)
28
+ arel (~> 4.0.0)
29
+ activerecord-deprecated_finders (1.0.3)
30
+ activesupport (4.0.0)
31
+ i18n (~> 0.6, >= 0.6.4)
32
+ minitest (~> 4.2)
33
+ multi_json (~> 1.3)
34
+ thread_safe (~> 0.1)
35
+ tzinfo (~> 0.3.37)
36
+ arel (4.0.0)
37
+ atomic (1.1.10)
38
+ builder (3.1.4)
39
+ coffee-rails (4.0.0)
40
+ coffee-script (>= 2.2.0)
41
+ railties (>= 4.0.0.beta, < 5.0)
42
+ coffee-script (2.2.0)
43
+ coffee-script-source
44
+ execjs
45
+ coffee-script-source (1.6.3)
46
+ erubis (2.7.0)
47
+ execjs (1.4.0)
48
+ multi_json (~> 1.0)
49
+ hike (1.2.3)
50
+ i18n (0.6.4)
51
+ mail (2.5.4)
52
+ mime-types (~> 1.16)
53
+ treetop (~> 1.4.8)
54
+ mime-types (1.23)
55
+ minitest (4.7.5)
56
+ multi_json (1.7.7)
57
+ polyglot (0.3.3)
58
+ rack (1.5.2)
59
+ rack-test (0.6.2)
60
+ rack (>= 1.0)
61
+ rails (4.0.0)
62
+ actionmailer (= 4.0.0)
63
+ actionpack (= 4.0.0)
64
+ activerecord (= 4.0.0)
65
+ activesupport (= 4.0.0)
66
+ bundler (>= 1.3.0, < 2.0)
67
+ railties (= 4.0.0)
68
+ sprockets-rails (~> 2.0.0)
69
+ railties (4.0.0)
70
+ actionpack (= 4.0.0)
71
+ activesupport (= 4.0.0)
72
+ rake (>= 0.8.7)
73
+ thor (>= 0.18.1, < 2.0)
74
+ rake (10.1.0)
75
+ sass (3.2.10)
76
+ sass-rails (4.0.0)
77
+ railties (>= 4.0.0.beta, < 5.0)
78
+ sass (>= 3.1.10)
79
+ sprockets-rails (~> 2.0.0)
80
+ sprockets (2.10.0)
81
+ hike (~> 1.2)
82
+ multi_json (~> 1.0)
83
+ rack (~> 1.0)
84
+ tilt (~> 1.1, != 1.3.0)
85
+ sprockets-rails (2.0.0)
86
+ actionpack (>= 3.0)
87
+ activesupport (>= 3.0)
88
+ sprockets (~> 2.8)
89
+ thor (0.18.1)
90
+ thread_safe (0.1.2)
91
+ atomic
92
+ tilt (1.4.1)
93
+ treetop (1.4.14)
94
+ polyglot
95
+ polyglot (>= 0.3.1)
96
+ tzinfo (0.3.37)
97
+
98
+ PLATFORMS
99
+ ruby
100
+
101
+ DEPENDENCIES
102
+ bundler (>= 1.0)
103
+ chosen-awesome-rails!
104
+ rails (>= 3.0)
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 heaven
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # Chosen awesome (with ajax support and dynamic options injection)
2
+
3
+ A written from the scratch library that wraps around default html select controls
4
+ and makes them more user friendly (Ruby on Rails package).
5
+
6
+ ## Usage
7
+
8
+ ### Install chosen-awesome-rails gem
9
+
10
+ Include `chosen-awesome-rails` in Gemefile
11
+
12
+ gem 'chosen-awesome-rails'
13
+
14
+ Then run `bundle install`
15
+
16
+ ### Include javascript assets
17
+
18
+ Add to your `app/assets/javascripts/application.js`
19
+
20
+ //= require chosen
21
+
22
+ ### Include chosen stylesheet assets
23
+
24
+ Add to your `app/assets/stylesheets/application.css`
25
+
26
+ *= require chosen
27
+
28
+ You might also use twitter bootstrap integration by adding
29
+
30
+ *= require chosen/bootstrap
31
+
32
+ ### Enable chosen
33
+ ```javascript
34
+ $("select").chosen()
35
+ ```
36
+
37
+ Default options are:
38
+
39
+ ```javascript
40
+ {
41
+ allow_insertion: false, // allows to add missing options dynamically, e.g. when you
42
+ // need to show a list of tags allowing users to add missing ones
43
+ inherit_classes: true, // whether chosen should inherit html class names from the
44
+ // original select element
45
+ option_parser: null, // a function that should return an object that
46
+ // will be passed right to jQuery's append method to build
47
+ // html option elemets: $("<option />", parsed_object)
48
+ option_formatter: null // a function that accepts an option object (jquery selector)
49
+ // and returns an array of 2 values where one is used
50
+ // for the dropdown item and another for the choice element
51
+ }
52
+ ```
53
+
54
+ Dynamic insertion example:
55
+
56
+ ![Dynamic insertion example]
57
+ (http://oi62.tinypic.com/14kb808.jpg)
58
+
59
+ The option formatter allows to build selects like this one:
60
+
61
+ ![Custom dropdown options]
62
+ (http://oi60.tinypic.com/28818i8.jpg)
63
+
64
+ You can also override text messages with:
65
+
66
+ ```javascript
67
+ {
68
+ locale: {
69
+ no_results: "No results found",
70
+ start_typing: "Please start typing",
71
+ add_new: "add new"
72
+ }
73
+ }
74
+ ```
75
+
76
+ And pass the next ajax options:
77
+
78
+ ```javascript
79
+ {
80
+ ajax: {
81
+ url: "where to fetch options",
82
+ type: "get", // optional
83
+ dataType: "json", // optional
84
+ data: {}, // optional
85
+ async: true, // optional
86
+ xhrFields: null // optional
87
+ }
88
+ }
89
+ ```
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/gem_tasks'
@@ -0,0 +1,42 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # stub: chosen-awesome-rails 0.0.1 ruby lib
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "chosen-awesome-rails"
6
+ s.version = "1.0.0"
7
+
8
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
9
+ s.require_paths = ["lib"]
10
+ s.authors = ["heaven"]
11
+ s.date = "2013-08-04"
12
+ s.description = "Chosen is a javascript library of select box enhancer for jQuery, integrates with Rails asset pipeline for ease of use."
13
+ s.email = ["alex@codeart.pw"]
14
+ s.files = [".gitignore", "Gemfile", "Gemfile.lock", "LICENSE.txt", "README.md", "Rakefile", "chosen-awesome-rails.gemspec", "lib/chosen-awesome-rails.rb", "lib/chosen-awesome-rails/engine.rb", "lib/chosen-awesome-rails/engine3.rb", "lib/chosen-awesome-rails/version.rb", "vendor/assets/images/chosen-arrow.gif", "vendor/assets/javascripts/chosen.js.coffee", "vendor/assets/javascripts/chosen/chosen.js.coffee", "vendor/assets/javascripts/chosen/multiple.js.coffee", "vendor/assets/javascripts/chosen/parser.js.coffee", "vendor/assets/javascripts/chosen/single.js.coffee", "vendor/assets/stylesheets/chosen.css.scss", "vendor/assets/stylesheets/chosen/bootstrap.css.scss", "vendor/assets/stylesheets/chosen/default.css.scss"]
15
+ s.homepage = "https://github.com/heaven/chosen-awesome-rails"
16
+ s.rubygems_version = "2.2.1"
17
+ s.summary = "Integrate Chosen javascript library with Rails asset pipeline"
18
+
19
+ if s.respond_to? :specification_version then
20
+ s.specification_version = 3
21
+
22
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
23
+ s.add_runtime_dependency(%q<railties>, [">= 3.0"])
24
+ s.add_runtime_dependency(%q<coffee-rails>, [">= 3.2"])
25
+ s.add_runtime_dependency(%q<sass-rails>, [">= 3.2"])
26
+ s.add_development_dependency(%q<bundler>, [">= 1.0"])
27
+ s.add_development_dependency(%q<rails>, [">= 3.0"])
28
+ else
29
+ s.add_dependency(%q<railties>, [">= 3.0"])
30
+ s.add_dependency(%q<coffee-rails>, [">= 3.2"])
31
+ s.add_dependency(%q<sass-rails>, [">= 3.2"])
32
+ s.add_dependency(%q<bundler>, [">= 1.0"])
33
+ s.add_dependency(%q<rails>, [">= 3.0"])
34
+ end
35
+ else
36
+ s.add_dependency(%q<railties>, [">= 3.0"])
37
+ s.add_dependency(%q<coffee-rails>, [">= 3.2"])
38
+ s.add_dependency(%q<sass-rails>, [">= 3.2"])
39
+ s.add_dependency(%q<bundler>, [">= 1.0"])
40
+ s.add_dependency(%q<rails>, [">= 3.0"])
41
+ end
42
+ end
@@ -0,0 +1,13 @@
1
+ module Chosen
2
+ module Rails
3
+ end
4
+ end
5
+
6
+ require 'chosen-awesome-rails/version'
7
+
8
+ case ::Rails.version.to_s
9
+ when /^4/
10
+ require 'chosen-awesome-rails/engine'
11
+ when /^3\.[12]/
12
+ require 'chosen-awesome-rails/engine3'
13
+ end
@@ -0,0 +1,7 @@
1
+ module Chosen
2
+ module Rails
3
+ class Engine < ::Rails::Engine
4
+ config.assets.precompile += %w[chosen-*.gif chosen-*.png]
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ module Chosen
2
+ module Rails
3
+ class Engine3 < ::Rails::Engine
4
+ initializer 'chosen.assets.precompile' do |app|
5
+ app.config.assets.precompile += %w[chosen-*.gif chosen-*.png]
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ module Chosen
2
+ module Rails
3
+ VERSION = '1.0.0'
4
+ end
5
+ end
@@ -0,0 +1,39 @@
1
+ #= require chosen/chosen
2
+ #= require chosen/multiple
3
+ #= require chosen/single
4
+ #= require chosen/parser
5
+
6
+ $ = jQuery
7
+
8
+ $.fn.extend
9
+ chosen: (options) ->
10
+ return @ unless Chosen.is_supported()
11
+
12
+ @each ->
13
+ $this = $(@)
14
+
15
+ unless $this.data("chosen")
16
+ $this.data('chosen',
17
+ if @multiple
18
+ new Chosen.Multiple($this, options)
19
+ else
20
+ new Chosen.Single($this, options)
21
+ ).trigger("chosen:ready")
22
+
23
+ $(window).bind("resize", (evt) ->
24
+ for chosen in Chosen.pool
25
+ chosen.update_dropdown_position()
26
+
27
+ return
28
+ ).bind "scroll", (evt) ->
29
+ for chosen in Chosen.pool
30
+ chosen.close() if chosen.opened
31
+
32
+ return
33
+
34
+ $(document).ready ->
35
+ $("body").on "click", "input[type=reset]", (evt) ->
36
+ $(evt.target.form).find("select.chosen").each ->
37
+ chosen = $(@).data("chosen")
38
+ chosen and chosen.reset()
39
+
@@ -0,0 +1,470 @@
1
+ $ = jQuery
2
+
3
+ class Chosen
4
+ constructor: (@$target, options = {}) ->
5
+ $.extend(@, $.extend($.extend($.extend({}, Chosen.defaults), @constructor.defaults), options))
6
+
7
+ @$body = $("body")
8
+ @target = @$target[0]
9
+ @parser = new Chosen.Parser(@)
10
+ @default_values = $.map @parser.selected_options, (option) -> option
11
+
12
+ @allow_deselect = @is_multiple or (@parser.includes_blank() and @allow_deselect != false)
13
+ @activated = false
14
+ @opened = false
15
+
16
+ @search_value = ""
17
+ @cursor_option = null
18
+
19
+ @build()
20
+ @load()
21
+ @complete()
22
+
23
+ complete: ->
24
+ Chosen.pool.push(@)
25
+
26
+ if @target.disabled
27
+ @disabled = false
28
+ @disable()
29
+ else
30
+ @disabled = true
31
+ @enable()
32
+
33
+ @$target.addClass("chosen").after(@$container)
34
+
35
+ destroy: ->
36
+ @unbind_events()
37
+
38
+ delete @$body
39
+
40
+ @$container.remove()
41
+ @$dropdown.remove()
42
+ @$target.removeData("chosen").removeClass("chosen").show()
43
+
44
+ delete @$container
45
+ delete @$dropdown
46
+ delete @$target
47
+ delete @target
48
+
49
+ @parser.destroy()
50
+
51
+ delete @parser
52
+
53
+ index = Chosen.pool.indexOf(@)
54
+ Chosen.pool.splice(index, 1) if index >= 0
55
+
56
+ reset: ->
57
+ @deselect_all()
58
+
59
+ $.each @default_values, (index, option) =>
60
+ @parser.restore(option)
61
+
62
+ @load()
63
+
64
+ build: ->
65
+ select_classes = ["chosen-container"]
66
+
67
+ select_classes.push if @is_multiple then "multiple" else "single"
68
+ select_classes.push "rtl" if @is_rtl
69
+ select_classes.push @target.className if @inherit_classes and @target.className
70
+
71
+ width = if @width? then @width else "#{@target.offsetWidth}px"
72
+
73
+ container_props =
74
+ class: select_classes.join ' '
75
+ style: "width: #{width}; min-width: #{width}; max-width: #{width}"
76
+
77
+ container_props.title = @target.title if @target.title.length
78
+ container_props.id = @target.id.replace(/[^\w]/g, '-') + "-chosen" if @target.id
79
+ placeholder = @$target.attr("placeholder") || @placeholder
80
+
81
+ @$container = $("<div />", container_props)
82
+ @$container.html "<ul class=\"chosen-choices\"><li class=\"chosen-search-field\"><input type=\"text\" placeholder=\"#{placeholder}\" autocomplete=\"off\" /></li></ul>"
83
+ @$container.$choices = @$container.find("ul.chosen-choices")
84
+ @$container.$search_container = @$container.$choices.find("li.chosen-search-field")
85
+ @$container.$search = @$container.$choices.find("input[type=text]").attr(tabindex: @target.tabindex || "0")
86
+
87
+ dropdown_classes = ["chosen-dropdown"]
88
+
89
+ dropdown_classes.push if @is_multiple then "multiple" else "single"
90
+ dropdown_classes.push "rtl" if @is_rtl
91
+
92
+ dropdown_props =
93
+ class: dropdown_classes.join ' '
94
+ unselectable: "on"
95
+ html: "<ul></ul>"
96
+
97
+ @$dropdown = $("<div />", dropdown_props)
98
+ @$dropdown.$list = @$dropdown.find("ul").first()
99
+ @$dropdown.$list.$no_results = $("<li />", class: "chosen-noresults")
100
+ @$dropdown.$list.suggestion = null
101
+
102
+ bind_events: ->
103
+ if @target.id.length
104
+ $("label[for=#{@target.id}]").bind "click", (evt) =>
105
+ @$container.$search.trigger("focus")
106
+ @open()
107
+ evt.preventDefault()
108
+
109
+ @$container.bind "mousedown", (evt) =>
110
+ @$container.$search.trigger("focus")
111
+ @open()
112
+ evt.preventDefault()
113
+
114
+ @$container.$search.bind "mousedown", (evt) =>
115
+ @$container.$search.trigger("focus")
116
+ @open()
117
+ evt.stopImmediatePropagation()
118
+
119
+ @$container.$search.bind "keydown", (evt) => @keydown(evt)
120
+ @$container.$search.bind "keyup", (evt) => @keyup(evt)
121
+ @$container.$search.bind "focus", (evt) => @focus(evt)
122
+ @$container.$search.bind "blur", (evt) => @blur(evt)
123
+
124
+ return true
125
+
126
+ unbind_events: ->
127
+ if @target.id.length
128
+ $("label[for=#{@target.id}]").unbind "click"
129
+
130
+ @$dropdown.unbind()
131
+ @$container.$search.unbind()
132
+ @$container.unbind()
133
+
134
+ return true
135
+
136
+ activate: ->
137
+ @$container.$search.trigger("focus")
138
+ return @
139
+
140
+ deactivate: ->
141
+ @$container.$search.trigger("blur")
142
+ return @
143
+
144
+ enable: ->
145
+ if @disabled
146
+ @$target.removeAttr("disabled")
147
+ @$container.$search.removeAttr("disabled")
148
+ @$container.removeClass("disabled")
149
+ @$container.find("a").each ->
150
+ $(@).attr(tabindex: @tabindex) if @tabindex
151
+
152
+ @bind_events()
153
+ @disabled = false
154
+
155
+ return @
156
+
157
+ disable: ->
158
+ unless @disabled
159
+ @close()
160
+ @blur()
161
+ @unbind_events()
162
+
163
+ @$container.find("a").each(->
164
+ $link = $(@)
165
+
166
+ @tabindex = $link.attr("tabindex")
167
+ $link.attr(tabindex: "-1")
168
+ )
169
+
170
+ @$container.addClass("disabled")
171
+ @$container.$search.attr(disabled: "disabled")
172
+ @$target.attr(disabled: "disabled")
173
+ @disabled = true
174
+
175
+ return @
176
+
177
+ focus: (evt) ->
178
+ return @ if @activated
179
+
180
+ @activated = true
181
+ @$container.addClass("focus")
182
+
183
+ return @
184
+
185
+ blur: (evt) ->
186
+ return @ unless @activated
187
+
188
+ @set_default_value()
189
+ @close()
190
+ @activated = false
191
+ @$container.removeClass("focus")
192
+
193
+ return @
194
+
195
+ open: ->
196
+ return @ if @opened
197
+
198
+ @opened = true
199
+
200
+ @redraw_dropdown()
201
+
202
+ @$container.$search.trigger("focus") unless @activated
203
+ @$body.append(@$dropdown)
204
+
205
+ @move_selection_to(@parser.index_of(@cursor_option))
206
+
207
+ @$dropdown.bind "mouseover", "li.chosen-option", (evt) => @dropdown_mouseover(evt)
208
+ @$dropdown.bind "mousedown", "li.chosen-option", (evt) => @dropdown_mousedown(evt)
209
+
210
+ @$container.addClass("opened")
211
+ @$dropdown.addClass("opened")
212
+
213
+ return @
214
+
215
+ close: ->
216
+ return @ unless @opened
217
+
218
+ @$container.removeClass("opened")
219
+ @$dropdown.removeClass("opened")
220
+ @$dropdown.unbind "mouseover mousedown"
221
+ @$dropdown.remove()
222
+ @opened = false
223
+
224
+ return @
225
+
226
+ loading: ->
227
+ @loaded()
228
+ @$container.addClass("loading")
229
+ @$dropdown.addClass("loading")
230
+ return @
231
+
232
+ loaded: ->
233
+ @$container.removeClass("loading error")
234
+ @$dropdown.removeClass("loading error")
235
+ return @
236
+
237
+ error: ->
238
+ @loaded()
239
+ @$container.addClass("error")
240
+ @$dropdown.addClass("error")
241
+ return @
242
+
243
+ dropdown_mouseover: (evt) ->
244
+ option = @parser.find_by_element(evt.target)
245
+
246
+ @move_selection_to(@parser.index_of(option)) if option
247
+
248
+ evt.preventDefault()
249
+ evt.stopImmediatePropagation()
250
+ return
251
+
252
+ dropdown_mousedown: (evt) ->
253
+ option = @parser.find_by_element(evt.target)
254
+
255
+ @select(option) if option
256
+
257
+ evt.preventDefault()
258
+ evt.stopImmediatePropagation()
259
+ return
260
+
261
+ keydown: (evt) ->
262
+ code = evt.which ? evt.keyCode
263
+
264
+ switch code
265
+ when 13
266
+ if @opened
267
+ @select(@cursor_option)
268
+ @move_selection(1) if @is_multiple
269
+ else
270
+ @open()
271
+ evt.preventDefault()
272
+ when 27
273
+ evt.preventDefault()
274
+ evt.stopPropagation()
275
+ when 38, 40
276
+ @open()
277
+ @move_selection(code - 39)
278
+ evt.preventDefault()
279
+ else
280
+ true
281
+
282
+ return
283
+
284
+ keyup: (evt) ->
285
+ code = evt.which ? evt.keyCode
286
+
287
+ return if [9, 13, 16, 35, 36, 37, 38, 39, 40].indexOf(code) >= 0
288
+
289
+ if code is 27 and @opened
290
+ @close()
291
+ evt.stopPropagation()
292
+ else if @has_filter_changed()
293
+ @open()
294
+
295
+ if @ajax then @pull_updates() else @redraw_dropdown()
296
+
297
+ return
298
+
299
+ redraw_dropdown: (data) ->
300
+ @parser.update(data) unless data is undefined
301
+
302
+ changed = @apply_filter()
303
+
304
+ @update_dropdown_position()
305
+ @update_dropdown_content()
306
+ @move_selection_to(0) if changed
307
+
308
+ return
309
+
310
+ update_dropdown_position: ->
311
+ return unless @opened
312
+
313
+ list = @$container.find("ul")
314
+ offsets = list.offset()
315
+ height = list.innerHeight()
316
+ width = list.innerWidth()
317
+
318
+ @$dropdown.css
319
+ left: "#{offsets.left}px",
320
+ top: "#{offsets.top + height}px"
321
+ width: "#{width}px"
322
+
323
+ return
324
+
325
+ update_dropdown_content: ->
326
+ @insert_suggestion()
327
+
328
+ if @parser.selectable_options.length
329
+ @$dropdown.$list.html(@parser.to_html())
330
+ else
331
+ @show_no_results()
332
+
333
+ return
334
+
335
+ insert_suggestion: ->
336
+ return unless @allow_insertion
337
+
338
+ if @$dropdown.$list.suggestion
339
+ @parser.remove(@$dropdown.$list.suggestion)
340
+
341
+ if @$container.$search[0].value and not @parser.exact_matches().length
342
+ @$dropdown.$list.suggestion = suggestion = @parser.insert(
343
+ value: @$container.$search[0].value
344
+ label: @$container.$search[0].value
345
+ )
346
+
347
+ value = "#{suggestion.value} (#{@locale.add_new})"
348
+
349
+ suggestion.$listed.contents().last()[0].nodeValue = value
350
+ suggestion.$choice.contents().last()[0].nodeValue = value
351
+ else if @$dropdown.$list.suggestion
352
+ @$dropdown.$list.suggestion = null
353
+
354
+ show_no_results: ->
355
+ text = if @ajax then @locale.start_typing else @locale.no_results
356
+
357
+ @$dropdown.$list.$no_results.text(text)
358
+ @$dropdown.$list.html(@$dropdown.$list.$no_results)
359
+
360
+ apply_filter: ->
361
+ return false unless @has_filter_changed()
362
+
363
+ @search_value = @$container.$search[0].value
364
+ @parser.apply_filter(@$container.$search[0].value)
365
+
366
+ true
367
+
368
+ has_filter_changed: ->
369
+ @search_value isnt @$container.$search[0].value
370
+
371
+ move_selection: (dir) ->
372
+ cursor = @parser.index_of(@cursor_option) + dir
373
+ cursor = @parser.available_options.length - 1 if cursor < 0
374
+ cursor = 0 if cursor > @parser.available_options.length - 1
375
+
376
+ @move_selection_to(cursor)
377
+
378
+ if @cursor_option and @cursor_option.selected and @parser.selectable_options.length
379
+ # TODO: optimize this
380
+ return @move_selection(dir)
381
+
382
+ return @
383
+
384
+ move_selection_to: (cursor) ->
385
+ if @cursor_option
386
+ @cursor_option.$listed.removeClass("active")
387
+
388
+ @cursor_option = @parser.available_options[cursor]
389
+
390
+ return unless @cursor_option
391
+
392
+ $element = @cursor_option.$listed.addClass("active")
393
+ top = $element.position().top + $element.height()
394
+ list_height = @$dropdown.height()
395
+ list_scroll = @$dropdown.scrollTop()
396
+
397
+ if top >= list_height + list_scroll or list_scroll >= top
398
+ @$dropdown.scrollTop($element.position().top)
399
+
400
+ return @
401
+
402
+ get_caret_position: ->
403
+ field = @$container.$search[0]
404
+
405
+ if document.selection
406
+ sel = document.selection.createRange()
407
+ length = sel.text.length
408
+
409
+ sel.moveStart('character', -field.value.length)
410
+
411
+ sel.text.length - length
412
+ else if field.selectionStart or field.selectionStart is '0'
413
+ field.selectionStart
414
+ else
415
+ 0
416
+
417
+ pull_updates: ->
418
+ return @ if not @ajax or not @$container.$search[0].value
419
+
420
+ if @ajax.pending_update
421
+ clearTimeout(@ajax.pending_update)
422
+
423
+ @ajax.pending_update = setTimeout =>
424
+ if @ajax.pending_request and @ajax.pending_request.readyState isnt 4
425
+ @ajax.pending_request.abort()
426
+
427
+ data =
428
+ query: @$container.$search[0].value
429
+
430
+ @ajax.pending_request = $.ajax
431
+ url: @ajax.url
432
+ type: @ajax.type or "get"
433
+ dataType: @ajax.dataType or "json"
434
+ data: $.extend(@ajax.data || {}, data)
435
+ async: @ajax.async or true
436
+ xhrFields: @ajax.xhrFields
437
+
438
+ beforeSend: (xhr) =>
439
+ @loading()
440
+ @ajax.beforeSend(xhr) if typeof @ajax.beforeSend is "function"
441
+ success: (data) =>
442
+ @loaded()
443
+ @redraw_dropdown(data)
444
+ error: =>
445
+ @error()
446
+
447
+ , 300
448
+
449
+ return @
450
+
451
+ @is_crappy_browser: (version) ->
452
+ window.navigator.appName == "Microsoft Internet Explorer" and document.documentMode <= version
453
+
454
+ @is_supported: ->
455
+ not Chosen.is_crappy_browser(6)
456
+
457
+ @defaults:
458
+ allow_insertion: false
459
+ inherit_classes: true
460
+ is_rtl: false
461
+ option_parser: null
462
+ option_formatter: null
463
+ locale:
464
+ no_results: "No results found"
465
+ start_typing: "Please start typing"
466
+ add_new: "add new"
467
+
468
+ @pool: []
469
+
470
+ @Chosen = Chosen