nested_fields_rails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .idea
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in nested_fields.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 gabriel
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # NestedFieldsRails
2
+
3
+ Manage multiple models in the same form. Inspired on [nested_form gem](https://github.com/ryanb/nested_form)
4
+
5
+ Tested with Rails 3.2.x and Ruby 1.9.3
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'nested_fields_rails'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install nested_fields_rails
20
+
21
+ And then add it to the Asset Pipeline in the application.js file:
22
+
23
+ //= require jquery_nested_fields
24
+
25
+ ## Usage
26
+
27
+ ### Model definition
28
+
29
+ class Person
30
+ has_many :phones
31
+ attr_accessible :phones_attributes
32
+ accepts_nested_attributes_for :phones, :allow_destroy => true
33
+ end
34
+
35
+ ### Form specification
36
+
37
+ = form_for @person do |f|
38
+ ...
39
+ %strong Phones
40
+ = f.link_to_add_nested_fields 'Add', :phones
41
+ = f.nested_fields_for :phones do |phones_form|
42
+ = phones_form.link_to_remove_nested_fields 'Remove'
43
+ = phones_form.text_field :number
44
+
45
+ ### Partials support
46
+
47
+ Main form
48
+
49
+ = form_for @person do |f|
50
+ ...
51
+ %strong Phones
52
+ = f.link_to_add_nested_fields 'Add', :phones
53
+ = f.nested_fields_for :phones
54
+
55
+ Partial for item
56
+
57
+ = f.link_to_remove_nested_fields 'Remove'
58
+ = f.text_field :number
59
+
60
+ ### Html wrappers
61
+
62
+ Table wrapper
63
+
64
+ = form_for @person do |f|
65
+ ...
66
+ %table
67
+ %thead
68
+ %tr
69
+ %td f.link_to_add_nested_fields 'Add', :phones
70
+ %td Phones
71
+ = f.nested_fields_for :phones, nil, :wrapper => :table do |phones_form|
72
+ %td= phones_form.link_to_remove_nested_fields 'Remove'
73
+ %td= phones_form.text_field :number
74
+
75
+ Custom wrapper
76
+
77
+ = form_for @person do |f|
78
+ ...
79
+ %strong Phones
80
+ = f.link_to_add_nested_fields 'Add', :phones
81
+ = f.nested_fields_for :phones, nil, :collection_wrapper => :ul, :element_wrapper => :li do |phones_form|
82
+ = phones_form.link_to_remove_nested_fields 'Remove'
83
+ = phones_form.text_field :number
84
+
85
+ ### Order support
86
+
87
+ = form_for @person do |f|
88
+ ...
89
+ %strong Phones
90
+ = f.link_to_add_nested_fields 'Add', :phones
91
+ = f.nested_fields_for :phones do |phones_form|
92
+ = phones_form.link_to_remove_nested_fields 'Remove'
93
+ = phones_form.link_to_up_nested_fields 'Up'
94
+ = phones_form.link_to_down_nested_fields 'Down'
95
+ = phones_form.text_field :number
96
+ = phones_form.index_nested_fields :order
97
+
98
+ ## Contributing
99
+
100
+ 1. Fork it
101
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
102
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
103
+ 4. Push to the branch (`git push origin my-new-feature`)
104
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,4 @@
1
+ module NestedFieldsRails
2
+ class Engine < ::Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,62 @@
1
+ module NestedFieldsRails
2
+ class ::ActionView::Helpers::FormBuilder
3
+
4
+ def link_to_add_nested_fields(*args, &block)
5
+ options = args.extract_options!.symbolize_keys
6
+ association = args.pop
7
+ options[:class] = [options[:class], 'add-nested-fields'].compact.join(' ')
8
+ options['data-association'] = association
9
+ args << (options.delete(:href) || 'javascript:void(0)')
10
+ args << options
11
+ @template.link_to(*args, &block)
12
+ end
13
+
14
+ def link_to_remove_nested_fields(*args, &block)
15
+ (hidden_field(:_destroy, :class => 'destroy') << link_to_action_nested_fields(:remove, *args, &block)).html_safe
16
+ end
17
+
18
+ def link_to_up_nested_fields(*args, &block)
19
+ link_to_action_nested_fields(:up, *args, &block)
20
+ end
21
+
22
+ def link_to_down_nested_fields(*args, &block)
23
+ link_to_action_nested_fields(:down, *args, &block)
24
+ end
25
+
26
+ def index_nested_fields(attribute_name)
27
+ hidden_field attribute_name, :class => 'index'
28
+ end
29
+
30
+ def nested_fields_for(association_name, record_object = nil, fields_options = {}, &block)
31
+ collection_wrapper = fields_options[:collection_wrapper] || (fields_options[:wrapper] && fields_options[:wrapper].to_sym == :table ? :tbody : nil) || :div
32
+ element_wrapper = fields_options[:element_wrapper] || (fields_options[:wrapper] && fields_options[:wrapper].to_sym == :table ? :tr : nil) || :div
33
+
34
+ fields_block = block || Proc.new { |fields| @template.render(:partial => "#{association_name.to_s.singularize}_fields", :locals => {:f => fields}) }
35
+ fields = @template.content_tag(collection_wrapper, fields_for(association_name, record_object, fields_options, &fields_block), :id => association_name, :class => 'nested-fields')
36
+
37
+ model_object = object.class.reflect_on_association(association_name).klass.new
38
+ template = fields_for(association_name, model_object, :element_wrapper => element_wrapper, :child_index => "new_#{association_name}", &fields_block)
39
+ template_options = {:id => "#{association_name}_fields_template", :type => 'text/x-jquery-tmpl'}
40
+ fields_template = @template.content_tag(:script, template, template_options)
41
+
42
+ fields + fields_template
43
+ end
44
+
45
+ alias default_fields_for_nested_model fields_for_nested_model
46
+ def fields_for_nested_model(name, object, options, block)
47
+ tag = options[:element_wrapper] || (options[:wrapper] && options[:wrapper].to_sym == :table ? :tr : nil) || :div
48
+ @template.content_tag(tag, default_fields_for_nested_model(name, object, options, block), :class => 'fields', 'data-object-id' => object.id || options[:child_index])
49
+ end
50
+
51
+ private
52
+
53
+ def link_to_action_nested_fields(action, *args, &block)
54
+ options = args.extract_options!.symbolize_keys
55
+ options[:class] = [options[:class], "#{action}-nested-fields"].compact.join(" ")
56
+ args << (options.delete(:href) || 'javascript:void(0)')
57
+ args << options
58
+ @template.link_to(*args, &block)
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,3 @@
1
+ module NestedFieldsRails
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,3 @@
1
+ require "nested_fields_rails/version"
2
+ require "nested_fields_rails/engine"
3
+ require 'nested_fields_rails/form_builder'
@@ -0,0 +1,18 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/nested_fields_rails/version', __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'nested_fields_rails'
6
+ s.version = NestedFieldsRails::VERSION
7
+
8
+ s.authors = ["gabriel"]
9
+ s.email = ["gnaiman@keepcon.com"]
10
+ s.homepage = 'https://github.com/gabynaiman/nested_fields_rails'
11
+ s.summary = 'Manage multiple models the same form'
12
+ s.description = 'Manage multiple models the same form'
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+ end
@@ -0,0 +1,97 @@
1
+ jQuery(function($) {
2
+
3
+ NestedFields = function(associationName) {
4
+ this.associationName = associationName;
5
+
6
+ this.add = function() {
7
+ var template = $('#' + this.associationName + '_fields_template').html();
8
+ var container = $('#' + this.associationName + '.nested-fields');
9
+ var regexp = new RegExp("new_" + this.associationName, "g");
10
+ var newId = new Date().getTime();
11
+ container.append(template.replace(regexp, newId))
12
+ this.updateIndex();
13
+ };
14
+
15
+ this.remove = function(objectId) {
16
+ var fields = this.findFields(objectId);
17
+ var destroyField = fields.find('.destroy');
18
+ destroyField.val('true');
19
+ fields.hide();
20
+ this.updateIndex();
21
+ };
22
+
23
+ this.up = function(objectId) {
24
+ var fields = this.findFields(objectId);
25
+ var container = fields.closest('.nested-fields');
26
+ var index = fields.index() - 1;
27
+
28
+ if (index >= 0) {
29
+ this.findFields(objectId).remove();
30
+ container.children('.fields').eq(index).before(fields);
31
+ this.updateIndex();
32
+ }
33
+ };
34
+
35
+ this.down = function(objectId) {
36
+ var fields = this.findFields(objectId);
37
+ var container = fields.closest('.nested-fields');
38
+ var index = fields.index();
39
+
40
+ if (fields.index() < container.children('.fields').size()) {
41
+ this.findFields(objectId).remove();
42
+ container.children('.fields').eq(index).after(fields);
43
+ this.updateIndex();
44
+ }
45
+ };
46
+
47
+ this.findFields = function(objectId) {
48
+ return $('#' + this.associationName + '.nested-fields .fields[data-object-id=' + objectId + ']');
49
+ };
50
+
51
+ this.updateIndex = function() {
52
+ var container = $('#' + this.associationName + '.nested-fields');
53
+ container.find('.index').each(function(index, element) {
54
+ $(element).val(index);
55
+ });
56
+ }
57
+
58
+ this.ids = function() {
59
+ var ids = [];
60
+ $('#' + this.associationName + '.nested-fields .fields').each(function(index, element) {
61
+ ids.push($(element).attr('data-object-id'));
62
+ });
63
+ return ids;
64
+ };
65
+ };
66
+
67
+ function nestedFieldContext(element) {
68
+ var link = $(element);
69
+ var fields = link.closest('.fields');
70
+ var objectId = fields.attr('data-object-id');
71
+ var container = fields.closest('.nested-fields');
72
+ var associationName = container.attr('id');
73
+ return {'associationName': associationName, 'objectId': objectId};
74
+ };
75
+
76
+ $('.add-nested-fields').live('click', function() {
77
+ var link = $(this);
78
+ var associationName = link.attr('data-association');
79
+ new NestedFields(associationName).add();
80
+ });
81
+
82
+ $('.remove-nested-fields').live('click', function() {
83
+ var context = nestedFieldContext(this);
84
+ new NestedFields(context.associationName).remove(context.objectId);
85
+ });
86
+
87
+ $('.up-nested-fields').live('click', function() {
88
+ var context = nestedFieldContext(this);
89
+ new NestedFields(context.associationName).up(context.objectId);
90
+ });
91
+
92
+ $('.down-nested-fields').live('click', function() {
93
+ var context = nestedFieldContext(this);
94
+ new NestedFields(context.associationName).down(context.objectId);
95
+ });
96
+
97
+ });
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nested_fields_rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - gabriel
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-30 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Manage multiple models the same form
15
+ email:
16
+ - gnaiman@keepcon.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - .gitignore
22
+ - Gemfile
23
+ - LICENSE
24
+ - README.md
25
+ - Rakefile
26
+ - lib/nested_fields_rails.rb
27
+ - lib/nested_fields_rails/engine.rb
28
+ - lib/nested_fields_rails/form_builder.rb
29
+ - lib/nested_fields_rails/version.rb
30
+ - nested_fields_rails.gemspec
31
+ - vendor/assets/javascripts/jquery_nested_fields.js
32
+ homepage: https://github.com/gabynaiman/nested_fields_rails
33
+ licenses: []
34
+ post_install_message:
35
+ rdoc_options: []
36
+ require_paths:
37
+ - lib
38
+ required_ruby_version: !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ! '>='
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ requirements: []
51
+ rubyforge_project:
52
+ rubygems_version: 1.8.16
53
+ signing_key:
54
+ specification_version: 3
55
+ summary: Manage multiple models the same form
56
+ test_files: []