nested_form 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +9 -0
- data/Gemfile +11 -0
- data/README.rdoc +23 -23
- data/Rakefile +23 -8
- data/lib/nested_form/builder_mixin.rb +1 -1
- data/spec/dummy/app/assets/javascripts/jquery_nested_form.js +33 -1
- data/spec/dummy/config/initializers/session_store.rb +1 -1
- data/spec/dummy/config/initializers/wrap_parameters.rb +1 -1
- data/spec/dummy/db/migrate/20110710143903_initial_tables.rb +5 -5
- data/spec/dummy/db/schema.rb +1 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/test.log +58 -0
- data/spec/dummy/tmp/cache/assets/C99/4D0/sprockets%2F5e30a6b911437f1428dc32c3ae182123 +0 -0
- data/spec/dummy/tmp/cache/assets/C99/7D0/sprockets%2F79513e6956e0ee8624976e041fd5636d +0 -0
- data/spec/dummy/tmp/cache/assets/CAA/C90/sprockets%2F1e6c8ee1258009385ccf5b84015424b3 +0 -0
- data/spec/dummy/tmp/cache/assets/CDB/8A0/sprockets%2Faed2a2575c376263c26e93b56b57051d +0 -0
- data/spec/dummy/tmp/cache/assets/D79/BC0/sprockets%2F85a1db977361cc5130fcefb4637ff67e +0 -0
- data/spec/dummy/tmp/cache/assets/D87/1F0/sprockets%2F61c9ceafb877fb740c67416ff6f782a9 +0 -0
- data/spec/dummy/tmp/cache/assets/DAD/4F0/sprockets%2F765acd1bf68dc90f7d3e61da78b1e659 +0 -0
- data/spec/dummy/tmp/cache/assets/E03/3F0/sprockets%2F82b37ae9eccec44c1ef44cfdd07d8534 +0 -0
- data/spec/dummy/tmp/cache/assets/E0A/CA0/sprockets%2F7fe72ac1c0db1a7e8e7f59cf25e8a39e +0 -0
- data/spec/dummy/tmp/cache/assets/E54/400/sprockets%2Fd0cbc16cc37efcf9dc41f242b5dbbf81 +0 -0
- data/spec/dummy/tmp/cache/assets/EB7/AB0/sprockets%2F801d29a5debdbfbfb4eef14d70d9bcdb +0 -0
- data/spec/dummy/tmp/cache/assets/F48/5E0/sprockets%2F26cd6ffcffbebbe2fd6cd1a8f0c2debc +0 -0
- data/spec/form_spec.rb +9 -7
- data/vendor/assets/javascripts/jquery_nested_form.js +103 -0
- data/vendor/assets/javascripts/prototype_nested_form.js +51 -0
- metadata +66 -9
- data/spec/dummy/db/development.sqlite3 +0 -0
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
0.2.1 (June 4, 2012)
|
2
|
+
|
3
|
+
* Added Travis integration (thanks fxposter)
|
4
|
+
|
5
|
+
* Make the "context" selector stricter, to work with deeply-nested forms. (thanks groe and nickhoffman)
|
6
|
+
|
7
|
+
* Include vendor folder in the gem for Rails 3.1 asset support (thanks dmarkow)
|
8
|
+
|
9
|
+
|
1
10
|
0.2.0 (February 7, 2012)
|
2
11
|
|
3
12
|
* Integration tests (thanks fxposter) - issue #58
|
data/Gemfile
ADDED
data/README.rdoc
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
= Nested Form
|
2
2
|
|
3
|
+
{<img src="https://secure.travis-ci.org/ryanb/nested_form.png?branch=master" alt="Build Status" />}[http://travis-ci.org/ryanb/nested_form]
|
4
|
+
|
3
5
|
This is a Rails gem for conveniently manage multiple nested models in a single form. It does so in an unobtrusive way through jQuery or Prototype.
|
4
6
|
|
5
7
|
This gem only works with Rails 3. See the {rails2 branch}[https://github.com/ryanb/nested_form/tree/rails2] for a plugin to work in Rails 2.
|
@@ -7,40 +9,24 @@ This gem only works with Rails 3. See the {rails2 branch}[https://github.com/rya
|
|
7
9
|
An example project showing how this works is available in the {complex-nested-forms/nested_form branch}[https://github.com/ryanb/complex-form-examples/tree/nested_form].
|
8
10
|
|
9
11
|
|
10
|
-
==
|
11
|
-
|
12
|
-
=== Enhanced jQuery javascript template
|
13
|
-
|
14
|
-
Now you can override default behavior of inserting new subforms into your form (jQuery-only feature, sorry). For example:
|
15
|
-
|
16
|
-
window.nestedFormEvents.insertFields = function(content, assoc, link) {
|
17
|
-
return $(link).closest('form').find(assoc + '_fields').append($(content));
|
18
|
-
}
|
19
|
-
|
20
|
-
=== Rails 3.1 support (with asset pipeline)
|
12
|
+
== Setup
|
21
13
|
|
22
|
-
|
23
|
-
Also support of Rails 3.1 led me to huge refactor of specs setup (now using Helper specs from rspec-rails instead of custom implementation spec context).
|
14
|
+
Add it to your Gemfile then run +bundle+ to install it.
|
24
15
|
|
25
|
-
|
16
|
+
gem "nested_form"
|
26
17
|
|
27
|
-
|
18
|
+
And then add it to the Asset Pipeline in the appication.js file:
|
28
19
|
|
29
20
|
//= require jquery_nested_form
|
30
|
-
// or
|
31
|
-
//= require prototype_nested_form
|
32
|
-
|
33
|
-
== Setup
|
34
21
|
|
35
|
-
Add it to your Gemfile then run +bundle+ to install it.
|
36
22
|
|
37
|
-
|
23
|
+
=== Non Asset Pipeline Setup
|
38
24
|
|
39
|
-
|
25
|
+
If you do not use the asset pipeline, run this generator to create the JavaScript file.
|
40
26
|
|
41
27
|
rails g nested_form:install
|
42
28
|
|
43
|
-
|
29
|
+
You can then include the generated JavaScript in your layout.
|
44
30
|
|
45
31
|
<%= javascript_include_tag :defaults, "nested_form" %>
|
46
32
|
|
@@ -83,6 +69,20 @@ In this case it will look for a partial called "task_fields" and pass the form b
|
|
83
69
|
If you are using jQuery, <tt>nested:fieldAdded</tt> and <tt>nested:fieldRemoved</tt> events are triggered on the +form+ element after adding and removing fields.
|
84
70
|
|
85
71
|
|
72
|
+
== Enhanced jQuery JavaScript template
|
73
|
+
|
74
|
+
You can override default behavior of inserting new subforms into your form. For example:
|
75
|
+
|
76
|
+
window.nestedFormEvents.insertFields = function(content, assoc, link) {
|
77
|
+
return $(link).closest('form').find(assoc + '_fields').append($(content));
|
78
|
+
}
|
79
|
+
|
80
|
+
|
81
|
+
== Project Status
|
82
|
+
|
83
|
+
Unfortunately I have not had time to actively work on this project recently. If you find a critical issue where it does not work as documented please {ping me on Twitter}[http://twitter.com/rbates] and I'll take a look.
|
84
|
+
|
85
|
+
|
86
86
|
== Special Thanks
|
87
87
|
|
88
88
|
This gem was originally based on the solution by Tim Riley in his {complex-form-examples fork}[https://github.com/timriley/complex-form-examples/tree/unobtrusive-jquery-deep-fix2].
|
data/Rakefile
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
# require 'appraisal'
|
3
2
|
require 'rake'
|
4
3
|
|
5
4
|
begin
|
@@ -13,17 +12,33 @@ rescue LoadError
|
|
13
12
|
end
|
14
13
|
|
15
14
|
task :default => :spec
|
15
|
+
|
16
|
+
namespace :db do
|
17
|
+
task :migrate do
|
18
|
+
system 'cd spec/dummy && rake db:migrate RAILS_ENV=test && rake db:migrate RAILS_ENV=development'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
16
22
|
namespace :spec do
|
17
23
|
task :install do
|
18
|
-
|
19
|
-
|
24
|
+
system 'bundle install'
|
25
|
+
system 'bundle install --gemfile=gemfiles/Gemfile.rails3_0'
|
26
|
+
system 'bundle install --gemfile=gemfiles/Gemfile.rails3_1'
|
20
27
|
end
|
21
|
-
|
22
|
-
task :
|
28
|
+
|
29
|
+
task :rails3_1 do
|
30
|
+
ENV['BUNDLE_GEMFILE'] = File.expand_path('../gemfiles/Gemfile.rails3_1', __FILE__)
|
31
|
+
Rake::Task["spec"].execute
|
32
|
+
end
|
33
|
+
|
34
|
+
task :rails3_0 do
|
23
35
|
ENV['BUNDLE_GEMFILE'] = File.expand_path('../gemfiles/Gemfile.rails3_0', __FILE__)
|
24
36
|
Rake::Task["spec"].execute
|
25
|
-
|
26
|
-
|
37
|
+
end
|
38
|
+
|
39
|
+
task :all do
|
27
40
|
Rake::Task["spec"].execute
|
41
|
+
Rake::Task["spec:rails3_1"].execute
|
42
|
+
Rake::Task["spec:rails3_0"].execute
|
28
43
|
end
|
29
|
-
end
|
44
|
+
end
|
@@ -45,7 +45,7 @@ module NestedForm
|
|
45
45
|
options[:class] = [options[:class], "remove_nested_fields"].compact.join(" ")
|
46
46
|
args << (options.delete(:href) || "javascript:void(0)")
|
47
47
|
args << options
|
48
|
-
hidden_field(:_destroy)
|
48
|
+
(hidden_field(:_destroy) << @template.link_to(*args, &block)).html_safe
|
49
49
|
end
|
50
50
|
|
51
51
|
def fields_for_with_nested_attributes(association_name, *args)
|
@@ -13,7 +13,8 @@ jQuery(function($) {
|
|
13
13
|
|
14
14
|
// Make the context correct by replacing new_<parents> with the generated ID
|
15
15
|
// of each of the parent objects
|
16
|
-
var context = ($(link).closest('.fields').
|
16
|
+
var context = ($(link).closest('.fields').closestChild('input:first').attr('name') || '').replace(new RegExp('\[[a-z]+\]$'), '');
|
17
|
+
|
17
18
|
|
18
19
|
// context will be something like this for a brand new form:
|
19
20
|
// project[tasks_attributes][new_1255929127459][assignments_attributes][new_1255929128105]
|
@@ -69,3 +70,34 @@ jQuery(function($) {
|
|
69
70
|
$('form a.add_nested_fields').live('click', nestedFormEvents.addFields);
|
70
71
|
$('form a.remove_nested_fields').live('click', nestedFormEvents.removeFields);
|
71
72
|
});
|
73
|
+
|
74
|
+
|
75
|
+
// http://plugins.jquery.com/project/closestChild
|
76
|
+
/*
|
77
|
+
* Copyright 2011, Tobias Lindig
|
78
|
+
*
|
79
|
+
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
|
80
|
+
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
|
81
|
+
*
|
82
|
+
*/
|
83
|
+
(function($) {
|
84
|
+
$.fn.closestChild = function(selector) {
|
85
|
+
// breadth first search for the first matched node
|
86
|
+
if (selector && selector != '') {
|
87
|
+
var queue = [];
|
88
|
+
queue.push(this);
|
89
|
+
while(queue.length > 0) {
|
90
|
+
var node = queue.shift();
|
91
|
+
var children = node.children();
|
92
|
+
for(var i = 0; i < children.length; ++i) {
|
93
|
+
var child = $(children[i]);
|
94
|
+
if (child.is(selector)) {
|
95
|
+
return child; //well, we found one
|
96
|
+
}
|
97
|
+
queue.push(child);
|
98
|
+
}
|
99
|
+
}
|
100
|
+
}
|
101
|
+
return $();//nothing found
|
102
|
+
};
|
103
|
+
})(jQuery);
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# Be sure to restart your server when you modify this file.
|
2
2
|
|
3
|
-
Dummy::Application.config.session_store :cookie_store, key
|
3
|
+
Dummy::Application.config.session_store :cookie_store, :key => '_dummy_session'
|
4
4
|
|
5
5
|
# Use the database for sessions instead of the cookie-based default,
|
6
6
|
# which shouldn't be used to store highly confidential information
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# is enabled by default.
|
5
5
|
|
6
6
|
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
|
7
|
-
ActionController::Base.wrap_parameters format
|
7
|
+
ActionController::Base.wrap_parameters :format => [:json] if ActionController::Base.respond_to?(:wrap_parameters)
|
8
8
|
|
9
9
|
# Disable root element in JSON by default.
|
10
10
|
if defined?(ActiveRecord)
|
@@ -1,21 +1,21 @@
|
|
1
1
|
class InitialTables < ActiveRecord::Migration
|
2
|
-
def up
|
3
|
-
create_table :projects
|
2
|
+
def self.up
|
3
|
+
create_table :projects do |t|
|
4
4
|
t.string :name
|
5
5
|
end
|
6
6
|
|
7
|
-
create_table :tasks
|
7
|
+
create_table :tasks do |t|
|
8
8
|
t.integer :project_id
|
9
9
|
t.string :name
|
10
10
|
end
|
11
11
|
|
12
|
-
create_table :milestones
|
12
|
+
create_table :milestones do |t|
|
13
13
|
t.integer :task_id
|
14
14
|
t.string :name
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
def down
|
18
|
+
def self.down
|
19
19
|
drop_table :projects
|
20
20
|
drop_table :tasks
|
21
21
|
drop_table :milestones
|
data/spec/dummy/db/schema.rb
CHANGED
data/spec/dummy/db/test.sqlite3
CHANGED
Binary file
|
@@ -0,0 +1,58 @@
|
|
1
|
+
Connecting to database specified by database.yml
|
2
|
+
|
3
|
+
|
4
|
+
Started GET "/projects/new" for 127.0.0.1 at 2012-06-04 11:03:17 -0700
|
5
|
+
Processing by ProjectsController#new as HTML
|
6
|
+
Completed 500 Internal Server Error in 1ms
|
7
|
+
Connecting to database specified by database.yml
|
8
|
+
[1m[36m (0.1ms)[0m [1mselect sqlite_version(*)[0m
|
9
|
+
[1m[35m (1.8ms)[0m CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL)
|
10
|
+
[1m[36m (0.0ms)[0m [1mPRAGMA index_list("schema_migrations")[0m
|
11
|
+
[1m[35m (1.7ms)[0m CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
|
12
|
+
[1m[36m (0.1ms)[0m [1mSELECT "schema_migrations"."version" FROM "schema_migrations" [0m
|
13
|
+
Migrating to InitialTables (20110710143903)
|
14
|
+
[1m[35m (0.0ms)[0m begin transaction
|
15
|
+
[1m[36m (0.2ms)[0m [1mCREATE TABLE "projects" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255)) [0m
|
16
|
+
[1m[35m (0.1ms)[0m CREATE TABLE "tasks" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "project_id" integer, "name" varchar(255))
|
17
|
+
[1m[36m (0.1ms)[0m [1mCREATE TABLE "milestones" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "task_id" integer, "name" varchar(255)) [0m
|
18
|
+
[1m[35m (0.1ms)[0m INSERT INTO "schema_migrations" ("version") VALUES ('20110710143903')
|
19
|
+
[1m[36m (2.3ms)[0m [1mcommit transaction[0m
|
20
|
+
[1m[35m (0.2ms)[0m select sqlite_version(*)
|
21
|
+
[1m[36m (0.1ms)[0m [1mSELECT "schema_migrations"."version" FROM "schema_migrations" [0m
|
22
|
+
[1m[35m (0.0ms)[0m PRAGMA index_list("milestones")
|
23
|
+
[1m[36m (0.0ms)[0m [1mPRAGMA index_list("projects")[0m
|
24
|
+
[1m[35m (0.0ms)[0m PRAGMA index_list("tasks")
|
25
|
+
Connecting to database specified by database.yml
|
26
|
+
|
27
|
+
|
28
|
+
Started GET "/projects/new" for 127.0.0.1 at 2012-06-04 11:08:28 -0700
|
29
|
+
Processing by ProjectsController#new as HTML
|
30
|
+
Rendered projects/new.html.erb within layouts/application (199.1ms)
|
31
|
+
Completed 200 OK in 908ms (Views: 904.8ms | ActiveRecord: 0.4ms)
|
32
|
+
|
33
|
+
|
34
|
+
Started GET "/assets/jquery.js" for 127.0.0.1 at 2012-06-04 11:08:29 -0700
|
35
|
+
Compiled jquery.js (21ms) (pid 52505)
|
36
|
+
Served asset /jquery.js - 200 OK (417ms)
|
37
|
+
|
38
|
+
|
39
|
+
Started GET "/assets/jquery_nested_form.js" for 127.0.0.1 at 2012-06-04 11:08:30 -0700
|
40
|
+
Compiled jquery_nested_form.js (0ms) (pid 52505)
|
41
|
+
Served asset /jquery_nested_form.js - 200 OK (25ms)
|
42
|
+
|
43
|
+
|
44
|
+
Started GET "/projects/new?type=prototype" for 127.0.0.1 at 2012-06-04 11:08:30 -0700
|
45
|
+
Processing by ProjectsController#new as HTML
|
46
|
+
Parameters: {"type"=>"prototype"}
|
47
|
+
Rendered projects/new.html.erb within layouts/application (2.1ms)
|
48
|
+
Completed 200 OK in 3ms (Views: 2.6ms | ActiveRecord: 0.0ms)
|
49
|
+
|
50
|
+
|
51
|
+
Started GET "/assets/prototype.js" for 127.0.0.1 at 2012-06-04 11:08:31 -0700
|
52
|
+
Compiled prototype.js (1ms) (pid 52505)
|
53
|
+
Served asset /prototype.js - 200 OK (413ms)
|
54
|
+
|
55
|
+
|
56
|
+
Started GET "/assets/prototype_nested_form.js" for 127.0.0.1 at 2012-06-04 11:08:31 -0700
|
57
|
+
Compiled prototype_nested_form.js (0ms) (pid 52505)
|
58
|
+
Served asset /prototype_nested_form.js - 200 OK (72ms)
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/spec/form_spec.rb
CHANGED
@@ -2,30 +2,32 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe 'NestedForm' do
|
4
4
|
include Capybara::DSL
|
5
|
-
|
5
|
+
|
6
6
|
def check_form
|
7
7
|
page.should have_no_css('form .fields input[id$=name]')
|
8
8
|
click_link 'Add new task'
|
9
9
|
page.should have_css('form .fields input[id$=name]', :count => 1)
|
10
10
|
find('form .fields input[id$=name]').should be_visible
|
11
11
|
find('form .fields input[id$=_destroy]').value.should == 'false'
|
12
|
-
|
12
|
+
|
13
13
|
click_link 'Remove'
|
14
14
|
find('form .fields input[id$=_destroy]').value.should == '1'
|
15
15
|
find('form .fields input[id$=name]').should_not be_visible
|
16
|
-
|
16
|
+
|
17
17
|
click_link 'Add new task'
|
18
18
|
click_link 'Add new task'
|
19
19
|
fields = all('form .fields')
|
20
20
|
fields.select { |field| field.visible? }.count.should == 2
|
21
21
|
fields.reject { |field| field.visible? }.count.should == 1
|
22
22
|
end
|
23
|
-
|
24
|
-
it 'should work with jQuery
|
23
|
+
|
24
|
+
it 'should work with jQuery', :js => true do
|
25
25
|
visit '/projects/new'
|
26
26
|
check_form
|
27
|
-
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should work with Prototype', :js => true do
|
28
30
|
visit '/projects/new?type=prototype'
|
29
31
|
check_form
|
30
32
|
end
|
31
|
-
end
|
33
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
jQuery(function($) {
|
2
|
+
window.NestedFormEvents = function() {
|
3
|
+
this.addFields = $.proxy(this.addFields, this);
|
4
|
+
this.removeFields = $.proxy(this.removeFields, this);
|
5
|
+
};
|
6
|
+
|
7
|
+
NestedFormEvents.prototype = {
|
8
|
+
addFields: function(e) {
|
9
|
+
// Setup
|
10
|
+
var link = e.currentTarget;
|
11
|
+
var assoc = $(link).attr('data-association'); // Name of child
|
12
|
+
var content = $('#' + assoc + '_fields_blueprint').html(); // Fields template
|
13
|
+
|
14
|
+
// Make the context correct by replacing new_<parents> with the generated ID
|
15
|
+
// of each of the parent objects
|
16
|
+
var context = ($(link).closest('.fields').closestChild('input:first').attr('name') || '').replace(new RegExp('\[[a-z]+\]$'), '');
|
17
|
+
|
18
|
+
|
19
|
+
// context will be something like this for a brand new form:
|
20
|
+
// project[tasks_attributes][new_1255929127459][assignments_attributes][new_1255929128105]
|
21
|
+
// or for an edit form:
|
22
|
+
// project[tasks_attributes][0][assignments_attributes][1]
|
23
|
+
if (context) {
|
24
|
+
var parentNames = context.match(/[a-z_]+_attributes/g) || [];
|
25
|
+
var parentIds = context.match(/(new_)?[0-9]+/g) || [];
|
26
|
+
|
27
|
+
for(var i = 0; i < parentNames.length; i++) {
|
28
|
+
if(parentIds[i]) {
|
29
|
+
content = content.replace(
|
30
|
+
new RegExp('(_' + parentNames[i] + ')_.+?_', 'g'),
|
31
|
+
'$1_' + parentIds[i] + '_');
|
32
|
+
|
33
|
+
content = content.replace(
|
34
|
+
new RegExp('(\\[' + parentNames[i] + '\\])\\[.+?\\]', 'g'),
|
35
|
+
'$1[' + parentIds[i] + ']');
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
// Make a unique ID for the new child
|
41
|
+
var regexp = new RegExp('new_' + assoc, 'g');
|
42
|
+
var new_id = new Date().getTime();
|
43
|
+
content = content.replace(regexp, "new_" + new_id);
|
44
|
+
|
45
|
+
var field = this.insertFields(content, assoc, link);
|
46
|
+
$(link).closest("form")
|
47
|
+
.trigger({ type: 'nested:fieldAdded', field: field })
|
48
|
+
.trigger({ type: 'nested:fieldAdded:' + assoc, field: field });
|
49
|
+
return false;
|
50
|
+
},
|
51
|
+
insertFields: function(content, assoc, link) {
|
52
|
+
return $(content).insertBefore(link);
|
53
|
+
},
|
54
|
+
removeFields: function(e) {
|
55
|
+
var link = e.currentTarget;
|
56
|
+
var hiddenField = $(link).prev('input[type=hidden]');
|
57
|
+
hiddenField.val('1');
|
58
|
+
// if (hiddenField) {
|
59
|
+
// $(link).v
|
60
|
+
// hiddenField.value = '1';
|
61
|
+
// }
|
62
|
+
var field = $(link).closest('.fields');
|
63
|
+
field.hide();
|
64
|
+
$(link).closest("form").trigger({ type: 'nested:fieldRemoved', field: field });
|
65
|
+
return false;
|
66
|
+
}
|
67
|
+
};
|
68
|
+
|
69
|
+
window.nestedFormEvents = new NestedFormEvents();
|
70
|
+
$('form a.add_nested_fields').live('click', nestedFormEvents.addFields);
|
71
|
+
$('form a.remove_nested_fields').live('click', nestedFormEvents.removeFields);
|
72
|
+
});
|
73
|
+
|
74
|
+
|
75
|
+
// http://plugins.jquery.com/project/closestChild
|
76
|
+
/*
|
77
|
+
* Copyright 2011, Tobias Lindig
|
78
|
+
*
|
79
|
+
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
|
80
|
+
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
|
81
|
+
*
|
82
|
+
*/
|
83
|
+
(function($) {
|
84
|
+
$.fn.closestChild = function(selector) {
|
85
|
+
// breadth first search for the first matched node
|
86
|
+
if (selector && selector != '') {
|
87
|
+
var queue = [];
|
88
|
+
queue.push(this);
|
89
|
+
while(queue.length > 0) {
|
90
|
+
var node = queue.shift();
|
91
|
+
var children = node.children();
|
92
|
+
for(var i = 0; i < children.length; ++i) {
|
93
|
+
var child = $(children[i]);
|
94
|
+
if (child.is(selector)) {
|
95
|
+
return child; //well, we found one
|
96
|
+
}
|
97
|
+
queue.push(child);
|
98
|
+
}
|
99
|
+
}
|
100
|
+
}
|
101
|
+
return $();//nothing found
|
102
|
+
};
|
103
|
+
})(jQuery);
|
@@ -0,0 +1,51 @@
|
|
1
|
+
document.observe('click', function(e, el) {
|
2
|
+
if (el = e.findElement('form a.add_nested_fields')) {
|
3
|
+
// Setup
|
4
|
+
var assoc = el.readAttribute('data-association'); // Name of child
|
5
|
+
var content = $(assoc + '_fields_blueprint').innerHTML; // Fields template
|
6
|
+
|
7
|
+
// Make the context correct by replacing new_<parents> with the generated ID
|
8
|
+
// of each of the parent objects
|
9
|
+
var context = (el.getOffsetParent('.fields').firstDescendant().readAttribute('name') || '').replace(new RegExp('\[[a-z]+\]$'), '');
|
10
|
+
|
11
|
+
// context will be something like this for a brand new form:
|
12
|
+
// project[tasks_attributes][new_1255929127459][assignments_attributes][new_1255929128105]
|
13
|
+
// or for an edit form:
|
14
|
+
// project[tasks_attributes][0][assignments_attributes][1]
|
15
|
+
if(context) {
|
16
|
+
var parent_names = context.match(/[a-z_]+_attributes/g) || [];
|
17
|
+
var parent_ids = context.match(/(new_)?[0-9]+/g) || [];
|
18
|
+
|
19
|
+
for(i = 0; i < parent_names.length; i++) {
|
20
|
+
if(parent_ids[i]) {
|
21
|
+
content = content.replace(
|
22
|
+
new RegExp('(_' + parent_names[i] + ')_.+?_', 'g'),
|
23
|
+
'$1_' + parent_ids[i] + '_');
|
24
|
+
|
25
|
+
content = content.replace(
|
26
|
+
new RegExp('(\\[' + parent_names[i] + '\\])\\[.+?\\]', 'g'),
|
27
|
+
'$1[' + parent_ids[i] + ']');
|
28
|
+
}
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
// Make a unique ID for the new child
|
33
|
+
var regexp = new RegExp('new_' + assoc, 'g');
|
34
|
+
var new_id = new Date().getTime();
|
35
|
+
content = content.replace(regexp, "new_" + new_id);
|
36
|
+
|
37
|
+
el.insert({ before: content });
|
38
|
+
return false;
|
39
|
+
}
|
40
|
+
});
|
41
|
+
|
42
|
+
document.observe('click', function(e, el) {
|
43
|
+
if (el = e.findElement('form a.remove_nested_fields')) {
|
44
|
+
var hidden_field = el.previous(0);
|
45
|
+
if(hidden_field) {
|
46
|
+
hidden_field.value = '1';
|
47
|
+
}
|
48
|
+
el.ancestors()[0].hide();
|
49
|
+
return false;
|
50
|
+
}
|
51
|
+
});
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nested_form
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,22 +10,59 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-06-04 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rake
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ! '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: bundler
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
type: :development
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
15
47
|
- !ruby/object:Gem::Dependency
|
16
48
|
name: rspec-rails
|
17
|
-
requirement:
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
18
50
|
none: false
|
19
51
|
requirements:
|
20
52
|
- - ~>
|
21
53
|
- !ruby/object:Gem::Version
|
22
|
-
version: 2.6
|
54
|
+
version: '2.6'
|
23
55
|
type: :development
|
24
56
|
prerelease: false
|
25
|
-
version_requirements:
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ~>
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '2.6'
|
26
63
|
- !ruby/object:Gem::Dependency
|
27
64
|
name: mocha
|
28
|
-
requirement:
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
29
66
|
none: false
|
30
67
|
requirements:
|
31
68
|
- - ! '>='
|
@@ -33,7 +70,12 @@ dependencies:
|
|
33
70
|
version: '0'
|
34
71
|
type: :development
|
35
72
|
prerelease: false
|
36
|
-
version_requirements:
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
37
79
|
description: Gem to conveniently handle multiple models in a single form with Rails
|
38
80
|
3 and jQuery or Prototype.
|
39
81
|
email: ryan@railscasts.com
|
@@ -80,10 +122,10 @@ files:
|
|
80
122
|
- spec/dummy/config/locales/en.yml
|
81
123
|
- spec/dummy/config/routes.rb
|
82
124
|
- spec/dummy/config.ru
|
83
|
-
- spec/dummy/db/development.sqlite3
|
84
125
|
- spec/dummy/db/migrate/20110710143903_initial_tables.rb
|
85
126
|
- spec/dummy/db/schema.rb
|
86
127
|
- spec/dummy/db/test.sqlite3
|
128
|
+
- spec/dummy/log/test.log
|
87
129
|
- spec/dummy/public/404.html
|
88
130
|
- spec/dummy/public/422.html
|
89
131
|
- spec/dummy/public/500.html
|
@@ -92,11 +134,26 @@ files:
|
|
92
134
|
- spec/dummy/script/rails
|
93
135
|
- spec/dummy/test/functional/projects_controller_test.rb
|
94
136
|
- spec/dummy/test/unit/helpers/projects_helper_test.rb
|
137
|
+
- spec/dummy/tmp/cache/assets/C99/4D0/sprockets%2F5e30a6b911437f1428dc32c3ae182123
|
138
|
+
- spec/dummy/tmp/cache/assets/C99/7D0/sprockets%2F79513e6956e0ee8624976e041fd5636d
|
139
|
+
- spec/dummy/tmp/cache/assets/CAA/C90/sprockets%2F1e6c8ee1258009385ccf5b84015424b3
|
140
|
+
- spec/dummy/tmp/cache/assets/CDB/8A0/sprockets%2Faed2a2575c376263c26e93b56b57051d
|
141
|
+
- spec/dummy/tmp/cache/assets/D79/BC0/sprockets%2F85a1db977361cc5130fcefb4637ff67e
|
142
|
+
- spec/dummy/tmp/cache/assets/D87/1F0/sprockets%2F61c9ceafb877fb740c67416ff6f782a9
|
143
|
+
- spec/dummy/tmp/cache/assets/DAD/4F0/sprockets%2F765acd1bf68dc90f7d3e61da78b1e659
|
144
|
+
- spec/dummy/tmp/cache/assets/E03/3F0/sprockets%2F82b37ae9eccec44c1ef44cfdd07d8534
|
145
|
+
- spec/dummy/tmp/cache/assets/E0A/CA0/sprockets%2F7fe72ac1c0db1a7e8e7f59cf25e8a39e
|
146
|
+
- spec/dummy/tmp/cache/assets/E54/400/sprockets%2Fd0cbc16cc37efcf9dc41f242b5dbbf81
|
147
|
+
- spec/dummy/tmp/cache/assets/EB7/AB0/sprockets%2F801d29a5debdbfbfb4eef14d70d9bcdb
|
148
|
+
- spec/dummy/tmp/cache/assets/F48/5E0/sprockets%2F26cd6ffcffbebbe2fd6cd1a8f0c2debc
|
95
149
|
- spec/form_spec.rb
|
96
150
|
- spec/nested_form/builder_spec.rb
|
97
151
|
- spec/nested_form/view_helper_spec.rb
|
98
152
|
- spec/spec_helper.rb
|
153
|
+
- vendor/assets/javascripts/jquery_nested_form.js
|
154
|
+
- vendor/assets/javascripts/prototype_nested_form.js
|
99
155
|
- CHANGELOG.rdoc
|
156
|
+
- Gemfile
|
100
157
|
- LICENSE
|
101
158
|
- Rakefile
|
102
159
|
- README.rdoc
|
@@ -120,7 +177,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
120
177
|
version: 1.3.4
|
121
178
|
requirements: []
|
122
179
|
rubyforge_project: nested_form
|
123
|
-
rubygems_version: 1.8.
|
180
|
+
rubygems_version: 1.8.23
|
124
181
|
signing_key:
|
125
182
|
specification_version: 3
|
126
183
|
summary: Gem to conveniently handle multiple models in a single form.
|
Binary file
|