better_select 0.0.2 → 0.0.3

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.
@@ -8,10 +8,10 @@ Gem::Specification.new do |gem|
8
8
  gem.summary = "A better HTMLSelectElement replacement, for Rails"
9
9
  gem.homepage = "http://www.benjaminbergstein.com"
10
10
 
11
- gem.files = `git ls-files`.split($\) + ['vendor/javascripts', 'vendor/stylesheets']
12
11
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
12
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
13
  gem.name = "better_select"
15
14
  gem.require_paths = ["lib", "vendor"]
15
+ gem.files = `git ls-files`.split($\) + ['vendor/javascripts/better-select.js.coffee', 'vendor/stylesheets/better-select.css.scss']
16
16
  gem.version = BetterSelect::VERSION
17
17
  end
@@ -1,3 +1,3 @@
1
1
  module BetterSelect
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -0,0 +1,185 @@
1
+ $$ = (html) ->
2
+ elm = document.createElement 'div'
3
+ elm.innerHTML = html
4
+ if elm.children.length > 1 then elm.children else elm.children[0]
5
+
6
+ getPos = (tgt, method) ->
7
+ pos = 0
8
+ while tgt
9
+ pos += tgt[method]
10
+ tgt = tgt.offsetParent
11
+ pos
12
+
13
+ getTop = (tgt) -> getPos tgt, 'offsetTop'
14
+ getLeft = (tgt) -> getPos tgt, 'offsetLeft'
15
+
16
+ getClasses = (tgt) -> tgt.getAttribute('class').split ' '
17
+
18
+ setClasses = (tgt, classes) ->
19
+ tgt.setAttribute 'class', classes.join ' '
20
+ tgt
21
+
22
+ addClass = (tgt, className) ->
23
+ classes = getClasses tgt
24
+ classes.push(className) if classes.indexOf(className) is -1
25
+ setClasses tgt, classes
26
+
27
+ removeClass = (tgt, className) ->
28
+ classes.splice(index, 1) unless index = (classes = getClasses tgt).indexOf className is -1
29
+ setClasses tgt, classes
30
+
31
+ 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 ' '
32
+ numbers = '0 1 2 3 4 5 6 7 8 9 0'.split ' '
33
+
34
+ build_element = (what, orig, obj) ->
35
+ elm = $$ _.template(obj["#{what}_template"]) obj["process_#{what}"] orig
36
+ elm.orig = orig
37
+ orig.better_version = elm
38
+ elm.better_select = obj
39
+ elm
40
+
41
+ renderOption = (orig_option, bs) ->
42
+ option = build_element 'option', orig_option, bs
43
+ option.reset = ->
44
+ @orig.selected = undefined
45
+ @setAttribute 'class', 'option'
46
+ bs.reset @
47
+ option.select = ->
48
+ @orig.selected = 'selected'
49
+ @setAttribute 'class', 'option selected'
50
+ bs.toggle() if bs.select.getAttribute('class').indexOf('open') isnt -1
51
+ bs.set_selected option
52
+ option.addEventListener 'click', -> option.select()
53
+ option.addEventListener 'mouseover', -> option.better_select.set_focused option
54
+ bs.options.push option
55
+ first_char = option.innerHTML.substr(0, 1).toLowerCase()
56
+ bs.options_by_first_char[first_char] = [] unless bs.options_by_first_char[first_char]
57
+ bs.options_by_first_char[first_char].push option
58
+ bs.options_by_first_char[first_char].sort()
59
+ option
60
+
61
+ renderOptionGroup = (orig_group, bs) ->
62
+ group = build_element 'option_group', orig_group, bs
63
+ group.appendChild(renderOption child, bs) for child in orig_group.children
64
+ bs.option_groups.push group
65
+ group
66
+
67
+ class BetterSelect
68
+ defaults:
69
+ positionDropdown: true
70
+ constructor: (elm, options) ->
71
+ return unless elm && elm.tagName && elm.tagName is 'SELECT'
72
+ @settings = _.extend {}, @defaults, options
73
+ @options = []
74
+ @options_by_first_char = {}
75
+ @option_groups = []
76
+ selected = elm.selectedOptions
77
+ @select = build_element 'select', elm, @
78
+ [@selected_option, @dropdown] = @select.children
79
+ if elm.id
80
+ @select.id = "#{elm.id}-better-select"
81
+ @dropdown.id = "#{elm.id}-better-select-dropdown"
82
+ @default_selected = [elm.children[elm.selectedIndex]]
83
+ elm.parentNode.insertBefore @select, elm
84
+ elm.parentNode.insertBefore elm, @select
85
+ elm.style.display = 'none'
86
+ children = elm.children
87
+ if @settings.positionDropdown
88
+ document.body.appendChild @dropdown
89
+ @dropdown.style.left = '-9999px'
90
+ for child in children
91
+ switch child.tagName
92
+ when 'OPTION'
93
+ method = renderOption
94
+ when 'OPTGROUP'
95
+ method = renderOptionGroup
96
+ @dropdown.appendChild(method child, @)
97
+ @default_selected[0].better_version.select() if @default_selected
98
+ @selected_option.addEventListener 'click', =>
99
+ @toggle()
100
+ @set_selected @dropdown_selected_option
101
+ window.addEventListener 'click', (e) =>
102
+ unless e.target == @selected_option || e.target == @select || @options.indexOf(e.target) isnt -1
103
+ @toggle() if @open
104
+ last_char = false
105
+ @selected_option.addEventListener 'focus', =>
106
+ document.body.style.overflow = 'hidden'
107
+ addClass @select, 'focus'
108
+ @selected_option.addEventListener 'blur', =>
109
+ removeClass @select, 'focus'
110
+ document.body.style.overflow = 'auto'
111
+ @toggle() if @open is true
112
+ true
113
+ @selected_option.addEventListener 'keydown', (e) => e.preventDefault() unless [38, 40].indexOf(e.keyCode) is -1
114
+ @selected_option.addEventListener 'keyup', (e) =>
115
+ @toggle() if @open is false
116
+ keyCode = e.keyCode
117
+ switch keyCode
118
+ when 38 then @set_focused @options[if (@focus_index -= 1) < 0 then @focus_index = @options.length - 1 else @focus_index]
119
+ when 40 then @set_focused @options[if (@focus_index += 1) >= @options.length then @focus_index = 0 else @focus_index]
120
+ when 13
121
+ @focused_option.select()
122
+ else
123
+ if keyCode > 47 && keyCode < 58
124
+ char = numbers[keyCode - 47]
125
+ else if keyCode > 64 && keyCode < 91
126
+ char = letters[keyCode - 65]
127
+ else
128
+ if @focused_option
129
+ removeClass @focused_option, 'focus'
130
+ @focused_option = false
131
+ @focus_index = -1
132
+ @toggle()
133
+ if char && @options_by_first_char[char]
134
+ @options_by_first_char[char].sort() unless last_char is char
135
+ option = @options_by_first_char[char].shift()
136
+ @options_by_first_char[char].push option
137
+ @set_focused option
138
+ @focus_index = @options.indexOf option
139
+ last_character = char
140
+ @dropdown.addEventListener('click', -> console.log arguments)
141
+ e.preventDefault()
142
+ e.stopPropagation()
143
+ e.returnValue = false
144
+ false
145
+ focused_option: false
146
+ focus_index: -1
147
+ set_focused: (option) ->
148
+ class_for_selected = (option) => if @selected_option && option.innerHTML is @selected_option.innerHTML then " selected" else ""
149
+ @focused_option.setAttribute('class', "option#{class_for_selected(@focused_option)}") if @focused_option
150
+ @focused_option = option
151
+ @focused_option.setAttribute("class", "option focus#{class_for_selected(option)}")
152
+ @focus_index = @options.indexOf @focused_option
153
+ open: false
154
+ toggle: ->
155
+ (if @open = !@open then addClass else removeClass)(@select, 'open')
156
+ if @settings.positionDropdown
157
+ if @dropdown.offsetHeight > window.innerHeight
158
+ height = window.innerHeight * .50
159
+ @dropdown.style.height = height + 'px'
160
+ @dropdown.style['overflow-y'] = 'auto'
161
+ if @dropdown_selected_option.offsetTop > height || @adjust_height
162
+ @dropdown_selected_option.scrollIntoView()
163
+ @adjust_height = true
164
+ top = top || (getTop(@select) - @dropdown_selected_option.offsetTop)
165
+ top = getTop(@select) - (@dropdown_selected_option.offsetTop - @dropdown.scrollTop)
166
+ @dropdown.style.top = (if top < 0 then 0 else top) + 'px'
167
+ @dropdown.style.left = if @open then getLeft(@select) + 'px' else '-9999px'
168
+ reset: (option) -> @default_selected[0].better_version.select() if @default_selected
169
+ set_selected: (option) ->
170
+ unless @selected_option.innerHTML == option.innerHTML
171
+ removeClass(@dropdown_selected_option, 'selected') if @dropdown_selected_option
172
+ addClass @dropdown_selected_option = option, 'selected'
173
+ @selected_option.innerHTML = option.innerHTML
174
+ e = document.createEvent('Event')
175
+ e.initEvent 'change', true, true
176
+ @select.orig.dispatchEvent e
177
+ option_template: '<div class="option"><%= innerHTML %></div>'
178
+ option_group_template: '<div class="optgroup"><div class="option-group-label"><%= label %></div></div>'
179
+ select_template: '<div class="select"><a href="javascript:void(0)" class="selected-option"></a><div class="better-select-dropdown dropdown"></div></div>'
180
+ process_option: (option) -> option
181
+ process_option_group: (option_group) -> option_group
182
+ process_select: (select) -> select
183
+
184
+
185
+ window.BetterSelect = BetterSelect
@@ -0,0 +1,32 @@
1
+ .better-select-dropdown {
2
+ position: fixed;
3
+
4
+ .option {
5
+ cursor: pointer;
6
+ }
7
+ }
8
+
9
+ .select {
10
+ position: static;
11
+
12
+ &.dont-position-dropdown {
13
+ position: relative;
14
+
15
+ .dropdown {
16
+ top: 100%;
17
+ left: -99999px;
18
+ }
19
+ }
20
+
21
+ &.open {
22
+ &.dont-position-dropdown {
23
+ .dropdown {
24
+ left: 0px;
25
+ }
26
+ }
27
+ }
28
+
29
+ .selected-option {
30
+ cursor: pointer;
31
+ }
32
+ }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: better_select
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -28,6 +28,8 @@ files:
28
28
  - lib/better_select.rb
29
29
  - lib/better_select/engine.rb
30
30
  - lib/better_select/version.rb
31
+ - vendor/javascripts/better-select.js.coffee
32
+ - vendor/stylesheets/better-select.css.scss
31
33
  homepage: http://www.benjaminbergstein.com
32
34
  licenses: []
33
35
  post_install_message: