awesome_nested_fields 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :gemcutter
2
+
3
+ # Specify your gem's dependencies in awesome_nested_fields.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,46 @@
1
+ module AwesomeNestedFieldsHelper
2
+ def nested_fields_items(builder, association, options={})
3
+ options = nested_fields_process_default_options(options, builder, association)
4
+
5
+ items = ''
6
+ builder.fields_for(association) do |f|
7
+ items << render(options[:partial], options[:builder_local] => f)
8
+ end
9
+
10
+ if options[:none_partial] and builder.object.send(association).empty?
11
+ items << render(options[:none_partial], options[:builder_local] => f)
12
+ end
13
+
14
+ items.html_safe
15
+ end
16
+
17
+ def nested_fields_template(builder, association, options={})
18
+ options = nested_fields_process_default_options(options, builder, association)
19
+
20
+ templates = content_tag(:script, type: 'text/html', class: options[:item_template_class]) do
21
+ builder.fields_for(association, options[:new_object], child_index: 'new_nested_item') do |f|
22
+ render(options[:partial], options[:builder_local] => f)
23
+ end
24
+ end
25
+
26
+ if options[:none_partial]
27
+ templates << content_tag(:script, type: 'text/html', class: options[:none_template_class]) do
28
+ builder.fields_for(association, options[:new_object], child_index: 'new_nested_item') do |f|
29
+ render(options[:none_partial], options[:builder_local] => f)
30
+ end
31
+ end
32
+ end
33
+
34
+ templates.html_safe
35
+ end
36
+
37
+ protected
38
+ def nested_fields_process_default_options(options, builder, association)
39
+ options[:new_object] ||= builder.object.class.reflect_on_association(association).klass.new
40
+ options[:partial] ||= association.to_s.singularize
41
+ options[:builder_local] ||= :builder
42
+ options[:item_template_class] ||= 'template item'
43
+ options[:none_template_class] ||= 'template none'
44
+ options
45
+ end
46
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/awesome_nested_fields/version', __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'awesome_nested_fields'
6
+ s.version = AwesomeNestedFields::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = %q[Lailson Bandeira]
9
+ s.email = %q[lailson@guava.com.br]
10
+ s.homepage = 'http://rubygems.org/gems/awesome_nested_fields'
11
+ s.summary = 'Awesome nested fields for Rails'
12
+ s.description = 'Awesome dynamic nested fields for Rails and jQuery'
13
+
14
+ s.required_rubygems_version = ">= 1.3.6"
15
+ s.rubyforge_project = "awesome_nested_fields"
16
+
17
+ s.add_development_dependency 'bundler', '>= 1.0.0'
18
+ s.add_runtime_dependency 'rails', '>= 3.0.0'
19
+
20
+ s.files = `git ls-files`.split("\n")
21
+ s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
22
+ s.require_path = 'lib'
23
+ end
@@ -0,0 +1,11 @@
1
+ module AwesomeNestedFields
2
+ class Engine < Rails::Engine
3
+ initializer 'awesome_nested_fields.add_middleware' do |app|
4
+ app.middleware.use ActionDispatch::Static, "#{root}/public"
5
+ end
6
+
7
+ config.to_prepare do
8
+ ApplicationController.helper(AwesomeNestedFieldsHelper)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module AwesomeNestedFields
2
+ VERSION = "0.0.3"
3
+ end
@@ -0,0 +1,195 @@
1
+ (function($) {
2
+
3
+ var defaultSettings = {
4
+ beforeInsert: function(item, callback) { callback() },
5
+ afterInsert: function(item) {},
6
+ beforeRemove: function(item, callback) { callback() },
7
+ afterRemove: function(item) {},
8
+ itemTemplate: '.item.template',
9
+ noneTemplate: '.none.template',
10
+ container: '.container',
11
+ item: '.item',
12
+ none: '.none',
13
+ addHandler: '.add',
14
+ removeHandler: '.remove',
15
+ newItemIndex: 'new_nested_item'
16
+ };
17
+
18
+ // PUBLIC API
19
+ var methods = {
20
+ init: function(options) {
21
+ var $this = $(this);
22
+ if($(this).data('nested-fields.options')) {
23
+ console.log('Nested fields already defined for this element. If you want to redefine options, destroy it and init again.');
24
+ return $this;
25
+ } else if(getOptions($this)) {
26
+ console.log('You cannot nest nested fields. Who would say that, uh?');
27
+ return $this;
28
+ }
29
+
30
+ options = $.extend({}, defaultSettings, options);
31
+ options.itemTemplate = $(options.itemTemplate, $this);
32
+ options.noneTemplate = $(options.noneTemplate, $this);
33
+ options.container = $(options.container, $this);
34
+ options.addHandler = $(options.addHandler, $this);
35
+ $this.data('nested-fields.options', options);
36
+
37
+ options.addHandler.bind('click.nested-fields', function(e) {
38
+ e.preventDefault();
39
+ var newItem = prepareTemplate(options);
40
+ insertItemWithCallbacks(newItem, null, options);
41
+ });
42
+
43
+ $(options.item, options.container).each(function(i, item) {
44
+ bindRemoveEvent(item, options);
45
+ });
46
+
47
+ return $this;
48
+ },
49
+
50
+ insert: function(callback, options) {
51
+ options = $.extend({}, getOptions(this), options);
52
+ var newItem = prepareTemplate(options);
53
+
54
+ insertItemWithCallbacks(newItem, callback, options);
55
+ },
56
+
57
+ remove: function(element, options) {
58
+ options = $.extend({}, getOptions(this), options);
59
+ return removeItem(element, options);
60
+ },
61
+
62
+ removeAll: function(options) {
63
+ options = $.extend({}, getOptions(this), options);
64
+ $(methods.items.apply(this)).each(function(i, el) {
65
+ methods.remove(el, options);
66
+ });
67
+ },
68
+
69
+ items: function() {
70
+ return findItems(getOptions(this));
71
+ },
72
+
73
+ destroy: function() {
74
+ $(this).removeData('nested-fields.options');
75
+ $('*', this).unbind('.nested-fields');
76
+ }
77
+ };
78
+
79
+ $.fn.nestedFields = function(method) {
80
+ if (methods[method]) {
81
+ return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
82
+ } else if (typeof method === 'object' || !method) {
83
+ return methods.init.apply(this, arguments);
84
+ } else {
85
+ $.error( 'Method ' + method + ' does not exist on jQuery.nestedFields' );
86
+ }
87
+ };
88
+
89
+ function getOptions(element) {
90
+ element = $(element);
91
+ while(element.length > 0) {
92
+ var data = element.data('nested-fields.options');
93
+ if(data) {
94
+ return data;
95
+ } else {
96
+ element = element.parent();
97
+ }
98
+ }
99
+ return null;
100
+ }
101
+
102
+ function prepareTemplate(options) {
103
+ var regexp = new RegExp(options.newItemIndex, 'g');
104
+ var newId = new Date().getTime();
105
+
106
+ var contents = options.itemTemplate.html();
107
+ var newItem = $(contents.replace(regexp, newId));
108
+ newItem.attr('data-new-record', true);
109
+ newItem.attr('data-record-id', newId);
110
+
111
+ bindRemoveEvent(newItem, options);
112
+
113
+ return newItem;
114
+ }
115
+
116
+ function insertItem(newItem, options) {
117
+ removeNone(options);
118
+ options.container.append(newItem);
119
+ }
120
+
121
+ function insertItemWithCallbacks(newItem, onInsertCallback, options) {
122
+ function insert() {
123
+ if(onInsertCallback) {
124
+ onInsertCallback(newItem);
125
+ }
126
+ insertItem(newItem, options);
127
+ }
128
+
129
+ if(!options.skipBefore) {
130
+ options.beforeInsert(newItem, insert);
131
+ } else {
132
+ insert();
133
+ }
134
+
135
+ if(!options.skipAfter) {
136
+ options.afterInsert(newItem);
137
+ }
138
+
139
+ return newItem;
140
+ }
141
+
142
+ function removeItem(element, options) {
143
+ function remove() {
144
+ if($element.attr('data-new-record')) { // record is new
145
+ $element.remove();
146
+ } else { // record should be marked and sent to server
147
+ $element.find("INPUT[name$='[_destroy]']").val('true');
148
+ $element.hide();
149
+ }
150
+ insertNone(options);
151
+ }
152
+
153
+ var $element = $(element);
154
+ if(!options.skipBefore) {
155
+ options.beforeRemove($element, remove);
156
+ } else {
157
+ remove();
158
+ }
159
+
160
+ if(!options.skipAfter) {
161
+ options.afterRemove($element);
162
+ }
163
+
164
+ return $element;
165
+ }
166
+
167
+ function bindRemoveEvent(item, options) {
168
+ var removeHandler = $(item).find(options.removeHandler);
169
+ var needsConfirmation = removeHandler.attr('data-confirm');
170
+
171
+ var event = needsConfirmation ? 'confirmed' : 'click';
172
+ removeHandler.bind(event + '.nested-fields', function(e) {
173
+ removeItem(item, options);
174
+ });
175
+ }
176
+
177
+ function insertNone(options) {
178
+ if(findItems(options).length == 0) {
179
+ options.container.append(options.noneTemplate.html());
180
+ }
181
+ }
182
+
183
+ function removeNone(options) {
184
+ findNone(options).remove();
185
+ }
186
+
187
+ function findItems(options) {
188
+ return options.container.find(options.item + ':visible');
189
+ }
190
+
191
+ function findNone(options) {
192
+ return options.container.find(options.none);
193
+ }
194
+
195
+ })(jQuery);
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: awesome_nested_fields
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 3
10
+ version: 0.0.3
11
+ platform: ruby
12
+ authors:
13
+ - Lailson Bandeira
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-02-12 00:00:00 -03:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: bundler
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 23
30
+ segments:
31
+ - 1
32
+ - 0
33
+ - 0
34
+ version: 1.0.0
35
+ type: :development
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: rails
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 7
46
+ segments:
47
+ - 3
48
+ - 0
49
+ - 0
50
+ version: 3.0.0
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ description: Awesome dynamic nested fields for Rails and jQuery
54
+ email: lailson@guava.com.br
55
+ executables: []
56
+
57
+ extensions: []
58
+
59
+ extra_rdoc_files: []
60
+
61
+ files:
62
+ - .gitignore
63
+ - Gemfile
64
+ - Rakefile
65
+ - app/helpers/awesome_nested_fields_helper.rb
66
+ - awesome_nested_fields.gemspec
67
+ - lib/awesome_nested_fields.rb
68
+ - lib/awesome_nested_fields/version.rb
69
+ - public/javascripts/jquery.nested-fields.js
70
+ has_rdoc: true
71
+ homepage: http://rubygems.org/gems/awesome_nested_fields
72
+ licenses: []
73
+
74
+ post_install_message:
75
+ rdoc_options: []
76
+
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ hash: 3
85
+ segments:
86
+ - 0
87
+ version: "0"
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ hash: 23
94
+ segments:
95
+ - 1
96
+ - 3
97
+ - 6
98
+ version: 1.3.6
99
+ requirements: []
100
+
101
+ rubyforge_project: awesome_nested_fields
102
+ rubygems_version: 1.3.7
103
+ signing_key:
104
+ specification_version: 3
105
+ summary: Awesome nested fields for Rails
106
+ test_files: []
107
+