uber_select_rails 0.5.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 55d7f2ac671dfba382d9ce1d1bd226fcac0b92d3c7473e720f1c200a398234e3
4
- data.tar.gz: ff3372fdb170c871823be80159c2c654d2982a8354e76442e16ec9337c250160
3
+ metadata.gz: bf09e09761faba19203a94b5cc53f7d59aaaf114dde0cef6b4624ba5d1b4a916
4
+ data.tar.gz: 6a22b0a860276671c3c10253165e3f06d0735ea383865e077ca3ed2ee81dc286
5
5
  SHA512:
6
- metadata.gz: 95851208aa9e978b3c544b818d27865d1015df4b62ccdc9c83aa35874f7bbd539c23dac85441aa2f9703ff7c741fb9e61d916900a619a5cd4de19ddddbf33485
7
- data.tar.gz: f4d6512cb2e83c586eb5d462292d47490bf76d3526dcdef559c49a0df5839d2f0748984208bb3581aecafc985e77560cf63c57b8410b55d33cfc1003df02d6c2
6
+ metadata.gz: 9adcece32e2b8db8049459f8daeac77c25e8f796295b0215297772a34e1b8faf70dd11e7676cdfb3e98d5f25d8ae9ec3ef572325471ec38418e38e7c65c1fa46
7
+ data.tar.gz: 53d97f64a172512b486aeff0094fa4d6493f45b662e4aebef91712535debf63386a1a410f9949daf3a6227a1ad0e8deeac347839da1ac5ee697bc4f9cbbbf9ab
@@ -1,3 +1,3 @@
1
1
  module UberSelectRails
2
- VERSION = "0.5.0"
2
+ VERSION = "0.6.1"
3
3
  end
@@ -3,13 +3,16 @@
3
3
  UberSelect is a fancy UI on top of a regular `<select>` element.
4
4
 
5
5
  ## Requirements
6
+
6
7
  Tested on jQuery 1.11.x to 3.3.x
7
8
 
8
9
  ## Parts
10
+
9
11
  UberSelect is composed of two main parts, an UberSearch that does all the of searching and UI, and an UberSelect which
10
12
  is used to connect an UberSearch to a `<select>` element.
11
13
 
12
14
  ### UberSelect
15
+
13
16
  This is the object that allows an UberSearch and a `<select>` element to work together. The select element can be used
14
17
  to control the state of the UberSearch, and vice-versa. This means you can programmatically change the state of the
15
18
  select, and UberSearch will update. Users can interact with the UberSearch, and the select will update. This also means
@@ -22,38 +25,61 @@ $('.my_selects').uberSelect(options);
22
25
  ```
23
26
 
24
27
  #### Attributes <a name="UberSearch attributes"></a>
28
+
25
29
  Attribtes on the outermost element can be specified by setting the `data-uber-attributes` attribute on the `<select>` element. Values should be passed
26
30
  as a JSON string of key/value pairs where the key is the attribute name and the value is the attribute value.
27
31
 
28
32
  #### Options
33
+
29
34
  Options can be specified by setting the `data-uber-options` attribute on the `<select>` element. Values should be passed
30
35
  as a JSON string. All options on the are passed to the underlying UberSearch, see [UberSearch options](#UberSearchOptions).
31
36
 
32
37
  - ##### prepopulateSearchOnOpen
38
+
33
39
  Determines whether the search input starts with the selected value in it when the pane is opened.
34
40
 
35
41
  Default: `false`
36
42
 
37
43
  - ##### clearSearchClearsSelect
44
+
38
45
  Determines whether the select value should be cleared when the search is cleared.
39
46
 
40
47
  Default: `false`
41
48
 
42
49
  - ##### placeholder
50
+
43
51
  Placeholder to show in the selected text area.
44
52
 
45
53
  Default: `<select>` element attributes `<select placeholder="my placeholder" data-placeholder="my placeholder">`
46
54
 
47
- - ##### dataUrl
55
+ - ##### dataUrl <a name="dataUrl"></a>
56
+
48
57
  A url to pre-fetch select options from. JSON response should be of the form
49
58
  `[{text:'option with explicit value', value: 'some value'}, {text:'option with implicit value'}]`. For a custom JSON response, use in conjunction with optionFromDatum.
50
59
 
51
60
  Default: `null`
52
61
 
62
+ - ##### dataFormatter
63
+
64
+ A function that can modify the data from the dataUrl before it is used.
65
+
66
+ The function signature is as follows:
67
+
68
+ ```js
69
+ function(data) {
70
+ // Modify the data
71
+
72
+ return modifiedData
73
+ }
74
+ ```
75
+ See <a href="#dataUrl">dataUrl</a> for details about the expected format of `data`.
76
+
53
77
  - ##### optionFromDatum
78
+
54
79
  A function that is used to customize the options value and text built from a JSON response. `datum` is a single result returned from the JSON response.
55
80
 
56
81
  The function signature is as follows:
82
+
57
83
  ```js
58
84
  function(datum) {
59
85
  return // a <option> element to represent the select
@@ -63,25 +89,36 @@ as a JSON string. All options on the are passed to the underlying UberSearch, se
63
89
  Default: `datum.value` populates the `<option>` value, `datum.text` populates the `<option>` text.
64
90
 
65
91
  - ##### value
92
+
66
93
  Initialize the UberSearch with this selected value
67
94
 
68
95
  Default: `<select>` element `value` property
69
96
 
97
+ - ##### ariaLabel
98
+
99
+ Add an aria-label attribute with this value to the uber_select element.
100
+
70
101
  #### Events Triggered
102
+
71
103
  - ##### uber-select:ready
104
+
72
105
  This fires when the UberSelect has initialized and is ready for user interaction
73
106
 
74
107
  #### Events Observed
108
+
75
109
  The `<select>` element observes the following events:
76
110
 
77
111
  - ##### uber-select:refreshOptions
112
+
78
113
  The UberSearch options list will be updated to match the `<select>` element's `<option>` list.
79
114
 
80
115
  - ##### uber-select:refresh
116
+
81
117
  The UberSearch will update its selected value to match the `<select>` element's. This handler also runs when the
82
118
  `<select>` element triggers a `change` event.
83
119
 
84
120
  ### UberSearch
121
+
85
122
  The UberSearch performs all of the heavy lifting. It creates the UI views, maintains state, and performs the searching.
86
123
  It can be instantiated without the use of an UberSelect, which can be useful for situations where the selected value is
87
124
  being used in purely in JS, and not being linked to a `<select>` element in a form.
@@ -93,117 +130,152 @@ new UberSearch(data, options);
93
130
  ```
94
131
 
95
132
  #### Data
133
+
96
134
  Data is an array of objects. Each object may have the following properties:
97
135
 
98
136
  - ##### text
137
+
99
138
  String shown to the user in the list of results. This value is required if *value* is not provided.
100
139
 
101
140
  - ##### selectedText
141
+
102
142
  String shown to the user in the output container when this option is selected. *optional*
103
143
 
104
144
  - ##### title
145
+
105
146
  Title text shown to the user when hovering over the result. *optional*
106
147
 
107
148
  - ##### value
149
+
108
150
  This is matched against the *value* option passed UberSearch and will appear selected if it matches. It is also used to match against search input text when the user searches. This value is required if *text* is not provided.
109
151
 
110
152
  - ##### matchValue
153
+
111
154
  This overrides the value used to match against search input text when the user searches. *optional*
112
155
 
113
156
  - ##### visibility
157
+
114
158
  This is used to determine whether the option appears only when searching or only when not searching. Values accepted: `query`, `no-query`. *optional*
115
159
 
116
160
  - ##### disabled
161
+
117
162
  This is used to determine whether the option appears disabled. *optional*
118
163
 
119
164
  - ##### group
165
+
120
166
  This is used to visually group options. All options with the same group will appear together. *optional*
121
167
 
122
168
  #### Methods
123
169
 
124
170
  - ##### setData(data)
171
+
125
172
  Sets the data. `data` should be an Array conforming to the specifications described in <a href="#data">Data</a>
126
173
 
174
+ - ##### getValue()
175
+
176
+ Returns the currently selected value.
177
+
178
+ - ##### getSelection()
179
+
180
+ Returns the currently selected element from the search results.
181
+
127
182
 
128
183
  #### Options <a name="UberSearch options"></a>
184
+
129
185
  Options can be specified by setting the `data-uber-options` attribute on the `<select>` element. Values should be passed
130
186
  as a JSON string.
131
187
 
132
188
  - ##### value
189
+
133
190
  Sets the initially selected value of the UberSearch. This value should match the `value` property of the desired
134
191
  option data.
135
192
 
136
193
  Default: `null`
137
194
 
138
195
  - ##### search
196
+
139
197
  Determines whether the search input be shown.
140
198
 
141
199
  Default: `true`
142
200
 
143
201
  - ##### clearSearchButton
202
+
144
203
  Sets the text content of clear search button.
145
204
 
146
205
  Default: `✕`
147
206
 
148
207
  - ##### selectCaret
208
+
149
209
  Sets the text content of clear select caret.
150
210
 
151
211
  Default: `⌄`
152
212
 
153
213
  - ##### hideBlankOption
214
+
154
215
  Sets whether blank options should be hidden automatically.
155
216
 
156
217
  Default: `false`
157
218
 
158
219
  - ##### treatBlankOptionAsPlaceholder
220
+
159
221
  Determines whether the `text` property of an option with a blank `value` property should be used as the placeholder
160
222
  text if no placeholder is specified.
161
223
 
162
224
  Default: `false`
163
225
 
164
226
  - ##### highlightByDefault
227
+
165
228
  Determines whether the first search result be auto-highlighted.
166
229
 
167
230
  Default: `true`
168
231
 
169
232
  - ##### minQueryLength
233
+
170
234
  Sets minimum number of characters the user must type before a search will be performed.
171
235
 
172
236
  Default: `0`
173
237
 
174
238
  - ##### minQueryMessage
239
+
175
240
  Sets the message shown to the user when the query doesn't exceed the minimum length. `true` for a default message,
176
241
  `false` for none, or provide a string to set a custom message.
177
242
 
178
243
  Default: `true`
179
244
 
180
245
  - ##### placeholder
246
+
181
247
  Sets the placeholder shown in the selected text area.
182
248
 
183
249
  Default: `null`
184
250
 
185
251
  - ##### searchPlaceholder
252
+
186
253
  Sets the placeholder shown in the search input.
187
254
 
188
255
  Default: `'Type to search'`
189
256
 
190
257
  - ##### noResultsText
258
+
191
259
  Sets the message shown when there are no results.
192
260
 
193
261
  Default: `'No Matches Found'`
194
262
 
195
263
  - ##### noDataText
264
+
196
265
  Sets the text to show when the results list is empty and no search is in progress
197
266
 
198
267
  Default: `'No options'`
199
-
268
+
200
269
  - ##### searchInputAttributes
270
+
201
271
  An Object containing attributes to add to the search input element.
202
272
 
203
273
  - ##### buildResult
274
+
204
275
  A function that is used to build result elements.
205
276
 
206
277
  The function signature is as follows:
278
+
207
279
  ```js
208
280
  function(listOptionData) {
209
281
  return // HTML/element to insert into the the results list
@@ -211,10 +283,12 @@ as a JSON string.
211
283
  ```
212
284
 
213
285
  - ##### resultPostprocessor
286
+
214
287
  A function that is run after a result is built and can be used to decorate it. This can be useful when extending the
215
288
  functionality of an existing UberSearch implementation.
216
289
 
217
290
  The function signature is as follows:
291
+
218
292
  ```js
219
293
  function(resultsListElement, listOptionData) { }
220
294
  ```
@@ -222,50 +296,63 @@ as a JSON string.
222
296
  Default: No-op
223
297
 
224
298
  - ##### onRender
299
+
225
300
  A function to run when the results container is rendered. If the result returns false, the default `select` event
226
301
  handler is not run and the event is cancelled.
227
302
 
228
303
  The function signature is as follows:
304
+
229
305
  ```js
230
306
  function(resultsContainer, searchResultsHTML) { }
231
307
  ```
232
308
 
233
309
  - ##### onSelect
310
+
234
311
  A function to run when a result is selected. If the result returns false, the default `select` event handler is not
235
312
  run and the event is cancelled.
236
313
 
237
314
  The function signature is as follows:
315
+
238
316
  ```js
239
317
  function(listOptionData, resultsListElement, clickEvent) { }
240
318
  ```
241
319
 
242
320
  - ##### onNoHighlightSubmit
321
+
243
322
  A function to run when a user presses enter without selecting a result.
244
323
  Should be used in combination with `highlightByDefault: false`.
245
324
 
246
325
  The function signature is as follows:
326
+
247
327
  ```js
248
328
  function(value) { }
249
329
  ```
250
330
 
251
331
  - ##### outputContainer (Deprecated)
332
+
252
333
  An object that receives the output once a result is selected. Must respond to `setValue(value)` and `view()`. This object serves to
253
334
  attach the result list to the DOM at the desired location.
254
335
 
255
336
  #### Events Triggered
337
+
256
338
  - ##### shown
339
+
257
340
  This fires when the UberSearch pane is opened.
258
341
 
259
342
  - ##### renderedResults
343
+
260
344
  This fires each time the list of results is updated.
261
345
 
262
346
  - ##### clear
347
+
263
348
  This fires when the user clicks the clear search button.
264
349
 
265
350
  - ##### select
351
+
266
352
  This fires when the user selects a result.
267
353
 
268
354
  The handler function signature is as follows:
355
+
269
356
  ```js
270
357
  function(event, [listOptionData, resultsContainer, originalEvent]) { }
271
358
  ```
@@ -17,6 +17,7 @@
17
17
  disabled: $(select).is(':disabled'), // Whether the select is currently disabled
18
18
  placeholder: $(select).attr('placeholder') || $(select).attr('data-placeholder'), // Placeholder to show in the selected text area
19
19
  dataUrl: null, // A url to pre-fetch select options from, see optionsFromData for data format
20
+ dataFormatter: function(data) { return data }, // A function to manipulate data received from the dataUrl before it is used. The function should return an array of data with desired modifications.
20
21
  optionFromDatum: optionFromDatum, // A function to create select options
21
22
  value: $(select).val() // Initialize the UberSearch with this selected value
22
23
  }, opts, $(select).data('uber-options'))
@@ -61,6 +62,7 @@
61
62
  hideSelect()
62
63
  if (options.dataUrl) {
63
64
  $.getJSON(options.dataUrl).done(function(data){
65
+ data = options.dataFormatter(data)
64
66
  $(select).append(optionsFromData(data))
65
67
  updateSelectValue(options.value)
66
68
  uberSearch.setData(dataFromSelect(select))
@@ -134,7 +136,11 @@
134
136
 
135
137
  // Copies the value of the select into the search input
136
138
  function updateSearchValueFromSelect(){
137
- uberSearch.searchField.input.val($(select).find('option:selected').text())
139
+ var index = select.selectedIndex
140
+
141
+ if (index == undefined) { return }
142
+
143
+ uberSearch.searchField.input.val($(select).find('option').eq(index).text())
138
144
  uberSearch.searchField.refresh()
139
145
  }
140
146
 
@@ -7,7 +7,7 @@ function List(options) {
7
7
  // BEHAVIOUR
8
8
 
9
9
  // Handle up and down arrow key presses
10
- $(options.keypressInput).on('keydown', function(event){
10
+ $(options.keypressInput || view).on('keydown', function(event){
11
11
  switch (event.which) {
12
12
  case 38: // Up Arrow
13
13
  stepHighlight(-1, true)
@@ -50,7 +50,7 @@ function List(options) {
50
50
 
51
51
  // Can be overridden to format how results are built
52
52
  this.buildResult = function(datum){
53
- return $('<li></li>').html(datum).addClass('result')
53
+ return $('<li role="option" class="result" tabindex="0"></li>').html(datum)
54
54
  }
55
55
 
56
56
  this.unhighlightResults = unhighlightResults
@@ -73,6 +73,7 @@ function List(options) {
73
73
  if (!result.length) { return }
74
74
 
75
75
  result.addClass('highlighted')
76
+ result.attr("aria-selected", true)
76
77
 
77
78
  if (options.scroll){
78
79
  scrollResultIntoView(result)
@@ -80,7 +81,7 @@ function List(options) {
80
81
  }
81
82
 
82
83
  function unhighlightResults(){
83
- highlightedResult().removeClass('highlighted')
84
+ highlightedResult().removeClass('highlighted').attr("aria-selected", false)
84
85
  }
85
86
 
86
87
  function highlightedResult(){
@@ -1,6 +1,6 @@
1
1
  var OutputContainer = function(options){
2
2
  options = $.extend({}, options)
3
- var view = $('<span class="selected_text_container" tabindex=0 role="button"></span>')
3
+ var view = $('<span class="selected_text_container" tabindex="0"></span>')
4
4
  var selectedText = $('<span class="selected_text"></span>').appendTo(view)
5
5
  var selectCaret = $('<span class="select_caret"></span>').appendTo(view).html(options.selectCaret)
6
6
 
@@ -1,48 +1,33 @@
1
- function Pane(options){
2
- options = $.extend({
3
- trigger: null
4
- }, options)
5
-
6
- var context = this
7
- var model = this.model = {}
8
- var isOpen = false
9
- var view = this.view = $('<div class="pane"></div>').toggle(isOpen)
1
+ function Pane(){
2
+ var eventsTriggered = {
3
+ shown: 'shown.UberSelect',
4
+ hidden: 'hidden.UberSelect'
5
+ }
6
+
7
+ var context = this
8
+ var model = {}
9
+ var isOpen = false
10
+ var view = $('<div class="pane"></div>').toggle(isOpen)
10
11
  var innerPane = $('<div class="pane_inner"></div>').appendTo(view)
11
12
 
12
13
 
13
14
  // PUBLIC INTERFACE
14
15
 
15
- $.extend(this, {view: view, addContent: addContent, removeContent: removeContent, show: show, hide: hide})
16
+ $.extend(this, {
17
+ model: model,
18
+ view: view,
19
+ addContent: addContent,
20
+ removeContent: removeContent,
21
+ show: show,
22
+ hide: hide,
23
+ toggle: toggle,
24
+ isOpen: paneIsOpen,
25
+ isClosed: paneIsClosed
26
+ })
16
27
 
17
28
 
18
29
  // BEHAVIOUR
19
30
 
20
- if (options.trigger){
21
- // Show the pane when the select element is clicked
22
- $(options.trigger).on('click', function(event){
23
- if ($(options.trigger).hasClass('disabled')) { return }
24
-
25
- context.show()
26
- })
27
-
28
- // Show the pane if the user was tabbed onto the trigger and pressed enter or space
29
- $(options.trigger).on('keyup', function(event){
30
- if ($(options.trigger).hasClass('disabled')) { return }
31
-
32
- if (event.which == 13 || event.which == 32){
33
- context.show()
34
- return false
35
- }
36
- })
37
- }
38
-
39
- // Hide the pane when clicked out
40
- $(document).on('mousedown', function(event){
41
- if (isEventOutsidePane(event) && isEventOutsideTrigger(event)){
42
- context.hide()
43
- }
44
- })
45
-
46
31
  // Make it possible to have elements in the pane that close it
47
32
  view.on('click', '[data-behaviour~=close-pane]', function(event){
48
33
  context.hide()
@@ -52,13 +37,21 @@ function Pane(options){
52
37
  $(document).on('keyup', function(event){
53
38
  if (event.which == 27 && isOpen){
54
39
  context.hide()
55
- options.trigger.focus()
40
+ return false
56
41
  }
57
42
  })
58
43
 
59
44
 
60
45
  // HELPER FUNCTIONS
61
46
 
47
+ function paneIsOpen(){
48
+ return isOpen
49
+ }
50
+
51
+ function paneIsClosed(){
52
+ return !isOpen
53
+ }
54
+
62
55
  function addContent(name, content){
63
56
  model[name] = content
64
57
  innerPane.append(content)
@@ -73,22 +66,24 @@ function Pane(options){
73
66
  if (isOpen) { return }
74
67
  isOpen = true
75
68
  view.show()
76
- $(context).trigger('shown')
69
+ triggerEvent(eventsTriggered.shown)
77
70
  }
78
71
  function hide(){
79
72
  if (!isOpen) { return }
80
73
  isOpen = false
81
74
  view.hide()
82
- $(context).trigger('hidden')
75
+ triggerEvent(eventsTriggered.hidden)
83
76
  }
84
-
85
- // returns true if the event originated outside the pane
86
- function isEventOutsidePane(event){
87
- return !$(event.target).closest(view).length
77
+ function toggle(){
78
+ if (isOpen) {
79
+ context.hide()
80
+ } else {
81
+ context.show()
82
+ }
88
83
  }
89
84
 
90
- function isEventOutsideTrigger(event){
91
- return !$(event.target).closest(options.trigger).length
85
+ function triggerEvent(eventType, callbackArgs){
86
+ view.trigger(eventType, callbackArgs)
87
+ $(context).trigger(eventType, callbackArgs)
92
88
  }
93
-
94
89
  }
@@ -7,6 +7,7 @@ var UberSearch = function(data, options){
7
7
  }
8
8
 
9
9
  options = $.extend({
10
+ ariaLabel: null,
10
11
  value: null, // Initialize with this selectedValue
11
12
  disabled: false, // Initialize with this disabled value
12
13
  search: true, // Show the search input
@@ -30,14 +31,22 @@ var UberSearch = function(data, options){
30
31
  }, options)
31
32
 
32
33
  var context = this
33
- var view = $('<span class="uber_select"></span>')
34
+ var view = $('<span class="uber_select" role="listbox"></span>')
34
35
  var selectedValue = options.value // Internally selected value
35
36
  var outputContainer = options.outputContainer || new OutputContainer({selectCaret: options.selectCaret})
36
- var searchField = new SearchField({placeholder: options.searchPlaceholder, clearButton: options.clearSearchButton})
37
37
  var resultsContainer = $('<div class="results_container"></div>')
38
38
  var messages = $('<div class="messages"></div>')
39
- var pane = new Pane({trigger: outputContainer.view})
40
- var search = new Search(searchField.input, resultsContainer, {
39
+ var pane = new Pane()
40
+
41
+ if (options.ariaLabel) { view.attr("aria-label", options.ariaLabel) }
42
+
43
+ var searchField = new SearchField({
44
+ placeholder: options.searchPlaceholder,
45
+ clearButton: options.clearSearchButton,
46
+ searchInputAttributes: options.searchInputAttributes
47
+ })
48
+
49
+ var search = new Search(searchField.input, resultsContainer, {
41
50
  model: {
42
51
  dataForMatching: dataForMatching,
43
52
  minQueryLength: options.minQueryLength,
@@ -48,23 +57,63 @@ var UberSearch = function(data, options){
48
57
  view: {
49
58
  renderResults: renderResults,
50
59
  buildResult: options.buildResult || buildResult,
51
- keypressInput: searchField.input
60
+ keypressInput: options.search ? searchField.input : null
52
61
  }
53
62
  })
54
63
 
55
64
 
56
65
  // BEHAVIOUR
57
66
 
67
+ // Show the pane when the select element is clicked
68
+ $(outputContainer.view).on('click', function(event){
69
+ if (outputContainer.view.hasClass('disabled')) { return }
70
+
71
+ pane.show()
72
+ })
73
+
74
+ // Hide the pane when clicked out or another pane is opened
75
+ $(document).on('click shown.UberSelect', function(event){
76
+ if (isEventOutsidePane(event) && isEventOutsideOutputContainer(event)){
77
+ pane.hide()
78
+ }
79
+ })
80
+
81
+ // Show the pane if the user was tabbed onto the trigger and pressed enter, space, or down arrow
82
+ $(outputContainer.view).on('keyup', function(event){
83
+ if (outputContainer.view.hasClass('disabled')) { return }
84
+
85
+ if (event.which === 32 || event.which === 40 && pane.isClosed()){
86
+ pane.show()
87
+ return false
88
+ }
89
+ else if (event.which === 13){ // toggle pane when enter is pressed
90
+ pane.toggle()
91
+ return false
92
+ }
93
+ })
94
+
58
95
  // When the pane is opened
59
96
  $(pane).on('shown', function(){
60
97
  search.clear()
61
98
  markSelected()
62
- $(searchField.input).focus()
63
99
  view.addClass('open')
64
100
 
101
+ if (options.search) {
102
+ $(searchField.input).focus()
103
+ } else {
104
+ pane.view.find("ul.results li:first").focus()
105
+ }
106
+
65
107
  triggerEvent(eventsTriggered.shown)
66
108
  })
67
109
 
110
+
111
+ // When the pane is hidden
112
+ $(pane).on('hidden', function(){
113
+ view.removeClass('open')
114
+ view.focus()
115
+ })
116
+
68
117
  // When the query is changed
69
118
  $(search).on('queryChanged', function(){
70
119
  updateMessages()
@@ -96,6 +145,8 @@ var UberSearch = function(data, options){
96
145
  return
97
146
  }
98
147
 
148
+ event.stopPropagation();
149
+
99
150
  setValue(valueFromResult(this))
100
151
  pane.hide()
101
152
  triggerEvent(eventsTriggered.select, [datum, this, event])
@@ -106,20 +157,13 @@ var UberSearch = function(data, options){
106
157
  options.onNoHighlightSubmit($(this).val())
107
158
  })
108
159
 
109
- // When the pane is hidden
110
- $(pane).on('hidden', function(){
111
- view.removeClass('open')
112
- })
113
-
114
160
 
115
161
  // INITIALIZATION
116
162
 
117
163
  setDisabled(options.disabled)
118
164
  setData(data)
119
165
 
120
- if (options.search){
121
- pane.addContent('search', searchField.view)
122
- }
166
+ if (options.search) { pane.addContent('search', searchField.view) }
123
167
  pane.addContent('messages', messages)
124
168
  pane.addContent('results', resultsContainer)
125
169
 
@@ -152,6 +196,11 @@ var UberSearch = function(data, options){
152
196
  markSelected()
153
197
  }
154
198
 
199
+ // Returns the selected value
200
+ function getValue(){
201
+ return selectedValue
202
+ }
203
+
155
204
  // Enables or disables UberSearch
156
205
  function setDisabled(boolean){
157
206
  outputContainer.setDisabled(boolean)
@@ -239,7 +288,7 @@ var UberSearch = function(data, options){
239
288
  }
240
289
 
241
290
  function buildResult(datum){
242
- var result = $('<li class="result"></li>')
291
+ var result = $('<li class="result" tabindex="0"></li>')
243
292
  .html((options.treatBlankOptionAsPlaceholder ? datum.text || options.placeholder : datum.text) || "&nbsp;")
244
293
  .data(datum) // Store the datum so we can get know what the value of the selected item is
245
294
 
@@ -317,6 +366,15 @@ var UberSearch = function(data, options){
317
366
  return search.getResults().length
318
367
  }
319
368
 
369
+ // returns true if the event originated outside the pane
370
+ function isEventOutsidePane(event){
371
+ return !$(event.target).closest(pane.view).length
372
+ }
373
+
374
+ function isEventOutsideOutputContainer(event){
375
+ return !$(event.target).closest(outputContainer.view).length
376
+ }
377
+
320
378
  // Allow observer to be attached to the UberSearch itself
321
379
  function triggerEvent(eventType, callbackArgs){
322
380
  view.trigger(eventType, callbackArgs)
@@ -325,5 +383,5 @@ var UberSearch = function(data, options){
325
383
 
326
384
  // PUBLIC INTERFACE
327
385
 
328
- $.extend(this, {view:view, searchField:searchField, setValue:setValue, setData:setData, setDisabled:setDisabled, options:options})
386
+ $.extend(this, {view:view, searchField:searchField, setValue:setValue, getValue: getValue, setData:setData, setDisabled:setDisabled, getSelection:getSelection, options:options})
329
387
  }
@@ -18,7 +18,7 @@
18
18
 
19
19
  <span class="example">
20
20
  <label for="select">
21
- search and placeholder
21
+ Search and placeholder
22
22
  </label>
23
23
  <select placeholder="Choose a gender">
24
24
  <option></option>
@@ -31,6 +31,17 @@
31
31
  </p>
32
32
  </span>
33
33
 
34
+ <span class="example">
35
+ <label for="select">
36
+ Search input attributes
37
+ </label>
38
+ <select data-uber-options='{"searchInputAttributes": {"aria-label": "This is a test"}}'>
39
+ <option></option>
40
+ <option>male</option>
41
+ <option>female</option>
42
+ </select>
43
+ <p>This example includes an aria label attribute for the search input element.</p>
44
+ </span>
34
45
 
35
46
  <span class="example">
36
47
  <label for="select">
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uber_select_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nicholas Jakobsen
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-01-25 00:00:00.000000000 Z
11
+ date: 2022-03-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -52,7 +52,7 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '10.0'
55
- description:
55
+ description:
56
56
  email:
57
57
  - nicholas.jakobsen@gmail.com
58
58
  executables: []
@@ -84,7 +84,7 @@ files:
84
84
  homepage: https://github.com/culturecode/uber_select_rails
85
85
  licenses: []
86
86
  metadata: {}
87
- post_install_message:
87
+ post_install_message:
88
88
  rdoc_options: []
89
89
  require_paths:
90
90
  - lib
@@ -99,8 +99,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
99
  - !ruby/object:Gem::Version
100
100
  version: '0'
101
101
  requirements: []
102
- rubygems_version: 3.0.8
103
- signing_key:
102
+ rubygems_version: 3.2.3
103
+ signing_key:
104
104
  specification_version: 4
105
105
  summary: A Rails gem containing a javascript plugin that adds a layer of UI goodness
106
106
  overtop of basic HTML select elements