activeadmin_dynamic_fields 0.2.6 → 0.4.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +85 -60
- data/Rakefile +1 -1
- data/app/assets/javascripts/activeadmin/dynamic_fields.js +217 -197
- data/lib/activeadmin/dynamic_fields/version.rb +1 -1
- metadata +136 -14
- data/.gitignore +0 -4
- data/.rubocop.yml +0 -73
- data/Gemfile +0 -4
- data/activeadmin_dynamic_fields.gemspec +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e095e90e8a67093d377cd4ba64763adead3eaf7f100e7e27a3a6ab60c2851763
|
4
|
+
data.tar.gz: ee22043cb52eea432818add1114b5e08f8b91deb450845c480ee289794f72809
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 116395a999d86f0f976a04cd7be8ba1ee994ce6bcb71c21d735e621ed037881aa24b73a57fa75e7be8062acfb6ea178e935da0e03b9d0c82f29ec8f73b7afff5
|
7
|
+
data.tar.gz: 6d7659ba3297a2f218829678bd24ea10a62703ed294822dc94ac5591671f92073d496e9d7432b6c7b80da25bd70238490e4285ef31e42c21e5a60d991c5a8448
|
data/LICENSE.txt
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c) 2017 Mattia Roccoberton
|
1
|
+
Copyright (c) 2017-2020 Mattia Roccoberton
|
2
2
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
4
|
|
data/README.md
CHANGED
@@ -1,57 +1,68 @@
|
|
1
|
-
# ActiveAdmin Dynamic Fields [![Gem Version](https://badge.fury.io/rb/activeadmin_dynamic_fields.svg)](https://badge.fury.io/rb/activeadmin_dynamic_fields)
|
1
|
+
# ActiveAdmin Dynamic Fields [![Gem Version](https://badge.fury.io/rb/activeadmin_dynamic_fields.svg)](https://badge.fury.io/rb/activeadmin_dynamic_fields) [![CircleCI](https://circleci.com/gh/blocknotes/activeadmin_dynamic_fields.svg?style=svg)](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
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
|
|
23
|
-
Options
|
22
|
+
## Options
|
23
|
+
Options are passed to fields using *input_html* parameter as *data* attributes.
|
24
24
|
|
25
|
+
Conditions:
|
25
26
|
- **data-if**: check a condition, values:
|
26
|
-
+ **checked**: check if a checkbox is checked
|
27
|
+
+ **checked**: check if a checkbox is checked (ex. `"data-if": "checked"`)
|
27
28
|
+ **not_checked**: check if a checkbox is not checked
|
28
29
|
+ **blank**: check if a field is blank
|
29
30
|
+ **not_blank**: check if a field is not blank
|
30
31
|
+ **changed**: check if the value of an input is changed (dirty)
|
31
|
-
- **data-eq**: check if a field has a specific value
|
32
|
-
- **data-not**: check if a field
|
33
|
-
- **data-
|
34
|
-
- **data-
|
35
|
-
- **data-
|
36
|
-
|
32
|
+
- **data-eq**: check if a field has a specific value (ex. `"data-eq": "42"`)
|
33
|
+
- **data-not**: check if a field has not a specific value
|
34
|
+
- **data-match**: check if a field match a regexp
|
35
|
+
- **data-mismatch**: check if a field doesn't match a regexp (ex. `"data-mismatch": "^\d+$"`)
|
36
|
+
- **data-function**: check the return value of a custom function (ex. `"data-function": "my_check"`)
|
37
|
+
|
38
|
+
Actions:
|
39
|
+
- **data-then**: action to trigger (alias **data-action**), values:
|
40
|
+
+ **hide**: hides elements (ex. `"data-then": "hide", "data-target": ".errors"`)
|
37
41
|
+ **slide**: hides elements (using sliding)
|
38
42
|
+ **fade**: hides elements (using fading)
|
39
|
-
+ **addClass**: adds classes
|
40
|
-
+ **
|
41
|
-
+ **
|
42
|
-
|
43
|
-
|
43
|
+
+ **addClass**: adds classes (ex. `"data-then": "addClass red"`)
|
44
|
+
+ **addStyle**: adds some styles (ex. `"data-then": "addStyle color: #fb1; font-size: 12px"`)
|
45
|
+
+ **setText**: set the text of an element (ex. `"data-then": "setText A sample text"`)
|
46
|
+
+ **setValue**: set the value of an input element (ex. `"data-then": "setValue A sample value"`)
|
47
|
+
+ **callback**: call a function (with arguments: **data-args**) (ex. `"data-then": "callback a_fun"`)
|
48
|
+
- **data-else**: action to trigger when the condition check is not true
|
49
|
+
- **data-args**: arguments passed to the callback function
|
50
|
+
|
51
|
+
Targets:
|
52
|
+
- **data-target**: target css selector (from parent fieldset, look for the closest match)
|
53
|
+
- **data-gtarget**: target css selector globally
|
54
|
+
|
55
|
+
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).
|
44
56
|
|
45
57
|
## Examples
|
46
58
|
|
47
59
|
### Dynamic fields examples
|
48
|
-
|
49
60
|
- A checkbox that hides other fields if is checked (ex. model *Article*):
|
50
61
|
|
51
62
|
```rb
|
52
63
|
form do |f|
|
53
64
|
f.inputs 'Article' do
|
54
|
-
f.input :published, input_html: { data: { if: 'checked',
|
65
|
+
f.input :published, input_html: { data: { if: 'checked', then: 'hide', target: '.grp1' } }
|
55
66
|
f.input :online_date, wrapper_html: { class: 'grp1' }
|
56
67
|
f.input :draft_notes, wrapper_html: { class: 'grp1' }
|
57
68
|
end
|
@@ -59,58 +70,71 @@ form do |f|
|
|
59
70
|
end
|
60
71
|
```
|
61
72
|
|
62
|
-
- Add 3 classes (*first*, *second*, *third*) if a checkbox is not checked:
|
73
|
+
- Add 3 classes (*first*, *second*, *third*) if a checkbox is not checked, else add "forth" class:
|
63
74
|
|
64
|
-
|
75
|
+
```rb
|
76
|
+
data = { if: 'not_checked', then: 'addClass first second third', target: '.grp1', else: 'addClass forth' }
|
77
|
+
f.input :published, input_html: { data: data }
|
78
|
+
```
|
65
79
|
|
66
80
|
- Set another field value if a string field is blank:
|
67
81
|
|
68
|
-
|
82
|
+
```rb
|
83
|
+
f.input :title, input_html: { data: { if: 'blank', then: 'setValue 10', target: '#article_position' } }
|
84
|
+
```
|
69
85
|
|
70
86
|
- Use a custom function for conditional check (*title_not_empty()* must be available on global scope) (with alternative syntax for data attributes):
|
71
87
|
|
72
|
-
|
88
|
+
```rb
|
89
|
+
attrs = { 'data-function': 'title_empty', 'data-then': 'slide', 'data-target': '#article_description_input' }
|
90
|
+
f.input :title, input_html: attrs
|
91
|
+
```
|
73
92
|
|
74
93
|
```js
|
75
|
-
function title_empty(
|
76
|
-
return (
|
94
|
+
function title_empty(el) {
|
95
|
+
return ($('#article_title').val().trim() === '');
|
77
96
|
}
|
78
97
|
```
|
79
98
|
|
80
99
|
- Call a callback function as action:
|
81
100
|
|
82
|
-
|
101
|
+
```rb
|
102
|
+
data = { if: 'checked', then: 'callback set_title', args: '["Unpublished !"]' }
|
103
|
+
f.input :published, input_html: { data: data }
|
104
|
+
```
|
83
105
|
|
84
106
|
```js
|
85
|
-
function set_title(
|
86
|
-
if(
|
87
|
-
$('#article_title').val(
|
88
|
-
$('#article_title').trigger(
|
107
|
+
function set_title(args) {
|
108
|
+
if($('#article_title').val().trim() === '') {
|
109
|
+
$('#article_title').val(args[0]);
|
110
|
+
$('#article_title').trigger('change');
|
89
111
|
}
|
90
112
|
}
|
91
113
|
```
|
92
114
|
|
93
115
|
- Custom function without action:
|
94
116
|
|
95
|
-
|
117
|
+
```rb
|
118
|
+
collection = [['Cat 1', 'cat1'], ['Cat 2', 'cat2'], ['Cat 3', 'cat3']]
|
119
|
+
f2.input :category, as: :select, collection: collection, input_html: { 'data-function': 'on_change_category' }
|
120
|
+
```
|
96
121
|
|
97
122
|
```js
|
98
|
-
function on_change_category(
|
99
|
-
var target = el.closest(
|
100
|
-
target.prop(
|
101
|
-
target.trigger(
|
123
|
+
function on_change_category(el) {
|
124
|
+
var target = el.closest('fieldset').find('.pub');
|
125
|
+
target.prop('checked', (el.val() == 'cat2');
|
126
|
+
target.trigger('change');
|
102
127
|
}
|
103
128
|
```
|
104
129
|
|
105
130
|
### Inline editing examples
|
106
|
-
|
107
131
|
- Prepare a custom member action to save data, an *update* helper function is available (third parameter is optional, allow to filter using strong parameters):
|
108
132
|
|
109
133
|
```rb
|
110
134
|
member_action :save, method: [:post] do
|
111
|
-
render ActiveAdmin::DynamicFields
|
112
|
-
# render ActiveAdmin::DynamicFields
|
113
|
-
# render ActiveAdmin::DynamicFields
|
135
|
+
render ActiveAdmin::DynamicFields.update(resource, params)
|
136
|
+
# render ActiveAdmin::DynamicFields.update(resource, params, [:published])
|
137
|
+
# render ActiveAdmin::DynamicFields.update(resource, params, Article::permit_params)
|
114
138
|
end
|
115
139
|
```
|
116
140
|
|
@@ -119,29 +143,28 @@ end
|
|
119
143
|
```rb
|
120
144
|
# Edit a string:
|
121
145
|
column :title do |row|
|
122
|
-
div row.title, ActiveAdmin::DynamicFields
|
146
|
+
div row.title, ActiveAdmin::DynamicFields.edit_string(:title, save_admin_article_path(row.id))
|
123
147
|
end
|
124
148
|
# Edit a boolean:
|
125
149
|
column :published do |row|
|
126
|
-
status_tag row.published, ActiveAdmin::DynamicFields
|
150
|
+
status_tag row.published, ActiveAdmin::DynamicFields.edit_boolean(:published, save_admin_article_path(row.id), row.published)
|
127
151
|
end
|
128
152
|
# Edit a select ([''] allow to have a blank value):
|
129
153
|
column :author do |row|
|
130
|
-
select ActiveAdmin::DynamicFields
|
131
|
-
options_for_select(
|
154
|
+
select ActiveAdmin::DynamicFields.edit_select(:author_id, save_admin_article_path(row.id)) do
|
155
|
+
options_for_select([''] + Author.pluck(:name, :id), row.author_id)
|
132
156
|
end
|
133
157
|
end
|
134
158
|
```
|
135
159
|
|
136
|
-
- In *show* config (
|
160
|
+
- In *show* config (inside `attributes_table` block):
|
137
161
|
```rb
|
138
162
|
row :title do |row|
|
139
|
-
div row.title, ActiveAdmin::DynamicFields
|
163
|
+
div row.title, ActiveAdmin::DynamicFields.edit_string(:title, save_admin_article_path(row.id))
|
140
164
|
end
|
141
165
|
```
|
142
166
|
|
143
167
|
### Dialog example
|
144
|
-
|
145
168
|
Example with 2 models: *Author* and *Article*
|
146
169
|
|
147
170
|
Prepare the content dialog - in Active Admin Author config:
|
@@ -150,12 +173,16 @@ Prepare the content dialog - in Active Admin Author config:
|
|
150
173
|
ActiveAdmin.register Author do
|
151
174
|
# ...
|
152
175
|
member_action :dialog do
|
153
|
-
|
154
|
-
|
155
|
-
|
176
|
+
record = resource
|
177
|
+
context = Arbre::Context.new do
|
178
|
+
dl do
|
179
|
+
%i[name age created_at].each do |field|
|
180
|
+
dt "#{Author.human_attribute_name(field)}:"
|
181
|
+
dd record[field]
|
182
|
+
end
|
183
|
+
end
|
156
184
|
end
|
157
|
-
|
158
|
-
render plain: content
|
185
|
+
render plain: context
|
159
186
|
end
|
160
187
|
# ...
|
161
188
|
end
|
@@ -170,7 +197,7 @@ ActiveAdmin.register Article do
|
|
170
197
|
attributes_table do
|
171
198
|
# ...
|
172
199
|
row :author do
|
173
|
-
link_to object.author.name, dialog_admin_author_path(
|
200
|
+
link_to object.author.name, dialog_admin_author_path(object.author), title: object.author.name, 'data-df-dialog': true, 'data-df-icon': true
|
174
201
|
end
|
175
202
|
end
|
176
203
|
end
|
@@ -181,15 +208,13 @@ end
|
|
181
208
|
The link url is loaded via AJAX before opening the dialog.
|
182
209
|
|
183
210
|
## Do you like it? Star it!
|
184
|
-
|
185
211
|
If you use this component just star it. A developer is more motivated to improve a project when there is some interest.
|
186
212
|
|
187
213
|
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.
|
188
214
|
|
189
215
|
## Contributors
|
190
|
-
|
191
|
-
-
|
216
|
+
- [Mattia Roccoberton](http://blocknot.es): author
|
217
|
+
- The good guys that opened issues and pull requests from time to time
|
192
218
|
|
193
219
|
## License
|
194
|
-
|
195
|
-
[MIT](LICENSE.txt)
|
220
|
+
The gem is available as open-source under the terms of the [MIT](LICENSE.txt).
|
data/Rakefile
CHANGED
@@ -1,209 +1,229 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
}
|
30
|
-
|
31
|
-
// Prepare a field
|
32
|
-
function dfSetupField(el) {
|
33
|
-
var action = el.data('action');
|
34
|
-
var target, args = {};
|
35
|
-
args.if = el.data('if');
|
36
|
-
args.eq = el.data('eq');
|
37
|
-
args.not = el.data('not');
|
38
|
-
args.fn = el.data('function');
|
39
|
-
if(el.data('target')) target = el.closest('fieldset').find(el.data('target')); // closest find for has many associations
|
40
|
-
else if(el.data('gtarget')) target = $(el.data('gtarget'));
|
41
|
-
if(action == 'hide') {
|
42
|
-
if(dfEvalCondition(el, args, false)) target.hide();
|
43
|
-
else target.show();
|
44
|
-
el.on('change', function(event) {
|
45
|
-
if(dfEvalCondition($(this), args, true)) target.hide();
|
46
|
-
else target.show();
|
47
|
-
});
|
48
|
-
}
|
49
|
-
else if(action == 'slide') {
|
50
|
-
if(dfEvalCondition(el, args, false)) target.slideDown();
|
51
|
-
else target.slideUp();
|
52
|
-
el.on('change', function(event) {
|
53
|
-
if(dfEvalCondition($(this), args, true)) target.slideDown();
|
54
|
-
else target.slideUp();
|
55
|
-
});
|
1
|
+
(function () {
|
2
|
+
'use strict'
|
3
|
+
|
4
|
+
const ACTIONS = {
|
5
|
+
addClass: (el, name) => el.addClass(name),
|
6
|
+
addStyle: (el, extra_style) => {
|
7
|
+
let style = (el.attr('style') || '').trim()
|
8
|
+
if (!style.includes(extra_style)) {
|
9
|
+
if (style) style = style.replace(/;$/, '') + '; ' // ensure style ends with ;
|
10
|
+
el.attr('style', `${style}${extra_style}`)
|
11
|
+
}
|
12
|
+
},
|
13
|
+
callback: (el, name) => {
|
14
|
+
if (window[name]) window[name](el.data('args'))
|
15
|
+
else {
|
16
|
+
el.attr('data-df-errors', 'callback function not found')
|
17
|
+
console.warn(`activeadmin_dynamic_fields callback function not found: ${name}`)
|
18
|
+
}
|
19
|
+
},
|
20
|
+
fade: el => el.fadeOut(),
|
21
|
+
hide: el => el.hide(),
|
22
|
+
setText: (el, text) => el.text(text),
|
23
|
+
setValue: (el, value) => {
|
24
|
+
if (el.attr('type') == 'checkbox') el.prop('checked', value == '1')
|
25
|
+
else el.val(value)
|
26
|
+
el.trigger('change')
|
27
|
+
},
|
28
|
+
slide: el => el.slideUp()
|
56
29
|
}
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
30
|
+
|
31
|
+
const CONDITIONS = {
|
32
|
+
blank: el => el.val().length === 0 || !el.val().trim(),
|
33
|
+
changed: _el => true,
|
34
|
+
checked: el => el.is(':checked'),
|
35
|
+
eq: (el, value) => el.val() == value,
|
36
|
+
match: (el, regexp) => regexp.test(el.val()),
|
37
|
+
mismatch: (el, regexp) => !regexp.test(el.val()),
|
38
|
+
not: (el, value) => el.val() != value,
|
39
|
+
not_blank: el => el.val().trim(),
|
40
|
+
not_checked: el => !el.is(':checked')
|
64
41
|
}
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
el
|
69
|
-
if(
|
70
|
-
}
|
42
|
+
|
43
|
+
const REVERSE_ACTIONS = {
|
44
|
+
addClass: (el, name) => el.removeClass(name),
|
45
|
+
addStyle: (el, extra_style) => {
|
46
|
+
if(el.attr('style')) el.attr('style', el.attr('style').replace(extra_style, ''))
|
47
|
+
},
|
48
|
+
fade: el => el.fadeIn(),
|
49
|
+
hide: el => el.show(),
|
50
|
+
slide: el => el.slideDown()
|
71
51
|
}
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
52
|
+
|
53
|
+
class Field {
|
54
|
+
constructor(el) {
|
55
|
+
const action = el.data('then') || el.data('action') || ''
|
56
|
+
const action_name = action.split(' ', 1)[0]
|
57
|
+
const else_action = el.data('else') || ''
|
58
|
+
const else_action_name = else_action.split(' ', 1)[0]
|
59
|
+
|
60
|
+
this.el = el
|
61
|
+
this.action = ACTIONS[action_name]
|
62
|
+
this.action_arg = action.substring(action.indexOf(' ') + 1)
|
63
|
+
this.reverse_action = REVERSE_ACTIONS[action_name]
|
64
|
+
this.else_action = ACTIONS[else_action_name]
|
65
|
+
this.else_action_arg = else_action.substring(else_action.indexOf(' ') + 1)
|
66
|
+
this.else_reverse_action = REVERSE_ACTIONS[else_action_name]
|
67
|
+
this.condition = CONDITIONS[el.data('if')]
|
68
|
+
if (!this.condition && el.data('eq')) {
|
69
|
+
[this.condition, this.condition_arg] = [CONDITIONS['eq'], el.data('eq')]
|
70
|
+
}
|
71
|
+
if (!this.condition && el.data('not')) {
|
72
|
+
[this.condition, this.condition_arg] = [CONDITIONS['not'], el.data('not')]
|
73
|
+
}
|
74
|
+
if (!this.condition && el.data('match')) {
|
75
|
+
[this.condition, this.condition_arg] = [CONDITIONS['match'], new RegExp(el.data('match'))]
|
76
|
+
}
|
77
|
+
if (!this.condition && el.data('mismatch')) {
|
78
|
+
[this.condition, this.condition_arg] = [CONDITIONS['mismatch'], new RegExp(el.data('mismatch'))]
|
79
|
+
}
|
80
|
+
this.custom_function = el.data('function')
|
81
|
+
if (!this.condition && this.custom_function) {
|
82
|
+
this.condition = window[this.custom_function]
|
83
|
+
if (!this.condition) {
|
84
|
+
el.attr('data-df-errors', 'custom function not found')
|
85
|
+
console.warn(`activeadmin_dynamic_fields custom function not found: ${this.custom_function}`)
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
// closest find for has many associations
|
90
|
+
if (el.data('target')) this.target = el.closest('fieldset').find(el.data('target'))
|
91
|
+
else if (el.data('gtarget')) this.target = $(el.data('gtarget'))
|
92
|
+
if (action_name == 'callback') this.target = el
|
93
|
+
}
|
94
|
+
|
95
|
+
apply(el) {
|
96
|
+
if (this.condition(el, this.condition_arg)) {
|
97
|
+
if (this.else_reverse_action) this.else_reverse_action(this.target, this.else_action_arg)
|
98
|
+
this.action(this.target, this.action_arg)
|
99
|
+
}
|
100
|
+
else {
|
101
|
+
if (this.reverse_action) this.reverse_action(this.target, this.action_arg)
|
102
|
+
if (this.else_action) this.else_action(this.target, this.else_action_arg)
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
is_valid() {
|
107
|
+
if (!this.condition) return false
|
108
|
+
if (!this.action && !this.custom_function) return false
|
109
|
+
|
110
|
+
return true
|
111
|
+
}
|
112
|
+
|
113
|
+
setup() {
|
114
|
+
if (!this.is_valid()) return
|
115
|
+
if (this.el.data('if') != 'changed') this.apply(this.el)
|
116
|
+
this.el.on('change', () => this.apply(this.el))
|
79
117
|
}
|
80
|
-
else console.log('Warning - activeadmin_dynamic_fields: ' + cb + '() not available [2]');
|
81
|
-
}
|
82
|
-
else if(action.substr(0, 8) == 'addClass') {
|
83
|
-
var classes = action.substr(8).trim();
|
84
|
-
if(dfEvalCondition(el, args, false)) target.removeClass(classes);
|
85
|
-
else target.addClass(classes);
|
86
|
-
el.on('change', function(event) {
|
87
|
-
if(dfEvalCondition($(this), args, true)) target.removeClass(classes);
|
88
|
-
else target.addClass(classes);
|
89
|
-
});
|
90
|
-
}
|
91
|
-
else if(args.fn) { // function without action
|
92
|
-
dfEvalCondition(el, args, false);
|
93
|
-
el.on('change', function(event) {
|
94
|
-
dfEvalCondition(el, args, true);
|
95
|
-
});
|
96
118
|
}
|
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
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
if($(this).data('show-errors')) {
|
129
|
-
var result = '';
|
130
|
-
var message = data.message;
|
131
|
-
for(var key in message) {
|
132
|
-
if(typeof(message[key]) === 'object') {
|
133
|
-
if(result) result += ' - ';
|
134
|
-
result += key + ': ' + message[key].join('; ');
|
119
|
+
|
120
|
+
// Inline update - must be called binded on the editing element
|
121
|
+
function dfUpdateField() {
|
122
|
+
if ($(this).data('loading') != '1') {
|
123
|
+
$(this).data('loading', '1');
|
124
|
+
let _this = $(this);
|
125
|
+
let type = $(this).data('field-type');
|
126
|
+
let new_value;
|
127
|
+
if (type == 'boolean') new_value = !$(this).data('field-value');
|
128
|
+
else if (type == 'select') new_value = $(this).val();
|
129
|
+
else new_value = $(this).text();
|
130
|
+
let data = {};
|
131
|
+
data[$(this).data('field')] = new_value;
|
132
|
+
$.ajax({
|
133
|
+
context: _this,
|
134
|
+
data: { data: data },
|
135
|
+
method: 'POST',
|
136
|
+
url: $(this).data('save-url'),
|
137
|
+
complete: function (req, status) {
|
138
|
+
$(this).data('loading', '0');
|
139
|
+
},
|
140
|
+
success: function (data, status, req) {
|
141
|
+
if (data.status == 'error') {
|
142
|
+
if ($(this).data('show-errors')) {
|
143
|
+
let result = '';
|
144
|
+
let message = data.message;
|
145
|
+
for (let key in message) {
|
146
|
+
if (typeof (message[key]) === 'object') {
|
147
|
+
if (result) result += ' - ';
|
148
|
+
result += key + ': ' + message[key].join('; ');
|
149
|
+
}
|
135
150
|
}
|
151
|
+
if (result) alert(result);
|
136
152
|
}
|
137
|
-
if(result) alert(result);
|
138
153
|
}
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
154
|
+
else {
|
155
|
+
$(this).data('field-value', new_value);
|
156
|
+
if ($(this).data('content')) {
|
157
|
+
let old_text = $(this).text();
|
158
|
+
let old_class = $(this).attr('class');
|
159
|
+
let content = $($(this).data('content'));
|
160
|
+
$(this).text(content.text());
|
161
|
+
$(this).attr('class', content.attr('class'));
|
162
|
+
content.text(old_text);
|
163
|
+
content.attr('class', old_class);
|
164
|
+
$(this).data('content', content);
|
165
|
+
}
|
151
166
|
}
|
152
167
|
}
|
153
|
-
}
|
154
|
-
});
|
155
|
-
}
|
156
|
-
}
|
157
|
-
|
158
|
-
// Init
|
159
|
-
$(document).ready(function() {
|
160
|
-
// Setup dynamic fields
|
161
|
-
$('.active_admin .input [data-if], .active_admin .input [data-function], .active_admin .input [data-eq], .active_admin .input [data-not]').each(function() {
|
162
|
-
dfSetupField($(this));
|
163
|
-
});
|
164
|
-
// Setup dynamic fields for has many associations
|
165
|
-
$('.active_admin .has_many_container').on('has_many_add:after', function(e, fieldset, container) {
|
166
|
-
$('.active_admin .input [data-if], .active_admin .input [data-function], .active_admin .input [data-eq], .active_admin .input [data-not]').each(function() {
|
167
|
-
dfSetupField($(this));
|
168
|
-
});
|
169
|
-
});
|
170
|
-
// Set dialog icon link
|
171
|
-
$('.active_admin [data-df-icon]').each(function() {
|
172
|
-
$(this).append(' »'); // ' •'
|
173
|
-
});
|
174
|
-
// Open content in dialog
|
175
|
-
$('.active_admin [data-df-dialog]').on('click', function(event) {
|
176
|
-
event.preventDefault();
|
177
|
-
$(this).blur();
|
178
|
-
if($('#df-dialog').data('loading') != '1') {
|
179
|
-
$('#df-dialog').data('loading', '1');
|
180
|
-
if($('#df-dialog').length == 0) $('body').append('<div id="df-dialog"></div>');
|
181
|
-
var title = $(this).attr('title');
|
182
|
-
$.ajax({
|
183
|
-
url: $(this).attr('href'),
|
184
|
-
complete: function(req, status) {
|
185
|
-
$('#df-dialog').data('loading', '0');
|
186
|
-
},
|
187
|
-
success: function(data, status, req) {
|
188
|
-
if(title) $('#df-dialog').attr('title', title);
|
189
|
-
$('#df-dialog').html(data);
|
190
|
-
$('#df-dialog').dialog({ modal: true });
|
191
|
-
},
|
192
168
|
});
|
193
169
|
}
|
194
|
-
}
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
$(
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
})
|
170
|
+
}
|
171
|
+
|
172
|
+
// Init
|
173
|
+
$(document).ready(function () {
|
174
|
+
// Setup dynamic fields
|
175
|
+
const selectors = '.active_admin .input [data-if], .active_admin .input [data-eq], .active_admin .input [data-not], .active_admin .input [data-match], .active_admin .input [data-mismatch], .active_admin .input [data-function]'
|
176
|
+
$(selectors).each(function () {
|
177
|
+
new Field($(this)).setup()
|
178
|
+
})
|
179
|
+
|
180
|
+
// Setup dynamic fields for associations
|
181
|
+
$('.active_admin .has_many_container').on('has_many_add:after', () => {
|
182
|
+
$(selectors).each(function () {
|
183
|
+
new Field($(this)).setup()
|
184
|
+
})
|
185
|
+
})
|
186
|
+
|
187
|
+
// Set dialog icon link
|
188
|
+
$('.active_admin [data-df-icon]').each(function () {
|
189
|
+
$(this).append(' »')
|
190
|
+
})
|
191
|
+
|
192
|
+
// Open content in dialog
|
193
|
+
$('.active_admin [data-df-dialog]').on('click', function (event) {
|
194
|
+
event.preventDefault()
|
195
|
+
$(this).blur()
|
196
|
+
if ($('#df-dialog').data('loading') != '1') {
|
197
|
+
$('#df-dialog').data('loading', '1')
|
198
|
+
if ($('#df-dialog').length == 0) $('body').append('<div id="df-dialog"></div>')
|
199
|
+
let title = $(this).attr('title')
|
200
|
+
$.ajax({
|
201
|
+
url: $(this).attr('href'),
|
202
|
+
complete: function (req, status) {
|
203
|
+
$('#df-dialog').data('loading', '0')
|
204
|
+
},
|
205
|
+
success: function (data, status, req) {
|
206
|
+
if (title) $('#df-dialog').attr('title', title)
|
207
|
+
$('#df-dialog').html(data)
|
208
|
+
$('#df-dialog').dialog({ modal: true })
|
209
|
+
},
|
210
|
+
})
|
211
|
+
}
|
212
|
+
})
|
213
|
+
|
214
|
+
// Inline editing
|
215
|
+
$('[data-field][data-field-type="boolean"][data-save-url]').each(function () {
|
216
|
+
$(this).on('click', $.proxy(dfUpdateField, $(this)))
|
217
|
+
})
|
218
|
+
$('[data-field][data-field-type="string"][data-save-url]').each(function () {
|
219
|
+
$(this).data('field-value', $(this).text())
|
220
|
+
let fnUpdate = $.proxy(dfUpdateField, $(this))
|
221
|
+
$(this).on('blur', function () {
|
222
|
+
if ($(this).data('field-value') != $(this).text()) fnUpdate()
|
223
|
+
})
|
224
|
+
})
|
225
|
+
$('[data-field][data-field-type="select"][data-save-url]').each(function () {
|
226
|
+
$(this).on('change', $.proxy(dfUpdateField, $(this)))
|
227
|
+
})
|
228
|
+
})
|
229
|
+
})()
|
metadata
CHANGED
@@ -1,42 +1,164 @@
|
|
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.4.4
|
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-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activeadmin
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
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
|
-
- ".rubocop.yml"
|
35
|
-
- Gemfile
|
36
159
|
- LICENSE.txt
|
37
160
|
- README.md
|
38
161
|
- Rakefile
|
39
|
-
- activeadmin_dynamic_fields.gemspec
|
40
162
|
- app/assets/javascripts/activeadmin/dynamic_fields.js
|
41
163
|
- lib/activeadmin/dynamic_fields.rb
|
42
164
|
- lib/activeadmin/dynamic_fields/engine.rb
|
@@ -46,7 +168,7 @@ homepage: https://github.com/blocknotes/activeadmin_dynamic_fields
|
|
46
168
|
licenses:
|
47
169
|
- MIT
|
48
170
|
metadata: {}
|
49
|
-
post_install_message:
|
171
|
+
post_install_message:
|
50
172
|
rdoc_options: []
|
51
173
|
require_paths:
|
52
174
|
- lib
|
@@ -61,8 +183,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
61
183
|
- !ruby/object:Gem::Version
|
62
184
|
version: '0'
|
63
185
|
requirements: []
|
64
|
-
rubygems_version: 3.0.
|
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/.rubocop.yml
DELETED
@@ -1,73 +0,0 @@
|
|
1
|
-
require:
|
2
|
-
- rubocop-rspec
|
3
|
-
|
4
|
-
Rails:
|
5
|
-
Enabled: true
|
6
|
-
|
7
|
-
AllCops:
|
8
|
-
TargetRubyVersion: 2.3.8
|
9
|
-
TargetRailsVersion: 5.2
|
10
|
-
Exclude:
|
11
|
-
- db/schema.rb
|
12
|
-
- bin/*
|
13
|
-
- node_modules/**/*
|
14
|
-
# Temporary files
|
15
|
-
- tmp/**/*
|
16
|
-
|
17
|
-
Rails/InverseOf:
|
18
|
-
Enabled: false
|
19
|
-
|
20
|
-
Style/Documentation:
|
21
|
-
Enabled: false
|
22
|
-
|
23
|
-
Metrics/ClassLength:
|
24
|
-
# Default value is 100
|
25
|
-
Max: 150
|
26
|
-
|
27
|
-
Metrics/LineLength:
|
28
|
-
# Default is 80
|
29
|
-
Max: 120
|
30
|
-
|
31
|
-
Metrics/ModuleLength:
|
32
|
-
# Default is 100
|
33
|
-
Max: 150
|
34
|
-
|
35
|
-
Metrics/ParameterLists:
|
36
|
-
# Default is 5
|
37
|
-
Max: 6
|
38
|
-
|
39
|
-
RSpec/ExampleLength:
|
40
|
-
# Default is 10
|
41
|
-
Max: 20
|
42
|
-
|
43
|
-
Style/FrozenStringLiteralComment:
|
44
|
-
# Deface DOES edit strings in place
|
45
|
-
Exclude:
|
46
|
-
- 'app/overrides/**/*'
|
47
|
-
|
48
|
-
RSpec/MultipleExpectations:
|
49
|
-
# Default is 3
|
50
|
-
Max: 5
|
51
|
-
|
52
|
-
RSpec/NestedGroups:
|
53
|
-
# Default is 3
|
54
|
-
Max: 6
|
55
|
-
|
56
|
-
Metrics/AbcSize:
|
57
|
-
Max: 25
|
58
|
-
|
59
|
-
Metrics/BlockLength:
|
60
|
-
# This value double the rubocop default
|
61
|
-
Max: 50
|
62
|
-
|
63
|
-
Metrics/CyclomaticComplexity:
|
64
|
-
# This value double the rubocop default
|
65
|
-
Max: 12
|
66
|
-
|
67
|
-
Metrics/MethodLength:
|
68
|
-
# This value double the rubocop default
|
69
|
-
Max: 20
|
70
|
-
|
71
|
-
Metrics/PerceivedComplexity:
|
72
|
-
# Default is 7
|
73
|
-
Max: 10
|
data/Gemfile
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
lib = File.expand_path('lib', __dir__)
|
4
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
-
require 'activeadmin/dynamic_fields/version'
|
6
|
-
|
7
|
-
Gem::Specification.new do |spec|
|
8
|
-
spec.name = 'activeadmin_dynamic_fields'
|
9
|
-
spec.version = ActiveAdmin::DynamicFields::VERSION
|
10
|
-
spec.summary = 'Dynamic fields for ActiveAdmin'
|
11
|
-
spec.description = 'An Active Admin plugin to add dynamic behaviors to fields'
|
12
|
-
spec.license = 'MIT'
|
13
|
-
spec.authors = ['Mattia Roccoberton']
|
14
|
-
spec.email = 'mat@blocknot.es'
|
15
|
-
spec.homepage = 'https://github.com/blocknotes/activeadmin_dynamic_fields'
|
16
|
-
|
17
|
-
spec.files = `git ls-files -z`.split("\x0")
|
18
|
-
spec.require_paths = ['lib']
|
19
|
-
|
20
|
-
spec.add_runtime_dependency 'activeadmin', '>= 1.0'
|
21
|
-
end
|