activeadmin_select_many 0.2.8 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3a289f4b6418d0af92538f32caed2af60a8149d6
4
- data.tar.gz: 37deed25511b1de438cae523b52a0f4c627d2d4e
3
+ metadata.gz: 2f658ea409967f4e0cfe78f48dd192d4047b0050
4
+ data.tar.gz: 4275e93e2a65befd4e712b3b884fe278bcd4c3c2
5
5
  SHA512:
6
- metadata.gz: a7774b3c4765e20abf7a18379a86f7faf0482c771fac313320bacb555e4a69c440c765da602c1ead8d93952e68a2acfc98d4ec0d626c22cc53f851f55d2242c9
7
- data.tar.gz: f7c76a2763f1a7977ea28e17eafbf1f7dde25a784f715d399f2f7b550f370573dd54161de5326e6e0c21ecd11660e6197f06cf3a90b79080ec4406583e42fc22
6
+ metadata.gz: 7d72c06453f4c81bb5fe90884ad92564e8f1f7ad5068db2e5bcc71bbb027e483e2e55945dc1aa8ad66c5da67614c097649bf84480ddfea32151b80cbc7edbdfe
7
+ data.tar.gz: 0e9e9dbc6d36d9c0757ca672d43478a081bf4f6806c49f69a83939eecc386ff8133fbf6846ed540d864e0814c8fede3735243978c4ffbed91cb4fefb01cf6d86
data/README.md CHANGED
@@ -8,6 +8,7 @@ Features for *select_many*:
8
8
  - local/remote collections
9
9
  - double click to add/remove items
10
10
  - sortable (with up/down buttons)
11
+ - key bindings to improve accessibility
11
12
 
12
13
  Features for *select_one*:
13
14
  - search box
@@ -15,6 +16,7 @@ Features for *select_one*:
15
16
  - remote collections
16
17
  - counter of items found
17
18
  - can be used as filter
19
+ - key bindings to improve accessibility
18
20
 
19
21
  ![screenshot](screenshot.png)
20
22
 
@@ -40,6 +40,7 @@ $(document).ready( function() {
40
40
  $.proxy( smActivate, $(this) )( event.target );
41
41
  });
42
42
 
43
+ // --- select_many ----------------------------------------------------------
43
44
  var onLocalSelect = smDebounce( function() {
44
45
  var cnt = 0, search = $(this).val().toLowerCase();
45
46
  $(this).closest( '.select_many' ).find( '[data-select="src"] option' ).each( function() {
@@ -49,10 +50,12 @@ $(document).ready( function() {
49
50
  });
50
51
  $(this).parent().find( '.available span' ).text( ' [' + cnt + ']' );
51
52
  }, 250 );
52
- var onRemoteSelect = smDebounce( function() {
53
+
54
+ var onRemoteSelect = smDebounce( function( event ) {
53
55
  var search = $(this).val().trim();
54
- if( search != '' && $(this).data( 'searching' ) != '1' ) {
56
+ if( $(this).data( 'searching' ) != '1' && search && $(this).data( 'last-search' ) != search ) {
55
57
  $(this).data( 'searching', '1' );
58
+ $(this).data( 'last-search', search );
56
59
  var _this = $(this);
57
60
  var data = {}
58
61
  var text_key = $(this).data('text');
@@ -82,8 +85,54 @@ $(document).ready( function() {
82
85
  var parent = $(this).parent();
83
86
  parent.find( '.available' ).append( '<span> [' + parent.find( '[data-select="src"] option' ).length + ']</span>' );
84
87
  parent.find( '.selected' ).append( '<span> [' + parent.find( '[data-select="dst"] option' ).length + ']</span>' );
85
- $(this).on( 'keyup', $(this).data( 'remote-collection' ) ? onRemoteSelect : onLocalSelect );
88
+ $(this).on( 'keydown', function( event ) {
89
+ if( event.which == 13 || event.which == 40 ) { // enter or arrow down
90
+ event.preventDefault();
91
+ $(this).closest( '.select_many' ).find( '[data-select="src"]' ).focus();
92
+ }
93
+ else $.proxy( $(this).data( 'remote-collection' ) ? onRemoteSelect : onLocalSelect, $(this) )( event );
94
+ });
95
+
96
+ // --- key bindings -------------------------------------------------------
97
+ parent.find( '[data-select="src"]' ).on( 'keydown', function( event ) {
98
+ if( event.which == 13 ) { // enter
99
+ event.preventDefault();
100
+ var opts = $(this).find( ':selected' );
101
+ if( opts.length > 0 ) {
102
+ var next = $( opts[0] ).next();
103
+ $.proxy( smActivate, $(this) )( opts[0] );
104
+ if( next.length > 0 ) $(this).val( next.val() );
105
+ }
106
+ }
107
+ else if( event.which == 9 || event.which == 39 ) { // tab or right arrow
108
+ event.preventDefault();
109
+ parent.find( '[data-select="dst"]' ).focus();
110
+ }
111
+ else if( event.which == 38 ) { // up arrow
112
+ if( $(this).find('option')[0] == $(this).find(':selected')[0] ) {
113
+ event.preventDefault();
114
+ parent.find( '.search-select' ).focus();
115
+ }
116
+ }
117
+ });
118
+ parent.find( '[data-select="dst"]' ).on( 'keydown', function( event ) {
119
+ if( event.which == 13 ) { // enter
120
+ event.preventDefault();
121
+ var opts = $(this).find( ':selected' );
122
+ if( opts.length > 0 ) {
123
+ var next = $( opts[0] ).next();
124
+ $.proxy( smActivate, $(this) )( opts[0] );
125
+ if( next.length > 0 ) $(this).val( next.val() );
126
+ }
127
+ }
128
+ else if( event.which == 37 ) { // left arrow
129
+ event.preventDefault();
130
+ parent.find( '[data-select="src"]' ).focus();
131
+ }
132
+ });
86
133
  });
134
+
135
+ // --- buttons --------------------------------------------------------------
87
136
  $('.select_many .add').on( 'click', function() {
88
137
  var select = $(this).parent().prev();
89
138
  var current = select.find( 'option:selected' )[0];
@@ -111,16 +160,19 @@ $(document).ready( function() {
111
160
  }
112
161
  });
113
162
 
163
+ // --- select one -----------------------------------------------------------
114
164
  var onRemoteSelectOne = smDebounce( function( event ) {
165
+ var search = $(this).val().trim();
115
166
  var select = $(this).next();
116
- if( select.data( 'searching' ) != '1' ) {
167
+ if( select.data( 'searching' ) != '1' && search && select.data( 'last-search' ) != search ) {
117
168
  select.data( 'searching', '1' );
169
+ select.data( 'last-search', search );
118
170
  var data = {}
119
171
  var search_key = $(this).data('search') ? $(this).data('search') : 'name_contains';
120
172
  var value_key = $(this).data('value') ? $(this).data('value') : 'id';
121
173
  var text_key = $(this).data('text') ? $(this).data('text') : 'name';
122
174
  var counter_limit = $(this).data('counter-limit') ? Number( $(this).data('counter-limit') ) : 0;
123
- data['q['+search_key+']'] = $(this).val();
175
+ data['q['+search_key+']'] = search;
124
176
  $.ajax({
125
177
  context: select,
126
178
  data: data,
@@ -139,5 +191,28 @@ $(document).ready( function() {
139
191
  });
140
192
  }
141
193
  }, 500 );
142
- $('.select-one-inputs > .search-select').on( 'keyup', onRemoteSelectOne );
194
+
195
+ $('.select-one-inputs').each( function() {
196
+ $(this).find( '.search-select' ).on( 'keydown', function( event ) {
197
+ if( event.which == 38 ) { // up arrow
198
+ event.preventDefault();
199
+ var select = $(this).closest( '.select-one-inputs' ).find( '[data-select="src"]' );
200
+ var prev = select.find( ':selected' ).prev();
201
+ if( prev.length ) select.val( prev.val() );
202
+ }
203
+ else if( event.which == 40 ) { // down arrow
204
+ event.preventDefault();
205
+ var select = $(this).closest( '.select-one-inputs' ).find( '[data-select="src"]' );
206
+ var next = select.find( ':selected' ).next();
207
+ if( next.length ) select.val( next.val() );
208
+ }
209
+ else $.proxy( onRemoteSelectOne, $(this) )( event );
210
+ });
211
+ $(this).find( '[data-select="src"]' ).on( 'keydown', function( event ) {
212
+ if( event.which == 37 ) { // left arrow
213
+ event.preventDefault();
214
+ $(this).closest( '.select-one-inputs' ).find( '.search-select' ).focus();
215
+ }
216
+ });
217
+ });
143
218
  });
@@ -1,5 +1,5 @@
1
1
  module ActiveAdmin
2
2
  module SelectMany
3
- VERSION = '0.2.8'
3
+ VERSION = '0.3.0'
4
4
  end
5
5
  end
@@ -10,9 +10,9 @@ module Formtastic
10
10
  template.content_tag( :div, opts ) do
11
11
  hidden_input <<
12
12
  search_box_html <<
13
- template.content_tag( :span, '', class: 'empty' ) <<
13
+ template.content_tag( :span, '', class: 'empty' ) <<
14
14
  template.content_tag( :span, template.t( 'inputs.select_many.available' ), class: 'available' ) <<
15
- template.content_tag( :span, template.t( 'inputs.select_many.selected' ), class: 'selected' ) <<
15
+ template.content_tag( :span, template.t( 'inputs.select_many.selected' ), class: 'selected' ) <<
16
16
  select_src_html <<
17
17
  buttons_html <<
18
18
  select_dst_html
@@ -40,8 +40,17 @@ module Formtastic
40
40
  end
41
41
 
42
42
  def search_box_html
43
- @opts ||= {id: nil, class: 'search-select', placeholder: options.delete( :placeholder ), 'data-remote-collection': options[:'data-remote-collection'], 'data-search': options[:search_param] ? options[:search_param] : 'name_contains', 'data-text': options[:member_label] ? options[:member_label] : ( options[:text_key] ? options[:text_key] : 'name' ), 'data-value': options[:value_key] ? options[:value_key] : 'id', 'data-counter-limit': options[:counter_limit].to_i}
44
- template.text_field_tag( nil, '', @opts )
43
+ opts = {
44
+ id: nil,
45
+ class: 'search-select',
46
+ placeholder: options.delete( :placeholder ),
47
+ 'data-counter-limit': options[:counter_limit].to_i,
48
+ 'data-remote-collection': options[:'data-remote-collection'],
49
+ 'data-search': options[:search_param] ? options[:search_param] : 'name_contains',
50
+ 'data-text': options[:member_label] ? options[:member_label] : ( options[:text_key] ? options[:text_key] : 'name' ),
51
+ 'data-value': options[:value_key] ? options[:value_key] : 'id',
52
+ }
53
+ template.text_field_tag( nil, '', opts )
45
54
  end
46
55
 
47
56
  def select_src_html
@@ -26,8 +26,18 @@ module Formtastic
26
26
 
27
27
  def search_box
28
28
  # TODO: remove text_key in next major version
29
- @opts ||= {id: nil, class: 'search-select', placeholder: options[:placeholder], 'data-remote-collection': options[:remote_collection], 'data-search': options[:search_param] ? options[:search_param] : 'name_contains', 'data-text': options[:member_label] ? options[:member_label] : ( options[:text_key] ? options[:text_key] : 'name' ), 'data-value': options[:value_key] ? options[:value_key] : 'id', 'data-msg': options[:msg_items], 'data-counter-limit': options[:counter_limit].to_i}
30
- template.text_field_tag( nil, '', @opts )
29
+ opts = {
30
+ id: nil,
31
+ class: 'search-select',
32
+ placeholder: options[:placeholder],
33
+ 'data-counter-limit': options[:counter_limit].to_i,
34
+ 'data-msg': options[:msg_items],
35
+ 'data-remote-collection': options[:remote_collection],
36
+ 'data-search': options[:search_param] ? options[:search_param] : 'name_contains',
37
+ 'data-text': options[:member_label] ? options[:member_label] : ( options[:text_key] ? options[:text_key] : 'name' ),
38
+ 'data-value': options[:value_key] ? options[:value_key] : 'id',
39
+ }
40
+ template.text_field_tag( nil, '', opts )
31
41
  end
32
42
 
33
43
  def select_html
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activeadmin_select_many
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.8
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mattia Roccoberton
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-14 00:00:00.000000000 Z
11
+ date: 2017-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activeadmin