Skip to content

Commit 40e5c04

Browse files
committed
Merge pull request #20 from m-Peter/master
Sync up changes from Peter's repo to the main one.
2 parents 097f3ef + 5562d80 commit 40e5c04

23 files changed

+158
-255
lines changed
Lines changed: 27 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,61 @@
11
(function($) {
22

3-
var element_counter = 0;
4-
53
var create_new_id = function() {
6-
return (new Date().getTime() + element_counter++);
7-
}
8-
9-
var newcontent_braced = function(id) {
10-
return '[' + id + ']$1';
11-
}
12-
13-
var newcontent_underscord = function(id) {
14-
return '_' + id + '_$1';
4+
return new Date().getTime();
155
}
166

177
$(document).on('click', '.add_fields', function(e) {
188
e.preventDefault();
19-
var $this = $(this),
20-
assoc = $this.data('association'),
21-
assocs = $this.data('associations'),
22-
content = $this.data('association-insertion-template'),
23-
insertionMethod = $this.data('association-insertion-method') || $this.data('association-insertion-position') || 'before',
24-
insertionNode = $this.data('association-insertion-node'),
25-
insertionTraversal = $this.data('association-insertion-traversal'),
26-
count = parseInt($this.data('count'), 10),
27-
regexp_braced = new RegExp('\\[new_' + assoc + '\\](.*?\\s)', 'g'),
28-
regexp_underscord = new RegExp('_new_' + assoc + '_(\\w*)', 'g'),
29-
new_id = create_new_id(),
30-
new_content = content.replace(regexp_braced, newcontent_braced(new_id)),
31-
new_contents = [];
32-
33-
34-
if (new_content == content) {
35-
regexp_braced = new RegExp('\\[new_' + assocs + '\\](.*?\\s)', 'g');
36-
regexp_underscord = new RegExp('_new_' + assocs + '_(\\w*)', 'g');
37-
new_content = content.replace(regexp_braced, newcontent_braced(new_id));
38-
}
39-
40-
new_content = new_content.replace(regexp_underscord, newcontent_underscord(new_id));
41-
new_contents = [new_content];
42-
43-
count = (isNaN(count) ? 1 : Math.max(count, 1));
44-
count -= 1;
45-
46-
while (count) {
47-
new_id = create_new_id();
48-
new_content = content.replace(regexp_braced, newcontent_braced(new_id));
49-
new_content = new_content.replace(regexp_underscord, newcontent_underscord(new_id));
50-
new_contents.push(new_content);
51-
52-
count -= 1;
53-
}
9+
10+
var $link = $(this);
11+
var assoc = $link.data('association');
12+
var content = $link.data('association-insertion-template');
13+
var insertionMethod = $link.data('association-insertion-method') || $link.data('association-insertion-position') || 'before';
14+
var insertionNode = $link.data('association-insertion-node');
15+
var insertionTraversal = $link.data('association-insertion-traversal');
16+
var new_id = create_new_id();
17+
var regex = new RegExp("new_" + assoc, "g");
18+
var new_content = content.replace(regex, new_id);
5419

5520
if (insertionNode){
5621
if (insertionTraversal){
57-
insertionNode = $this[insertionTraversal](insertionNode);
22+
insertionNode = $link[insertionTraversal](insertionNode);
5823
} else {
59-
insertionNode = insertionNode == "this" ? $this : $(insertionNode);
24+
insertionNode = insertionNode == "this" ? $link : $(insertionNode);
6025
}
6126
} else {
62-
insertionNode = $this.parent();
27+
insertionNode = $link.parent();
6328
}
6429

65-
$.each(new_contents, function(i, node) {
66-
var contentNode = $(node);
30+
var contentNode = $(new_content);
31+
insertionNode.trigger('before-insert', [contentNode]);
6732

68-
insertionNode.trigger('cocoon:before-insert', [contentNode]);
33+
var addedContent = insertionNode[insertionMethod](contentNode);
6934

70-
// allow any of the jquery dom manipulation methods (after, before, append, prepend, etc)
71-
// to be called on the node. allows the insertion node to be the parent of the inserted
72-
// code and doesn't force it to be a sibling like after/before does. default: 'before'
73-
var addedContent = insertionNode[insertionMethod](contentNode);
74-
75-
insertionNode.trigger('cocoon:after-insert', [contentNode]);
76-
});
35+
insertionNode.trigger('after-insert', [contentNode]);
7736
});
7837

7938
$(document).on('click', '.remove_fields.dynamic, .remove_fields.existing', function(e) {
80-
var $this = $(this),
81-
wrapper_class = $this.data('wrapper-class') || 'nested-fields',
82-
node_to_delete = $this.closest('.' + wrapper_class),
83-
trigger_node = node_to_delete.parent();
84-
8539
e.preventDefault();
8640

87-
trigger_node.trigger('cocoon:before-remove', [node_to_delete]);
41+
var $link = $(this);
42+
var wrapper_class = $link.data('wrapper-class') || 'nested-fields';
43+
var node_to_delete = $link.closest('.' + wrapper_class);
44+
var trigger_node = node_to_delete.parent();
45+
46+
trigger_node.trigger('before-remove', [node_to_delete]);
8847

8948
var timeout = trigger_node.data('remove-timeout') || 0;
9049

9150
setTimeout(function() {
92-
if ($this.hasClass('dynamic')) {
51+
if ($link.hasClass('dynamic')) {
9352
node_to_delete.remove();
9453
} else {
95-
$this.prev("input[type=hidden]").val("1");
54+
$link.prev("input[type=hidden]").val("1");
9655
node_to_delete.hide();
9756
}
98-
trigger_node.trigger('cocoon:after-remove', [node_to_delete]);
57+
trigger_node.trigger('after-remove', [node_to_delete]);
9958
}, timeout);
10059
});
10160

102-
$('.remove_fields.existing.destroyed').each(function(i, obj) {
103-
var $this = $(this),
104-
wrapper_class = $this.data('wrapper-class') || 'nested-fields';
105-
106-
$this.closest('.' + wrapper_class).hide();
107-
});
108-
10961
})(jQuery);

lib/active_form/view_helpers.rb

Lines changed: 19 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,15 @@
11
module ActiveForm
22
module ViewHelpers
33

4-
def link_to_remove_association(*args)
5-
name = args[0]
6-
f = args[1]
7-
html_options = args[2] || {}
8-
is_existing = f.object.persisted?
9-
4+
def link_to_remove_association(name, f, html_options={})
105
classes = []
116
classes << "remove_fields"
12-
classes << (is_existing ? 'existing' : 'dynamic')
13-
#classes << 'destroyed' if f.object.marked_for_destruction?
14-
html_options[:class] = [html_options[:class], classes.join(' ')].compact.join(' ')
157

8+
is_existing = f.object.persisted?
9+
classes << (is_existing ? 'existing' : 'dynamic')
10+
1611
wrapper_class = html_options.delete(:wrapper_class)
12+
html_options[:class] = [html_options[:class], classes.join(' ')].compact.join(' ')
1713
html_options[:'data-wrapper-class'] = wrapper_class if wrapper_class.present?
1814

1915
if is_existing
@@ -23,38 +19,33 @@ def link_to_remove_association(*args)
2319
end
2420
end
2521

26-
def render_association(association, f, new_object, form_name, render_options={}, custom_partial=nil)
22+
def render_association(association, f, new_object, render_options={}, custom_partial=nil)
2723
partial = get_partial_path(custom_partial, association)
28-
locals = render_options.delete(:locals) || {}
29-
method_name = f.respond_to?(:semantic_fields_for) ? :semantic_fields_for : (f.respond_to?(:simple_fields_for) ? :simple_fields_for : :fields_for)
24+
25+
if f.respond_to?(:semantic_fields_for)
26+
method_name = :semantic_fields_for
27+
elsif f.respond_to?(:simple_fields_for)
28+
method_name = :simple_fields_for
29+
else
30+
method_name = :fields_for
31+
end
3032

3133
f.send(method_name, association, new_object, {:child_index => "new_#{association}"}.merge(render_options)) do |builder|
32-
partial_options = {form_name.to_sym => builder, :dynamic => true}.merge(locals)
33-
render(partial, partial_options)
34+
render(partial: partial, locals: {:f => builder})
3435
end
3536
end
3637

37-
def link_to_add_association(*args)
38-
name = args[0]
39-
f = args[1]
40-
association = args[2]
41-
html_options = args[3] || {}
42-
43-
render_options = html_options.delete(:render_options)
38+
def link_to_add_association(name, f, association, html_options={})
39+
render_options = html_options.delete(:render_options)
4440
render_options ||= {}
4541
override_partial = html_options.delete(:partial)
46-
form_parameter_name = html_options.delete(:form_name) || 'f'
47-
count = html_options.delete(:count).to_i
4842

4943
html_options[:class] = [html_options[:class], "add_fields"].compact.join(' ')
50-
html_options[:'data-association'] = association.to_s.singularize
51-
html_options[:'data-associations'] = association.to_s.pluralize
44+
html_options[:'data-association'] = association.to_s
5245

5346
new_object = create_object(f, association)
5447

55-
html_options[:'data-association-insertion-template'] = CGI.escapeHTML(render_association(association, f, new_object, form_parameter_name, render_options, override_partial).to_str).html_safe
56-
57-
html_options[:'data-count'] = count if count > 0
48+
html_options[:'data-association-insertion-template'] = CGI.escapeHTML(render_association(association, f, new_object, render_options, override_partial).to_str).html_safe
5849

5950
link_to(name, '#', html_options)
6051
end
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
require 'rails/generators'
2+
require 'rails/generators/base'
3+
4+
module ActiveForm
5+
module Generators
6+
class InstallGenerator < Rails::Generators::Base
7+
8+
desc "Creates a forms directory into your app and test directories and includes the necessary JS file."
9+
10+
def create_forms_app_directory
11+
empty_directory "app/forms"
12+
end
13+
14+
def create_forms_test_directory
15+
if File.directory?("spec")
16+
empty_directory "spec/forms"
17+
else
18+
empty_directory "test/forms"
19+
end
20+
end
21+
22+
def include_js_file
23+
insert_into_file "app/assets/javascripts/application.js", "//= require link_helpers", :before => "//= require_tree ."
24+
end
25+
end
26+
end
27+
end

test/dummy/app/assets/javascripts/projects.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ $(document).ready(function() {
33
data("association-insertion-position", 'before').
44
data("association-insertion-node", 'this');
55

6-
$('#owner').bind('cocoon:after-insert',
6+
$('#owner').bind('after-insert',
77
function() {
88
$("#owner_from_list").hide();
99
$("#owner a.add_fields").hide();
1010
});
11-
$('#owner').bind("cocoon:after-remove",
11+
$('#owner').bind("after-remove",
1212
function() {
1313
$("#owner_from_list").show();
1414
$("#owner a.add_fields").show();
@@ -18,27 +18,27 @@ $(document).ready(function() {
1818
data("association-insertion-position", 'before').
1919
data("association-insertion-node", 'this');
2020

21-
$('#tags').bind('cocoon:after-insert',
21+
$('#tags').bind('after-insert',
2222
function(e, tag) {
2323
$(".project-tag-fields a.add_fields").
2424
data("association-insertion-position", 'before').
2525
data("association-insertion-node", 'this');
26-
$('.project-tag-fields').bind('cocoon:after-insert',
26+
$('.project-tag-fields').bind('after-insert',
2727
function() {
2828
$(this).children("#tag_from_list").remove();
2929
$(this).children("a.add_fields").hide();
3030
});
3131
});
3232

33-
$('#tasks').bind('cocoon:before-insert', function(e,task_to_be_added) {
33+
$('#tasks').bind('before-insert', function(e,task_to_be_added) {
3434
task_to_be_added.fadeIn('slow');
3535
});
3636

37-
$('#tasks').bind('cocoon:after-insert', function(e, added_task) {
37+
$('#tasks').bind('after-insert', function(e, added_task) {
3838
//added_task.css("background","red");
3939
});
4040

41-
$('#tasks').bind('cocoon:before-remove', function(e, task) {
41+
$('#tasks').bind('before-remove', function(e, task) {
4242
$(this).data('remove-timeout', 1000);
4343
task.fadeOut('slow');
4444
})

test/dummy/app/forms/project_form.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class ProjectForm < ActiveForm::Base
1010
end
1111
end
1212

13-
association :contributors do
13+
association :contributors, records: 2 do
1414
attributes :name, :description, :role
1515
end
1616

test/dummy/app/forms/survey_form.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ class SurveyForm < ActiveForm::Base
22
self.main_model = :survey
33
attribute :name, required: true
44

5-
association :questions, records: 1 do
5+
association :questions do
66
attribute :content, required: true
77

88
association :answers, records: 2 do
File renamed without changes.

test/forms/conference_form_fixture.rb

Lines changed: 0 additions & 12 deletions
This file was deleted.

test/forms/conference_form_test.rb

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
require 'test_helper'
2-
require_relative 'conference_form_fixture'
32

43
class ConferenceFormTest < ActiveSupport::TestCase
54
include ActiveModel::Lint::Tests
65
fixtures :conferences, :speakers, :presentations
76

87
def setup
98
@conference = Conference.new
10-
@form = ConferenceFormFixture.new(@conference)
9+
@form = ConferenceForm.new(@conference)
1110
@model = @form
1211
end
1312

@@ -66,7 +65,7 @@ def setup
6665
test "presentations sub-form fetches parent and association objects" do
6766
conference = conferences(:ruby)
6867

69-
form = ConferenceFormFixture.new(conference)
68+
form = ConferenceForm.new(conference)
7069

7170
assert_equal conference.name, form.name
7271
assert_equal 2, form.speaker.presentations.size
@@ -279,7 +278,7 @@ def setup
279278

280279
test "main form updates its model and the models in nested sub-forms" do
281280
conference = conferences(:ruby)
282-
form = ConferenceFormFixture.new(conference)
281+
form = ConferenceForm.new(conference)
283282
params = {
284283
name: "GoGaruco",
285284
city: "Golden State",
@@ -316,7 +315,7 @@ def setup
316315

317316
test "main form updates its model and saves dynamically added models in nested sub-forms" do
318317
conference = conferences(:ruby)
319-
form = ConferenceFormFixture.new(conference)
318+
form = ConferenceForm.new(conference)
320319
params = {
321320
name: "GoGaruco",
322321
city: "Golden State",
@@ -356,7 +355,7 @@ def setup
356355

357356
test "main form deletes models in nested sub-forms" do
358357
conference = conferences(:ruby)
359-
form = ConferenceFormFixture.new(conference)
358+
form = ConferenceForm.new(conference)
360359
params = {
361360
name: "GoGaruco",
362361
city: "Golden State",
@@ -396,7 +395,7 @@ def setup
396395

397396
test "main form deletes and adds models in nested sub-forms" do
398397
conference = conferences(:ruby)
399-
form = ConferenceFormFixture.new(conference)
398+
form = ConferenceForm.new(conference)
400399
params = {
401400
name: "GoGaruco",
402401
city: "Golden State",

0 commit comments

Comments
 (0)