dynamic_fieldsets 0.1.6 → 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +6 -0
- data/VERSION +1 -1
- data/app/helpers/dynamic_fieldsets_helper.rb +3 -2
- data/app/models/dynamic_fieldsets/checkbox_field.rb +8 -1
- data/app/views/dynamic_fieldsets/form_partials/_input_header.html.erb +2 -2
- data/app/views/dynamic_fieldsets/form_partials/_radio_field.html.erb +1 -1
- data/app/views/dynamic_fieldsets/shared/_javascript_watcher.html.erb +139 -190
- data/dynamic_fieldsets.gemspec +2 -2
- metadata +3 -3
data/CHANGELOG
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
== unreleased changes
|
2
2
|
|
3
|
+
== 0.1.7
|
4
|
+
* Major refactor of the dependency javascript. All dependencies now work and dependencies on duplicate fields on the same page in different associators now work.
|
5
|
+
* Renamed the dependency list variable to dynamic_fieldsets_dependencies
|
6
|
+
* Fixed an issue on the checkbox field view where the id was not being set correctly
|
7
|
+
* Fixed an issue on the radio field view where the id was not being set correctly
|
8
|
+
|
3
9
|
== 0.1.6
|
4
10
|
|
5
11
|
* Fixed missing li tags in the show multiple answer partial
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.7
|
@@ -60,7 +60,8 @@ module DynamicFieldsetsHelper
|
|
60
60
|
field_markup.push render(:partial => field.form_header_partial, :locals => {
|
61
61
|
:classes => classes,
|
62
62
|
:field => field,
|
63
|
-
:fieldset_child => fieldset_child
|
63
|
+
:fieldset_child => fieldset_child,
|
64
|
+
:field_input_name => DynamicFieldsets.config.form_fieldset_associator_prefix + fsa.id.to_s + "_" + DynamicFieldsets.config.form_field_prefix + fieldset_child.id.to_s,
|
64
65
|
})
|
65
66
|
end
|
66
67
|
|
@@ -143,7 +144,7 @@ module DynamicFieldsetsHelper
|
|
143
144
|
# @return [String] The javascript variable that shows what fields have dependencies
|
144
145
|
def javascript_renderer(fsa)
|
145
146
|
unless fsa.id == nil
|
146
|
-
rendered_javascript = "<script type='text/javascript'> var
|
147
|
+
rendered_javascript = "<script type='text/javascript'> var dynamic_fieldsets_dependencies = #{fsa.dependency_child_hash.to_json}; </script>"
|
147
148
|
rendered_javascript += render "dynamic_fieldsets/shared/javascript_watcher"
|
148
149
|
return rendered_javascript.html_safe
|
149
150
|
else
|
@@ -15,12 +15,19 @@ module DynamicFieldsets
|
|
15
15
|
output = super
|
16
16
|
output[:options] = []
|
17
17
|
field_options.each do |option|
|
18
|
+
# rails is screwing up the ids just for the checkbox field
|
19
|
+
# this is a (hopefully) temporary solution/hack to get the id right (JH 3-29-2012)
|
20
|
+
# another possibility would be to update the html attributes method and add fsa and fsc arguments to it
|
21
|
+
adjusted_html_attributes = html_attribute_hash.merge({
|
22
|
+
:id => "#{DynamicFieldsets.config.form_fieldset_associator_prefix}#{args[:fsa].id}_#{DynamicFieldsets.config.form_field_prefix}#{args[:fieldset_child].id}_#{option.id.to_s}"
|
23
|
+
});
|
24
|
+
|
18
25
|
output[:options] << {
|
19
26
|
:name => "#{DynamicFieldsets.config.form_fieldset_associator_prefix}#{args[:fsa].id}[#{DynamicFieldsets.config.form_field_prefix}#{args[:fieldset_child].id}][]",
|
20
27
|
:value => option.id.to_s,
|
21
28
|
:checked => values_or_defaults_for_form(args[:values]).include?(option.id.to_s),
|
22
29
|
:label => option.name,
|
23
|
-
:html_attributes =>
|
30
|
+
:html_attributes => adjusted_html_attributes,
|
24
31
|
}
|
25
32
|
end
|
26
33
|
return output
|
@@ -1,5 +1,5 @@
|
|
1
|
-
<li class='<%= classes %>' id='input-<%=
|
2
|
-
|
1
|
+
<li class='<%= classes %>' id='input-<%= field_input_name %>'>
|
2
|
+
<label for ='<%= field_input_name %>'>
|
3
3
|
<%= field.label %>
|
4
4
|
<% if field.required? %>
|
5
5
|
<abbr title='required'>*</abbr>
|
@@ -1,101 +1,86 @@
|
|
1
1
|
<script type='text/javascript'>
|
2
2
|
|
3
3
|
// The only inputs we care about are visible... not hidden
|
4
|
-
var
|
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
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
var id_array = field.attr('id').split('-');
|
36
|
-
return id_array[id_array.length-1];
|
37
|
-
default:
|
38
|
-
return ''
|
39
|
-
}
|
40
|
-
};
|
41
|
-
|
42
|
-
/***************************************************************************
|
43
|
-
|
44
|
-
evaluate() does the logical computing between two values with a given
|
45
|
-
relationship.
|
46
|
-
|
47
|
-
params [entered_value] - The current value of the input that called the
|
48
|
-
change()
|
49
|
-
params [relationship] - The relationship of the dependency that the
|
50
|
-
input that called the change() is tied to
|
51
|
-
params [value] - The value that we are testing against for the dependency
|
52
|
-
that the input that called the change() is tied to
|
53
|
-
returns [bool] - The boolean value by comparing the entered_value against
|
54
|
-
the value using the relationship.
|
4
|
+
var all_inputs = $(":input:not(:hidden)");
|
5
|
+
|
6
|
+
//Return the fieldset child id for the input
|
7
|
+
//This uniquely associated the fieldset child with the fieldset associator
|
8
|
+
//New fields should use the fieldset_child_id data attribute
|
9
|
+
//But older fields can still attempt to parse it out of the id of the dom element
|
10
|
+
//
|
11
|
+
// field: Field dom element from dynamic fieldsets
|
12
|
+
// type: The type of element from get_type
|
13
|
+
// return: The fieldset child id of the field
|
14
|
+
function get_fieldset_child_id(field, type) {
|
15
|
+
if(typeof(field.attr("data-fsc_id")) != "undefined") {
|
16
|
+
return field.attr("data-fsc_id")
|
17
|
+
} else {
|
18
|
+
switch(type)
|
19
|
+
{
|
20
|
+
case 'text':
|
21
|
+
case 'textarea':
|
22
|
+
case 'select':
|
23
|
+
case 'multi-select':
|
24
|
+
var id_array = field.attr('id').split('-');
|
25
|
+
return id_array[id_array.length-1];
|
26
|
+
case 'radio':
|
27
|
+
case 'checkbox':
|
28
|
+
var id_array = field.closest("div").attr("id").split('-');
|
29
|
+
return id_array[id_array.length-1];
|
30
|
+
default:
|
31
|
+
return ''
|
32
|
+
}
|
33
|
+
}
|
34
|
+
}
|
55
35
|
|
56
|
-
|
36
|
+
// Pulls the fieldset associator id from the data attribute
|
37
|
+
// And falls back on the the string between '-' and '_' at the beginning of the id
|
38
|
+
function get_fieldset_associator_id(field) {
|
39
|
+
if(typeof(field.attr("data-fsa_id")) != "undefined") {
|
40
|
+
return field.attr("data-fsa_id")
|
41
|
+
} else {
|
42
|
+
//format should be fsa-###_field-###
|
43
|
+
return field.attr('id').split("_")[0].split("-")[1]
|
44
|
+
}
|
45
|
+
}
|
57
46
|
|
58
|
-
|
47
|
+
//Determines whether the dependency has been satisfied
|
48
|
+
//CHANGE THIS if the dependency model changes which relationships are allowed.
|
49
|
+
//
|
50
|
+
// user_value: The value on the form
|
51
|
+
// stored_value: The value that satisfies the dependency
|
52
|
+
// relationship: The predicate used to compare the user and stored values
|
53
|
+
//
|
54
|
+
// returns the result of the relationship between user and stored valued
|
55
|
+
function evaluate_dependency(user_value, relationship, stored_value) {
|
59
56
|
switch(relationship)
|
60
57
|
{
|
61
|
-
/* CHANGE THIS if the model changes on which relationships
|
62
|
-
are allowed. */
|
63
58
|
case 'equals':
|
64
|
-
return
|
59
|
+
return user_value == stored_value;
|
65
60
|
case 'not equals':
|
66
|
-
return
|
61
|
+
return user_value != stored_value;
|
67
62
|
case 'includes':
|
68
|
-
return
|
63
|
+
return $.inArray(stored_value, user_value) != -1;
|
69
64
|
case 'not includes':
|
70
|
-
return
|
65
|
+
return $.inArray(stored_value, user_value) == -1;
|
71
66
|
case 'blank':
|
72
|
-
return
|
67
|
+
return user_value == "";
|
73
68
|
case 'not blank':
|
74
|
-
return
|
69
|
+
return user_value != "";
|
75
70
|
default:
|
76
71
|
return false;
|
77
72
|
}
|
78
73
|
};
|
79
74
|
|
80
|
-
|
75
|
+
// What to do to the field based on the dependency information
|
76
|
+
// CHANGE THIS if the dependency group model changes which actions are allowed
|
77
|
+
//
|
78
|
+
// success_flag: whether the dependency group returned true or false
|
79
|
+
// action: the type of update to apply to the field
|
80
|
+
// group_field: the field to update (generally not the field that triggered the change)
|
81
|
+
function dependency_action(success_flag, action, group_field) {
|
81
82
|
|
82
|
-
|
83
|
-
appropriate action upon the group_field of the dependency_group.
|
84
|
-
|
85
|
-
params [success_flag] - Either set to succeed or failure to indicate
|
86
|
-
the results of evaluate()
|
87
|
-
params [action] - Either set to show or enable.
|
88
|
-
params [group_field] - The field tied to the dependency_group that is
|
89
|
-
to experience the action based off of the success of evaluate()
|
90
|
-
returns - changes the group_field
|
91
|
-
|
92
|
-
*************************************************************************/
|
93
|
-
|
94
|
-
function group_action(success_flag, action, group_field) {
|
95
|
-
|
96
|
-
/* CHANGE THIS if the model change on which actions are allowed */
|
97
|
-
|
98
|
-
if (success_flag == true){
|
83
|
+
if (success_flag){
|
99
84
|
switch(action)
|
100
85
|
{
|
101
86
|
case 'show':
|
@@ -114,142 +99,106 @@ function group_action(success_flag, action, group_field) {
|
|
114
99
|
}
|
115
100
|
};
|
116
101
|
|
117
|
-
function
|
102
|
+
function get_input_value(field, type) {
|
118
103
|
switch(type)
|
119
104
|
{
|
120
105
|
case 'text':
|
121
|
-
return field.attr('value').toLowerCase();
|
122
|
-
case 'radio':
|
123
|
-
if (field.val() == $(':checked').val())
|
124
|
-
{
|
125
|
-
field_val = field.attr('id').split('-').slice(2);
|
126
|
-
return field_val.join(" ").toLowerCase();
|
127
|
-
}
|
128
106
|
case 'textarea':
|
129
107
|
return field.val();
|
130
|
-
case '
|
131
|
-
|
132
|
-
|
133
|
-
var sibling_ray = field.closest('div').children().children();
|
134
|
-
var checked_ray = $('input:checked');
|
135
|
-
value_ray = getIntersect(sibling_ray, checked_ray)
|
136
|
-
for (var element in value_ray) {
|
137
|
-
field_ray.push(value_ray[element].id.split('-').slice(2)[0]);
|
108
|
+
case 'radio':
|
109
|
+
if (field.attr('checked') == 'checked') {
|
110
|
+
return $.trim(field.parent('label').text());
|
138
111
|
}
|
139
|
-
|
112
|
+
case 'checkbox':
|
113
|
+
return $('input[name="' + field.attr('name') + '"]:checked').map(function(index,option) {
|
114
|
+
return $.trim($(option).parent('label').text())
|
115
|
+
});
|
140
116
|
case 'select':
|
141
|
-
return
|
117
|
+
return field.find(':selected').text();
|
142
118
|
case 'multi-select':
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
{
|
147
|
-
var temp = value_ray[element].text;
|
148
|
-
if (typeof(temp) == "string") { field_ray.push(temp.toLowerCase()); }
|
149
|
-
}
|
150
|
-
return field_ray;
|
119
|
+
return field.find(':selected').map(function(index, option) {
|
120
|
+
return $(option).text();
|
121
|
+
});
|
151
122
|
default:
|
152
123
|
return '';
|
153
124
|
}
|
154
125
|
};
|
155
126
|
|
156
|
-
|
157
|
-
|
158
|
-
|
127
|
+
//returns the input type for the field
|
128
|
+
//this code is necessary to handle text areas and multiple selects
|
129
|
+
function get_field_type(field) {
|
130
|
+
if (field.attr('type') != undefined) {
|
159
131
|
return field.attr('type')
|
160
|
-
}
|
161
|
-
else if ($('textarea#'+field.attr('id')).length > 0)
|
162
|
-
{
|
132
|
+
} else if ($('textarea#'+field.attr('id')).length > 0) {
|
163
133
|
return "textarea";
|
164
|
-
}
|
165
|
-
|
166
|
-
{
|
167
|
-
if (field.attr('multiple') == "multiple")
|
168
|
-
{
|
134
|
+
} else if ($('select#'+field.attr('id')).length > 0) {
|
135
|
+
if (field.attr('multiple') == "multiple") {
|
169
136
|
return "multi-select";
|
170
|
-
}
|
171
|
-
else {
|
137
|
+
} else {
|
172
138
|
return "select";
|
173
139
|
}
|
174
|
-
}
|
175
|
-
else
|
176
|
-
{
|
140
|
+
} else {
|
177
141
|
return "invalid";
|
178
142
|
}
|
179
143
|
}
|
180
144
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
145
|
+
// when a dynamic fieldsets field fires a change event,
|
146
|
+
// update the page based on dependency information
|
147
|
+
//
|
148
|
+
// the dependency information is stored in dynamic_fieldsets_dependencies
|
149
|
+
all_inputs.change( function() {
|
150
|
+
var field = $(this);
|
151
|
+
var type = get_field_type(field);
|
152
|
+
var fieldset_child_id = get_fieldset_child_id(field, type);
|
153
|
+
var fieldset_associator_id = get_fieldset_associator_id(field);
|
154
|
+
var user_input = get_input_value(field, type)
|
155
|
+
|
156
|
+
|
157
|
+
if (fieldset_child_id in dynamic_fieldsets_dependencies) {
|
158
|
+
$.each(dynamic_fieldsets_dependencies[fieldset_child_id], function(index, group) {
|
159
|
+
update_dependency_group_for_fieldset_child(group, user_input, fieldset_associator_id);
|
160
|
+
});
|
161
|
+
}
|
162
|
+
});
|
163
|
+
|
164
|
+
// checks the clauses for a dependency group and runs the action
|
165
|
+
// group: the dependency group
|
166
|
+
// user_input: the input from the form
|
167
|
+
function update_dependency_group_for_fieldset_child(group, user_input, fieldset_associator_id) {
|
168
|
+
var action = group['action'];
|
169
|
+
var group_fsc_id = group['fieldset_child_id'];
|
170
|
+
var group_field_id = group['field_id'];
|
171
|
+
var group_field = '<%= DynamicFieldsets.config.form_fieldset_associator_prefix %>' + fieldset_associator_id + '_' + '<%=DynamicFieldsets.config.form_field_prefix %>' + group_fsc_id;
|
172
|
+
|
173
|
+
dependency_action(all_dependency_clauses_true(group, user_input), action, group_field)
|
192
174
|
}
|
193
175
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
var field = $(this);
|
207
|
-
var type = grab_type(field);
|
208
|
-
var fieldset_child_id = grab_fsc_id(field, type);
|
209
|
-
var entered_value = grab_value(field, type)
|
210
|
-
if (fieldset_child_id in json_holder) {
|
211
|
-
for (var group in json_holder[fieldset_child_id]) {
|
212
|
-
var action = json_holder[fieldset_child_id][group]['action'];
|
213
|
-
var group_fsc_id = json_holder[fieldset_child_id][group]['fieldset_child_id'];
|
214
|
-
var group_field_id = json_holder[fieldset_child_id][group]['field_id'];
|
215
|
-
var group_field = '<%= DynamicFieldsets.config.form_field_prefix %>' + group_field_id + '-child-' + group_fsc_id;
|
216
|
-
|
217
|
-
// As each dependency clause is AND'd together, we'll assume it'll be
|
218
|
-
// true until short circuited into being false.`
|
219
|
-
var group_break_flag = true;
|
220
|
-
group:
|
221
|
-
for (var clause in json_holder[fieldset_child_id][group]["clause"]) {
|
222
|
-
// As each clause ORs dependencies together, we'll assume it'll be
|
223
|
-
// false until short circuited into being true.
|
224
|
-
var clause_break_flag = false;
|
225
|
-
clause:
|
226
|
-
for (var dependency in json_holder[fieldset_child_id][group]["clause"][clause])
|
227
|
-
{
|
228
|
-
var relationship = json_holder[fieldset_child_id][group]["clause"][clause][dependency]['relationship'];
|
229
|
-
var value = json_holder[fieldset_child_id][group]["clause"][clause][dependency]['value'].toLowerCase();
|
230
|
-
// Short circuit from looking at each dependency in the case
|
231
|
-
// we determine a true dependency (OR)
|
232
|
-
if (evaluate(entered_value, relationship, value)) {
|
233
|
-
clause_break_flag = true;
|
234
|
-
break clause;
|
235
|
-
}
|
236
|
-
}
|
237
|
-
|
238
|
-
// Short circuit from looking at each clause in the case we determine
|
239
|
-
// a false dependency (AND)
|
240
|
-
if (clause_break_flag == false) {
|
241
|
-
group_break_flag = false;
|
242
|
-
break group;
|
243
|
-
}
|
244
|
-
}
|
245
|
-
// If successful, group_break_flag will pass true into group_action
|
246
|
-
group_action(group_break_flag, action, group_field);
|
247
|
-
|
248
|
-
}
|
176
|
+
//all dependencies must be satisfied
|
177
|
+
//the first one that is false makes this return false
|
178
|
+
//only return true if all return true
|
179
|
+
function all_dependency_clauses_true(group, user_input) {
|
180
|
+
for(var key in group["clause"]) {
|
181
|
+
var clause = group["clause"][key]
|
182
|
+
if(!at_least_one_dependency_true(clause, user_input)) {
|
183
|
+
return false;
|
184
|
+
}
|
185
|
+
}
|
186
|
+
return true;
|
187
|
+
}
|
249
188
|
|
250
|
-
|
189
|
+
//The dependencies are ORed together
|
190
|
+
//So as soon as one returns true, return true
|
191
|
+
//Only return false if all are false
|
192
|
+
function at_least_one_dependency_true(clause, user_input) {
|
193
|
+
for(var key in clause) {
|
194
|
+
var dependency = clause[key]
|
195
|
+
if(evaluate_dependency(user_input, dependency["relationship"], dependency["value"])) {
|
196
|
+
return true
|
197
|
+
}
|
198
|
+
}
|
199
|
+
return false
|
200
|
+
}
|
251
201
|
|
252
|
-
|
253
|
-
.change();
|
202
|
+
all_inputs.change();
|
254
203
|
|
255
204
|
</script>
|
data/dynamic_fieldsets.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "dynamic_fieldsets"
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.7"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jeremiah Hemphill", "Ethan Pemble", "John Carter"]
|
12
|
-
s.date = "2012-03-
|
12
|
+
s.date = "2012-03-30"
|
13
13
|
s.description = "Dynamic fieldsets for rails controllers"
|
14
14
|
s.email = "jeremiah@cloudspace.com"
|
15
15
|
s.extra_rdoc_files = [
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: dynamic_fieldsets
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.1.
|
5
|
+
version: 0.1.7
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Jeremiah Hemphill
|
@@ -12,7 +12,7 @@ autorequire:
|
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
14
|
|
15
|
-
date: 2012-03-
|
15
|
+
date: 2012-03-30 00:00:00 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: rails
|
@@ -431,7 +431,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
431
431
|
requirements:
|
432
432
|
- - ">="
|
433
433
|
- !ruby/object:Gem::Version
|
434
|
-
hash: -
|
434
|
+
hash: -3084786597539631494
|
435
435
|
segments:
|
436
436
|
- 0
|
437
437
|
version: "0"
|