better_select 0.0.4 → 0.1.0

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.
@@ -1,3 +1,12 @@
1
1
  [submodule "vendor"]
2
2
  path = vendor
3
3
  url = git@github.com:benastan/better_select.git
4
+ [submodule "vendor/better_select"]
5
+ path = vendor/better_select
6
+ url = git@github.com:benastan/better_select.git
7
+ [submodule "vendor/assets/better_select"]
8
+ path = vendor/assets/better_select
9
+ url = git@github.com:benastan/better_select.git
10
+ [submodule "vendor/assets/javascripts/better_select"]
11
+ path = vendor/assets/javascripts/better_select
12
+ url = git@github.com:benastan/better_select.git
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # BetterSelect
1
+ # BetterSelect (for Rails)
2
2
 
3
- TODO: Write a gem description
3
+ Easily get better HTML Select elements into your rails projects.
4
4
 
5
5
  ## Installation
6
6
 
@@ -8,17 +8,25 @@ Add this line to your application's Gemfile:
8
8
 
9
9
  gem 'better_select'
10
10
 
11
+ Or install it yourself as:
12
+
13
+ $ gem install better_select
14
+
11
15
  And then execute:
12
16
 
13
17
  $ bundle
14
18
 
15
- Or install it yourself as:
19
+ Add to application.js:
16
20
 
17
- $ gem install better_select
21
+ //= require 'better-select'
22
+
23
+ Add to any stylesheet:
24
+
25
+ @import 'better-select';
18
26
 
19
27
  ## Usage
20
28
 
21
- TODO: Write usage instructions here
29
+ See https://github.com/benastan/better_select for detailed usage.
22
30
 
23
31
  ## Contributing
24
32
 
@@ -16,4 +16,5 @@ Gem::Specification.new do |gem|
16
16
  gem.version = BetterSelect::VERSION
17
17
 
18
18
  gem.add_dependency "railties", "~> 3.1"
19
+ gem.add_dependency "underscore-rails"
19
20
  end
@@ -1,3 +1,3 @@
1
1
  module BetterSelect
2
- VERSION = "0.0.4"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1 @@
1
+ //=require better_select/lib/better-select
@@ -0,0 +1,4 @@
1
+ compile:
2
+ coffee -co ./build ./lib/better-select.coffee
3
+ sass lib/better-select.css.scss > ./build/better-select.css
4
+
@@ -0,0 +1,68 @@
1
+ # BetterSelect
2
+
3
+ HTML5 still hasn't gotten these right. Here's a simple JavaScript HTMLSelectElement
4
+ replacer.
5
+
6
+ ## Installation
7
+
8
+ Add to HTML web page:
9
+
10
+ <!-- Underscore is BetterSelect's only dependency -->
11
+ <script type="text/javascript" src="http://underscorejs.org/underscore-min.js"></script>
12
+ <script type="text/javascript" src="https://raw.github.com/benastan/better_select/master/build/better-select.js"></script>
13
+
14
+ Or clone source:
15
+
16
+ git clone git@github.com:benastan/better_select.git
17
+
18
+ ## Usage
19
+
20
+ Plain JavaScript:
21
+
22
+ <select id="boring-select"><option>What a bore!</option><option>This
23
+ is boring!</option></select>
24
+
25
+ boring_select = document.getElementById('boring-select')
26
+ better_select = new BetterSelect(boring_select)
27
+
28
+ The BetterSelect instance offers a number of helpful properties, for
29
+ example:
30
+
31
+ better_select.select // HTML Element of the replacement select.
32
+ better_select.dropdown // HTML Element containing the new options list.
33
+ better_select.selected_option // HTML Element containing the new options list.
34
+
35
+ BetterSelect doesn't interfere with how the original select element
36
+ operates. When the form submits, the value still comes from the select
37
+ element itself.
38
+
39
+ Additionally, you can attach events to the original element the same way
40
+ as always:
41
+
42
+ ChangeHandler = function() { alert("It changed!") }
43
+ boring_select.addEventListener('change', ChangeHandler)
44
+
45
+ Or, with jQuery:
46
+
47
+ $(boring_select).on('change', ChangeHandler)
48
+
49
+ ## CSS
50
+
51
+ BetterSelect comes with a very limited amount of CSS -- just enough to
52
+ make BetterSelect functional. All other styling choices are up to you.
53
+
54
+ ## TODO
55
+
56
+ 1. There are still a few ways that BetterSelect does not quite feel like
57
+ a standard select element. One is that when you type out a value when
58
+ focused, BetterSelect only focuses based on the first letter.
59
+ 2. Create themes.
60
+ 3. Code clean up.
61
+
62
+ ## Contributing
63
+
64
+ 1. Fork it
65
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
66
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
67
+ 4. Push to the branch (`git push origin my-new-feature`)
68
+ 5. Create new Pull Request
@@ -42,8 +42,7 @@
42
42
 
43
43
  addClass = function(tgt, className) {
44
44
  var classes;
45
- classes = getClasses(tgt);
46
- if (classes.indexOf(className) === -1) {
45
+ if ((classes = getClasses(tgt)).indexOf(className) === -1) {
47
46
  classes.push(className);
48
47
  }
49
48
  return setClasses(tgt, classes);
@@ -51,7 +50,7 @@
51
50
 
52
51
  removeClass = function(tgt, className) {
53
52
  var classes, index;
54
- if (!(index = (classes = getClasses(tgt)).indexOf(className === -1))) {
53
+ if ((index = (classes = getClasses(tgt)).indexOf(className)) !== -1) {
55
54
  classes.splice(index, 1);
56
55
  }
57
56
  return setClasses(tgt, classes);
@@ -63,9 +62,7 @@
63
62
 
64
63
  build_element = function(what, orig, obj) {
65
64
  var elm;
66
- elm = $$(_.template(obj["" + what + "_template"])(obj["process_" + what](orig)));
67
- elm.orig = orig;
68
- orig.better_version = elm;
65
+ ((elm = $$(_.template(obj["" + what + "_template"])(obj["process_" + what](orig)))).orig = orig).better_version = elm;
69
66
  elm.better_select = obj;
70
67
  return elm;
71
68
  };
@@ -81,10 +78,10 @@
81
78
  option.select = function() {
82
79
  this.orig.selected = 'selected';
83
80
  this.setAttribute('class', 'option selected');
84
- if (bs.select.getAttribute('class').indexOf('open') !== -1) {
85
- bs.toggle();
81
+ bs.set_selected(option);
82
+ if (bs.open) {
83
+ return bs.toggle();
86
84
  }
87
- return bs.set_selected(option);
88
85
  };
89
86
  option.addEventListener('click', function() {
90
87
  return option.select();
@@ -96,6 +93,11 @@
96
93
  first_char = option.innerHTML.substr(0, 1).toLowerCase();
97
94
  if (!bs.options_by_first_char[first_char]) {
98
95
  bs.options_by_first_char[first_char] = [];
96
+ bs.options_by_first_char[first_char].sort = function() {
97
+ var sorted;
98
+ (sorted = _(this).sortBy('innerHTML')).unshift(0, this.length);
99
+ return this.splice.apply(this, sorted);
100
+ };
99
101
  }
100
102
  bs.options_by_first_char[first_char].push(option);
101
103
  bs.options_by_first_char[first_char].sort();
@@ -117,11 +119,12 @@
117
119
  BetterSelect = (function() {
118
120
 
119
121
  BetterSelect.prototype.defaults = {
120
- positionDropdown: true
122
+ positionDropdown: true,
123
+ resizeDropdown: true
121
124
  };
122
125
 
123
126
  function BetterSelect(elm, options) {
124
- var child, children, last_char, method, selected, _i, _len, _ref,
127
+ var child, children, method, selected, _i, _len, _ref,
125
128
  _this = this;
126
129
  if (!(elm && elm.tagName && elm.tagName === 'SELECT')) {
127
130
  return;
@@ -133,6 +136,7 @@
133
136
  selected = elm.selectedOptions;
134
137
  this.select = build_element('select', elm, this);
135
138
  _ref = this.select.children, this.selected_option = _ref[0], this.dropdown = _ref[1];
139
+ this.selected_option.better_select = this;
136
140
  if (elm.id) {
137
141
  this.select.id = "" + elm.id + "-better-select";
138
142
  this.dropdown.id = "" + elm.id + "-better-select-dropdown";
@@ -161,8 +165,14 @@
161
165
  this.default_selected[0].better_version.select();
162
166
  }
163
167
  this.selected_option.addEventListener('click', function() {
164
- _this.toggle();
165
- return _this.set_selected(_this.dropdown_selected_option);
168
+ if (_this.open) {
169
+ if (_this.focused_option) {
170
+ _this.focused_option.select();
171
+ }
172
+ } else {
173
+ _this.set_focused(_this.dropdown_selected_option);
174
+ }
175
+ return _this.toggle();
166
176
  });
167
177
  window.addEventListener('click', function(e) {
168
178
  if (!(e.target === _this.selected_option || e.target === _this.select || _this.options.indexOf(e.target) !== -1)) {
@@ -171,7 +181,7 @@
171
181
  }
172
182
  }
173
183
  });
174
- last_char = false;
184
+ this.last_char = false;
175
185
  this.selected_option.addEventListener('focus', function() {
176
186
  document.body.style.overflow = 'hidden';
177
187
  return addClass(_this.select, 'focus');
@@ -184,58 +194,18 @@
184
194
  }
185
195
  return true;
186
196
  });
187
- this.selected_option.addEventListener('keydown', function(e) {
197
+ this.selected_option.addEventListener('keyup', function(e) {
188
198
  if ([38, 40].indexOf(e.keyCode) !== -1) {
189
199
  return e.preventDefault();
190
200
  }
191
201
  });
192
- this.selected_option.addEventListener('keyup', function(e) {
193
- var char, keyCode, last_character, option;
194
- if (_this.open === false) {
195
- _this.toggle();
196
- }
197
- keyCode = e.keyCode;
198
- switch (keyCode) {
199
- case 38:
200
- _this.set_focused(_this.options[(_this.focus_index -= 1) < 0 ? _this.focus_index = _this.options.length - 1 : _this.focus_index]);
201
- break;
202
- case 40:
203
- _this.set_focused(_this.options[(_this.focus_index += 1) >= _this.options.length ? _this.focus_index = 0 : _this.focus_index]);
204
- break;
205
- case 13:
206
- _this.focused_option.select();
207
- break;
208
- default:
209
- if (keyCode > 47 && keyCode < 58) {
210
- char = numbers[keyCode - 47];
211
- } else if (keyCode > 64 && keyCode < 91) {
212
- char = letters[keyCode - 65];
213
- } else {
214
- if (_this.focused_option) {
215
- removeClass(_this.focused_option, 'focus');
216
- _this.focused_option = false;
217
- _this.focus_index = -1;
218
- }
219
- _this.toggle();
220
- }
221
- if (char && _this.options_by_first_char[char]) {
222
- if (last_char !== char) {
223
- _this.options_by_first_char[char].sort();
224
- }
225
- option = _this.options_by_first_char[char].shift();
226
- _this.options_by_first_char[char].push(option);
227
- _this.set_focused(option);
228
- _this.focus_index = _this.options.indexOf(option);
229
- last_character = char;
230
- }
202
+ this.selected_option.addEventListener('keydown', function(e) {
203
+ return _this.process_key_event(e);
204
+ });
205
+ window.addEventListener('keydown', function(e) {
206
+ if (_this.open) {
207
+ return _this.process_key_event(e);
231
208
  }
232
- _this.dropdown.addEventListener('click', function() {
233
- return console.log(arguments);
234
- });
235
- e.preventDefault();
236
- e.stopPropagation();
237
- e.returnValue = false;
238
- return false;
239
209
  });
240
210
  }
241
211
 
@@ -243,6 +213,61 @@
243
213
 
244
214
  BetterSelect.prototype.focus_index = -1;
245
215
 
216
+ BetterSelect.prototype.select_focused = function() {
217
+ if (this.focused_option) {
218
+ return this.focused_option.select();
219
+ }
220
+ };
221
+
222
+ BetterSelect.prototype.process_key_event = function(e) {
223
+ var char, isLetter, isNumber, keyCode, option;
224
+ keyCode = e.keyCode;
225
+ isNumber = keyCode > 47 && keyCode < 58;
226
+ isLetter = keyCode > 64 && keyCode < 91;
227
+ if (keyCode === 9 && this.open) {
228
+ return this.select_focused();
229
+ }
230
+ if (!([13, 38, 40].indexOf(keyCode) !== -1 || isLetter || isNumber)) {
231
+ return;
232
+ }
233
+ if ([13, 38, 40].indexOf(keyCode) !== -1 && this.open === false) {
234
+ this.toggle();
235
+ }
236
+ switch (keyCode) {
237
+ case 38:
238
+ this.set_focused(this.options[(this.focus_index -= 1) < 0 ? this.focus_index = this.options.length - 1 : this.focus_index]);
239
+ break;
240
+ case 40:
241
+ this.set_focused(this.options[(this.focus_index += 1) >= this.options.length ? this.focus_index = 0 : this.focus_index]);
242
+ break;
243
+ case 13:
244
+ this.select_focused();
245
+ break;
246
+ default:
247
+ if (isNumber) {
248
+ char = numbers[new String(keyCode - 48)];
249
+ } else if (isLetter) {
250
+ char = letters[keyCode - 65];
251
+ }
252
+ if (char && this.options_by_first_char[char]) {
253
+ if (!this.open) {
254
+ this.toggle();
255
+ }
256
+ if (this.last_char !== char) {
257
+ this.options_by_first_char[char].sort();
258
+ }
259
+ option = this.options_by_first_char[char].shift();
260
+ this.options_by_first_char[char].push(option);
261
+ this.set_focused(option);
262
+ this.focus_index = this.options.indexOf(option);
263
+ this.last_char = char;
264
+ }
265
+ }
266
+ e.preventDefault();
267
+ e.stopPropagation();
268
+ return e.returnValue = false;
269
+ };
270
+
246
271
  BetterSelect.prototype.set_focused = function(option) {
247
272
  var class_for_selected,
248
273
  _this = this;
@@ -258,7 +283,8 @@
258
283
  }
259
284
  this.focused_option = option;
260
285
  this.focused_option.setAttribute("class", "option focus" + (class_for_selected(option)));
261
- return this.focus_index = this.options.indexOf(this.focused_option);
286
+ this.focus_index = this.options.indexOf(this.focused_option);
287
+ return this.focused_option.scrollIntoView();
262
288
  };
263
289
 
264
290
  BetterSelect.prototype.open = false;
@@ -266,6 +292,9 @@
266
292
  BetterSelect.prototype.toggle = function() {
267
293
  var height, top;
268
294
  ((this.open = !this.open) ? addClass : removeClass)(this.select, 'open');
295
+ if (this.settings.resizeDropdown) {
296
+ this.dropdown.style.width = this.select.offsetWidth + 'px';
297
+ }
269
298
  if (this.settings.positionDropdown) {
270
299
  if (this.dropdown.offsetHeight > window.innerHeight) {
271
300
  height = window.innerHeight * .50;
@@ -279,8 +308,11 @@
279
308
  top = top || (getTop(this.select) - this.dropdown_selected_option.offsetTop);
280
309
  top = getTop(this.select) - (this.dropdown_selected_option.offsetTop - this.dropdown.scrollTop);
281
310
  this.dropdown.style.top = (top < 0 ? 0 : top) + 'px';
282
- return this.dropdown.style.left = this.open ? getLeft(this.select) + 'px' : '-9999px';
311
+ this.dropdown.style.left = this.open ? getLeft(this.select) + 'px' : '-9999px';
283
312
  }
313
+ return _(this.options_by_first_char).each(function(options) {
314
+ return options.sort();
315
+ });
284
316
  };
285
317
 
286
318
  BetterSelect.prototype.reset = function(option) {
@@ -299,15 +331,16 @@
299
331
  this.selected_option.innerHTML = option.innerHTML;
300
332
  e = document.createEvent('Event');
301
333
  e.initEvent('change', true, true);
302
- return this.select.orig.dispatchEvent(e);
334
+ this.select.orig.dispatchEvent(e);
303
335
  }
336
+ return this.selected_option.focus();
304
337
  };
305
338
 
306
339
  BetterSelect.prototype.option_template = '<div class="option"><%= innerHTML %></div>';
307
340
 
308
341
  BetterSelect.prototype.option_group_template = '<div class="optgroup"><div class="option-group-label"><%= label %></div></div>';
309
342
 
310
- BetterSelect.prototype.select_template = '<div class="select"><a href="javascript:void(0)" class="selected-option"></a><div class="better-select-dropdown dropdown"></div></div>';
343
+ BetterSelect.prototype.select_template = '<div class="select better-select"><a href="javascript:void(0)" class="selected-option"></a><div class="better-select-dropdown dropdown"></div></div>';
311
344
 
312
345
  BetterSelect.prototype.process_option = function(option) {
313
346
  return option;
@@ -20,12 +20,11 @@ setClasses = (tgt, classes) ->
20
20
  tgt
21
21
 
22
22
  addClass = (tgt, className) ->
23
- classes = getClasses tgt
24
- classes.push(className) if classes.indexOf(className) is -1
23
+ classes.push(className) if (classes = getClasses tgt).indexOf(className) is -1
25
24
  setClasses tgt, classes
26
25
 
27
26
  removeClass = (tgt, className) ->
28
- classes.splice(index, 1) unless index = (classes = getClasses tgt).indexOf className is -1
27
+ classes.splice(index, 1) unless (index = (classes = getClasses tgt).indexOf className) is -1
29
28
  setClasses tgt, classes
30
29
 
31
30
  letters = 'a b c d e f g h i j k l m n o p q r s t u v w x y z'.split ' '
@@ -38,20 +37,30 @@ build_element = (what, orig, obj) ->
38
37
 
39
38
  renderOption = (orig_option, bs) ->
40
39
  option = build_element 'option', orig_option, bs
40
+
41
41
  option.reset = ->
42
42
  @orig.selected = undefined
43
43
  @setAttribute 'class', 'option'
44
44
  bs.reset @
45
+
45
46
  option.select = ->
46
47
  @orig.selected = 'selected'
47
48
  @setAttribute 'class', 'option selected'
48
- bs.toggle() if bs.select.getAttribute('class').indexOf('open') isnt -1
49
49
  bs.set_selected option
50
- option.addEventListener 'click', -> option.select()
50
+ bs.toggle() if bs.open
51
+
52
+ option.addEventListener 'click', ->
53
+ option.select()
54
+
51
55
  option.addEventListener 'mouseover', -> option.better_select.set_focused option
56
+
52
57
  bs.options.push option
53
58
  first_char = option.innerHTML.substr(0, 1).toLowerCase()
54
- bs.options_by_first_char[first_char] = [] unless bs.options_by_first_char[first_char]
59
+ unless bs.options_by_first_char[first_char]
60
+ bs.options_by_first_char[first_char] = []
61
+ bs.options_by_first_char[first_char].sort = ->
62
+ (sorted = _(@).sortBy 'innerHTML').unshift 0, @.length
63
+ @.splice.apply @, sorted
55
64
  bs.options_by_first_char[first_char].push option
56
65
  bs.options_by_first_char[first_char].sort()
57
66
  option
@@ -63,8 +72,11 @@ renderOptionGroup = (orig_group, bs) ->
63
72
  group
64
73
 
65
74
  class BetterSelect
75
+
66
76
  defaults:
67
77
  positionDropdown: true
78
+ resizeDropdown: true
79
+
68
80
  constructor: (elm, options) ->
69
81
  return unless elm && elm.tagName && elm.tagName is 'SELECT'
70
82
  @settings = _.extend {}, @defaults, options
@@ -74,17 +86,22 @@ class BetterSelect
74
86
  selected = elm.selectedOptions
75
87
  @select = build_element 'select', elm, @
76
88
  [@selected_option, @dropdown] = @select.children
89
+ @selected_option.better_select = @
90
+
77
91
  if elm.id
78
92
  @select.id = "#{elm.id}-better-select"
79
93
  @dropdown.id = "#{elm.id}-better-select-dropdown"
94
+
80
95
  @default_selected = [elm.children[elm.selectedIndex]]
81
96
  elm.parentNode.insertBefore @select, elm
82
97
  elm.parentNode.insertBefore elm, @select
83
98
  elm.style.display = 'none'
84
99
  children = elm.children
100
+
85
101
  if @settings.positionDropdown
86
102
  document.body.appendChild @dropdown
87
103
  @dropdown.style.left = '-9999px'
104
+
88
105
  for child in children
89
106
  switch child.tagName
90
107
  when 'OPTION'
@@ -92,65 +109,90 @@ class BetterSelect
92
109
  when 'OPTGROUP'
93
110
  method = renderOptionGroup
94
111
  @dropdown.appendChild(method child, @)
112
+
95
113
  @default_selected[0].better_version.select() if @default_selected
114
+
96
115
  @selected_option.addEventListener 'click', =>
116
+ if @open
117
+ @focused_option.select() if @focused_option
118
+ else
119
+ @set_focused @dropdown_selected_option
97
120
  @toggle()
98
- @set_selected @dropdown_selected_option
121
+
99
122
  window.addEventListener 'click', (e) =>
100
123
  unless e.target == @selected_option || e.target == @select || @options.indexOf(e.target) isnt -1
101
124
  @toggle() if @open
102
- last_char = false
125
+
126
+ @last_char = false
127
+
103
128
  @selected_option.addEventListener 'focus', =>
104
129
  document.body.style.overflow = 'hidden'
105
130
  addClass @select, 'focus'
131
+
106
132
  @selected_option.addEventListener 'blur', =>
107
133
  removeClass @select, 'focus'
108
134
  document.body.style.overflow = 'auto'
109
135
  @toggle() if @open is true
110
136
  true
111
- @selected_option.addEventListener 'keydown', (e) => e.preventDefault() unless [38, 40].indexOf(e.keyCode) is -1
112
- @selected_option.addEventListener 'keyup', (e) =>
113
- @toggle() if @open is false
114
- keyCode = e.keyCode
115
- switch keyCode
116
- when 38 then @set_focused @options[if (@focus_index -= 1) < 0 then @focus_index = @options.length - 1 else @focus_index]
117
- when 40 then @set_focused @options[if (@focus_index += 1) >= @options.length then @focus_index = 0 else @focus_index]
118
- when 13
119
- @focused_option.select()
120
- else
121
- if keyCode > 47 && keyCode < 58
122
- char = numbers[keyCode - 47]
123
- else if keyCode > 64 && keyCode < 91
124
- char = letters[keyCode - 65]
125
- else
126
- if @focused_option
127
- removeClass @focused_option, 'focus'
128
- @focused_option = false
129
- @focus_index = -1
130
- @toggle()
131
- if char && @options_by_first_char[char]
132
- @options_by_first_char[char].sort() unless last_char is char
133
- option = @options_by_first_char[char].shift()
134
- @options_by_first_char[char].push option
135
- @set_focused option
136
- @focus_index = @options.indexOf option
137
- last_character = char
138
- @dropdown.addEventListener('click', -> console.log arguments)
139
- e.preventDefault()
140
- e.stopPropagation()
141
- e.returnValue = false
142
- false
137
+
138
+ @selected_option.addEventListener 'keyup', (e) => e.preventDefault() unless [38, 40].indexOf(e.keyCode) is -1
139
+
140
+ @selected_option.addEventListener 'keydown', (e) => @process_key_event(e)
141
+
142
+ window.addEventListener 'keydown', (e) => @process_key_event(e) if @open
143
+
143
144
  focused_option: false
144
145
  focus_index: -1
146
+ select_focused: -> @focused_option.select() if @focused_option
147
+
148
+ process_key_event: (e) ->
149
+ keyCode = e.keyCode
150
+ isNumber = keyCode > 47 && keyCode < 58
151
+ isLetter = keyCode > 64 && keyCode < 91
152
+
153
+ return @select_focused() if keyCode is 9 && @open
154
+
155
+ return unless [13, 38, 40].indexOf(keyCode) isnt -1 || isLetter || isNumber
156
+
157
+ @toggle() if [13, 38, 40].indexOf(keyCode) isnt -1 && @open is false
158
+
159
+ switch keyCode
160
+ when 38 then @set_focused @options[if (@focus_index -= 1) < 0 then @focus_index = @options.length - 1 else @focus_index]
161
+ when 40 then @set_focused @options[if (@focus_index += 1) >= @options.length then @focus_index = 0 else @focus_index]
162
+ when 13 then @select_focused()
163
+ else
164
+ if isNumber
165
+ char = numbers[new String(keyCode - 48)]
166
+ else if isLetter
167
+ char = letters[keyCode - 65]
168
+
169
+ if char && @options_by_first_char[char]
170
+ @toggle() unless @open
171
+ @options_by_first_char[char].sort() unless @last_char is char
172
+ option = @options_by_first_char[char].shift()
173
+ @options_by_first_char[char].push option
174
+ @set_focused option
175
+ @focus_index = @options.indexOf option
176
+ @last_char = char
177
+
178
+ e.preventDefault()
179
+ e.stopPropagation()
180
+ e.returnValue = false
181
+
145
182
  set_focused: (option) ->
146
183
  class_for_selected = (option) => if @selected_option && option.innerHTML is @selected_option.innerHTML then " selected" else ""
147
184
  @focused_option.setAttribute('class', "option#{class_for_selected(@focused_option)}") if @focused_option
148
185
  @focused_option = option
149
186
  @focused_option.setAttribute("class", "option focus#{class_for_selected(option)}")
150
187
  @focus_index = @options.indexOf @focused_option
188
+ @focused_option.scrollIntoView()
189
+
151
190
  open: false
191
+
152
192
  toggle: ->
153
193
  (if @open = !@open then addClass else removeClass)(@select, 'open')
194
+ if @settings.resizeDropdown
195
+ @dropdown.style.width = @select.offsetWidth + 'px'
154
196
  if @settings.positionDropdown
155
197
  if @dropdown.offsetHeight > window.innerHeight
156
198
  height = window.innerHeight * .50
@@ -163,7 +205,10 @@ class BetterSelect
163
205
  top = getTop(@select) - (@dropdown_selected_option.offsetTop - @dropdown.scrollTop)
164
206
  @dropdown.style.top = (if top < 0 then 0 else top) + 'px'
165
207
  @dropdown.style.left = if @open then getLeft(@select) + 'px' else '-9999px'
208
+ _(@options_by_first_char).each (options) -> options.sort()
209
+
166
210
  reset: (option) -> @default_selected[0].better_version.select() if @default_selected
211
+
167
212
  set_selected: (option) ->
168
213
  unless @selected_option.innerHTML == option.innerHTML
169
214
  removeClass(@dropdown_selected_option, 'selected') if @dropdown_selected_option
@@ -172,12 +217,13 @@ class BetterSelect
172
217
  e = document.createEvent('Event')
173
218
  e.initEvent 'change', true, true
174
219
  @select.orig.dispatchEvent e
220
+ @selected_option.focus()
221
+
175
222
  option_template: '<div class="option"><%= innerHTML %></div>'
176
223
  option_group_template: '<div class="optgroup"><div class="option-group-label"><%= label %></div></div>'
177
- select_template: '<div class="select"><a href="javascript:void(0)" class="selected-option"></a><div class="better-select-dropdown dropdown"></div></div>'
224
+ select_template: '<div class="select better-select"><a href="javascript:void(0)" class="selected-option"></a><div class="better-select-dropdown dropdown"></div></div>'
178
225
  process_option: (option) -> option
179
226
  process_option_group: (option_group) -> option_group
180
227
  process_select: (select) -> select
181
228
 
182
-
183
229
  window.BetterSelect = BetterSelect