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.
- data/.gitmodules +9 -0
- data/README.md +13 -5
- data/better_select.gemspec +1 -0
- data/lib/better_select/version.rb +1 -1
- data/vendor/assets/javascripts/better-select.js +1 -0
- data/vendor/{LICENSE → assets/javascripts/better_select/LICENSE} +0 -0
- data/vendor/assets/javascripts/better_select/Makefile +4 -0
- data/vendor/assets/javascripts/better_select/README.md +68 -0
- data/vendor/assets/{build → javascripts/better_select/build}/better-select.css +0 -0
- data/vendor/assets/{build → javascripts/better_select/build}/better-select.js +98 -65
- data/vendor/assets/{lib → javascripts/better_select/lib}/better-select.coffee +88 -42
- data/vendor/assets/{lib → javascripts/better_select/lib}/better-select.css.scss +0 -0
- data/vendor/assets/stylesheets/better-select.css.scss +1 -31
- metadata +26 -20
- data/vendor/Makefile +0 -8
- data/vendor/README.md +0 -29
- data/vendor/assets/LICENSE +0 -22
- data/vendor/assets/Makefile +0 -8
- data/vendor/assets/README.md +0 -29
- data/vendor/assets/better_select.gemspec +0 -17
- data/vendor/assets/javascripts/better-select.js.coffee +0 -185
- data/vendor/build/better-select.css +0 -16
- data/vendor/build/better-select.js +0 -330
- data/vendor/javascripts/better-select.js.coffee +0 -185
- data/vendor/lib/better-select.coffee +0 -183
- data/vendor/lib/better-select.css.scss +0 -32
- data/vendor/stylesheets/better-select.css.scss +0 -32
data/.gitmodules
CHANGED
@@ -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
|
-
|
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
|
-
|
19
|
+
Add to application.js:
|
16
20
|
|
17
|
-
|
21
|
+
//= require 'better-select'
|
22
|
+
|
23
|
+
Add to any stylesheet:
|
24
|
+
|
25
|
+
@import 'better-select';
|
18
26
|
|
19
27
|
## Usage
|
20
28
|
|
21
|
-
|
29
|
+
See https://github.com/benastan/better_select for detailed usage.
|
22
30
|
|
23
31
|
## Contributing
|
24
32
|
|
data/better_select.gemspec
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
//=require better_select/lib/better-select
|
File without changes
|
@@ -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
|
File without changes
|
@@ -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 (
|
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
|
-
|
85
|
-
|
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,
|
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.
|
165
|
-
|
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('
|
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('
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
112
|
-
@selected_option.addEventListener 'keyup', (e) =>
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
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
|