activeadmin_select_many 0.2.8 → 0.4.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 +5 -5
- data/README.md +20 -13
- data/app/assets/javascripts/activeadmin/select_many.js +151 -72
- data/lib/activeadmin/select_many/version.rb +1 -1
- data/lib/formtastic/inputs/select_many_input.rb +58 -32
- data/lib/formtastic/inputs/select_one_input.rb +23 -16
- metadata +134 -13
- data/.gitignore +0 -3
- data/Gemfile +0 -4
- data/activeadmin_select_many.gemspec +0 -19
- data/screenshot.png +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 125c98dc457c8e510aa9e35d0c03c9d86341a42c6395cbd5da501f32a0782ab3
|
4
|
+
data.tar.gz: aa9ab407d84de81df360209eba4c868da7232805fe6606d19d2e3b3c74d00279
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f40eda600327c6a7262548e7052ae0662c65b88a40cdd21d4138d7b2ce9e4df37e9884384d23dc34e34236f778e876e2a7d48f575d11af8d361598189e7b3ffa
|
7
|
+
data.tar.gz: 5e0d0b7b131174658ad5dfde9c235dedb5ddfb09c703efed47ea4141b4b0ac06fec1f3591c4ab6b790167f1793570f70a5d2b3a557b7196bed4bb993f4ed9035
|
data/README.md
CHANGED
@@ -1,20 +1,22 @@
|
|
1
1
|
# ActiveAdmin Select Many [](https://badge.fury.io/rb/activeadmin_select_many)
|
2
2
|
|
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)
|
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
5
|
Features for *select_many*:
|
6
|
-
- search box
|
7
|
-
- available items on the left, selected items on the right
|
8
|
-
- local/remote collections
|
9
|
-
- double click to add/remove items
|
10
|
-
- sortable (with up/down buttons)
|
6
|
+
- search box;
|
7
|
+
- available items on the left, selected items on the right;
|
8
|
+
- local/remote collections;
|
9
|
+
- double click to add/remove items;
|
10
|
+
- sortable (with up/down buttons);
|
11
|
+
- key bindings to improve accessibility.
|
11
12
|
|
12
13
|
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
|
14
|
+
- search box;
|
15
|
+
- selected items on the right;
|
16
|
+
- remote collections;
|
17
|
+
- counter of items found;
|
18
|
+
- can be used as filter;
|
19
|
+
- key bindings to improve accessibility.
|
18
20
|
|
19
21
|

|
20
22
|
|
@@ -36,6 +38,7 @@ Features for *select_one*:
|
|
36
38
|
- **collection**: local collection
|
37
39
|
- **counter_limit**: if results count is greater than or equal to this limit a '+' is shown
|
38
40
|
- **filter_form**: for *select_one* only, allow to use it as filter
|
41
|
+
- **include_blank**: for *select_one* only, default true, allow to include a blank value on top
|
39
42
|
- **member_label**: key to use as text for select options
|
40
43
|
- **placeholder**: placeholder string for search box
|
41
44
|
- **remote_collection**: JSON path
|
@@ -44,7 +47,7 @@ Features for *select_one*:
|
|
44
47
|
- **size**: number of rows of both the selects (default: 4)
|
45
48
|
- **sortable**: set to true to enable sortable buttons (default: not set)
|
46
49
|
|
47
|
-
##
|
50
|
+
## Examples with select_many
|
48
51
|
|
49
52
|
Add to ActiveAdmin model config, in *form* block.
|
50
53
|
|
@@ -82,7 +85,7 @@ ActiveAdmin.register Tag do
|
|
82
85
|
end
|
83
86
|
```
|
84
87
|
|
85
|
-
##
|
88
|
+
## Examples with select_one
|
86
89
|
|
87
90
|
In a form:
|
88
91
|
|
@@ -92,6 +95,10 @@ As filter:
|
|
92
95
|
|
93
96
|
`filter :article_id_eq, as: :select_one, filter_form: true, placeholder: 'Search...', search_param: 'title_contains', member_label: 'title', remote_collection: '/admin/articles.json'`
|
94
97
|
|
98
|
+
## Notes
|
99
|
+
|
100
|
+
- To use this plugins with ActiveAdmin 1.x please use the version 0.3.4
|
101
|
+
|
95
102
|
## Do you like it? Star it!
|
96
103
|
|
97
104
|
If you use this component just star it. A developer is more motivated to improve a project when there is some interest.
|
@@ -1,15 +1,15 @@
|
|
1
|
-
function smActivate(
|
2
|
-
if(
|
3
|
-
var parent = $(this).closest(
|
1
|
+
function smActivate(target) {
|
2
|
+
if(target.tagName.toLowerCase() == 'option') {
|
3
|
+
var parent = $(this).closest('.select_many');
|
4
4
|
var opt = $(target);
|
5
|
-
var dst = parent.find(
|
6
|
-
dst.append(
|
5
|
+
var dst = parent.find($(this).data('select') == 'src' ? '[data-select="dst"]' : '[data-select="src"]');
|
6
|
+
dst.append($('<option>', { value: opt.val(), text: opt.text() }));
|
7
7
|
opt.remove();
|
8
|
-
smUpdateValues(
|
8
|
+
smUpdateValues(parent);
|
9
9
|
}
|
10
10
|
}
|
11
11
|
|
12
|
-
function smDebounce(
|
12
|
+
function smDebounce(func, wait, immediate) {
|
13
13
|
var timeout;
|
14
14
|
return function() {
|
15
15
|
var context = this, args = arguments;
|
@@ -24,120 +24,199 @@ function smDebounce( func, wait, immediate ) {
|
|
24
24
|
};
|
25
25
|
};
|
26
26
|
|
27
|
-
function smUpdateValues(
|
28
|
-
var cnt = 0, values = parent.find(
|
27
|
+
function smUpdateValues(parent) {
|
28
|
+
var cnt = 0, values = parent.find('.values');
|
29
29
|
values.empty();
|
30
|
-
parent.find(
|
31
|
-
values.append(
|
30
|
+
parent.find('[data-select="dst"] option').each(function() {
|
31
|
+
values.append($('<input>', { type: 'hidden', name: values.data('name'), value: $(this).val() }));
|
32
32
|
cnt++;
|
33
33
|
});
|
34
|
-
if(
|
35
|
-
parent.find(
|
34
|
+
if(cnt == 0) values.append($('<input>', { type: 'hidden', name: values.data('name') }));
|
35
|
+
parent.find('.selected span').text(' [' + cnt + ']');
|
36
|
+
parent.find('.available span').text(' [' + parent.find('[data-select="src"] option').length + ']');
|
36
37
|
}
|
37
38
|
|
38
|
-
$(document).ready(
|
39
|
-
$('.select_many.input select').on(
|
40
|
-
$.proxy(
|
39
|
+
$(document).ready(function() {
|
40
|
+
$('.select_many.input select').on('dblclick', function(event) {
|
41
|
+
$.proxy(smActivate, $(this))(event.target);
|
41
42
|
});
|
42
43
|
|
43
|
-
|
44
|
+
// --- select_many ----------------------------------------------------------
|
45
|
+
var onLocalSelect = smDebounce(function() {
|
44
46
|
var cnt = 0, search = $(this).val().toLowerCase();
|
45
|
-
$(this).closest(
|
46
|
-
var found = $(this).text().toLowerCase().indexOf(
|
47
|
-
$(this).toggle(
|
48
|
-
if(
|
47
|
+
$(this).closest('.select_many').find('[data-select="src"] option').each(function() {
|
48
|
+
var found = $(this).text().toLowerCase().indexOf(search) >= 0;
|
49
|
+
$(this).toggle(found);
|
50
|
+
if(found) cnt++;
|
49
51
|
});
|
50
|
-
$(this).parent().find(
|
51
|
-
}, 250
|
52
|
-
|
52
|
+
$(this).parent().find('.available span').text(' [' + cnt + ']');
|
53
|
+
}, 250);
|
54
|
+
|
55
|
+
var onRemoteSelect = smDebounce(function(event) {
|
53
56
|
var search = $(this).val().trim();
|
54
|
-
if(
|
55
|
-
$(this).data(
|
57
|
+
if($(this).data('searching') != '1' && search && $(this).data('last-search') != search) {
|
58
|
+
$(this).data('searching', '1');
|
59
|
+
$(this).data('last-search', search);
|
56
60
|
var _this = $(this);
|
57
61
|
var data = {}
|
58
62
|
var text_key = $(this).data('text');
|
59
63
|
var value_key = $(this).data('value');
|
60
|
-
var counter_limit = $(this).data('counter-limit') ? Number(
|
64
|
+
var counter_limit = $(this).data('counter-limit') ? Number($(this).data('counter-limit')) : 0;
|
61
65
|
data['q['+$(this).data('search')+']'] = search;
|
62
66
|
$.ajax({
|
63
67
|
context: _this,
|
64
68
|
data: data,
|
65
|
-
url: $(this).data(
|
66
|
-
complete: function(
|
67
|
-
$(this).data(
|
69
|
+
url: $(this).data('remote-collection'),
|
70
|
+
complete: function(req, status) {
|
71
|
+
$(this).data('searching', '');
|
68
72
|
},
|
69
|
-
success: function(
|
70
|
-
var select = $(this).closest(
|
73
|
+
success: function(data, status, req) {
|
74
|
+
var select = $(this).closest('.select_many').find('[data-select="src"]');
|
71
75
|
select.empty();
|
72
|
-
data.forEach(
|
73
|
-
select.append(
|
76
|
+
data.forEach(function(item) {
|
77
|
+
select.append($('<option>', { value: item[value_key], text: item[text_key] }));
|
74
78
|
});
|
75
|
-
$(this).parent().find(
|
79
|
+
$(this).parent().find('.available span').text(' [' + ((counter_limit > 0 && data.length >= counter_limit) ? (counter_limit + '+') : data.length) + ']');
|
76
80
|
},
|
77
81
|
});
|
78
82
|
}
|
79
|
-
}, 400
|
83
|
+
}, 400);
|
80
84
|
|
81
|
-
$('.select_many.input .search-select').each(
|
85
|
+
$('.select_many.input .search-select').each(function() {
|
82
86
|
var parent = $(this).parent();
|
83
|
-
parent.find(
|
84
|
-
parent.find(
|
85
|
-
$(this).on(
|
87
|
+
parent.find('.available').append('<span> [' + parent.find('[data-select="src"] option').length + ']</span>');
|
88
|
+
parent.find('.selected').append('<span> [' + parent.find('[data-select="dst"] option').length + ']</span>');
|
89
|
+
$(this).on('keydown', function(event) {
|
90
|
+
if(event.which == 13 || event.which == 40) { // enter or arrow down
|
91
|
+
event.preventDefault();
|
92
|
+
$(this).closest('.select_many').find('[data-select="src"]').focus();
|
93
|
+
}
|
94
|
+
else $.proxy($(this).data('remote-collection') ? onRemoteSelect : onLocalSelect, $(this))(event);
|
95
|
+
});
|
96
|
+
|
97
|
+
// --- key bindings -------------------------------------------------------
|
98
|
+
parent.find('[data-select="src"]').on('keydown', function(event) {
|
99
|
+
if(event.which == 13) { // enter
|
100
|
+
event.preventDefault();
|
101
|
+
var opts = $(this).find(':selected');
|
102
|
+
if(opts.length > 0) {
|
103
|
+
var next = $(opts[0]).next();
|
104
|
+
$.proxy(smActivate, $(this))(opts[0]);
|
105
|
+
if(next.length > 0) $(this).val(next.val());
|
106
|
+
}
|
107
|
+
}
|
108
|
+
else if(event.which == 9 || event.which == 39) { // tab or right arrow
|
109
|
+
event.preventDefault();
|
110
|
+
parent.find('[data-select="dst"]').focus();
|
111
|
+
}
|
112
|
+
else if(event.which == 38) { // up arrow
|
113
|
+
if($(this).find('option')[0] == $(this).find(':selected')[0]) {
|
114
|
+
event.preventDefault();
|
115
|
+
parent.find('.search-select').focus();
|
116
|
+
}
|
117
|
+
}
|
118
|
+
});
|
119
|
+
parent.find('[data-select="dst"]').on('keydown', function(event) {
|
120
|
+
if(event.which == 13) { // enter
|
121
|
+
event.preventDefault();
|
122
|
+
var opts = $(this).find(':selected');
|
123
|
+
if(opts.length > 0) {
|
124
|
+
var next = $(opts[0]).next();
|
125
|
+
$.proxy(smActivate, $(this))(opts[0]);
|
126
|
+
if(next.length > 0) $(this).val(next.val());
|
127
|
+
}
|
128
|
+
}
|
129
|
+
else if(event.which == 37) { // left arrow
|
130
|
+
event.preventDefault();
|
131
|
+
parent.find('[data-select="src"]').focus();
|
132
|
+
}
|
133
|
+
});
|
86
134
|
});
|
87
|
-
|
135
|
+
|
136
|
+
// --- buttons --------------------------------------------------------------
|
137
|
+
$('.select_many .add').on('click', function() {
|
88
138
|
var select = $(this).parent().prev();
|
89
|
-
var current = select.find(
|
90
|
-
if(
|
139
|
+
var current = select.find('option:selected')[0];
|
140
|
+
if(current) $.proxy(smActivate, select)(current);
|
91
141
|
});
|
92
|
-
$('.select_many .remove').on(
|
142
|
+
$('.select_many .remove').on('click', function() {
|
93
143
|
var select = $(this).parent().next();
|
94
|
-
var current = select.find(
|
95
|
-
if(
|
144
|
+
var current = select.find('option:selected')[0];
|
145
|
+
if(current) $.proxy(smActivate, select)(current);
|
96
146
|
});
|
97
|
-
$('.select_many [sortable] .move_up').on(
|
147
|
+
$('.select_many [sortable] .move_up').on('click', function() {
|
98
148
|
var select = $(this).parent().next();
|
99
|
-
var current = select.find(
|
100
|
-
if(
|
101
|
-
$(current).prev().before(
|
102
|
-
smUpdateValues(
|
149
|
+
var current = select.find('option:selected')[0];
|
150
|
+
if(current) {
|
151
|
+
$(current).prev().before(current);
|
152
|
+
smUpdateValues($(this).closest('.select_many'));
|
103
153
|
}
|
104
154
|
});
|
105
|
-
$('.select_many [sortable] .move_down').on(
|
155
|
+
$('.select_many [sortable] .move_down').on('click', function() {
|
106
156
|
var select = $(this).parent().next();
|
107
|
-
var current = select.find(
|
108
|
-
if(
|
109
|
-
$(current).next().after(
|
110
|
-
smUpdateValues(
|
157
|
+
var current = select.find('option:selected')[0];
|
158
|
+
if(current) {
|
159
|
+
$(current).next().after(current);
|
160
|
+
smUpdateValues($(this).closest('.select_many'));
|
111
161
|
}
|
112
162
|
});
|
113
163
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
164
|
+
// --- select one -----------------------------------------------------------
|
165
|
+
var onRemoteSelectOne = smDebounce(function(event) {
|
166
|
+
var search = $(this).val().trim();
|
167
|
+
var select = $(this).closest('.select_one').find('[data-select="src"]');;
|
168
|
+
if(select.data('searching') != '1' && search && select.data('last-search') != search) {
|
169
|
+
select.data('searching', '1');
|
170
|
+
select.data('last-search', search);
|
118
171
|
var data = {}
|
119
172
|
var search_key = $(this).data('search') ? $(this).data('search') : 'name_contains';
|
120
173
|
var value_key = $(this).data('value') ? $(this).data('value') : 'id';
|
121
174
|
var text_key = $(this).data('text') ? $(this).data('text') : 'name';
|
122
|
-
var counter_limit = $(this).data('counter-limit') ? Number(
|
123
|
-
data['q['+search_key+']'] =
|
175
|
+
var counter_limit = $(this).data('counter-limit') ? Number($(this).data('counter-limit')) : 0;
|
176
|
+
data['q['+search_key+']'] = search;
|
124
177
|
$.ajax({
|
125
178
|
context: select,
|
126
179
|
data: data,
|
127
|
-
url: $(this).data(
|
128
|
-
complete: function(
|
129
|
-
$(this).data(
|
180
|
+
url: $(this).data('remote-collection'),
|
181
|
+
complete: function(req, status) {
|
182
|
+
$(this).data('searching', '');
|
130
183
|
},
|
131
|
-
success: function(
|
132
|
-
var sel = $(this);
|
184
|
+
success: function(data, status, req) {
|
185
|
+
var first = false, sel = $(this);
|
133
186
|
sel.empty();
|
134
|
-
data
|
135
|
-
|
187
|
+
if(sel.data('include-blank')) sel.append($('<option>', { value: '', text: '' }));
|
188
|
+
data.forEach(function(item) {
|
189
|
+
sel.append($('<option>', { value: item[value_key], text: item[text_key] }));
|
190
|
+
if(!first) first = item[value_key];
|
136
191
|
});
|
137
|
-
sel.parent().find(
|
192
|
+
sel.parent().find('.status').text('[' + ((counter_limit > 0 && data.length >= counter_limit) ? (counter_limit + '+') : data.length) + ']');
|
193
|
+
if(first) sel.val(first);
|
138
194
|
},
|
139
195
|
});
|
140
196
|
}
|
141
|
-
}, 500
|
142
|
-
|
197
|
+
}, 500);
|
198
|
+
|
199
|
+
$('.select-one-inputs').each(function() {
|
200
|
+
$(this).find('.search-select').on('keydown', function(event) {
|
201
|
+
if(event.which == 38) { // up arrow
|
202
|
+
event.preventDefault();
|
203
|
+
var select = $(this).closest('.select-one-inputs').find('[data-select="src"]');
|
204
|
+
var prev = select.find(':selected').prev();
|
205
|
+
if(prev.length) select.val(prev.val());
|
206
|
+
}
|
207
|
+
else if(event.which == 40) { // down arrow
|
208
|
+
event.preventDefault();
|
209
|
+
var select = $(this).closest('.select-one-inputs').find('[data-select="src"]');
|
210
|
+
var next = select.find(':selected').next();
|
211
|
+
if(next.length) select.val(next.val());
|
212
|
+
}
|
213
|
+
else $.proxy(onRemoteSelectOne, $(this))(event);
|
214
|
+
});
|
215
|
+
$(this).find('[data-select="src"]').on('keydown', function(event) {
|
216
|
+
if(event.which == 37) { // left arrow
|
217
|
+
event.preventDefault();
|
218
|
+
$(this).closest('.select-one-inputs').find('.search-select').focus();
|
219
|
+
}
|
220
|
+
});
|
221
|
+
});
|
143
222
|
});
|
@@ -1,18 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Formtastic
|
2
4
|
module Inputs
|
3
5
|
class SelectManyInput < SelectInput
|
4
6
|
def to_html
|
5
|
-
options[:'data-remote-collection'] = options.delete(
|
7
|
+
options[:'data-remote-collection'] = options.delete(:remote_collection)
|
6
8
|
opts = { class: 'select-many-inputs' }
|
7
|
-
opts[:sortable] = options.delete(
|
9
|
+
opts[:sortable] = options.delete(:sortable) if options[:sortable]
|
8
10
|
input_wrapping do
|
9
11
|
label_html <<
|
10
|
-
template.content_tag(
|
12
|
+
template.content_tag(:div, opts) do
|
11
13
|
hidden_input <<
|
12
14
|
search_box_html <<
|
13
|
-
template.content_tag(
|
14
|
-
template.content_tag(
|
15
|
-
template.content_tag(
|
15
|
+
template.content_tag(:span, '', class: 'empty') <<
|
16
|
+
template.content_tag(:span, ::I18n.t('inputs.select_many.available'), class: 'available') <<
|
17
|
+
template.content_tag(:span, ::I18n.t('inputs.select_many.selected'), class: 'selected') <<
|
16
18
|
select_src_html <<
|
17
19
|
buttons_html <<
|
18
20
|
select_dst_html
|
@@ -21,48 +23,72 @@ module Formtastic
|
|
21
23
|
end
|
22
24
|
|
23
25
|
def hidden_input
|
24
|
-
template.content_tag(
|
25
|
-
values = object.send(
|
26
|
-
values = [values] if values.is_a?
|
26
|
+
template.content_tag(:div, class: 'values', 'data-name': input_html_options[:name]) do
|
27
|
+
values = object.send(input_name)
|
28
|
+
values = [values] if values.is_a? Integer
|
27
29
|
values.each do |value|
|
28
|
-
template.concat template.hidden_field_tag(
|
30
|
+
template.concat template.hidden_field_tag(input_html_options[:name], value, {id: nil})
|
29
31
|
end if values
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
33
35
|
def buttons_html
|
34
|
-
template.content_tag(
|
35
|
-
template.link_to(
|
36
|
-
template.link_to(
|
37
|
-
template.link_to(
|
38
|
-
template.link_to(
|
36
|
+
template.content_tag(:div, class: 'buttons') do
|
37
|
+
template.link_to('→'.html_safe, 'Javascript:void(0)', class: 'add') +
|
38
|
+
template.link_to('←'.html_safe, 'Javascript:void(0)', class: 'remove') +
|
39
|
+
template.link_to('↑'.html_safe, 'Javascript:void(0)', class: 'move_up') +
|
40
|
+
template.link_to('↓'.html_safe, 'Javascript:void(0)', class: 'move_down')
|
39
41
|
end
|
40
42
|
end
|
41
43
|
|
42
44
|
def search_box_html
|
43
|
-
|
44
|
-
|
45
|
+
opts = {
|
46
|
+
id: nil,
|
47
|
+
class: 'search-select',
|
48
|
+
placeholder: options.delete(:placeholder),
|
49
|
+
'data-counter-limit': options[:counter_limit].to_i,
|
50
|
+
'data-remote-collection': options[:'data-remote-collection'],
|
51
|
+
'data-search': options[:search_param] ? options[:search_param] : 'name_contains',
|
52
|
+
'data-text': options[:member_label] ? options[:member_label] : (options[:text_key] ? options[:text_key] : 'name'),
|
53
|
+
'data-value': options[:value_key] ? options[:value_key] : 'id',
|
54
|
+
}
|
55
|
+
template.text_field_tag(nil, '', opts)
|
45
56
|
end
|
46
57
|
|
47
58
|
def select_src_html
|
48
|
-
coll =
|
49
|
-
[]
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
59
|
+
coll =
|
60
|
+
if options[:'data-remote-collection']
|
61
|
+
[]
|
62
|
+
else
|
63
|
+
# TODO: add option unique ?
|
64
|
+
selected = object.send(input_name)
|
65
|
+
selected = [selected] if selected.is_a? Integer
|
66
|
+
selected ? collection.select { |option| !selected.include?(option[1]) } : collection
|
67
|
+
end
|
68
|
+
opts = {
|
69
|
+
id: nil,
|
70
|
+
include_blank: false,
|
71
|
+
multiple: true,
|
72
|
+
name: nil,
|
73
|
+
size: options[:size] || 4,
|
74
|
+
'data-select': 'src'
|
75
|
+
}
|
76
|
+
template.select_tag nil, template.options_for_select(coll), input_options.merge(opts)
|
58
77
|
end
|
59
78
|
|
60
79
|
def select_dst_html
|
61
|
-
selected = options[:selected]
|
62
|
-
selected = [selected] if selected.is_a?
|
63
|
-
coll = selected ? collection.select { |option| selected.include?(
|
64
|
-
opts =
|
65
|
-
|
80
|
+
selected = options[:selected] || object.send(input_name)
|
81
|
+
selected = [selected] if selected.is_a? Integer
|
82
|
+
coll = selected ? collection.select { |option| selected.include?(option[1]) } : []
|
83
|
+
opts = {
|
84
|
+
id: nil,
|
85
|
+
include_blank: false,
|
86
|
+
multiple: true,
|
87
|
+
name: nil,
|
88
|
+
size: options[:size] || 4,
|
89
|
+
'data-select': 'dst'
|
90
|
+
}
|
91
|
+
template.select_tag nil, template.options_for_select(coll), input_options.merge(opts)
|
66
92
|
end
|
67
93
|
end
|
68
94
|
end
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Formtastic
|
2
4
|
module Inputs
|
3
5
|
class SelectOneInput < SelectInput
|
4
|
-
def input_options
|
5
|
-
|
6
|
-
end
|
6
|
+
# def input_options
|
7
|
+
# super.merge include_blank: false
|
8
|
+
# end
|
7
9
|
|
8
10
|
def input_wrapping(&block)
|
9
11
|
template.content_tag(options[:filter_form] ? :div : :li,
|
@@ -16,30 +18,35 @@ module Formtastic
|
|
16
18
|
opts = { class: 'select-one-inputs' }
|
17
19
|
input_wrapping do
|
18
20
|
label_html <<
|
19
|
-
template.content_tag(
|
21
|
+
template.content_tag(:div, opts) do
|
20
22
|
search_box <<
|
21
23
|
select_html <<
|
22
|
-
template.content_tag(
|
24
|
+
template.content_tag(:span, '', class: 'status')
|
23
25
|
end
|
24
26
|
end
|
25
27
|
end
|
26
28
|
|
27
29
|
def search_box
|
28
30
|
# TODO: remove text_key in next major version
|
29
|
-
|
30
|
-
|
31
|
+
opts = {
|
32
|
+
id: nil,
|
33
|
+
class: 'search-select',
|
34
|
+
placeholder: options[:placeholder],
|
35
|
+
'data-counter-limit': options[:counter_limit].to_i,
|
36
|
+
'data-msg': options[:msg_items],
|
37
|
+
'data-remote-collection': options[:remote_collection],
|
38
|
+
'data-search': options[:search_param] || 'name_contains',
|
39
|
+
'data-text': options[:member_label] || options[:text_key] || 'name',
|
40
|
+
'data-value': options[:value_key] || 'id'
|
41
|
+
}
|
42
|
+
template.text_field_tag(nil, '', opts)
|
31
43
|
end
|
32
44
|
|
33
45
|
def select_html
|
34
|
-
selected = options[:selected]
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
sel = template.options_for_select( [item], selected ) if item[1] == selected
|
39
|
-
break
|
40
|
-
end
|
41
|
-
end
|
42
|
-
builder.select(input_name, sel, input_options, input_html_options.merge( 'data-select': 'src' ) )
|
46
|
+
selected = options[:selected] || object.send(input_name)
|
47
|
+
opts = input_html_options.merge('data-select': 'src')
|
48
|
+
opts['data-include-blank'] = '1' if input_options[:include_blank]
|
49
|
+
template.select_tag input_name, template.options_for_select(collection, selected), input_options.merge(opts)
|
43
50
|
end
|
44
51
|
end
|
45
52
|
end
|
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.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mattia Roccoberton
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-08-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activeadmin
|
@@ -16,14 +16,140 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '2.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activestorage
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 6.0.3.2
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 6.0.3.2
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: capybara
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 3.33.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 3.33.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.13.1
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.13.1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: puma
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 4.3.5
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 4.3.5
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec_junit_formatter
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.4.1
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.4.1
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec-rails
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 4.0.1
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 4.0.1
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: selenium-webdriver
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 3.142.7
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 3.142.7
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: simplecov
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 0.19.0
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 0.19.0
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: sqlite3
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 1.4.2
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 1.4.2
|
27
153
|
description: An Active Admin plugin which improves one-to-many and many-to-many associations
|
28
154
|
selection (jQuery required)
|
29
155
|
email: mat@blocknot.es
|
@@ -31,12 +157,9 @@ executables: []
|
|
31
157
|
extensions: []
|
32
158
|
extra_rdoc_files: []
|
33
159
|
files:
|
34
|
-
- ".gitignore"
|
35
|
-
- Gemfile
|
36
160
|
- LICENSE.txt
|
37
161
|
- README.md
|
38
162
|
- Rakefile
|
39
|
-
- activeadmin_select_many.gemspec
|
40
163
|
- app/assets/javascripts/activeadmin/select_many.js
|
41
164
|
- app/assets/stylesheets/activeadmin/_select_many.sass
|
42
165
|
- config/locales/en.yml
|
@@ -46,12 +169,11 @@ files:
|
|
46
169
|
- lib/activeadmin_select_many.rb
|
47
170
|
- lib/formtastic/inputs/select_many_input.rb
|
48
171
|
- lib/formtastic/inputs/select_one_input.rb
|
49
|
-
- screenshot.png
|
50
172
|
homepage: https://github.com/blocknotes/activeadmin_select_many
|
51
173
|
licenses:
|
52
174
|
- MIT
|
53
175
|
metadata: {}
|
54
|
-
post_install_message:
|
176
|
+
post_install_message:
|
55
177
|
rdoc_options: []
|
56
178
|
require_paths:
|
57
179
|
- lib
|
@@ -66,9 +188,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
66
188
|
- !ruby/object:Gem::Version
|
67
189
|
version: '0'
|
68
190
|
requirements: []
|
69
|
-
|
70
|
-
|
71
|
-
signing_key:
|
191
|
+
rubygems_version: 3.0.3
|
192
|
+
signing_key:
|
72
193
|
specification_version: 4
|
73
194
|
summary: SelectMany plugin for ActiveAdmin
|
74
195
|
test_files: []
|
data/.gitignore
DELETED
data/Gemfile
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
lib = File.expand_path('../lib', __FILE__)
|
2
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
-
require 'activeadmin/select_many/version'
|
4
|
-
|
5
|
-
Gem::Specification.new do |spec|
|
6
|
-
spec.name = 'activeadmin_select_many'
|
7
|
-
spec.version = ActiveAdmin::SelectMany::VERSION
|
8
|
-
spec.summary = 'SelectMany plugin for ActiveAdmin'
|
9
|
-
spec.description = 'An Active Admin plugin which improves one-to-many and many-to-many associations selection (jQuery required)'
|
10
|
-
spec.license = 'MIT'
|
11
|
-
spec.authors = ['Mattia Roccoberton']
|
12
|
-
spec.email = 'mat@blocknot.es'
|
13
|
-
spec.homepage = 'https://github.com/blocknotes/activeadmin_select_many'
|
14
|
-
|
15
|
-
spec.files = `git ls-files -z`.split("\x0")
|
16
|
-
spec.require_paths = ['lib']
|
17
|
-
|
18
|
-
spec.add_runtime_dependency 'activeadmin', '~> 1.0'
|
19
|
-
end
|
data/screenshot.png
DELETED
Binary file
|