activeadmin_dynamic_fields 0.2.0 → 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 +5 -5
- data/README.md +57 -53
- data/Rakefile +2 -2
- data/app/assets/javascripts/activeadmin/dynamic_fields.js +185 -194
- data/lib/activeadmin/dynamic_fields.rb +2 -0
- data/lib/activeadmin/dynamic_fields/engine.rb +28 -11
- data/lib/activeadmin/dynamic_fields/version.rb +3 -1
- data/lib/activeadmin_dynamic_fields.rb +2 -0
- metadata +134 -12
- data/.gitignore +0 -3
- data/Gemfile +0 -4
- data/activeadmin_dynamic_fields.gemspec +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1af148e7cd9d7704c902e17fdb022acbb1c0c2012bf423f9be6e4ae92cdb6f5f
|
4
|
+
data.tar.gz: ad108b3ae42ba846251dcab61487e68809e4cfaf21e453039a7ad3cb0cb22bd8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0c76b4cb42b90bf7c88c4cafbbab1bb40f8fa61efbaa8acef0cb3230c6dd2f3eea3b0bf88413431c2a275538ef7c1f37aa0463a2445f0e2a61eae17b189955b5
|
7
|
+
data.tar.gz: d09b1cfe869567e5634236a31385608800375be5cef690b5ee1c420d2cba8a5018f642c5bec0d2996078338a8bdfa0499c02d839e264b9704fb5581e5659d44d
|
data/README.md
CHANGED
@@ -1,36 +1,37 @@
|
|
1
|
-
# ActiveAdmin Dynamic Fields [](https://badge.fury.io/rb/activeadmin_dynamic_fields)
|
1
|
+
# ActiveAdmin Dynamic Fields [](https://badge.fury.io/rb/activeadmin_dynamic_fields) [](https://circleci.com/gh/blocknotes/activeadmin_dynamic_fields)
|
2
2
|
|
3
|
-
An Active Admin plugin to add dynamic behaviors to fields.
|
3
|
+
An Active Admin plugin to add dynamic behaviors to some fields.
|
4
4
|
|
5
5
|
Features:
|
6
|
-
|
7
6
|
- set conditional checks on fields
|
8
|
-
- trigger
|
7
|
+
- trigger actions on target elements
|
9
8
|
- inline field editing
|
10
9
|
- create links to load some content in a dialog
|
11
10
|
|
12
|
-
The easiest way to show how this plugin works is looking the examples [below](#examples
|
11
|
+
The easiest way to show how this plugin works is looking the examples [below](#examples).
|
13
12
|
|
14
13
|
## Install
|
15
|
-
|
16
14
|
- Add to your Gemfile: `gem 'activeadmin_dynamic_fields'`
|
17
15
|
- Execute bundle
|
18
16
|
- Add at the end of your ActiveAdmin javascripts (_app/assets/javascripts/active_admin.js_):
|
19
|
-
`//= require activeadmin/dynamic_fields`
|
20
17
|
|
21
|
-
|
18
|
+
```js
|
19
|
+
//= require activeadmin/dynamic_fields
|
20
|
+
```
|
22
21
|
|
22
|
+
## Options
|
23
23
|
Options are passed to fields using *input_html* parameter as *data* attributes:
|
24
|
-
|
25
24
|
- **data-if**: check a condition, values:
|
26
25
|
+ **checked**: check if a checkbox is checked
|
27
26
|
+ **not_checked**: check if a checkbox is not checked
|
28
27
|
+ **blank**: check if a field is blank
|
29
28
|
+ **not_blank**: check if a field is not blank
|
29
|
+
+ **changed**: check if the value of an input is changed (dirty)
|
30
30
|
- **data-eq**: check if a field has a specific value
|
31
31
|
- **data-not**: check if a field hasn't a specific value
|
32
|
-
- **data-target**: target css selector
|
33
|
-
- **data-
|
32
|
+
- **data-target**: target css selector (from parent fieldset, look for the closest match)
|
33
|
+
- **data-gtarget**: target css selector globally
|
34
|
+
- **data-then**: the action to trigger (alias **data-action**), values:
|
34
35
|
+ **hide**: hides elements
|
35
36
|
+ **slide**: hides elements (using sliding)
|
36
37
|
+ **fade**: hides elements (using fading)
|
@@ -40,50 +41,51 @@ Options are passed to fields using *input_html* parameter as *data* attributes:
|
|
40
41
|
- **data-function**: check the return value of a custom function
|
41
42
|
- **data-arg**: argument passed to the custom set function (as array of strings)
|
42
43
|
|
44
|
+
A check condition or a custom check function are required. A trigger action is required too, unless you are using a custom function (in that case it is optional).
|
45
|
+
|
43
46
|
## Examples
|
44
47
|
|
45
48
|
### Dynamic fields examples
|
46
|
-
|
47
|
-
- A checkbox that hides other fields if false (ex. model *Article*):
|
49
|
+
- A checkbox that hides other fields if is checked (ex. model *Article*):
|
48
50
|
|
49
51
|
```rb
|
50
52
|
form do |f|
|
51
53
|
f.inputs 'Article' do
|
52
|
-
f.input :published, input_html: { data: { if: '
|
54
|
+
f.input :published, input_html: { data: { if: 'checked', then: 'hide', target: '.grp1' } }
|
53
55
|
f.input :online_date, wrapper_html: { class: 'grp1' }
|
54
|
-
f.input :
|
56
|
+
f.input :draft_notes, wrapper_html: { class: 'grp1' }
|
55
57
|
end
|
56
58
|
f.actions
|
57
59
|
end
|
58
60
|
```
|
59
61
|
|
60
|
-
- Add 3 classes (*first*, *second*, *third*) if a checkbox is
|
62
|
+
- Add 3 classes (*first*, *second*, *third*) if a checkbox is not checked:
|
61
63
|
|
62
|
-
`f.input :published, input_html: { data: { if: '
|
64
|
+
`f.input :published, input_html: { data: { if: 'not_checked', then: 'addClass first second third', target: '.grp1' } }`
|
63
65
|
|
64
66
|
- Set another field value if a string field is blank:
|
65
67
|
|
66
|
-
`f.input :title, input_html: { data: { if: 'blank',
|
68
|
+
`f.input :title, input_html: { data: { if: 'blank', then: 'setValue 10', target: '#article_position' } }`
|
67
69
|
|
68
70
|
- Use a custom function for conditional check (*title_not_empty()* must be available on global scope) (with alternative syntax for data attributes):
|
69
71
|
|
70
|
-
`f.input :title, input_html: { 'data-function': 'title_empty', 'data-
|
72
|
+
`f.input :title, input_html: { 'data-function': 'title_empty', 'data-then': 'slide', 'data-target': '#article_description_input' }`
|
71
73
|
|
72
74
|
```js
|
73
|
-
function title_empty(
|
74
|
-
return (
|
75
|
+
function title_empty(el) {
|
76
|
+
return ($('#article_title').val().trim() === '');
|
75
77
|
}
|
76
78
|
```
|
77
79
|
|
78
80
|
- Call a callback function as action:
|
79
81
|
|
80
|
-
`f.input :published, input_html: { data: { if: 'checked',
|
82
|
+
`f.input :published, input_html: { data: { if: 'checked', then: 'callback set_title', args: '["Unpublished !"]' } }`
|
81
83
|
|
82
84
|
```js
|
83
|
-
function set_title(
|
84
|
-
if(
|
85
|
-
$('#article_title').val(
|
86
|
-
$('#article_title').trigger(
|
85
|
+
function set_title(args) {
|
86
|
+
if($('#article_title').val().trim() === '') {
|
87
|
+
$('#article_title').val(args[0]);
|
88
|
+
$('#article_title').trigger('change');
|
87
89
|
}
|
88
90
|
}
|
89
91
|
```
|
@@ -93,22 +95,21 @@ function set_title( args ) {
|
|
93
95
|
`f2.input :category, as: :select, collection: [ [ 'Cat 1', 'cat1' ], [ 'Cat 2', 'cat2' ], [ 'Cat 3', 'cat3' ] ], input_html: { 'data-function': 'on_change_category' }`
|
94
96
|
|
95
97
|
```js
|
96
|
-
function on_change_category(
|
97
|
-
var target = el.closest(
|
98
|
-
target.prop(
|
99
|
-
target.trigger(
|
98
|
+
function on_change_category(el) {
|
99
|
+
var target = el.closest('fieldset').find('.pub');
|
100
|
+
target.prop('checked', (el.val() == 'cat2');
|
101
|
+
target.trigger('change');
|
100
102
|
}
|
101
103
|
```
|
102
104
|
|
103
|
-
### Inline editing
|
104
|
-
|
105
|
+
### Inline editing examples
|
105
106
|
- Prepare a custom member action to save data, an *update* helper function is available (third parameter is optional, allow to filter using strong parameters):
|
106
107
|
|
107
108
|
```rb
|
108
109
|
member_action :save, method: [:post] do
|
109
|
-
render ActiveAdmin::DynamicFields
|
110
|
-
# render ActiveAdmin::DynamicFields
|
111
|
-
# render ActiveAdmin::DynamicFields
|
110
|
+
render ActiveAdmin::DynamicFields.update(resource, params)
|
111
|
+
# render ActiveAdmin::DynamicFields.update(resource, params, [:published])
|
112
|
+
# render ActiveAdmin::DynamicFields.update(resource, params, Article::permit_params)
|
112
113
|
end
|
113
114
|
```
|
114
115
|
|
@@ -117,29 +118,28 @@ end
|
|
117
118
|
```rb
|
118
119
|
# Edit a string:
|
119
120
|
column :title do |row|
|
120
|
-
div row.title, ActiveAdmin::DynamicFields
|
121
|
+
div row.title, ActiveAdmin::DynamicFields.edit_string(:title, save_admin_article_path(row.id))
|
121
122
|
end
|
122
123
|
# Edit a boolean:
|
123
124
|
column :published do |row|
|
124
|
-
status_tag row.published, ActiveAdmin::DynamicFields
|
125
|
+
status_tag row.published, ActiveAdmin::DynamicFields.edit_boolean(:published, save_admin_article_path(row.id), row.published)
|
125
126
|
end
|
126
127
|
# Edit a select ([''] allow to have a blank value):
|
127
128
|
column :author do |row|
|
128
|
-
select ActiveAdmin::DynamicFields
|
129
|
-
options_for_select(
|
129
|
+
select ActiveAdmin::DynamicFields.edit_select(:author_id, save_admin_article_path(row.id)) do
|
130
|
+
options_for_select([''] + Author.pluck(:name, :id), row.author_id)
|
130
131
|
end
|
131
132
|
end
|
132
133
|
```
|
133
134
|
|
134
|
-
- In *show* config (
|
135
|
+
- In *show* config (inside `attributes_table` block):
|
135
136
|
```rb
|
136
137
|
row :title do |row|
|
137
|
-
div row.title, ActiveAdmin::DynamicFields
|
138
|
+
div row.title, ActiveAdmin::DynamicFields.edit_string(:title, save_admin_article_path(row.id))
|
138
139
|
end
|
139
140
|
```
|
140
141
|
|
141
142
|
### Dialog example
|
142
|
-
|
143
143
|
Example with 2 models: *Author* and *Article*
|
144
144
|
|
145
145
|
Prepare the content dialog - in Active Admin Author config:
|
@@ -148,12 +148,16 @@ Prepare the content dialog - in Active Admin Author config:
|
|
148
148
|
ActiveAdmin.register Author do
|
149
149
|
# ...
|
150
150
|
member_action :dialog do
|
151
|
-
|
152
|
-
|
153
|
-
|
151
|
+
record = resource
|
152
|
+
context = Arbre::Context.new do
|
153
|
+
dl do
|
154
|
+
%i[name age created_at].each do |field|
|
155
|
+
dt "#{Author.human_attribute_name(field)}:"
|
156
|
+
dd record[field]
|
157
|
+
end
|
158
|
+
end
|
154
159
|
end
|
155
|
-
|
156
|
-
render plain: content
|
160
|
+
render plain: context
|
157
161
|
end
|
158
162
|
# ...
|
159
163
|
end
|
@@ -168,7 +172,7 @@ ActiveAdmin.register Article do
|
|
168
172
|
attributes_table do
|
169
173
|
# ...
|
170
174
|
row :author do
|
171
|
-
link_to object.author.name, dialog_admin_author_path(
|
175
|
+
link_to object.author.name, dialog_admin_author_path(object.author), title: object.author.name, 'data-df-dialog': true, 'data-df-icon': true
|
172
176
|
end
|
173
177
|
end
|
174
178
|
end
|
@@ -179,13 +183,13 @@ end
|
|
179
183
|
The link url is loaded via AJAX before opening the dialog.
|
180
184
|
|
181
185
|
## Do you like it? Star it!
|
182
|
-
|
183
186
|
If you use this component just star it. A developer is more motivated to improve a project when there is some interest.
|
184
187
|
|
185
|
-
|
188
|
+
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.
|
186
189
|
|
187
|
-
|
190
|
+
## Contributors
|
191
|
+
- [Mattia Roccoberton](http://blocknot.es): author
|
192
|
+
- The good guys that opened issues and pull requests from time to time
|
188
193
|
|
189
194
|
## License
|
190
|
-
|
191
|
-
[MIT](LICENSE.txt)
|
195
|
+
The gem is available as open-source under the terms of the [MIT](LICENSE.txt).
|
data/Rakefile
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require 'bundler/gem_tasks'
|
@@ -1,208 +1,199 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
return el.val().length !== 0 && el.val().trim();
|
18
|
-
}
|
19
|
-
else if( args.eq ) {
|
20
|
-
return el.val() == args.eq;
|
21
|
-
}
|
22
|
-
else if( args.not ) {
|
23
|
-
return el.val() != args.not;
|
24
|
-
}
|
25
|
-
return undefined;
|
26
|
-
}
|
27
|
-
|
28
|
-
// Prepare a field
|
29
|
-
function dfSetupField( el ) {
|
30
|
-
var action = el.data( 'action' );
|
31
|
-
var target, args = {};
|
32
|
-
args.if = el.data( 'if' );
|
33
|
-
args.eq = el.data( 'eq' );
|
34
|
-
args.not = el.data( 'not' );
|
35
|
-
args.fn = el.data( 'function' );
|
36
|
-
if( el.data( 'target' ) ) target = el.closest( 'fieldset' ).find( el.data( 'target' ) )
|
37
|
-
if( action == 'hide' ) {
|
38
|
-
if( dfEvalCondition( el, args ) ) target.show();
|
39
|
-
else target.hide();
|
40
|
-
el.on( 'change', function( event ) {
|
41
|
-
if( dfEvalCondition( $(this), args ) ) target.show();
|
42
|
-
else target.hide();
|
43
|
-
});
|
44
|
-
}
|
45
|
-
else if( action == 'slide' ) {
|
46
|
-
if( dfEvalCondition( el, args ) ) target.slideDown();
|
47
|
-
else target.slideUp();
|
48
|
-
el.on( 'change', function( event ) {
|
49
|
-
if( dfEvalCondition( $(this), args ) ) target.slideDown();
|
50
|
-
else target.slideUp();
|
51
|
-
});
|
1
|
+
(function () {
|
2
|
+
'use strict'
|
3
|
+
|
4
|
+
const ACTIONS = {
|
5
|
+
addClass: (el, name) => el.addClass(name),
|
6
|
+
callback: (el, name) => {
|
7
|
+
if (window[name]) window[name](el.data('args'))
|
8
|
+
else {
|
9
|
+
el.attr('data-df-errors', 'callback function not found')
|
10
|
+
console.warn(`activeadmin_dynamic_fields callback function not found: ${name}`)
|
11
|
+
}
|
12
|
+
},
|
13
|
+
fade: el => el.fadeOut(),
|
14
|
+
hide: el => el.hide(),
|
15
|
+
setValue: (el, value) => dfSetValue(el, value),
|
16
|
+
slide: el => el.slideUp()
|
52
17
|
}
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
18
|
+
|
19
|
+
const CONDITIONS = {
|
20
|
+
blank: el => el.val().length === 0 || !el.val().trim(),
|
21
|
+
changed: _el => true,
|
22
|
+
checked: el => el.is(':checked'),
|
23
|
+
eq: (el, value) => el.val() == value,
|
24
|
+
not: (el, value) => el.val() != value,
|
25
|
+
not_blank: el => el.val().trim(),
|
26
|
+
not_checked: el => !el.is(':checked')
|
60
27
|
}
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
el
|
65
|
-
|
66
|
-
|
28
|
+
|
29
|
+
const REVERSE_ACTIONS = {
|
30
|
+
addClass: (el, name) => el.removeClass(name),
|
31
|
+
fade: el => el.fadeIn(),
|
32
|
+
hide: el => el.show(),
|
33
|
+
slide: el => el.slideDown()
|
67
34
|
}
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
35
|
+
|
36
|
+
function dfEvalCondition(el) {
|
37
|
+
let condition = CONDITIONS[el.data('if')]
|
38
|
+
let condition_arg
|
39
|
+
|
40
|
+
if(!condition && el.data('eq')) {
|
41
|
+
condition = CONDITIONS['eq']
|
42
|
+
condition_arg = el.data('eq')
|
43
|
+
}
|
44
|
+
if(!condition && el.data('not')) {
|
45
|
+
condition = CONDITIONS['not']
|
46
|
+
condition_arg = el.data('not')
|
75
47
|
}
|
76
|
-
|
48
|
+
if(!condition && el.data('function')) {
|
49
|
+
condition = window[el.data('function')]
|
50
|
+
if(!condition) {
|
51
|
+
el.attr('data-df-errors', 'custom function not found')
|
52
|
+
console.warn(`activeadmin_dynamic_fields custom function not found: ${el.data('function')}`)
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
return [condition, condition_arg]
|
77
57
|
}
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
58
|
+
|
59
|
+
function dfInitField(el) {
|
60
|
+
const [condition, condition_arg] = dfEvalCondition(el)
|
61
|
+
const action_name = (el.data('then') || el.data('action') || '').substr(0, 8)
|
62
|
+
const action = ACTIONS[action_name]
|
63
|
+
const arg = (el.data('then') || el.data('action') || '').substr(9)
|
64
|
+
const reverse_action = REVERSE_ACTIONS[action_name]
|
65
|
+
if (typeof condition === 'undefined') return
|
66
|
+
if (typeof action === 'undefined' && !el.data('function')) return
|
67
|
+
|
68
|
+
// closest find for has many associations
|
69
|
+
let target
|
70
|
+
if (el.data('target')) target = el.closest('fieldset').find(el.data('target'))
|
71
|
+
else if (el.data('gtarget')) target = $(el.data('gtarget'))
|
72
|
+
if (action_name == 'callback') target = el
|
73
|
+
|
74
|
+
if (condition(el, condition_arg) && el.data('if') != 'changed') action(target, arg)
|
75
|
+
else if (reverse_action) reverse_action(target, arg)
|
76
|
+
|
77
|
+
el.on('change', () => {
|
78
|
+
if (condition(el, condition_arg)) action(target, arg)
|
79
|
+
else if (reverse_action) reverse_action(target, arg)
|
80
|
+
})
|
86
81
|
}
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
82
|
+
|
83
|
+
// Set the value of an element
|
84
|
+
function dfSetValue(el, val) {
|
85
|
+
if (el.attr('type') == 'checkbox') el.prop('checked', val == '1')
|
86
|
+
else el.val(val)
|
87
|
+
el.trigger('change')
|
92
88
|
}
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
if( $(this).data( 'show-errors' ) ) {
|
125
|
-
var result = '';
|
126
|
-
var message = data.message;
|
127
|
-
for( var key in message ) {
|
128
|
-
if( typeof( message[key] ) === 'object' ) {
|
129
|
-
if( result ) result += ' - ';
|
130
|
-
result += key + ': ' + message[key].join( '; ' );
|
89
|
+
|
90
|
+
// Inline update - must be called binded on the editing element
|
91
|
+
function dfUpdateField() {
|
92
|
+
if ($(this).data('loading') != '1') {
|
93
|
+
$(this).data('loading', '1');
|
94
|
+
let _this = $(this);
|
95
|
+
let type = $(this).data('field-type');
|
96
|
+
let new_value;
|
97
|
+
if (type == 'boolean') new_value = !$(this).data('field-value');
|
98
|
+
else if (type == 'select') new_value = $(this).val();
|
99
|
+
else new_value = $(this).text();
|
100
|
+
let data = {};
|
101
|
+
data[$(this).data('field')] = new_value;
|
102
|
+
$.ajax({
|
103
|
+
context: _this,
|
104
|
+
data: { data: data },
|
105
|
+
method: 'POST',
|
106
|
+
url: $(this).data('save-url'),
|
107
|
+
complete: function (req, status) {
|
108
|
+
$(this).data('loading', '0');
|
109
|
+
},
|
110
|
+
success: function (data, status, req) {
|
111
|
+
if (data.status == 'error') {
|
112
|
+
if ($(this).data('show-errors')) {
|
113
|
+
let result = '';
|
114
|
+
let message = data.message;
|
115
|
+
for (let key in message) {
|
116
|
+
if (typeof (message[key]) === 'object') {
|
117
|
+
if (result) result += ' - ';
|
118
|
+
result += key + ': ' + message[key].join('; ');
|
119
|
+
}
|
131
120
|
}
|
121
|
+
if (result) alert(result);
|
132
122
|
}
|
133
|
-
if( result ) alert( result );
|
134
123
|
}
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
124
|
+
else {
|
125
|
+
$(this).data('field-value', new_value);
|
126
|
+
if ($(this).data('content')) {
|
127
|
+
let old_text = $(this).text();
|
128
|
+
let old_class = $(this).attr('class');
|
129
|
+
let content = $($(this).data('content'));
|
130
|
+
$(this).text(content.text());
|
131
|
+
$(this).attr('class', content.attr('class'));
|
132
|
+
content.text(old_text);
|
133
|
+
content.attr('class', old_class);
|
134
|
+
$(this).data('content', content);
|
135
|
+
}
|
147
136
|
}
|
148
137
|
}
|
149
|
-
},
|
150
|
-
// error: function( req, status, error ) {
|
151
|
-
// // if( $(this).data( 'show-errors' ) && req.responseJSON.message ) { }
|
152
|
-
// },
|
153
|
-
});
|
154
|
-
}
|
155
|
-
}
|
156
|
-
|
157
|
-
// Init
|
158
|
-
$(document).ready( function() {
|
159
|
-
// Setup dynamic fields
|
160
|
-
$('.active_admin .input [data-if], .active_admin .input [data-function], .active_admin .input [data-eq], .active_admin .input [data-not]').each( function() {
|
161
|
-
dfSetupField( $(this) );
|
162
|
-
});
|
163
|
-
// Setup dynamic fields for has many associations
|
164
|
-
$('.active_admin .has_many_container').on( 'has_many_add:after', function( e, fieldset, container ) {
|
165
|
-
$('.active_admin .input [data-if], .active_admin .input [data-function], .active_admin .input [data-eq], .active_admin .input [data-not]').each( function() {
|
166
|
-
dfSetupField( $(this) );
|
167
|
-
});
|
168
|
-
});
|
169
|
-
// Set dialog icon link
|
170
|
-
$('.active_admin [data-df-icon]').each( function() {
|
171
|
-
$(this).append( ' »' ); // ' •'
|
172
|
-
});
|
173
|
-
// Open content in dialog
|
174
|
-
$('.active_admin [data-df-dialog]').on( 'click', function( event ) {
|
175
|
-
event.preventDefault();
|
176
|
-
$(this).blur();
|
177
|
-
if( $('#df-dialog').data( 'loading' ) != '1' ) {
|
178
|
-
$('#df-dialog').data( 'loading', '1' );
|
179
|
-
if( $('#df-dialog').length == 0 ) $('body').append( '<div id="df-dialog"></div>' );
|
180
|
-
var title = $(this).attr( 'title' );
|
181
|
-
$.ajax({
|
182
|
-
url: $(this).attr( 'href' ),
|
183
|
-
complete: function( req, status ) {
|
184
|
-
$('#df-dialog').data( 'loading', '0' );
|
185
|
-
},
|
186
|
-
success: function( data, status, req ) {
|
187
|
-
if( title ) $('#df-dialog').attr( 'title', title );
|
188
|
-
$('#df-dialog').html( data );
|
189
|
-
$('#df-dialog').dialog({ modal: true });
|
190
|
-
},
|
191
138
|
});
|
192
139
|
}
|
193
|
-
}
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
$(
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
})
|
140
|
+
}
|
141
|
+
|
142
|
+
// Init
|
143
|
+
$(document).ready(function () {
|
144
|
+
// Setup dynamic fields
|
145
|
+
const selectors = '.active_admin .input [data-if], .active_admin .input [data-eq], .active_admin .input [data-not], .active_admin .input [data-function]'
|
146
|
+
$(selectors).each(function () {
|
147
|
+
dfInitField($(this))
|
148
|
+
})
|
149
|
+
|
150
|
+
// Setup dynamic fields for associations
|
151
|
+
$('.active_admin .has_many_container').on('has_many_add:after', () => {
|
152
|
+
$(selectors).each(function () {
|
153
|
+
dfInitField($(this))
|
154
|
+
})
|
155
|
+
})
|
156
|
+
|
157
|
+
// Set dialog icon link
|
158
|
+
$('.active_admin [data-df-icon]').each(function () {
|
159
|
+
$(this).append(' »')
|
160
|
+
})
|
161
|
+
|
162
|
+
// Open content in dialog
|
163
|
+
$('.active_admin [data-df-dialog]').on('click', function (event) {
|
164
|
+
event.preventDefault()
|
165
|
+
$(this).blur()
|
166
|
+
if ($('#df-dialog').data('loading') != '1') {
|
167
|
+
$('#df-dialog').data('loading', '1')
|
168
|
+
if ($('#df-dialog').length == 0) $('body').append('<div id="df-dialog"></div>')
|
169
|
+
let title = $(this).attr('title')
|
170
|
+
$.ajax({
|
171
|
+
url: $(this).attr('href'),
|
172
|
+
complete: function (req, status) {
|
173
|
+
$('#df-dialog').data('loading', '0')
|
174
|
+
},
|
175
|
+
success: function (data, status, req) {
|
176
|
+
if (title) $('#df-dialog').attr('title', title)
|
177
|
+
$('#df-dialog').html(data)
|
178
|
+
$('#df-dialog').dialog({ modal: true })
|
179
|
+
},
|
180
|
+
})
|
181
|
+
}
|
182
|
+
})
|
183
|
+
|
184
|
+
// Inline editing
|
185
|
+
$('[data-field][data-field-type="boolean"][data-save-url]').each(function () {
|
186
|
+
$(this).on('click', $.proxy(dfUpdateField, $(this)))
|
187
|
+
})
|
188
|
+
$('[data-field][data-field-type="string"][data-save-url]').each(function () {
|
189
|
+
$(this).data('field-value', $(this).text())
|
190
|
+
let fnUpdate = $.proxy(dfUpdateField, $(this))
|
191
|
+
$(this).on('blur', function () {
|
192
|
+
if ($(this).data('field-value') != $(this).text()) fnUpdate()
|
193
|
+
})
|
194
|
+
})
|
195
|
+
$('[data-field][data-field-type="select"][data-save-url]').each(function () {
|
196
|
+
$(this).on('change', $.proxy(dfUpdateField, $(this)))
|
197
|
+
})
|
198
|
+
})
|
199
|
+
})()
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_admin'
|
2
4
|
|
3
5
|
module ActiveAdmin
|
@@ -6,24 +8,39 @@ module ActiveAdmin
|
|
6
8
|
engine_name 'activeadmin_dynamic_fields'
|
7
9
|
end
|
8
10
|
|
9
|
-
def self.edit_boolean(
|
10
|
-
{
|
11
|
+
def self.edit_boolean(field, url, value)
|
12
|
+
{
|
13
|
+
'data-field': field,
|
14
|
+
'data-field-type': 'boolean',
|
15
|
+
'data-field-value': value,
|
16
|
+
'data-content': "<span class=\"status_tag changed\">#{value ? 'no' : 'yes'}</span>",
|
17
|
+
'data-save-url': url,
|
18
|
+
'data-show-errors': '1'
|
19
|
+
}
|
11
20
|
end
|
12
21
|
|
13
|
-
def self.edit_select(
|
14
|
-
{
|
15
|
-
|
16
|
-
|
17
|
-
|
22
|
+
def self.edit_select(field, url)
|
23
|
+
{
|
24
|
+
'data-field': field,
|
25
|
+
'data-field-type': 'select',
|
26
|
+
'data-save-url': url,
|
27
|
+
'data-show-errors': '1'
|
28
|
+
}
|
18
29
|
end
|
19
30
|
|
20
|
-
def self.edit_string(
|
21
|
-
{
|
31
|
+
def self.edit_string(field, url)
|
32
|
+
{
|
33
|
+
contenteditable: true,
|
34
|
+
'data-field': field,
|
35
|
+
'data-field-type': 'string',
|
36
|
+
'data-save-url': url,
|
37
|
+
'data-show-errors': '1'
|
38
|
+
}
|
22
39
|
end
|
23
40
|
|
24
|
-
def self.update(
|
41
|
+
def self.update(resource, params, permit_params = nil)
|
25
42
|
if params[:data]
|
26
|
-
if resource.update(
|
43
|
+
if resource.update(permit_params ? params[:data].permit(permit_params) : params[:data].permit!)
|
27
44
|
{ json: { status: 'ok' } }
|
28
45
|
else
|
29
46
|
{ json: { status: 'error', message: resource.errors } }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activeadmin_dynamic_fields
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.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-09-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activeadmin
|
@@ -16,26 +16,149 @@ 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: rubocop
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.90.0
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.90.0
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: selenium-webdriver
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 3.142.7
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 3.142.7
|
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 to add dynamic behaviors to fields
|
28
154
|
email: mat@blocknot.es
|
29
155
|
executables: []
|
30
156
|
extensions: []
|
31
157
|
extra_rdoc_files: []
|
32
158
|
files:
|
33
|
-
- ".gitignore"
|
34
|
-
- Gemfile
|
35
159
|
- LICENSE.txt
|
36
160
|
- README.md
|
37
161
|
- Rakefile
|
38
|
-
- activeadmin_dynamic_fields.gemspec
|
39
162
|
- app/assets/javascripts/activeadmin/dynamic_fields.js
|
40
163
|
- lib/activeadmin/dynamic_fields.rb
|
41
164
|
- lib/activeadmin/dynamic_fields/engine.rb
|
@@ -45,7 +168,7 @@ homepage: https://github.com/blocknotes/activeadmin_dynamic_fields
|
|
45
168
|
licenses:
|
46
169
|
- MIT
|
47
170
|
metadata: {}
|
48
|
-
post_install_message:
|
171
|
+
post_install_message:
|
49
172
|
rdoc_options: []
|
50
173
|
require_paths:
|
51
174
|
- lib
|
@@ -60,9 +183,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
60
183
|
- !ruby/object:Gem::Version
|
61
184
|
version: '0'
|
62
185
|
requirements: []
|
63
|
-
|
64
|
-
|
65
|
-
signing_key:
|
186
|
+
rubygems_version: 3.0.3
|
187
|
+
signing_key:
|
66
188
|
specification_version: 4
|
67
189
|
summary: Dynamic fields for ActiveAdmin
|
68
190
|
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/dynamic_fields/version'
|
4
|
-
|
5
|
-
Gem::Specification.new do |spec|
|
6
|
-
spec.name = 'activeadmin_dynamic_fields'
|
7
|
-
spec.version = ActiveAdmin::DynamicFields::VERSION
|
8
|
-
spec.summary = 'Dynamic fields for ActiveAdmin'
|
9
|
-
spec.description = 'An Active Admin plugin to add dynamic behaviors to fields'
|
10
|
-
spec.license = 'MIT'
|
11
|
-
spec.authors = ['Mattia Roccoberton']
|
12
|
-
spec.email = 'mat@blocknot.es'
|
13
|
-
spec.homepage = 'https://github.com/blocknotes/activeadmin_dynamic_fields'
|
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
|