cocooned 1.4.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +178 -0
- data/README.md +244 -172
- data/app/assets/javascripts/cocoon.js +1 -13
- data/app/assets/javascripts/cocooned.js +929 -399
- data/app/assets/stylesheets/cocooned.css +1 -9
- data/cocooned.gemspec +27 -18
- data/lib/cocooned/association/builder.rb +66 -0
- data/lib/cocooned/association/renderer.rb +53 -0
- data/lib/cocooned/association.rb +8 -0
- data/lib/cocooned/deprecation.rb +105 -0
- data/lib/cocooned/helpers/containers.rb +72 -0
- data/lib/cocooned/helpers/tags/add.rb +136 -0
- data/lib/cocooned/helpers/tags/down.rb +76 -0
- data/lib/cocooned/helpers/tags/remove.rb +78 -0
- data/lib/cocooned/helpers/tags/up.rb +76 -0
- data/lib/cocooned/helpers/tags.rb +60 -0
- data/lib/cocooned/helpers.rb +3 -329
- data/lib/cocooned/railtie.rb +7 -2
- data/lib/cocooned/tags/add.rb +61 -0
- data/lib/cocooned/tags/base.rb +61 -0
- data/lib/cocooned/tags/down.rb +19 -0
- data/lib/cocooned/tags/remove.rb +35 -0
- data/lib/cocooned/tags/up.rb +19 -0
- data/lib/cocooned/tags.rb +12 -0
- data/lib/cocooned/tags_helper.rb +83 -0
- data/lib/cocooned/version.rb +1 -1
- data/lib/cocooned.rb +6 -1
- metadata +51 -86
- data/History.md +0 -283
- data/Rakefile +0 -113
- data/lib/cocooned/association_builder.rb +0 -68
- data/lib/cocooned/helpers/cocoon_compatibility.rb +0 -27
- data/lib/cocooned/helpers/deprecate.rb +0 -47
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 = '
|
15
|
-
spec.description =
|
16
|
-
|
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
|
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(
|
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.
|
41
|
+
spec.required_ruby_version = '>= 2.6'
|
29
42
|
|
30
|
-
spec.add_dependency 'rails', '>=
|
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 '
|
34
|
-
spec.add_development_dependency 'rake'
|
35
|
-
spec.add_development_dependency 'rspec', '~> 3.
|
36
|
-
spec.add_development_dependency 'rspec-rails', '
|
37
|
-
spec.add_development_dependency '
|
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,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
|