cocooned 1.4.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cocooned
4
+ module Helpers
5
+ module Tags
6
+ # Output an action link to move an item up.
7
+ #
8
+ # = Signatures
9
+ #
10
+ # cocooned_move_item_up_link(label, form, options = {})
11
+ # # Explicit name
12
+ #
13
+ # cocooned_move_item_up_link(form, options = {}) do
14
+ # # Name as a block
15
+ # end
16
+ #
17
+ # cocooned_move_item_up_link(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 Up
28
+ # Output a link to move an item up.
29
+ #
30
+ # = Signatures
31
+ #
32
+ # cocooned_move_item_up_link(label, form, options = {})
33
+ # # Explicit name
34
+ #
35
+ # cocooned_move_item_up_link(form, options = {}) do
36
+ # # Name as a block
37
+ # end
38
+ #
39
+ # cocooned_move_item_up_link(form, options = {})
40
+ # # Use default name
41
+ #
42
+ # See Cocooned::Helpers::Tags::Up main documentation for a reference of
43
+ # supported parameters.
44
+ #
45
+ # See the documentation of +ActionView::Base#link_to+ for additional
46
+ # options.
47
+ def cocooned_move_item_up_link(*args, &block)
48
+ cocooned_link(Cocooned::Tags::Up, *args, &block)
49
+ end
50
+
51
+ # Output a button to move an item up.
52
+ #
53
+ # = Signatures
54
+ #
55
+ # cocooned_move_item_up_button(label, form, options = {})
56
+ # # Explicit name
57
+ #
58
+ # cocooned_move_item_up_button(form, options = {}) do
59
+ # # Name as a block
60
+ # end
61
+ #
62
+ # cocooned_move_item_up_button(form, options = {})
63
+ # # Use default name
64
+ #
65
+ # See Cocooned::Helpers::Tags::Up 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_up_button(*args, &block)
71
+ cocooned_button(Cocooned::Tags::Up, *args, &block)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cocooned
4
+ module Helpers
5
+ # Cocooned tags helpers output action link to interact with a dynamic nested form.
6
+ #
7
+ # Each action has its dedicated helpers:
8
+ #
9
+ # - `cocooned_add_item_link` / `cocooned_add_item_button` to add an item
10
+ # - `cocooned_remove_item_link` / `cocooned_remove_item_button` to remove
11
+ # an item
12
+ # - `cocooned_move_item_up_link` / `cocooned_move_item_up_button` to move
13
+ # an item up (in a reorderable form)
14
+ # - `cocooned_move_item_down_link` / `cocooned_move_item_down_link` to move
15
+ # an item down (in a reorderable form)
16
+ #
17
+ # Labelling action links
18
+ #
19
+ # The label of any action links can be given explicitly as helper's first
20
+ # argument or as a block, just as you can do on ActionView's `link_to` or
21
+ # similar helpers.
22
+ #
23
+ # Additionally, Cocooned helpers will lookup I18n translations for a default
24
+ # label based on the action name (`add`, `remove`, `up`, `down`) and the
25
+ # association name.
26
+ #
27
+ # For `add` action links, the association name used is the same as passed as
28
+ # argument. On other action triggers, it is extracted from nested form
29
+ # #object_name.
30
+ #
31
+ # You can declare default labels in your translation files with following
32
+ # keys:
33
+ #
34
+ # - `cocooned.{association}.{action}` (Ex: `cocooned.items.add`)
35
+ # - `cocooned.defaults.{action}`
36
+ #
37
+ # If no translation is found, the default label will be the humanized action
38
+ # name.
39
+ module Tags
40
+ autoload :Add, 'cocooned/helpers/tags/add'
41
+ autoload :Down, 'cocooned/helpers/tags/down'
42
+ autoload :Remove, 'cocooned/helpers/tags/remove'
43
+ autoload :Up, 'cocooned/helpers/tags/up'
44
+
45
+ include Cocooned::Deprecated::Helpers::Tags
46
+
47
+ protected
48
+
49
+ def cocooned_link(klass, *args, &block)
50
+ options = args.extract_options!
51
+ klass.create(self, *args, **options, &block).render(as: :link)
52
+ end
53
+
54
+ def cocooned_button(klass, *args, &block)
55
+ options = args.extract_options!
56
+ klass.create(self, *args, **options, &block).render(as: :button)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -1,334 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'cocooned/helpers/deprecate'
4
- require 'cocooned/helpers/cocoon_compatibility'
5
- require 'cocooned/association_builder'
6
-
7
3
  module Cocooned
8
- # TODO: Remove in 3.0 (Only Cocoon class names).
9
- HELPER_CLASSES = {
10
- add: %w[cocooned-add add_fields],
11
- remove: %w[cocooned-remove remove_fields],
12
- up: %w[cocooned-move-up],
13
- down: %w[cocooned-move-down]
14
- }.freeze
15
-
16
- module Helpers # rubocop:disable Metrics/ModuleLength
17
- # Create aliases to old Cocoon method name
18
- # TODO: Remove in 3.0
19
- include Cocooned::Helpers::CocoonCompatibility
20
-
21
- # Output an action link to add an item in a nested form.
22
- #
23
- # ==== Signatures
24
- #
25
- # cocooned_add_item_link(label, form, association, options = {})
26
- # # Explicit name
27
- #
28
- # cocooned_add_item_link(form, association, options = {}) do
29
- # # Name as a block
30
- # end
31
- #
32
- # cocooned_add_item_link(form, association, options = {})
33
- # # Use default name
34
- #
35
- # ==== Parameters
36
- #
37
- # `label` is the text to be used as the link label.
38
- # Just as when you use the Rails builtin helper +link_to+, you can give an explicit
39
- # label to your link or use a block to build it.
40
- # If you provide neither an explicit label nor a block, Cocooned will try to use I18n
41
- # to find a suitable label. This lookup will check the following keys:
42
- #
43
- # - `cocooned.{association}.add`
44
- # - `cocooned.defaults.add`
45
- #
46
- # If none of these translation exist, it will fallback to 'Add'.
47
- #
48
- #
49
- # `form` is your form builder. Can be a SimpleForm::Builder, Formtastic::Builder
50
- # or a standard Rails FormBuilder.
51
- #
52
- # `association` is the name of the nested association.
53
- # Ex: cocooned_add_item_link "Add an item", form, :items
54
- #
55
- # ==== Options
56
- #
57
- # `options` can be any of the following.
58
- #
59
- # Rendering options:
60
- #
61
- # - **partial**: the nested form partial.
62
- # Defaults to `{association.singular_name}_fields`.
63
- # - **form_name**: name used to access the form builder in the nested form partial.
64
- # Defaults to `:f`.
65
- # - **form_options**: options to be passed to the nested form builder. Can be used
66
- # to specify a wrapper for simple_form_fields if you use its Bootstrap setup, for
67
- # example.
68
- # No defaults.
69
- # - **locals**: a hash of local variables, will be forwarded to the partial.
70
- # No default.
71
- #
72
- # Association options:
73
- #
74
- # - **insertion_method** : the jQuery method to be used to insert new items.
75
- # Can be any of `before`, `after`, `append`, `prepend`, `replaceWith`.
76
- # Defaults to `before`
77
- # - **insertion_traversal** and **insertion_node** : respectively the jQuery
78
- # traversal method and the jQuery compatible selector that will be used to find
79
- # the insertion node, relative to the generated link.
80
- # When both are specified, `$(addLink).{traversal}({node})` will be used.
81
- # When only **insertion_node** is specified, `$({node})` will be used.
82
- # When only **insertion_traversal** is specified, it will be ignored.
83
- # When none is specified, `$(addLink).parent()` will be used.
84
- # - **count**: how many item will be inserted on click.
85
- # Defaults to 1.
86
- # - **wrap_object**: anything responding to `call` to be used to wrap the newly build
87
- # item instance. Can be useful with decorators or special initialisations.
88
- # Ex: cocooned_add_item_link "Add an item", form, :items,
89
- # wrap_object: Proc.new { |comment| CommentDecorator.new(comment) })
90
- # No default.
91
- # - **force_non_association_create**: force to build instances of the nested model
92
- # outside association (i.e. without calling `build_{association}` or `{association}.build`)
93
- # Can be usefull if, for some specific reason, you need an object to _not_ be created
94
- # on the association, for example if you did not want `after_add` callbacks to be triggered.
95
- # Defaults to false.
96
- #
97
- # Link HTML options:
98
- #
99
- # You can pass any option supported by +link_to+. It will be politely forwarded.
100
- # See the documentation of +link_to+ for more informations.
101
- #
102
- # Compatibility options:
103
- #
104
- # These options are supported for backward compatibility with the original Cocoon.
105
- # **Support for these options will be removed in the next major release !**.
106
- #
107
- # - **render_options**: A nested Hash originaly used to pass locals and form builder
108
- # options.
109
- #
110
- def cocooned_add_item_link(*args, &block)
111
- if block_given?
112
- cocooned_add_item_link(capture(&block), *args)
113
-
114
- elsif args.first.respond_to?(:object)
115
- association = args.second
116
- cocooned_add_item_link(cocooned_default_label(:add, association), *args)
117
-
118
- else
119
- name, form, association, html_options = *args
120
- html_options ||= {}
121
- html_options = html_options.dup.with_indifferent_access
122
-
123
- builder_options = cocooned_extract_builder_options!(html_options)
124
- render_options = cocooned_extract_render_options!(html_options)
125
-
126
- builder = Cocooned::AssociationBuilder.new(form, association, builder_options)
127
- rendered = cocooned_render_association(builder, render_options)
128
-
129
- data = cocooned_extract_data!(html_options).merge!(
130
- association: builder.singular_name,
131
- associations: builder.plural_name,
132
- association_insertion_template: CGI.escapeHTML(rendered.to_str).html_safe
133
- )
134
-
135
- html_options[:data] = (html_options[:data] || {}).merge(data)
136
- html_options[:class] = [Array(html_options.delete(:class)).collect { |k| k.to_s.split(' ') },
137
- Cocooned::HELPER_CLASSES[:add]].flatten.compact.uniq.join(' ')
138
-
139
- link_to(name, '#', html_options)
140
- end
141
- end
142
-
143
- # Output an action link to remove an item (and an hidden field to mark
144
- # it as destroyed if it has already been persisted).
145
- #
146
- # ==== Signatures
147
- #
148
- # cocooned_remove_item_link(label, form, html_options = {})
149
- # # Explicit name
150
- #
151
- # cocooned_remove_item_link(form, html_options = {}) do
152
- # # Name as a block
153
- # end
154
- #
155
- # cocooned_remove_item_link(form, html_options = {})
156
- # # Use default name
157
- #
158
- # See the documentation of +link_to+ for valid options.
159
- def cocooned_remove_item_link(name, form = nil, html_options = {}, &block)
160
- # rubocop:disable Style/ParallelAssignment
161
- html_options, form = form, nil if form.is_a?(Hash)
162
- form, name = name, form if form.nil?
163
- # rubocop:enable Style/ParallelAssignment
164
-
165
- return cocooned_remove_item_link(capture(&block), form, html_options) if block_given?
166
-
167
- association = form.object.class.to_s.tableize
168
- return cocooned_remove_item_link(cocooned_default_label(:remove, association), form, html_options) if name.nil?
169
-
170
- link_options = html_options.dup
171
- link_options[:class] = [html_options[:class], Cocooned::HELPER_CLASSES[:remove]].flatten.compact
172
- link_options[:class] << (form.object.new_record? ? 'dynamic' : 'existing')
173
- link_options[:class] << 'destroyed' if form.object.marked_for_destruction?
174
-
175
- form.hidden_field(:_destroy, value: form.object._destroy) << link_to(name, '#', link_options)
176
- end
177
-
178
- # Output an action link to move an item up.
179
- #
180
- # ==== Signatures
181
- #
182
- # cocooned_move_item_up_link(label, form, html_options = {})
183
- # # Explicit name
184
- #
185
- # cocooned_move_item_up_link(form, html_options = {}) do
186
- # # Name as a block
187
- # end
188
- #
189
- # cocooned_move_item_up_link(form, html_options = {})
190
- # # Use default name
191
- #
192
- # See the documentation of +link_to+ for valid options.
193
- def cocooned_move_item_up_link(name, form = nil, html_options = {}, &block)
194
- cocooned_move_item_link(:up, name, form, html_options, &block)
195
- end
196
-
197
- # Output an action link to move an item down.
198
- #
199
- # ==== Signatures
200
- #
201
- # cocooned_move_item_down_link(label, html_options = {})
202
- # # Explicit name
203
- #
204
- # cocooned_move_item_down_link(html_options = {}) do
205
- # # Name as a block
206
- # end
207
- #
208
- # cocooned_move_item_down_link(html_options = {})
209
- # # Use default name
210
- #
211
- # See the documentation of +link_to+ for valid options.
212
- def cocooned_move_item_down_link(name, form = nil, html_options = {}, &block)
213
- cocooned_move_item_link(:down, name, form, html_options, &block)
214
- end
215
-
216
- private
217
-
218
- def cocooned_move_item_link(direction, name, form = nil, html_options = {}, &block)
219
- form, name = name, form if form.nil?
220
- return cocooned_move_item_link(direction, capture(&block), form, html_options) if block_given?
221
- return cocooned_move_item_link(direction, cocooned_default_label(direction), form, html_options) if name.nil?
222
-
223
- link_options = html_options.dup
224
- link_options[:class] = [html_options[:class], Cocooned::HELPER_CLASSES[direction]].flatten.compact.join(' ')
225
- link_to name, '#', link_options
226
- end
227
-
228
- def cocooned_default_label(action, association = nil)
229
- # TODO: Remove in 3.0
230
- if I18n.exists?(:cocoon)
231
- msg = Cocooned::Helpers::Deprecate.deprecate_release_message('the :cocoon i18n scope', ':cocooned')
232
- warn msg
233
- end
234
-
235
- keys = ["cocooned.defaults.#{action}", "cocoon.defaults.#{action}"]
236
- keys.unshift("cocooned.#{association}.#{action}", "cocoon.#{association}.#{action}") unless association.nil?
237
- keys.collect!(&:to_sym)
238
- keys << action.to_s.humanize
239
-
240
- I18n.translate(keys.take(1).first, default: keys.drop(1))
241
- end
242
-
243
- def cocooned_render_association(builder, options = {})
244
- render_options = options.dup
245
- locals = (render_options.delete(:locals) || {}).symbolize_keys
246
- partial = render_options.delete(:partial) || "#{builder.singular_name}_fields"
247
- form_name = render_options.delete(:form_name)
248
- form_options = (render_options.delete(:form_options) || {}).symbolize_keys
249
- form_options.reverse_merge!(child_index: "new_#{builder.association}")
250
-
251
- builder.form.send(cocooned_form_method(builder.form),
252
- builder.association,
253
- builder.build_object,
254
- form_options) do |form_builder|
255
- partial_options = { form_name.to_sym => form_builder, :dynamic => true }.merge(locals)
256
- render(partial, partial_options)
257
- end
258
- end
259
-
260
- def cocooned_form_method(form)
261
- ancestors = form.class.ancestors.map(&:to_s)
262
- if ancestors.include?('SimpleForm::FormBuilder')
263
- :simple_fields_for
264
- elsif ancestors.include?('Formtastic::FormBuilder')
265
- :semantic_fields_for
266
- else
267
- :fields_for
268
- end
269
- end
270
-
271
- def cocooned_extract_builder_options!(html_options)
272
- %i[wrap_object force_non_association_create].each_with_object({}) do |option_name, opts|
273
- opts[option_name] = html_options.delete(option_name) if html_options.key?(option_name)
274
- end
275
- end
276
-
277
- def cocooned_extract_render_options!(html_options)
278
- render_options = { form_name: :f }
279
-
280
- # TODO: Remove in 2.0
281
- if html_options.key?(:render_options)
282
- msg = Cocooned::Helpers::Deprecate.deprecate_release_message(':render_options', :none)
283
- warn msg
284
-
285
- options = html_options.delete(:render_options)
286
- render_options[:locals] = options.delete(:locals) if options.key?(:locals)
287
- render_options[:form_options] = options
288
- end
289
-
290
- %i[locals partial form_name form_options].each_with_object(render_options) do |option_name, opts|
291
- opts[option_name] = html_options.delete(option_name) if html_options.key?(option_name)
292
- end
293
- end
294
-
295
- def cocooned_extract_data!(html_options)
296
- data = {
297
- count: [
298
- html_options.delete(:count).to_i,
299
- (html_options.key?(:data) ? html_options[:data].delete(:count) : 0).to_i,
300
- 1
301
- ].compact.max,
302
- association_insertion_node: cocooned_extract_single_data!(html_options, :insertion_node),
303
- association_insertion_method: cocooned_extract_single_data!(html_options, :insertion_method),
304
- association_insertion_traversal: cocooned_extract_single_data!(html_options, :insertion_traversal)
305
- }
306
-
307
- # Compatibility with the old way to pass data attributes to Rails view helpers
308
- # Has we build a :data key, they will not be looked up.
309
- html_options.keys.select { |k| k.to_s.match?(/data[_-]/) }.each_with_object(data) do |data_key, d|
310
- key = data_key.to_s.gsub(/^data[_-]/, '')
311
- d[key] = html_options.delete(data_key)
312
- end
313
- data.compact
314
- end
315
-
316
- def cocooned_extract_single_data!(hash, key)
317
- k = key.to_s
318
- return hash.delete(k) if hash.key?(k)
319
-
320
- # Compatibility alternatives
321
- # TODO: Remove in 2.0
322
- return hash.delete("association_#{k}") if hash.key?("association_#{k}")
323
- return hash.delete("data_association_#{k}") if hash.key?("data_association_#{k}")
324
- return hash.delete("data-association-#{k.tr('_', '-')}") if hash.key?("data-association-#{k.tr('_', '-')}")
325
- return nil unless hash.key?(:data)
326
-
327
- d = hash[:data].with_indifferent_access
328
- return d.delete("association_#{k}") if d.key?("association_#{k}")
329
- return d.delete("association-#{k.tr('_', '-')}") if d.key?("association-#{k.tr('_', '-')}")
330
-
331
- nil
332
- end
4
+ module Helpers # :nodoc:
5
+ autoload :Containers, 'cocooned/helpers/containers'
6
+ autoload :Tags, 'cocooned/helpers/tags'
333
7
  end
334
8
  end
@@ -4,10 +4,15 @@ require 'rails'
4
4
  require 'cocooned/helpers'
5
5
 
6
6
  module Cocooned
7
- class Railtie < ::Rails::Engine
7
+ class Railtie < ::Rails::Engine # :nodoc:
8
8
  initializer 'cocooned.initialize' do |_app|
9
9
  ActiveSupport.on_load :action_view do
10
- ActionView::Base.include Cocooned::Helpers
10
+ include Cocooned::Helpers::Tags,
11
+ Cocooned::Helpers::Tags::Add,
12
+ Cocooned::Helpers::Tags::Down,
13
+ Cocooned::Helpers::Tags::Remove,
14
+ Cocooned::Helpers::Tags::Up,
15
+ Cocooned::Helpers::Containers
11
16
  end
12
17
  end
13
18
  end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cocooned
4
+ module Tags
5
+ class Add < Base # :nodoc:
6
+ module AssociationOptions # :nodoc:
7
+ protected
8
+
9
+ def association_options
10
+ # TODO: Replace with compact_blank when dropping support for Rails 6.0
11
+ {
12
+ association: association,
13
+ template: html_template_name,
14
+ association_insertion_count: [options.delete(:count).to_i, 1].compact.max,
15
+ association_insertion_node: options.delete(:insertion_node),
16
+ association_insertion_method: options.delete(:insertion_method),
17
+ association_insertion_traversal: options.delete(:insertion_traversal)
18
+ }.reject { |_, value| value.blank? }
19
+ end
20
+ end
21
+
22
+ include Cocooned::TagsHelper::AssociationLabel
23
+
24
+ include Cocooned::TagsHelper::Renderer
25
+ include Cocooned::Deprecated::TagsHelper::Renderer
26
+ include AssociationOptions
27
+ include Cocooned::Deprecated::TagsHelper::AssociationOptions
28
+
29
+ def initialize(template, form, association, **options, &block)
30
+ @association = association
31
+ super(template, form, **options, &block)
32
+ end
33
+
34
+ def render(as: :link)
35
+ template.safe_join([super(as: as), html_template])
36
+ end
37
+
38
+ protected
39
+
40
+ attr_reader :association
41
+
42
+ def html_template
43
+ template.content_tag(:template, data: { name: html_template_name }) do
44
+ renderer.render.html_safe # rubocop:disable Rails/OutputSafety
45
+ end
46
+ end
47
+
48
+ def html_template_name
49
+ @html_template_name ||= SecureRandom.uuid
50
+ end
51
+
52
+ def html_classes
53
+ super + %w[cocooned-add add_fields]
54
+ end
55
+
56
+ def html_data
57
+ super.merge(association_options, cocooned_trigger: :add)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cocooned
4
+ module Tags
5
+ class Base # :nodoc:
6
+ include Cocooned::TagsHelper::DefaultLabel
7
+ include Cocooned::Deprecated::TagsHelper::DefaultLabel
8
+
9
+ include Cocooned::TagsHelper::DataAttributes
10
+ include Cocooned::Deprecated::TagsHelper::DataAttributes
11
+
12
+ class << self
13
+ def create(template, *args, **kwargs, &block)
14
+ return new(template, *args, **kwargs, &block) if block
15
+ return new(template, *args, **kwargs) unless args.first.is_a?(String)
16
+
17
+ label = args.shift
18
+ new(template, *args, **kwargs) { label }
19
+ end
20
+ end
21
+
22
+ def initialize(template, form, **options, &block)
23
+ @template = template
24
+ @form = form
25
+ @options = options.dup.symbolize_keys
26
+ @label_block = block if block
27
+ end
28
+
29
+ def render(as: :link)
30
+ return template.link_to('#', html_options) { label } if as == :link
31
+ return template.button_tag(type: :button, **html_options) { label } if as == :button
32
+
33
+ raise ArgumentError, "Unsupported value for :as. Expected :link or :button, got #{as}."
34
+ end
35
+
36
+ protected
37
+
38
+ attr_reader :template, :form, :options, :label_block
39
+
40
+ def label
41
+ return default_label if label_block.blank?
42
+
43
+ label_block.call
44
+ end
45
+
46
+ def html_options
47
+ @html_options ||= begin
48
+ options[:class] = html_classes
49
+ options[:data] = html_data
50
+ # TODO: Replace with compact_blank when dropping support for Rails 6.0
51
+ options.reject { |_, value| value.blank? }
52
+ end
53
+ end
54
+
55
+ def html_classes
56
+ # TODO: Replace with compact_blank when dropping support for Rails 6.0
57
+ Array.wrap(options.delete(:class)).flat_map { |k| k.to_s.split }.reject(&:blank?)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cocooned
4
+ module Tags
5
+ class Down < Base # :nodoc:
6
+ include Cocooned::TagsHelper::AssociationLabel
7
+
8
+ protected
9
+
10
+ def html_classes
11
+ super + %w[cocooned-move-down]
12
+ end
13
+
14
+ def html_data
15
+ super.merge(cocooned_trigger: :down)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cocooned
4
+ module Tags
5
+ class Remove < Base # :nodoc:
6
+ include Cocooned::TagsHelper::AssociationLabel
7
+
8
+ def render(as: :link)
9
+ template.safe_join([hidden_field, super(as: as)])
10
+ end
11
+
12
+ protected
13
+
14
+ def hidden_field
15
+ form.hidden_field(:_destroy, value: marked_for_destruction?)
16
+ end
17
+
18
+ def html_classes
19
+ super + %w[cocooned-remove remove_fields]
20
+ end
21
+
22
+ def html_data
23
+ super.merge(cocooned_trigger: :remove, cocooned_persisted: persisted?)
24
+ end
25
+
26
+ def persisted?
27
+ !!form.object.try(:persisted?)
28
+ end
29
+
30
+ def marked_for_destruction?
31
+ !!form.object.try(:marked_for_destruction?)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cocooned
4
+ module Tags
5
+ class Up < Base # :nodoc:
6
+ include Cocooned::TagsHelper::AssociationLabel
7
+
8
+ protected
9
+
10
+ def html_classes
11
+ super + %w[cocooned-move-up]
12
+ end
13
+
14
+ def html_data
15
+ super.merge(cocooned_trigger: :up)
16
+ end
17
+ end
18
+ end
19
+ end