cocooned 1.4.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +1 @@
1
-
2
- .cocooned-visible-item {
3
- transition: opacity .45s ease-out;
4
- opacity: 1;
5
- }
6
-
7
- .cocooned-hidden-item {
8
- opacity: 0;
9
- }
1
+ /* TODO: Remove in 3.0 */
data/cocooned.gemspec CHANGED
@@ -11,32 +11,41 @@ Gem::Specification.new do |spec|
11
11
  spec.authors = ['Gaël-Ian Havard', 'Nathan Van der Auwera']
12
12
  spec.email = ['gael-ian@notus.sh', 'nathan@dixis.com']
13
13
 
14
- spec.summary = 'Unobtrusive Rails nested forms handling, with or without jQuery.'
15
- spec.description = 'Easier nested form. Supports standard Rails forms, Formtastic and SimpleForm.'
16
- spec.homepage = 'http://github.com/notus-sh/cocooned'
14
+ spec.summary = 'Form builder agnostic handling of Rails nested forms'
15
+ spec.description = <<-DESC.gsub(/\s+/, ' ')
16
+ Easier nested form in Rails with capabilities to add, remove, reorder or limit nested items.
17
+ Works with standard Rails form builder, Formtastic or SimpleForm, and with or without jQuery.
18
+ DESC
19
+ spec.homepage = 'https://github.com/notus-sh/cocooned'
17
20
 
18
21
  raise 'RubyGems 2.0 or newer is required.' unless spec.respond_to?(:metadata)
19
22
 
20
- spec.metadata['allowed_push_host'] = 'https://rubygems.org'
23
+ spec.metadata = {
24
+ 'allowed_push_host' => 'https://rubygems.org',
25
+ 'rubygems_mfa_required' => 'true',
26
+
27
+ 'bug_tracker_uri' => 'https://github.com/notus-sh/cocooned/issues',
28
+ 'changelog_uri' => 'https://github.com/notus-sh/cocooned/blob/main/CHANGELOG.md',
29
+ 'homepage_uri' => 'https://github.com/notus-sh/cocooned',
30
+ 'source_code_uri' => 'https://github.com/notus-sh/cocooned',
31
+ 'funding_uri' => 'https://opencollective.com/notus-sh'
32
+ }
21
33
 
22
34
  spec.require_paths = ['lib']
35
+
36
+ excluded_dirs = %r{^(.github|dev|npm|spec)/}
37
+ excluded_files = %w[.gitignore .rspec Gemfile Gemfile.lock Rakefile package.json yarn.lock]
23
38
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
24
- f.match(%r{^(config|gemfiles|npm|spec)/}) ||
25
- %w[.gitignore .rspec .travis.yml].include?(f) ||
26
- %w[Gemfile Gemfile.lock package.json yarn.lock].include?(f)
39
+ f.match(excluded_dirs) || excluded_files.include?(f)
27
40
  end
28
- spec.required_ruby_version = '>= 2.5'
41
+ spec.required_ruby_version = '>= 2.6'
29
42
 
30
- spec.add_dependency 'rails', '>= 5.0', '<= 7.1'
43
+ spec.add_dependency 'rails', '>= 6.0', '<= 7.1'
31
44
 
32
45
  spec.add_development_dependency 'bundler', '~> 2.1'
33
- spec.add_development_dependency 'jasmine', '~> 3.2'
34
- spec.add_development_dependency 'rake'
35
- spec.add_development_dependency 'rspec', '~> 3.10.0'
36
- spec.add_development_dependency 'rspec-rails', '~> 5.0.0'
37
- spec.add_development_dependency 'rubocop'
38
- spec.add_development_dependency 'rubocop-performance'
39
- spec.add_development_dependency 'rubocop-rails'
40
- spec.add_development_dependency 'rubocop-rake'
41
- spec.add_development_dependency 'rubocop-rspec'
46
+ spec.add_development_dependency 'formtastic', '~> 4.0'
47
+ spec.add_development_dependency 'rake', '~> 13.0'
48
+ spec.add_development_dependency 'rspec', '~> 3.11'
49
+ spec.add_development_dependency 'rspec-rails', '>= 5.0'
50
+ spec.add_development_dependency 'simple_form', '~> 5.1'
42
51
  end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cocooned
4
+ module Association
5
+ class Builder # :nodoc:
6
+ attr_reader :association, :record
7
+
8
+ def initialize(record, association, options = {})
9
+ @record = record
10
+ @association = association
11
+ @options = options.dup.symbolize_keys.reverse_merge(force_non_association_create: false, wrap_object: false)
12
+ end
13
+
14
+ def build
15
+ model = reflection ? build_with_reflection : build_without_reflection
16
+ model = options[:wrap_object].call(model) if options[:wrap_object].respond_to?(:call)
17
+ model
18
+ end
19
+
20
+ protected
21
+
22
+ attr_reader :options
23
+
24
+ def model
25
+ record.class
26
+ end
27
+
28
+ def reflection
29
+ @reflection ||= model.try(:reflect_on_association, association)
30
+ end
31
+
32
+ def build_with_reflection
33
+ return build_with_conditions if should_use_conditions?
34
+
35
+ # Assume ActiveRecord or compatible
36
+ # We use a clone of the current form object to not link
37
+ # object together (even if unsaved)
38
+ dummy = record.dup
39
+ model = if reflection.collection?
40
+ dummy.send(association).build
41
+ else
42
+ dummy.send("build_#{association}")
43
+ end
44
+ model = model.dup if model.frozen?
45
+ model
46
+ end
47
+
48
+ def build_without_reflection
49
+ methods = %W[build_#{association.to_s.pluralize} build_#{association.to_s.singularize}]
50
+ available_methods = methods.select { |m| record.respond_to?(m) }
51
+ raise "Association #{association} doesn't exist on #{model}" unless available_methods.any?
52
+
53
+ record.send(available_methods.first)
54
+ end
55
+
56
+ def should_use_conditions?
57
+ reflection.class.name.starts_with?('Mongoid::') || options[:force_non_association_create]
58
+ end
59
+
60
+ def build_with_conditions
61
+ conditions = reflection.respond_to?(:conditions) ? reflection.conditions.flatten : []
62
+ reflection.klass.new(*conditions)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cocooned
4
+ module Association
5
+ class Renderer # :nodoc:
6
+ def initialize(template, form, association, object, options = {})
7
+ @template = template
8
+ @form = form
9
+ @association = association
10
+ @object = object
11
+ @options = options.dup.symbolize_keys
12
+ end
13
+
14
+ def render
15
+ form.public_send(form_method, association, object, form_options) do |form|
16
+ template.render(partial, **render_options(form))
17
+ end
18
+ end
19
+
20
+ protected
21
+
22
+ attr_reader :template, :form, :association, :object, :options
23
+
24
+ def singular_association
25
+ association.to_s.singularize
26
+ end
27
+
28
+ def form_method
29
+ ancestors = form.class.ancestors.map(&:to_s)
30
+ return :simple_fields_for if ancestors.include?('SimpleForm::FormBuilder')
31
+ return :semantic_fields_for if ancestors.include?('Formtastic::FormBuilder')
32
+
33
+ :fields_for
34
+ end
35
+
36
+ def form_options
37
+ options.fetch(:form_options, {}).symbolize_keys.reverse_merge(child_index: "new_#{association}")
38
+ end
39
+
40
+ def partial
41
+ options.fetch(:partial, "#{singular_association}_fields")
42
+ end
43
+
44
+ def render_options(form)
45
+ options.fetch(:locals, {}).merge(form_name => form)
46
+ end
47
+
48
+ def form_name
49
+ options.fetch(:form_name, :f).to_sym
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cocooned
4
+ module Association # :nodoc:
5
+ autoload :Builder, 'cocooned/association/builder'
6
+ autoload :Renderer, 'cocooned/association/renderer'
7
+ end
8
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/deprecation'
4
+
5
+ module Cocooned
6
+ # Custom deprecator to use with ActiveSupport::Deprecation methods
7
+ class Deprecation < ActiveSupport::Deprecation
8
+ @deprecators = {}
9
+
10
+ def self.[](deprecation_horizon = nil)
11
+ @deprecators[deprecation_horizon] ||= new(deprecation_horizon)
12
+ end
13
+
14
+ def initialize(deprecation_horizon = nil, gem_name = 'Cocooned')
15
+ deprecation_horizon ||= format('%<major>d.0', major: Gem::Version.new(Cocooned::VERSION).segments.first + 1)
16
+ super(deprecation_horizon, gem_name)
17
+ end
18
+ end
19
+
20
+ # Deprecated methods
21
+ module Deprecated # :nodoc:
22
+ module Helpers # :nodoc:
23
+ module Tags # :nodoc:
24
+ # @deprecated: Please use {#cocooned_add_item_link} instead
25
+ def link_to_add_association(*args, &block)
26
+ cocooned_add_item_link(*args, &block)
27
+ end
28
+ deprecate link_to_add_association: 'Use :cocooned_add_link instead',
29
+ deprecator: Deprecation['3.0']
30
+
31
+ # @deprecated: Please use {#cocooned_remove_item_link} instead
32
+ def link_to_remove_association(*args, &block)
33
+ cocooned_remove_item_link(*args, &block)
34
+ end
35
+ deprecate link_to_remove_association: 'Use :cocooned_remove_item_link instead',
36
+ deprecator: Deprecation['3.0']
37
+ end
38
+ end
39
+
40
+ module TagsHelper # :nodoc:
41
+ module DefaultLabel # :nodoc:
42
+ protected
43
+
44
+ def i18n_namespaces
45
+ return super unless I18n.exists?(:cocoon)
46
+
47
+ Deprecation['3.0'].warn 'Support for the :cocoon i18n namespace will be removed in 3.0', caller_locations(3)
48
+ super + %w[cocoon]
49
+ end
50
+ end
51
+
52
+ module DataAttributes # :nodoc:
53
+ protected
54
+
55
+ # Compatibility with the old way to pass data attributes to Rails view helpers
56
+ # Has we use the :data key (introduced in Rails 3.1), they will not be looked up.
57
+ def html_data
58
+ return super unless data_keys.size.positive?
59
+
60
+ Deprecation['3.0'].warn 'Compatibility with options named data-* will be removed in 3.0', caller_locations(3)
61
+ html_data_normalize super.merge(data_options)
62
+ end
63
+
64
+ def data_keys
65
+ options.keys.select { |k| k.to_s.match?(/data[_-]/) }
66
+ end
67
+
68
+ def data_options
69
+ data_keys.each_with_object({}) do |original_key, extracted|
70
+ key = original_key.to_s.gsub(/^data[_-]/, '')
71
+ extracted[key] = options.delete(original_key)
72
+ end
73
+ end
74
+ end
75
+
76
+ module AssociationOptions # :nodoc:
77
+ protected
78
+
79
+ def association_options
80
+ if options.key? :insertion_traversal
81
+ Deprecation['3.0'].warn 'Support for the :insertion_traversal will be removed in 3.0', caller_locations(3)
82
+ end
83
+
84
+ super
85
+ end
86
+ end
87
+
88
+ module Renderer # :nodoc:
89
+ protected
90
+
91
+ def renderer_options
92
+ return super unless options.key?(:render_options)
93
+
94
+ Deprecation['3.0'].warn 'Support for :render_options will be removed in 3.0', caller_locations(3)
95
+ legacy_options = options.delete(:render_options)
96
+
97
+ super.tap do |opts|
98
+ opts[:locals] = legacy_options.delete(:locals) if legacy_options.key?(:locals)
99
+ opts[:form_options] = legacy_options
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cocooned
4
+ module Helpers
5
+ # Cocooned containers helpers output container or item wrappers as expected by
6
+ # the JavaScript companion package.
7
+ module Containers
8
+ # Wrap content with the expected markup for a Cocooned container.
9
+ #
10
+ # This is a wrapper around `ActionView::Base#content_tag` to automatically
11
+ # add default classes and data-attributes that define a Cocooned
12
+ # container.
13
+ #
14
+ # = Signatures
15
+ #
16
+ # cocooned_container(*arguments, **options) do
17
+ # # Container content
18
+ # end
19
+ #
20
+ # = Parameters
21
+ #
22
+ # `cocooned_container` supports following options:
23
+ #
24
+ # - `:limit` [Integer]
25
+ # Enable the limit plugin and set the accepted maximum number of items
26
+ # - `:reorderable` [Boolean|Hash]
27
+ # Enable the reorderable plugin. When a boolean, use plugin's default.
28
+ # You can also pass a Hash with explicit options (ex: `{ startAt: 1 }`).
29
+ #
30
+ # Any other argument or option supported by `ActionView::Base#content_tag`
31
+ # will be forwarded.
32
+ def cocooned_container(*args, &block)
33
+ options = args.extract_options!.dup
34
+ defaults = cocooned_wrapper_defaults(options, %w[cocooned-container], :'cocooned-container')
35
+ defaults[:data][:cocooned_options] = options.extract!(:limit, :reorderable).to_json
36
+
37
+ content_tag(:div, *args, **options.deep_merge(defaults), &block)
38
+ end
39
+
40
+ # Wrap content with the expected markup for a Cocooned item.
41
+ #
42
+ # This is a wrapper around `ActionView::Base#content_tag` to automatically
43
+ # add default classes and data-attributes that define a Cocooned item.
44
+ #
45
+ # = Signatures
46
+ #
47
+ # cocooned_item(*arguments, **options) do
48
+ # # Item content
49
+ # end
50
+ #
51
+ # = Parameters
52
+ #
53
+ # Any argument or option supported by `ActionView::Base#content_tag` will
54
+ # be forwarded.
55
+ def cocooned_item(*args, &block)
56
+ options = args.extract_options!.dup
57
+ defaults = cocooned_wrapper_defaults(options, %w[cocooned-item nested-fields], :'cocooned-item')
58
+
59
+ content_tag(:div, *args, **options.deep_merge(defaults), &block)
60
+ end
61
+
62
+ protected
63
+
64
+ def cocooned_wrapper_defaults(options, additional_classes, mark)
65
+ # TODO: Replace with compact_blank when dropping support for Rails 6.0
66
+ classes = Array.wrap(options.delete(:class)).flat_map { |k| k.to_s.split }.reject(&:blank?)
67
+
68
+ { class: (classes + additional_classes), data: { mark => true } }
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cocooned
4
+ module Helpers
5
+ module Tags
6
+ # Helpers to generate action triggers to add items in a nested form.
7
+ #
8
+ # = Signatures
9
+ #
10
+ # {method}(label, form, association, options = {})
11
+ # # Explicit name
12
+ #
13
+ # {method}(form, association, options = {}) do
14
+ # # Name as a block
15
+ # end
16
+ #
17
+ # {method}(form, association, options = {})
18
+ # # Use default name
19
+ #
20
+ # = Parameters
21
+ #
22
+ # `label` is the text to be used as the link label. See the main
23
+ # documentation for Cocooned::Helpers::Tags for more about labelling.
24
+ #
25
+ # `form` is your form builder. Can be a SimpleForm::Builder,
26
+ # Formtastic::Builder or a standard Rails FormBuilder.
27
+ #
28
+ # `association` is the name of the nested association.
29
+ # Ex: cocooned_add_item_link "Add an item", form, :items
30
+ #
31
+ # = Options
32
+ #
33
+ # `options` can be any of the following.
34
+ #
35
+ # Association options:
36
+ #
37
+ # - **insertion_method** : the method to be used to insert new items.
38
+ # Can be any of `before`, `after`, `append`, `prepend`, `replaceWith`.
39
+ # Defaults to `before`
40
+ # - **insertion_node** : a CSS selector to match new items insertion node.
41
+ # Can be any CSS selector supported by `document.querySelector`.
42
+ # For compatibility with the original Cocoon:
43
+ # * 'this' is supported as a special value to use the trigger itself as
44
+ # insertion node.
45
+ # * If no value is specified, the trigger's parent will be used.
46
+ # - **count**: how many item will be inserted on click.
47
+ # Defaults to 1.
48
+ #
49
+ # Rendering options:
50
+ #
51
+ # - **partial**: the nested form partial.
52
+ # Defaults to `{association.singular_name}_fields`.
53
+ # - **form_name**: name used to access the form builder in the nested form
54
+ # partial. Defaults to `:f`.
55
+ # - **form_options**: options to be passed to the nested form builder. Can
56
+ # be used to specify a wrapper for simple_form_fields if you use its
57
+ # Bootstrap setup, for example. No defaults.
58
+ # - **locals**: a hash of local variables to forward to the partial. No
59
+ # default.
60
+ #
61
+ # Building options:
62
+ #
63
+ # - **wrap_object**: anything responding to `call` to be used to wrap the
64
+ # newly build item instance. Can be useful with decorators or special
65
+ # initialisations. No default.
66
+ # Ex:
67
+ # cocooned_add_item_link "Add an item", form, :items,
68
+ # wrap_object: Proc.new { |comment| CommentDecorator.new(comment) })
69
+ # - **force_non_association_create**: force to build instances of the
70
+ # nested model without calling association build methods
71
+ # (`build_{association}` or `{association}.build`). Can be usefull if,
72
+ # for some specific reason, you need an object to _not_ be created on
73
+ # the association, for example if you did not want `after_add` callbacks
74
+ # to be triggered. Defaults to false.
75
+ #
76
+ # Compatibility options:
77
+ #
78
+ # These options are supported for backward compatibility with the original
79
+ # Cocoon. **Support for these options will be removed in the next major
80
+ # release !**.
81
+ #
82
+ # - **insertion_traversal**: a jQuery DOM traversal method name to use in
83
+ # combination with **insertion_node** to find the insertion node from
84
+ # the trigger. Can be any of `closest`, `parent`, `prev`, `next` or
85
+ # `siblings`.
86
+ # Expressed in jQuery pseudo-code, the insertion node will be determined
87
+ # as the result of `$(trigger).{traversal}({insertion_node})`.
88
+ # - **render_options**: A nested Hash originally used to pass locals and form
89
+ # builder options.
90
+ module Add
91
+ # Output a link to add an item in a nested form.
92
+ #
93
+ # = Signatures
94
+ #
95
+ # cocooned_add_item_link(label, form, association, options = {})
96
+ # # Explicit name
97
+ #
98
+ # cocooned_add_item_link(form, association, options = {}) do
99
+ # # Name as a block
100
+ # end
101
+ #
102
+ # cocooned_add_item_link(form, association, options = {})
103
+ # # Use default name
104
+ #
105
+ # See Cocooned::Helpers::Tags::Add main documentation for a reference of
106
+ # supported parameters.
107
+ #
108
+ # See the documentation of +ActionView::Base#link_to+ for additional
109
+ # options.
110
+ def cocooned_add_item_link(*args, &block)
111
+ cocooned_link(Cocooned::Tags::Add, *args, &block)
112
+ end
113
+
114
+ # Output a button to add an item in a nested form.
115
+ #
116
+ # = Signatures
117
+ #
118
+ # cocooned_add_item_button(label, form, association, options = {})
119
+ # # Explicit name
120
+ #
121
+ # cocooned_add_item_button(form, association, options = {}) do
122
+ # # Name as a block
123
+ # end
124
+ #
125
+ # cocooned_add_item_button(form, association, options = {})
126
+ # # Use default name
127
+ #
128
+ # See Cocooned::Helpers::Tags::Add main documentation for a reference of
129
+ # supported options.
130
+ def cocooned_add_item_button(*args, &block)
131
+ cocooned_button(Cocooned::Tags::Add, *args, &block)
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cocooned
4
+ module Helpers
5
+ module Tags
6
+ # Helpers to generate action triggers to move items down in a nested form.
7
+ #
8
+ # = Signatures
9
+ #
10
+ # {method}(label, form, options = {})
11
+ # # Explicit name
12
+ #
13
+ # {method}(form, options = {}) do
14
+ # # Name as a block
15
+ # end
16
+ #
17
+ # {method}(form, options = {})
18
+ # # Use default name
19
+ #
20
+ # = Parameters
21
+ #
22
+ # `label` is the text to be used as the link label. See the main
23
+ # documentation for Cocooned::Helpers::Tags for more about labelling.
24
+ #
25
+ # `form` is your form builder. Can be a SimpleForm::Builder,
26
+ # Formtastic::Builder or a standard Rails FormBuilder.
27
+ module Down
28
+ # Output a link to move an item down.
29
+ #
30
+ # = Signatures
31
+ #
32
+ # cocooned_move_item_down_link(label, form, options = {})
33
+ # # Explicit name
34
+ #
35
+ # cocooned_move_item_down_link(form, options = {}) do
36
+ # # Name as a block
37
+ # end
38
+ #
39
+ # cocooned_move_item_down_link(form, options = {})
40
+ # # Use default name
41
+ #
42
+ # See Cocooned::Helpers::Tags::Down main documentation for a reference
43
+ # of supported parameters.
44
+ #
45
+ # See the documentation of +ActionView::Base#link_to+ for additional
46
+ # options.
47
+ def cocooned_move_item_down_link(*args, &block)
48
+ cocooned_link(Cocooned::Tags::Down, *args, &block)
49
+ end
50
+
51
+ # Output a button to move an item down.
52
+ #
53
+ # = Signatures
54
+ #
55
+ # cocooned_move_item_down_button(label, form, options = {})
56
+ # # Explicit name
57
+ #
58
+ # cocooned_move_item_down_button(form, options = {}) do
59
+ # # Name as a block
60
+ # end
61
+ #
62
+ # cocooned_move_item_down_button(form, options = {})
63
+ # # Use default name
64
+ #
65
+ # See Cocooned::Helpers::Tags::Add main documentation for a reference of
66
+ # supported parameters.
67
+ #
68
+ # See the documentation of +ActionView::Helpers::FormBuilder#button+ for
69
+ # valid options.
70
+ def cocooned_move_item_down_button(*args, &block)
71
+ cocooned_button(Cocooned::Tags::Down, *args, &block)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cocooned
4
+ module Helpers
5
+ module Tags
6
+ # Helpers to generate action triggers to remove items in a nested form.
7
+ #
8
+ # = Signatures
9
+ #
10
+ # {method}(label, form, options = {})
11
+ # # Explicit name
12
+ #
13
+ # {method}(form, options = {}) do
14
+ # # Name as a block
15
+ # end
16
+ #
17
+ # {method}(form, options = {})
18
+ # # Use default name
19
+ #
20
+ # = Parameters
21
+ #
22
+ # `label` is the text to be used as the link label. See the main
23
+ # documentation for Cocooned::Helpers::Tags for more about labelling.
24
+ #
25
+ # `form` is your form builder. Can be a SimpleForm::Builder,
26
+ # Formtastic::Builder or a standard Rails FormBuilder.
27
+ module Remove
28
+ # Output a link to remove an item (and an hidden field to mark
29
+ # it as destroyed if it has already been persisted).
30
+ #
31
+ # = Signatures
32
+ #
33
+ # cocooned_remove_item_link(label, form, options = {})
34
+ # # Explicit name
35
+ #
36
+ # cocooned_remove_item_link(form, options = {}) do
37
+ # # Name as a block
38
+ # end
39
+ #
40
+ # cocooned_remove_item_link(form, options = {})
41
+ # # Use default name
42
+ #
43
+ # See Cocooned::Helpers::Tags::Remove main documentation for a reference
44
+ # of supported parameters.
45
+ #
46
+ # See the documentation of +ActionView::Base#link_to+ for additional
47
+ # options.
48
+ def cocooned_remove_item_link(*args, &block)
49
+ cocooned_link(Cocooned::Tags::Remove, *args, &block)
50
+ end
51
+
52
+ # Output a button to remove an item (and an hidden field to mark
53
+ # it as destroyed if it has already been persisted).
54
+ #
55
+ # = Signatures
56
+ #
57
+ # cocooned_remove_item_link(label, form, options = {})
58
+ # # Explicit name
59
+ #
60
+ # cocooned_remove_item_link(form, options = {}) do
61
+ # # Name as a block
62
+ # end
63
+ #
64
+ # cocooned_remove_item_link(form, options = {})
65
+ # # Use default name
66
+ #
67
+ # See Cocooned::Helpers::Tags::Remove main documentation for a reference
68
+ # of supported parameters.
69
+ #
70
+ # See the documentation of +ActionView::Base#link_to+ for additional
71
+ # options.
72
+ def cocooned_remove_item_button(*args, &block)
73
+ cocooned_button(Cocooned::Tags::Remove, *args, &block)
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end