activeadmin_select_many 0.1.4 → 0.2.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: 45fd55dbb9b440057b38aeef68aca5494f89247b
4
- data.tar.gz: afa5035de499e0997a1fb2e8c81c3b21dd343e07
3
+ metadata.gz: dc928a64768e531eb353bfb5aecc59b92151a4ff
4
+ data.tar.gz: 8b4ff87b759f176fa8f1d0a0806e5bff7be878be
5
5
  SHA512:
6
- metadata.gz: b71c96131788ee4b9b883ed73186abad17ff7fc85d05b985f674f5561ff1f89681b7395e64636aca366c2f38a9829f639f24b0ba9aa677ff86d35aab278a3c53
7
- data.tar.gz: 5d9f79c90856223aa9cd45810bc1679a6fde32cc39b8b21b93205f081fe5b38c3a22fcc202a2a29e75f0fc4e2f732ab5c8c94dd4a5caf195e0d4502701eaf24d
6
+ metadata.gz: 7b754c3cf2c094ea2eec2d805b8cf99b760680d74471fadcaa35ea8fe4437d0e05f75bded2ac68e817722b9005e093db3e84f44102d0abd8eacfbf8846c7f1fc
7
+ data.tar.gz: 6244aa2b14352c08cc696319dc93f49d79c44a49f59d8176d572cfc8c71f5aa12e9786a912bc180e98012367be57ee5b6cfb08bf6dd00ca0203e518bead4991c
data/README.md CHANGED
@@ -1,17 +1,25 @@
1
1
  # ActiveAdmin Select Many [![Gem Version](https://badge.fury.io/rb/activeadmin_select_many.svg)](https://badge.fury.io/rb/activeadmin_select_many)
2
2
 
3
- An Active Admin plugin which improves one-to-many and many-to-many associations selection (jQuery required).
3
+ An Active Admin plugin which improves one-to-many / many-to-many / many-to-one associations selection using 2 new inputs: **select_many** and **select_one** (jQuery required)
4
4
 
5
- Features:
5
+ Features for *select_many*:
6
6
  - search box
7
- - select on the left with available items
8
- - select on the right with selected items
7
+ - available items on the left, selected items on the right
9
8
  - local/remote collections
10
9
  - double click to add/remove items
11
- - sortable
10
+ - sortable (with up/down buttons)
11
+
12
+ Features for *select_one*:
13
+ - search box
14
+ - selected items on the right
15
+ - remote collections
16
+ - counter of items found
17
+ - can be used as filter
12
18
 
13
19
  ![screenshot](screenshot.png)
14
20
 
21
+ *(inspired by RailsAdmin associations selector)*
22
+
15
23
  ## Install
16
24
 
17
25
  - Add to your Gemfile:
@@ -23,7 +31,18 @@ Features:
23
31
  `//= require activeadmin/select_many`
24
32
  - Use the input with `as: :select_many` in Active Admin model conf
25
33
 
26
- ## Examples
34
+ ## Options
35
+
36
+ - **collection**: local collection
37
+ - **filter_form**: for *select_one* only, allow to use it as filter
38
+ - **placeholder**: placeholder string for search box
39
+ - **remote_collection**: JSON path
40
+ - **search_param**: parameter to use as search key (ransack format)
41
+ - **sortable**: set to true to enable sortable buttons (default: not set)
42
+ - **size**: number of rows of both the selects (default: 4)
43
+ - **text_key**: key to use as text for select options
44
+
45
+ ## Example with select_many
27
46
 
28
47
  Add to ActiveAdmin model config, in *form* block.
29
48
 
@@ -35,8 +54,10 @@ Add to ActiveAdmin model config, in *form* block.
35
54
  `f.input :tags, as: :select_many, remote_collection: admin_tags_path( format: :json ), search_param: 'category_contains', text_key: 'category', placeholder: 'Type something...'`
36
55
  - Sortable (items position must be saved manually):
37
56
  `f.input :tags, as: :select_many, remote_collection: admin_tags_path( format: :json ), sortable: true`
57
+
58
+ Example to update *position* field:
59
+
38
60
  ```rb
39
- # Manually update position field
40
61
  after_save :on_after_save
41
62
  controller do
42
63
  def on_after_save( object )
@@ -53,26 +74,28 @@ Example to enable JSON response on an ActiveAdmin model:
53
74
 
54
75
  ```rb
55
76
  ActiveAdmin.register Tag do
56
- config.per_page = 30
77
+ config.per_page = 30 # to limit served items
57
78
  config.sort_order = 'name_asc'
58
79
  index download_links: [:json]
59
80
  end
60
81
  ```
61
82
 
62
- ## Options
83
+ ## Example with select_one
63
84
 
64
- - **collection**: local collection
65
- - **placeholder**: placeholder string for search box
66
- - **remote_collection**: JSON path
67
- - **search_param**: parameter to use as search key (ransack style)
68
- - **sortable**: set to true to enable sortable buttons (default: not set)
69
- - **size**: number of rows of both the selects (default: 4)
70
- - **text_key**: key to use as text for select options
85
+ In a form:
86
+
87
+ `f.input :article, as: :select_one, placeholder: 'Search...', remote_collection: admin_articles_path( format: :json ), search_param: 'title_contains', text_key: 'title'`
88
+
89
+ As filter:
90
+
91
+ `filter :article_id_eq, as: :select_one, filter_form: true, placeholder: 'Search...', search_param: 'title_contains', text_key: 'title', remote_collection: '/admin/articles.json'`
71
92
 
72
93
  ## Do you like it? Star it!
73
94
 
74
95
  If you use this component just star it. A developer is more motivated to improve a project when there is some interest.
75
96
 
97
+ Take a look at [other ActiveAdmin components](https://github.com/blocknotes?utf8=✓&tab=repositories&q=activeadmin&type=source) that I made if you are curious.
98
+
76
99
  ## Contributors
77
100
 
78
101
  - [Mattia Roccoberton](http://blocknot.es) - creator, maintainer
@@ -57,7 +57,7 @@ $(document).ready( function() {
57
57
  $.ajax({
58
58
  context: _this,
59
59
  data: data,
60
- url: $(this).data( 'remote' ),
60
+ url: $(this).data( 'remote-collection' ),
61
61
  complete: function( req, status ) {
62
62
  $(this).data( 'searching', '' );
63
63
  },
@@ -74,7 +74,7 @@ $(document).ready( function() {
74
74
  }, 400 );
75
75
 
76
76
  $('.select_many.input .search-select').each( function() {
77
- $(this).on( 'keyup', $(this).data( 'remote' ) ? onRemoteSelect : onLocalSelect );
77
+ $(this).on( 'keyup', $(this).data( 'remote-collection' ) ? onRemoteSelect : onLocalSelect );
78
78
  });
79
79
  $('.select_many .add').on( 'click', function() {
80
80
  var select = $(this).parent().prev();
@@ -103,32 +103,32 @@ $(document).ready( function() {
103
103
  }
104
104
  });
105
105
 
106
- // // WORK IN PROGRESS
107
- // var onRemoteSelectOne = smDebounce( function( event ) {
108
- // if( $(this).data( 'searching' ) != '1' ) {
109
- // $(this).data( 'searching', '1' );
110
- // var _this = $(this);
111
- // var data = {}
112
- // var search_key = $(this).data('search') ? $(this).data('search') : 'name_contains';
113
- // var value_key = $(this).data('value') ? $(this).data('value') : 'id';
114
- // var text_key = $(this).data('text') ? $(this).data('text') : 'name';
115
- // data['q['+search_key+']'] = event.key;
116
- // $.ajax({
117
- // context: _this,
118
- // data: data,
119
- // url: $(this).data( 'remote' ),
120
- // complete: function( req, status ) {
121
- // $(this).data( 'searching', '' );
122
- // },
123
- // success: function( data, status, req ) {
124
- // var select = $(this);
125
- // select.empty();
126
- // data.forEach( function( item ) {
127
- // select.append( $('<option>', { value: item[value_key], text: item[text_key] }) );
128
- // });
129
- // },
130
- // });
131
- // }
132
- // }, 400 );
133
- // $('.select_one.input select').on( 'keyup', onRemoteSelectOne );
106
+ var onRemoteSelectOne = smDebounce( function( event ) {
107
+ var select = $(this).next();
108
+ if( select.data( 'searching' ) != '1' ) {
109
+ select.data( 'searching', '1' );
110
+ var data = {}
111
+ var search_key = $(this).data('search') ? $(this).data('search') : 'name_contains';
112
+ var value_key = $(this).data('value') ? $(this).data('value') : 'id';
113
+ var text_key = $(this).data('text') ? $(this).data('text') : 'name';
114
+ data['q['+search_key+']'] = $(this).val();
115
+ $.ajax({
116
+ context: select,
117
+ data: data,
118
+ url: $(this).data( 'remote-collection' ),
119
+ complete: function( req, status ) {
120
+ $(this).data( 'searching', '' );
121
+ },
122
+ success: function( data, status, req ) {
123
+ var sel = $(this);
124
+ sel.empty();
125
+ data.forEach( function( item ) {
126
+ sel.append( $('<option>', { value: item[value_key], text: item[text_key] }) );
127
+ });
128
+ sel.parent().find( '.status' ).text( '[' + data.length + ']' );
129
+ },
130
+ });
131
+ }
132
+ }, 500 );
133
+ $('.select-one-inputs > .search-select').on( 'keyup', onRemoteSelectOne );
134
134
  });
@@ -16,21 +16,39 @@ body.active_admin
16
16
  display: none
17
17
  &:hover
18
18
  background: #e0e0e0
19
- .search-select
20
- margin-bottom: 1px
21
- .selects
19
+ .select-many-inputs
22
20
  display: flex
23
21
  flex-wrap: wrap
24
22
  > input[type="text"], > select, > span
25
23
  min-width: auto
26
- width: calc(50% - 12px);
24
+ width: calc(50% - 12px)
27
25
  > span
28
26
  padding: 3px 6px 1px 6px
27
+ .empty
28
+ width: 20%
29
29
  .available
30
30
  font-style: italic
31
+ padding: 0 6px 0 6px
31
32
  .selected
32
33
  font-style: italic
33
- padding-left: 30px
34
+ padding: 0 0 0 12px
35
+ .search-select
36
+ margin-bottom: 1px
37
+ width: 50%
34
38
  [sortable] >.buttons
35
39
  a.move_up, a.move_down
36
40
  display: block
41
+
42
+ .formtastic > .inputs .select_one
43
+ .select-one-inputs
44
+ display: flex
45
+ > input[type="text"], > select, > span
46
+ display: inline-block
47
+ width: calc(50% - 12px)
48
+ .status
49
+ line-height: 26px
50
+ margin-left: 5px
51
+
52
+ .filter_form .select-one-inputs
53
+ .status
54
+ display: none
@@ -3,3 +3,5 @@ en:
3
3
  select_many:
4
4
  available: Available
5
5
  selected: Selected
6
+ select_one:
7
+ status: ''
@@ -1,5 +1,5 @@
1
1
  module ActiveAdmin
2
2
  module SelectMany
3
- VERSION = '0.1.4'
3
+ VERSION = '0.2.0'
4
4
  end
5
5
  end
@@ -1,4 +1,4 @@
1
1
  require 'activeadmin/select_many'
2
2
 
3
3
  require 'formtastic/inputs/select_many_input'
4
- require 'formtastic/inputs/select_one_input' # WORK IN PROGRESS
4
+ require 'formtastic/inputs/select_one_input'
@@ -1,23 +1,20 @@
1
1
  module Formtastic
2
2
  module Inputs
3
3
  class SelectManyInput < SelectInput
4
- # def input_html_options
5
- # super.merge( class: 'select-many' )
6
- # end
7
-
8
4
  def to_html
9
- opts = { class: 'selects' }
10
- opts[:sortable] = options[:sortable] if options[:sortable]
5
+ options[:'data-remote-collection'] = options.delete( :remote_collection )
6
+ opts = { class: 'select-many-inputs' }
7
+ opts[:sortable] = options.delete( :sortable ) if options[:sortable]
11
8
  input_wrapping do
12
9
  label_html <<
13
- hidden_input <<
14
10
  template.content_tag( :div, opts ) do
15
- search_box_html +
16
- template.content_tag( :span, '' ) +
17
- template.content_tag( :span, template.t( 'inputs.select_many.available' ), class: 'available' ) +
18
- template.content_tag( :span, template.t( 'inputs.select_many.selected' ), class: 'selected' ) +
19
- select_src_html +
20
- buttons_html +
11
+ hidden_input <<
12
+ search_box_html <<
13
+ template.content_tag( :span, '', class: 'empty' ) <<
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' ) <<
16
+ select_src_html <<
17
+ buttons_html <<
21
18
  select_dst_html
22
19
  end
23
20
  end
@@ -43,12 +40,12 @@ module Formtastic
43
40
  end
44
41
 
45
42
  def search_box_html
46
- @opts ||= {id: nil, class: 'search-select', placeholder: options[:placeholder], 'data-remote': options[:remote_collection], 'data-search': options[:search_param] ? options[:search_param] : 'name_contains', 'data-text': options[:text_key] ? options[:text_key] : 'name', 'data-value': options[:value_key] ? options[:value_key] : 'id'}
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[:text_key] ? options[:text_key] : 'name', 'data-value': options[:value_key] ? options[:value_key] : 'id'}
47
44
  template.text_field_tag( nil, '', @opts )
48
45
  end
49
46
 
50
47
  def select_src_html
51
- coll = if options[:remote_collection]
48
+ coll = if options[:'data-remote-collection']
52
49
  []
53
50
  else
54
51
  # TODO: add option unique ?
@@ -5,66 +5,31 @@ module Formtastic
5
5
  super.merge include_blank: false
6
6
  end
7
7
 
8
- # def input_html_options
9
- # super.merge( class: 'select-one' )
10
- # end
11
-
8
+ def input_wrapping(&block)
9
+ template.content_tag(options[:filter_form] ? :div : :li,
10
+ [template.capture(&block), error_html, hint_html].join("\n").html_safe,
11
+ wrapper_html_options
12
+ )
13
+ end
12
14
 
13
15
  def to_html
16
+ opts = { class: 'select-one-inputs' }
14
17
  input_wrapping do
15
18
  label_html <<
16
- search_box <<
17
- select_html
19
+ template.content_tag( :div, opts ) do
20
+ search_box <<
21
+ select_html <<
22
+ # template.content_tag( :span, '' ) <<
23
+ template.content_tag( :span, template.t( 'inputs.select_one.status' ), class: 'status' )
24
+ end
18
25
  end
19
26
  end
20
27
 
21
- # def hidden_input
22
- # template.content_tag( :div, class: 'values', 'data-name': input_html_options[:name] ) do
23
- # values = object.send( input_name )
24
- # values = [values] if values.is_a? Fixnum
25
- # values.each do |value|
26
- # template.concat template.hidden_field_tag( input_html_options[:name], value, {id: nil} )
27
- # end if values
28
- # end
29
- # end
30
-
31
28
  def search_box
32
- @opts ||= {id: nil, class: 'search-select', placeholder: options[:placeholder], 'data-remote': options[:remote_collection], 'data-search': options[:search_param] ? options[:search_param] : 'name_contains', 'data-text': options[:text_key] ? options[:text_key] : 'name', 'data-value': options[:value_key] ? options[:value_key] : 'id'}
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[:text_key] ? options[:text_key] : 'name', 'data-value': options[:value_key] ? options[:value_key] : 'id', 'data-msg': options[:msg_items]}
33
30
  template.text_field_tag( nil, '', @opts )
34
31
  end
35
32
 
36
- # def select_src_html
37
- # coll = if options[:remote_collection]
38
- # []
39
- # else
40
- # # TODO: add option unique ?
41
- # selected = object.send( input_name )
42
- # selected = [selected] if selected.is_a? Fixnum
43
- # selected ? collection.select { |option| !selected.include?( option[1] ) } : collection
44
- # end
45
- # opts = input_options.dup.merge( name: nil, id: nil, multiple: true, 'data-select': 'src' )
46
- # template.select_tag nil, template.options_for_select( coll ), opts
47
- # end
48
-
49
-
50
- # def select_dst_html
51
- # selected = object.send( input_name )
52
- # selected = [selected] if selected.is_a? Fixnum
53
- # coll = selected ? collection.select { |option| selected.include?( option[1] ) } : collection
54
- # opts = input_options.dup.merge( name: nil, id: nil, multiple: true, 'data-select': 'dst' )
55
- # template.select_tag nil, template.options_for_select( coll ), opts
56
- # end
57
-
58
- # # def select_html
59
- # # selected = object.send( input_name )
60
- # # coll = collection.select { |option| selected.include?( option[1] ) }
61
-
62
- # # opts = input_options.dup.merge( name: nil, id: nil, multiple: true )
63
- # # template.select_tag nil, template.options_for_select( coll ), opts
64
-
65
- # # # builder.select(input_name, coll, input_options, input_html_options)
66
- # # end
67
-
68
33
  def select_html
69
34
  selected = object.send( input_name )
70
35
  sel = ''
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.1.4
4
+ version: 0.2.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-09-26 00:00:00.000000000 Z
11
+ date: 2017-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activeadmin