activeadmin_dynamic_fields 0.3.0 → 0.4.0
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 +34 -13
- data/Rakefile +1 -1
- data/app/assets/javascripts/activeadmin/dynamic_fields.js +60 -49
- data/lib/activeadmin/dynamic_fields/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf72bdd2f498f04dd656b044b1b711cd1e4962ad98d9190807ac9b4bfa423ba0
|
4
|
+
data.tar.gz: 036c3c43e6b00ed99b900f21216b824b00dccbf3a3d871cdfa331080f30eceb3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94007fc44295a8e251f011ef78884c31a03904e53d264bc9b5aa716645c268a0c3a7343f75b0831f790a36b14f1dcdb03ea6a87fb8e819accb36b871c5617f14
|
7
|
+
data.tar.gz: bc6beec26ce12eb2f40c70cc8b9fd12f3cdd416ecf735380fd77343d395e7e7b3f2665cfc2fed8a8339651dcbc12db1eaaae3ce7c6019b5cf6bdf133c4390e31
|
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
@@ -20,7 +20,9 @@ The easiest way to show how this plugin works is looking the examples [below](#e
|
|
20
20
|
```
|
21
21
|
|
22
22
|
## Options
|
23
|
-
Options are passed to fields using *input_html* parameter as *data* attributes
|
23
|
+
Options are passed to fields using *input_html* parameter as *data* attributes.
|
24
|
+
|
25
|
+
Conditions:
|
24
26
|
- **data-if**: check a condition, values:
|
25
27
|
+ **checked**: check if a checkbox is checked
|
26
28
|
+ **not_checked**: check if a checkbox is not checked
|
@@ -29,17 +31,22 @@ Options are passed to fields using *input_html* parameter as *data* attributes:
|
|
29
31
|
+ **changed**: check if the value of an input is changed (dirty)
|
30
32
|
- **data-eq**: check if a field has a specific value
|
31
33
|
- **data-not**: check if a field hasn't a specific value
|
32
|
-
- **data-
|
33
|
-
|
34
|
-
|
34
|
+
- **data-function**: check the return value of a custom function
|
35
|
+
|
36
|
+
Actions:
|
37
|
+
- **data-then**: action to trigger (alias **data-action**), values:
|
35
38
|
+ **hide**: hides elements
|
36
39
|
+ **slide**: hides elements (using sliding)
|
37
40
|
+ **fade**: hides elements (using fading)
|
38
41
|
+ **addClass**: adds classes
|
39
42
|
+ **setValue**: set a value
|
40
|
-
+ **callback**: call a function
|
41
|
-
- **data-
|
42
|
-
- **data-
|
43
|
+
+ **callback**: call a function (with arguments: **data-args**)
|
44
|
+
- **data-else**: action to trigger when the condition check is not true
|
45
|
+
- **data-args**: arguments passed to the callback function
|
46
|
+
|
47
|
+
Targets:
|
48
|
+
- **data-target**: target css selector (from parent fieldset, look for the closest match)
|
49
|
+
- **data-gtarget**: target css selector globally
|
43
50
|
|
44
51
|
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
52
|
|
@@ -59,17 +66,25 @@ form do |f|
|
|
59
66
|
end
|
60
67
|
```
|
61
68
|
|
62
|
-
- Add 3 classes (*first*, *second*, *third*) if a checkbox is not checked:
|
69
|
+
- Add 3 classes (*first*, *second*, *third*) if a checkbox is not checked, else add "forth" class:
|
63
70
|
|
64
|
-
|
71
|
+
```rb
|
72
|
+
data = { if: 'not_checked', then: 'addClass first second third', target: '.grp1', else: 'addClass forth' }
|
73
|
+
f.input :published, input_html: { data: data }
|
74
|
+
```
|
65
75
|
|
66
76
|
- Set another field value if a string field is blank:
|
67
77
|
|
68
|
-
|
78
|
+
```rb
|
79
|
+
f.input :title, input_html: { data: { if: 'blank', then: 'setValue 10', target: '#article_position' } }
|
80
|
+
```
|
69
81
|
|
70
82
|
- Use a custom function for conditional check (*title_not_empty()* must be available on global scope) (with alternative syntax for data attributes):
|
71
83
|
|
72
|
-
|
84
|
+
```rb
|
85
|
+
attrs = { 'data-function': 'title_empty', 'data-then': 'slide', 'data-target': '#article_description_input' }
|
86
|
+
f.input :title, input_html: attrs
|
87
|
+
```
|
73
88
|
|
74
89
|
```js
|
75
90
|
function title_empty(el) {
|
@@ -79,7 +94,10 @@ function title_empty(el) {
|
|
79
94
|
|
80
95
|
- Call a callback function as action:
|
81
96
|
|
82
|
-
|
97
|
+
```rb
|
98
|
+
data = { if: 'checked', then: 'callback set_title', args: '["Unpublished !"]' }
|
99
|
+
f.input :published, input_html: { data: data }
|
100
|
+
```
|
83
101
|
|
84
102
|
```js
|
85
103
|
function set_title(args) {
|
@@ -92,7 +110,10 @@ function set_title(args) {
|
|
92
110
|
|
93
111
|
- Custom function without action:
|
94
112
|
|
95
|
-
|
113
|
+
```rb
|
114
|
+
collection = [['Cat 1', 'cat1'], ['Cat 2', 'cat2'], ['Cat 3', 'cat3']]
|
115
|
+
f2.input :category, as: :select, collection: collection, input_html: { 'data-function': 'on_change_category' }
|
116
|
+
```
|
96
117
|
|
97
118
|
```js
|
98
119
|
function on_change_category(el) {
|
data/Rakefile
CHANGED
@@ -12,7 +12,11 @@
|
|
12
12
|
},
|
13
13
|
fade: el => el.fadeOut(),
|
14
14
|
hide: el => el.hide(),
|
15
|
-
setValue: (el, value) =>
|
15
|
+
setValue: (el, value) => {
|
16
|
+
if (el.attr('type') == 'checkbox') el.prop('checked', value == '1')
|
17
|
+
else el.val(value)
|
18
|
+
el.trigger('change')
|
19
|
+
},
|
16
20
|
slide: el => el.slideUp()
|
17
21
|
}
|
18
22
|
|
@@ -33,58 +37,65 @@
|
|
33
37
|
slide: el => el.slideDown()
|
34
38
|
}
|
35
39
|
|
36
|
-
|
37
|
-
|
38
|
-
|
40
|
+
class Field {
|
41
|
+
constructor(el) {
|
42
|
+
const action = el.data('then') || el.data('action') || ''
|
43
|
+
const action_name = action.split(' ', 1)[0]
|
44
|
+
const else_action = el.data('else') || ''
|
45
|
+
const else_action_name = else_action.split(' ', 1)[0]
|
46
|
+
|
47
|
+
this.el = el
|
48
|
+
this.action = ACTIONS[action_name]
|
49
|
+
this.action_arg = action.substring(action.indexOf(' ') + 1)
|
50
|
+
this.reverse_action = REVERSE_ACTIONS[action_name]
|
51
|
+
this.else_action = ACTIONS[else_action_name]
|
52
|
+
this.else_action_arg = else_action.substring(else_action.indexOf(' ') + 1)
|
53
|
+
this.else_reverse_action = REVERSE_ACTIONS[else_action_name]
|
54
|
+
this.condition = CONDITIONS[el.data('if')]
|
55
|
+
if (!this.condition && el.data('eq')) {
|
56
|
+
[this.condition, this.condition_arg] = [CONDITIONS['eq'], el.data('eq')]
|
57
|
+
}
|
58
|
+
if (!this.condition && el.data('not')) {
|
59
|
+
[this.condition, this.condition_arg] = [CONDITIONS['not'], el.data('not')]
|
60
|
+
}
|
61
|
+
this.custom_function = el.data('function')
|
62
|
+
if (!this.condition && this.custom_function) {
|
63
|
+
this.condition = window[this.custom_function]
|
64
|
+
if (!this.condition) {
|
65
|
+
el.attr('data-df-errors', 'custom function not found')
|
66
|
+
console.warn(`activeadmin_dynamic_fields custom function not found: ${this.custom_function}`)
|
67
|
+
}
|
68
|
+
}
|
39
69
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
if(!condition && el.data('not')) {
|
45
|
-
condition = CONDITIONS['not']
|
46
|
-
condition_arg = el.data('not')
|
70
|
+
// closest find for has many associations
|
71
|
+
if (el.data('target')) this.target = el.closest('fieldset').find(el.data('target'))
|
72
|
+
else if (el.data('gtarget')) this.target = $(el.data('gtarget'))
|
73
|
+
if (action_name == 'callback') this.target = el
|
47
74
|
}
|
48
|
-
|
49
|
-
|
50
|
-
if(
|
51
|
-
|
52
|
-
|
75
|
+
|
76
|
+
apply(el) {
|
77
|
+
if (this.condition(el, this.condition_arg)) {
|
78
|
+
if (this.else_reverse_action) this.else_reverse_action(this.target, this.else_action_arg)
|
79
|
+
this.action(this.target, this.action_arg)
|
80
|
+
}
|
81
|
+
else {
|
82
|
+
if (this.reverse_action) this.reverse_action(this.target, this.action_arg)
|
83
|
+
if (this.else_action) this.else_action(this.target, this.else_action_arg)
|
53
84
|
}
|
54
85
|
}
|
55
86
|
|
56
|
-
|
57
|
-
|
87
|
+
is_valid() {
|
88
|
+
if (!this.condition) return false
|
89
|
+
if (!this.action && !this.custom_function) return false
|
58
90
|
|
59
|
-
|
60
|
-
|
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
|
-
})
|
81
|
-
}
|
91
|
+
return true
|
92
|
+
}
|
82
93
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
94
|
+
setup() {
|
95
|
+
if (!this.is_valid()) return
|
96
|
+
if (this.el.data('if') != 'changed') this.apply(this.el)
|
97
|
+
this.el.on('change', () => this.apply(this.el))
|
98
|
+
}
|
88
99
|
}
|
89
100
|
|
90
101
|
// Inline update - must be called binded on the editing element
|
@@ -144,14 +155,14 @@
|
|
144
155
|
// Setup dynamic fields
|
145
156
|
const selectors = '.active_admin .input [data-if], .active_admin .input [data-eq], .active_admin .input [data-not], .active_admin .input [data-function]'
|
146
157
|
$(selectors).each(function () {
|
147
|
-
|
158
|
+
new Field($(this)).setup()
|
148
159
|
})
|
149
160
|
|
150
161
|
// Setup dynamic fields for associations
|
151
162
|
$('.active_admin .has_many_container').on('has_many_add:after', () => {
|
152
163
|
$(selectors).each(function () {
|
153
|
-
|
154
|
-
})
|
164
|
+
new Field($(this)).setup()
|
165
|
+
})
|
155
166
|
})
|
156
167
|
|
157
168
|
// Set dialog icon link
|
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.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mattia Roccoberton
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-09-
|
11
|
+
date: 2020-09-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activeadmin
|