nested_form 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|