From a5ff7eedfa47155c3e9d78e12672a5ee6a9043a0 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Wed, 9 Feb 2011 16:47:32 -0500 Subject: [PATCH 1/8] Provide two versions of the nest_form javascript support file: one for jquery and one for prototype. --- ...{nested_form.js => jquery_nested_forms.js} | 0 .../templates/prototype_nested_forms.js | 48 +++++++++++++++++++ 2 files changed, 48 insertions(+) rename lib/generators/nested_form/templates/{nested_form.js => jquery_nested_forms.js} (100%) create mode 100644 lib/generators/nested_form/templates/prototype_nested_forms.js diff --git a/lib/generators/nested_form/templates/nested_form.js b/lib/generators/nested_form/templates/jquery_nested_forms.js similarity index 100% rename from lib/generators/nested_form/templates/nested_form.js rename to lib/generators/nested_form/templates/jquery_nested_forms.js diff --git a/lib/generators/nested_form/templates/prototype_nested_forms.js b/lib/generators/nested_form/templates/prototype_nested_forms.js new file mode 100644 index 00000000..64d796ae --- /dev/null +++ b/lib/generators/nested_form/templates/prototype_nested_forms.js @@ -0,0 +1,48 @@ +document.observe('click', function(e, el) { + if (el = e.findElement('fieldset a.add_nested_fields')) { + // Setup + var assoc = el.readAttribute('data-association'); // Name of child + var content = $(assoc + '_fields_blueprint').innerHTML; // Fields template + + // Make the context correct by replacing new_ with the generated ID + // of each of the parent objects + var context = (el.getOffsetParent('.fields').firstDescendant().readAttribute('name') || '').replace(new RegExp('\[[a-z]+\]$'), ''); + + // context will be something like this for a brand new form: + // project[tasks_attributes][1255929127459][assignments_attributes][1255929128105] + // or for an edit form: + // project[tasks_attributes][0][assignments_attributes][1] + if(context) { + var parent_names = context.match(/[a-z_]+_attributes/g) || []; + var parent_ids = context.match(/[0-9]+/g); + + for(i = 0; i < parent_names.length; i++) { + if(parent_ids[i]) { + content = content.replace( + new RegExp('(\\[' + parent_names[i] + '\\])\\[.+?\\]', 'g'), + '$1[' + parent_ids[i] + ']' + ) + } + } + } + + // Make a unique ID for the new child + var regexp = new RegExp('new_' + assoc, 'g'); + var new_id = new Date().getTime(); + content = content.replace(regexp, new_id); + + el.insert({ before: content }); + return false; + } +}); + +document.observe('click', function(e, el) { + if (el = e.findElement('fieldset a.remove_nested_fields')) { + var hidden_field = el.previous(0); + if(hidden_field) { + hidden_field.value = '1'; + } + el.ancestors()[0].hide(); + return false; + } +}); From a44830fad14c359eb55a7331c12496b0ce6bfc12 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Wed, 9 Feb 2011 16:48:15 -0500 Subject: [PATCH 2/8] Conditionally copy the nested_form javascript depending on which javascript framework is used. Currently, if not prototype, then assume jquery. --- lib/generators/nested_form/install_generator.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/generators/nested_form/install_generator.rb b/lib/generators/nested_form/install_generator.rb index be785652..b6a8a370 100644 --- a/lib/generators/nested_form/install_generator.rb +++ b/lib/generators/nested_form/install_generator.rb @@ -7,8 +7,13 @@ def self.source_root def copy_jquery_file - copy_file 'nested_form.js', 'public/javascripts/nested_form.js' + stat = File.stat('public/javascripts/prototype.js') + if stat.file? + copy_file 'prototype_nested_form.js', 'public/javascripts/nested_form.js' + else + copy_file 'jquery_nested_form.js', 'public/javascripts/nested_form.js' + end end end end -end \ No newline at end of file +end From 4ced8160a0c137ad12b60e7eb422908f1fcfc4ae Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Wed, 9 Feb 2011 17:02:00 -0500 Subject: [PATCH 3/8] To be consistent with upstream, reference the DOM object as "form a.xxxx" instead of "fieldset a.xxxx" --- .../nested_form/templates/prototype_nested_forms.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/generators/nested_form/templates/prototype_nested_forms.js b/lib/generators/nested_form/templates/prototype_nested_forms.js index 64d796ae..8386b8ec 100644 --- a/lib/generators/nested_form/templates/prototype_nested_forms.js +++ b/lib/generators/nested_form/templates/prototype_nested_forms.js @@ -1,5 +1,5 @@ document.observe('click', function(e, el) { - if (el = e.findElement('fieldset a.add_nested_fields')) { + if (el = e.findElement('form a.add_nested_fields')) { // Setup var assoc = el.readAttribute('data-association'); // Name of child var content = $(assoc + '_fields_blueprint').innerHTML; // Fields template @@ -37,7 +37,7 @@ document.observe('click', function(e, el) { }); document.observe('click', function(e, el) { - if (el = e.findElement('fieldset a.remove_nested_fields')) { + if (el = e.findElement('form a.remove_nested_fields')) { var hidden_field = el.previous(0); if(hidden_field) { hidden_field.value = '1'; From 013a558be64329a915809003ae8b4a401bbd3e2a Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Sat, 12 Feb 2011 18:32:56 -0500 Subject: [PATCH 4/8] Rename template files to their singular form. Improved test of javascript framework with File.exists?() --- lib/generators/nested_form/install_generator.rb | 4 +--- .../{jquery_nested_forms.js => jquery_nested_form.js} | 0 .../{prototype_nested_forms.js => prototype_nested_form.js} | 0 3 files changed, 1 insertion(+), 3 deletions(-) rename lib/generators/nested_form/templates/{jquery_nested_forms.js => jquery_nested_form.js} (100%) rename lib/generators/nested_form/templates/{prototype_nested_forms.js => prototype_nested_form.js} (100%) diff --git a/lib/generators/nested_form/install_generator.rb b/lib/generators/nested_form/install_generator.rb index b6a8a370..73fcd306 100644 --- a/lib/generators/nested_form/install_generator.rb +++ b/lib/generators/nested_form/install_generator.rb @@ -5,10 +5,8 @@ def self.source_root File.dirname(__FILE__) + "/templates" end - def copy_jquery_file - stat = File.stat('public/javascripts/prototype.js') - if stat.file? + if File.exists?('public/javascripts/prototype.js') copy_file 'prototype_nested_form.js', 'public/javascripts/nested_form.js' else copy_file 'jquery_nested_form.js', 'public/javascripts/nested_form.js' diff --git a/lib/generators/nested_form/templates/jquery_nested_forms.js b/lib/generators/nested_form/templates/jquery_nested_form.js similarity index 100% rename from lib/generators/nested_form/templates/jquery_nested_forms.js rename to lib/generators/nested_form/templates/jquery_nested_form.js diff --git a/lib/generators/nested_form/templates/prototype_nested_forms.js b/lib/generators/nested_form/templates/prototype_nested_form.js similarity index 100% rename from lib/generators/nested_form/templates/prototype_nested_forms.js rename to lib/generators/nested_form/templates/prototype_nested_form.js From 8f8ec86df6390e7e13e3b8563c269bd07bfb5265 Mon Sep 17 00:00:00 2001 From: Franck Pasquier Date: Thu, 17 Feb 2011 21:01:35 +0800 Subject: [PATCH 5/8] modifying js template file for supporting context attribute name with underscore and one to one association (where parent_ids is null) --- .../templates/jquery_nested_form.js | 22 ++++++++++--------- .../templates/prototype_nested_form.js | 20 +++++++++-------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/lib/generators/nested_form/templates/jquery_nested_form.js b/lib/generators/nested_form/templates/jquery_nested_form.js index 5a805f11..dac6e831 100644 --- a/lib/generators/nested_form/templates/jquery_nested_form.js +++ b/lib/generators/nested_form/templates/jquery_nested_form.js @@ -6,7 +6,7 @@ $('form a.add_nested_fields').live('click', function() { // Make the context correct by replacing new_ with the generated ID // of each of the parent objects - var context = ($(this).closest('.fields').find('input:first').attr('name') || '').replace(new RegExp('\[[a-z]+\]$'), ''); + var context = ($(this).closest('.fields').find('input:first').attr('name') || '').replace(new RegExp('\[[a-z_]+\]$'), ''); // context will be something like this for a brand new form: // project[tasks_attributes][1255929127459][assignments_attributes][1255929128105] @@ -15,15 +15,17 @@ $('form a.add_nested_fields').live('click', function() { if(context) { var parent_names = context.match(/[a-z_]+_attributes/g) || []; var parent_ids = context.match(/[0-9]+/g); - - for(i = 0; i < parent_names.length; i++) { - if(parent_ids[i]) { - content = content.replace( - new RegExp('(\\[' + parent_names[i] + '\\])\\[.+?\\]', 'g'), - '$1[' + parent_ids[i] + ']' - ) - } - } + + if(parent_ids) { + for(i = 0; i < parent_names.length; i++) { + if(parent_ids[i]) { + content = content.replace( + new RegExp('(\\[' + parent_names[i] + '\\])\\[.+?\\]', 'g'), + '$1[' + parent_ids[i] + ']' + ) + } + } + } } // Make a unique ID for the new child diff --git a/lib/generators/nested_form/templates/prototype_nested_form.js b/lib/generators/nested_form/templates/prototype_nested_form.js index 8386b8ec..86231bdc 100644 --- a/lib/generators/nested_form/templates/prototype_nested_form.js +++ b/lib/generators/nested_form/templates/prototype_nested_form.js @@ -6,7 +6,7 @@ document.observe('click', function(e, el) { // Make the context correct by replacing new_ with the generated ID // of each of the parent objects - var context = (el.getOffsetParent('.fields').firstDescendant().readAttribute('name') || '').replace(new RegExp('\[[a-z]+\]$'), ''); + var context = (el.getOffsetParent('.fields').firstDescendant().readAttribute('name') || '').replace(new RegExp('\[[a-z_]+\]$'), ''); // context will be something like this for a brand new form: // project[tasks_attributes][1255929127459][assignments_attributes][1255929128105] @@ -16,14 +16,16 @@ document.observe('click', function(e, el) { var parent_names = context.match(/[a-z_]+_attributes/g) || []; var parent_ids = context.match(/[0-9]+/g); - for(i = 0; i < parent_names.length; i++) { - if(parent_ids[i]) { - content = content.replace( - new RegExp('(\\[' + parent_names[i] + '\\])\\[.+?\\]', 'g'), - '$1[' + parent_ids[i] + ']' - ) - } - } + if(parent_ids) { + for(i = 0; i < parent_names.length; i++) { + if(parent_ids[i]) { + content = content.replace( + new RegExp('(\\[' + parent_names[i] + '\\])\\[.+?\\]', 'g'), + '$1[' + parent_ids[i] + ']' + ) + } + } + } } // Make a unique ID for the new child From 3f37fcc9cab7a9ab8aa3ffea634a3b70f608bcd7 Mon Sep 17 00:00:00 2001 From: Ryan Bates Date: Fri, 18 Feb 2011 02:56:07 +0800 Subject: [PATCH 6/8] adding paragraph tag around Add link in readme --- README.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rdoc b/README.rdoc index 26e43435..db7899a8 100644 --- a/README.rdoc +++ b/README.rdoc @@ -34,7 +34,7 @@ Use this form just like normal, including the fields_for helper method for nesti <%= task_form.text_field :name %> <%= task_form.link_to_remove "Remove this task" %> <% end %> - <%= f.link_to_add "Add a task", :tasks %> +

<%= f.link_to_add "Add a task", :tasks %>

This generates links which dynamically add and remove fields. From 7188a2d946706c5bf0004209b04ff61d47a03669 Mon Sep 17 00:00:00 2001 From: Jordan Bach Date: Tue, 2 Nov 2010 11:58:58 +0800 Subject: [PATCH 7/8] this test would fail randomly because callbacks are not guaranteed to be called in any particular order --- spec/nested_form/view_helper_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/nested_form/view_helper_spec.rb b/spec/nested_form/view_helper_spec.rb index 08fc4234..94f18aba 100644 --- a/spec/nested_form/view_helper_spec.rb +++ b/spec/nested_form/view_helper_spec.rb @@ -26,7 +26,8 @@ @template.after_nested_form(:tasks) { @template.concat("123") } @template.after_nested_form(:milestones) { @template.concat("456") } @template.nested_form_for(Project.new) {} - @template.output_buffer.should include("123456") + @template.output_buffer.should include("123") + @template.output_buffer.should include("456") end end From eed32cb9c45a9e78945ae223cbb649330c7d9b7e Mon Sep 17 00:00:00 2001 From: Patrick Jakubowski Date: Fri, 25 Feb 2011 19:15:57 +0800 Subject: [PATCH 8/8] Added support for arbitrary HTML attributes on the add nested form link --- Rakefile | 9 +++------ lib/nested_form/builder.rb | 14 +++++++++++--- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/Rakefile b/Rakefile index 8eb48594..c5806454 100644 --- a/Rakefile +++ b/Rakefile @@ -3,14 +3,11 @@ Bundler::GemHelper.install_tasks require 'rubygems' require 'rake' -require 'spec/rake/spectask' - -spec_files = Rake::FileList["spec/**/*_spec.rb"] +require 'rspec/core/rake_task' desc "Run specs" -Spec::Rake::SpecTask.new do |t| - t.spec_files = spec_files - t.spec_opts = ["-c"] +RSpec::Core::RakeTask.new(:spec) do |t| + t.rspec_opts = ["-c"] end task :default => :spec diff --git a/lib/nested_form/builder.rb b/lib/nested_form/builder.rb index ca370d0a..453678f7 100644 --- a/lib/nested_form/builder.rb +++ b/lib/nested_form/builder.rb @@ -1,6 +1,6 @@ module NestedForm class Builder < ActionView::Helpers::FormBuilder - def link_to_add(name, association) + def link_to_add(name, association, html_options = {}) @fields ||= {} @template.after_nested_form(association) do model_object = object.class.reflect_on_association(association).klass.new @@ -9,7 +9,15 @@ def link_to_add(name, association) output.safe_concat('') output end - @template.link_to(name, "javascript:void(0)", :class => "add_nested_fields", "data-association" => association) + #@template.link_to(name, "javascript:void(0)", :class => "add_nested_fields", "data-association" => association, html_options.merge!{html_options}) + linkclass = "add_nested_fields" + if html_options.has_key?(:class) + html_options[:class] << " #{linkclass}" + else + html_options.merge!({:class => linkclass}) + end + html_options.merge!({"data-association" => association}) + @template.link_to(name, "javascript:void(0)", html_options) end def link_to_remove(name) @@ -31,4 +39,4 @@ def fields_for_nested_model(name, association, args, block) output end end -end \ No newline at end of file +end