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.
- 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/README.md
CHANGED
@@ -1,77 +1,105 @@
|
|
1
1
|
# Cocooned
|
2
2
|
|
3
|
-
[](https://github.com/notus-sh/cocooned/actions/workflows/unit-tests.yml)
|
4
|
+
[](https://badge.fury.io/rb/cocooned)
|
4
5
|
|
5
|
-
Cocooned makes it easier to handle nested forms in
|
6
|
+
Cocooned makes it easier to handle nested forms in Rails.
|
6
7
|
|
7
|
-
Cocooned is form builder-agnostic: it works with standard Rails (>=
|
8
|
+
Cocooned is form builder-agnostic: it works with standard Rails (>= 6.0, < 7.1) form helpers, [Formtastic](https://github.com/justinfrench/formtastic) or [SimpleForm](https://github.com/plataformatec/simple_form).
|
9
|
+
|
10
|
+
1. [Background](#some-background)
|
11
|
+
2. [Installation](#installation)
|
12
|
+
3. [Getting started](#getting-started)
|
13
|
+
4. [Going further with plugins](#plugins)
|
14
|
+
5. [Links or buttons ?](#links-or-buttons)
|
15
|
+
5. [I18n integration](#internationalisation)
|
16
|
+
6. [JavaScript](#javascript)
|
17
|
+
7. [Styling](#styling-forms)
|
18
|
+
8. [Migration from a previous version](#migration-from-a-previous-version) or from Cocoon
|
8
19
|
|
9
20
|
## Some Background
|
10
21
|
|
11
22
|
Cocooned is a fork of [Cocoon](https://github.com/nathanvda/cocoon) by [Nathan Van der Auwera](https://github.com/nathanvda). He and all Cocoon contributors did a great job to maintain it for years. Many thanks to them!
|
12
23
|
|
13
|
-
However, the project seems to have only received minimal fixes since 2018 and many pull requests, even simple ones, have been on hold for a long time. In 2019, as I needed
|
14
|
-
|
15
|
-
Cocooned is almost a complete rewrite of Cocoon, with more functionnalities, a more fluent API (I hope) and integration with modern toolchains (including webpacker).
|
24
|
+
However, the project seems to have only received minimal fixes since 2018 and many pull requests, even simple ones, have been on hold for a long time. In 2019, as I needed more than what Cocoon provided at this time, I had the choice to either maintain an extension or to fork it and integrate everything that was waiting and more.
|
16
25
|
|
17
|
-
|
26
|
+
Over the time, Cocooned turned into an almost complete rewrite of Cocoon with more functionnalities, a more fluent API (I hope) and integration with modern toolchains. Still, **Cocooned is completely compatible with Cocoon and can be used as a drop-in replacement** as long as we talk about Ruby code. Change the name of the gem in your Gemfile and you're done. **This compatibility layer with the original Cocoon API will be dropped in the next major release.**
|
18
27
|
|
19
|
-
|
20
|
-
|
21
|
-
On the JavaScript side, Cocoon 1.2.13 introduced the original browser event as a third parameter to all event handlers. Meanwhile, Cocooned already started to use this positional parameter to pass the Cocooned object instance (since 1.3.0). To get access to the original event, [you'll have to change your handlers and use `event.originalEvent`](#javascript-callbacks).
|
28
|
+
On the JavaScript side, Cocooned 2.0 removed the dependency to jQuery (Yeah! :tada:). See [JavaScript](#javascript) for details.
|
22
29
|
|
23
30
|
## Installation
|
24
31
|
|
25
|
-
|
32
|
+
Add `cocooned` to your `Gemfile`:
|
26
33
|
|
27
34
|
```ruby
|
28
|
-
gem
|
35
|
+
gem 'cocooned'
|
36
|
+
```
|
37
|
+
|
38
|
+
### Load Cocooned JavaScript
|
39
|
+
|
40
|
+
Cocooned comes with an NPM companion package: [`@notus.sh/cocooned`](https://www.npmjs.com/package/@notus.sh/cocooned).
|
41
|
+
It bundles JavaScript files to handles in-browser interactions with your nested forms.
|
42
|
+
|
43
|
+
If you use import maps (Rails 7.0+ default), add it with:
|
44
|
+
|
45
|
+
```shell
|
46
|
+
$ bin/importmap pin @notus.sh/cocooned
|
47
|
+
```
|
48
|
+
|
49
|
+
If you use Yarn and Webpack (Rails 5.1+ default), add it with:
|
50
|
+
|
51
|
+
```shell
|
52
|
+
$ yarn add @notus.sh/cocooned
|
53
|
+
```
|
54
|
+
|
55
|
+
**Note:** To ensure you will always get the version of the companion package that match with the gem version, you should specify the same version constraint you used for the `cocooned` gem in your `Gemfile`.
|
56
|
+
|
57
|
+
Once installed, load it into your application with:
|
58
|
+
|
59
|
+
```javascript
|
60
|
+
import Cocooned from '@notus.sh/cocooned'
|
61
|
+
Cocooned.start()
|
29
62
|
```
|
30
63
|
|
31
|
-
|
64
|
+
If you still use Sprockets to bundle your javascripts (Rails 3.1+ default), you can either install the companion package from npmjs.org with the package manager of your choice, configure Sprockets to look for files in your application's `/node_modules` directory and load it as above (recommended) or require `cocooned` in your `application.js` with:
|
32
65
|
|
33
|
-
|
66
|
+
```javascript
|
67
|
+
//= require 'cocooned'
|
68
|
+
```
|
34
69
|
|
35
|
-
|
70
|
+
**This compatibility with aging Rails assets pipelines will be removed in the next major release.**
|
36
71
|
|
37
|
-
##
|
72
|
+
## Getting started
|
38
73
|
|
39
74
|
For all the following examples, we will consider modelisation of an administrable list with items.
|
40
75
|
Here are the two ActiveRecord models : `List` and `Item`:
|
41
76
|
|
42
77
|
```ruby
|
43
|
-
|
78
|
+
# == Schema Info
|
79
|
+
#
|
80
|
+
# Table name: lists
|
81
|
+
#
|
82
|
+
# id :integer(11) not null, primary key
|
83
|
+
# name :string
|
84
|
+
class List < ApplicationRecord
|
44
85
|
has_many :items, inverse_of: :list
|
45
86
|
accepts_nested_attributes_for :items, reject_if: :all_blank, allow_destroy: true
|
46
87
|
end
|
47
88
|
|
89
|
+
# == Schema Info
|
90
|
+
#
|
91
|
+
# Table name: items
|
92
|
+
#
|
93
|
+
# id :integer(11) not null, primary key
|
94
|
+
# list_id :integer(11) not null
|
95
|
+
# description :text
|
96
|
+
# done :bool not null, default(false)
|
48
97
|
class Item < ApplicationRecord
|
49
98
|
belongs_to :list
|
50
99
|
end
|
51
100
|
```
|
52
101
|
|
53
|
-
We will build a form where we can dynamically add
|
54
|
-
|
55
|
-
### Strong Parameters Gotcha
|
56
|
-
|
57
|
-
To destroy nested models, Rails uses a virtual attribute called `_destroy`.
|
58
|
-
When `_destroy` is set, the nested model will be deleted. If the record has previously been persisted, Rails generate and use an automatic `id` field to fetch the wannabe destroyed record.
|
59
|
-
|
60
|
-
When using Rails > 4.0 (or strong parameters), you need to explicitly add both `:id` and `:_destroy` to the list of permitted parameters.
|
61
|
-
|
62
|
-
E.g. in your `ListsController`:
|
63
|
-
|
64
|
-
```ruby
|
65
|
-
def list_params
|
66
|
-
params.require(:list).permit(:name, tasks_attributes: [:id, :description, :done, :_destroy])
|
67
|
-
end
|
68
|
-
```
|
69
|
-
|
70
|
-
### Has One Gotcha
|
71
|
-
|
72
|
-
If you have a `has_one` association, then you (probably) need to set `force_non_association_create: true` on `link_to_add_association` or the associated object will be destroyed every time the edit form is rendered (which is probably not what you expect).
|
73
|
-
|
74
|
-
See the [original merge request](https://github.com/nathanvda/cocoon/pull/247) for more details.
|
102
|
+
We will build a form where we can dynamically add items to a list, remove or reorder them.
|
75
103
|
|
76
104
|
### Basic form
|
77
105
|
|
@@ -79,48 +107,54 @@ See the [original merge request](https://github.com/nathanvda/cocoon/pull/247) f
|
|
79
107
|
|
80
108
|
```erb
|
81
109
|
<% # `app/views/lists/_form.html.erb` %>
|
82
|
-
<%= form_for @list do |
|
83
|
-
<%=
|
110
|
+
<%= form_for @list do |form| %>
|
111
|
+
<%= form.text_field :name %>
|
84
112
|
|
85
113
|
<h3>Items</h3>
|
86
|
-
<%=
|
87
|
-
<% # This block is repeated for every task in @list.items %>
|
114
|
+
<%= form.fields_for :items do |item_form| %>
|
88
115
|
<%= item_form.label :description %>
|
89
116
|
<%= item_form.text_field :description %>
|
90
117
|
<%= item_form.check_box :done %>
|
91
118
|
<% end %>
|
92
119
|
|
93
|
-
<%=
|
120
|
+
<%= form.submit "Save" %>
|
94
121
|
<% end %>
|
95
122
|
```
|
96
123
|
|
97
124
|
To enable Cocooned on this form, we need to:
|
98
125
|
|
99
126
|
1. Move the nested form to a partial
|
100
|
-
2.
|
101
|
-
3. Add a way to
|
102
|
-
4.
|
127
|
+
2. Signal to Cocooned it should handle your form
|
128
|
+
3. Add a way to add a new item to the list
|
129
|
+
4. Add a way to remove an item from the collection
|
103
130
|
|
104
131
|
Let's do it.
|
105
132
|
|
106
|
-
|
133
|
+
**Note:** In this example, we will use Cocooned helpers named with a `_link` suffix. If you want to use buttons in your forms instead, the same helpers exist with a `_button` suffix.
|
107
134
|
|
108
|
-
|
135
|
+
### 1. Move the nested form to a partial
|
109
136
|
|
110
|
-
|
137
|
+
Change your main form as follow:
|
138
|
+
|
139
|
+
```diff
|
111
140
|
<% # `app/views/lists/_form.html.erb` %>
|
112
141
|
<%= form_for @list do |form| %>
|
113
|
-
<%= form.
|
142
|
+
<%= form.text_field :name %>
|
114
143
|
|
115
144
|
<h3>Items</h3>
|
116
145
|
<%= form.fields_for :items do |item_form|
|
117
|
-
|
146
|
+
- <%= item_form.label :description %>
|
147
|
+
- <%= item_form.text_field :description %>
|
148
|
+
- <%= item_form.check_box :done %>
|
149
|
+
+ <%= render 'item_fields', f: item_form %>
|
118
150
|
<% end %>
|
119
151
|
|
120
152
|
<%= form.submit "Save" %>
|
121
153
|
<% end %>
|
122
154
|
```
|
123
155
|
|
156
|
+
And create a new file where items fields are defined:
|
157
|
+
|
124
158
|
```erb
|
125
159
|
<% # `app/views/lists/_item_fields.html.erb` %>
|
126
160
|
<%= f.label :description %>
|
@@ -128,196 +162,234 @@ We now have two files:
|
|
128
162
|
<%= f.check_box :done %>
|
129
163
|
```
|
130
164
|
|
131
|
-
|
165
|
+
### 2. Signal to Cocooned it should handle your form
|
132
166
|
|
133
|
-
|
167
|
+
Change your main form as follow:
|
168
|
+
|
169
|
+
```diff
|
134
170
|
<% # `app/views/lists/_form.html.erb` %>
|
135
171
|
<%= form_for @list do |form| %>
|
136
172
|
<%= form.input :name %>
|
137
173
|
|
138
174
|
<h3>Items</h3>
|
139
|
-
|
140
|
-
<%= form.fields_for :
|
175
|
+
+ <%= cocooned_container do %>
|
176
|
+
<%= form.fields_for :items do |item_form| %>
|
141
177
|
<%= render 'item_fields', f: item_form %>
|
142
178
|
<% end %>
|
143
|
-
|
144
|
-
<div class="links">
|
145
|
-
<%= cocooned_add_item_link 'Add an item', form, :items %>
|
146
|
-
</div>
|
147
|
-
</div>
|
179
|
+
+ <% end %>
|
148
180
|
|
149
181
|
<%= form.submit "Save" %>
|
150
182
|
<% end %>
|
151
183
|
```
|
152
184
|
|
153
|
-
|
185
|
+
And your sub form as follow:
|
154
186
|
|
155
|
-
|
156
|
-
|
157
|
-
```erb
|
187
|
+
```diff
|
158
188
|
<% # `app/views/lists/_item_fields.html.erb` %>
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
</div>
|
189
|
+
+ <%= cocooned_item do %>
|
190
|
+
<%= f.label :description %>
|
191
|
+
<%= f.text_field :description %>
|
192
|
+
<%= f.check_box :done %>
|
193
|
+
+ <% end %>
|
165
194
|
```
|
166
195
|
|
167
|
-
The `
|
196
|
+
The `cocooned_container` and `cocooned_item` helpers will set for you the HTML attributes the JavaScript part of Cocooned expect to find to hook on. They will forward any option supported by ActionView's `content_tag`.
|
168
197
|
|
169
|
-
|
198
|
+
### 3. Add a way to add a new item to the list
|
170
199
|
|
171
|
-
|
172
|
-
This detection is based on the presence of a `data-cocooned-options` attribute on the nested forms container.
|
200
|
+
Change your main form as follow:
|
173
201
|
|
174
|
-
```
|
202
|
+
```diff
|
175
203
|
<% # `app/views/lists/_form.html.erb` %>
|
176
204
|
<%= form_for @list do |form| %>
|
177
205
|
<%= form.input :name %>
|
178
206
|
|
179
207
|
<h3>Items</h3>
|
180
|
-
|
181
|
-
<%= form.fields_for :
|
208
|
+
<%= cocooned_container do %>
|
209
|
+
<%= form.fields_for :items do |item_form| %>
|
182
210
|
<%= render 'item_fields', f: item_form %>
|
183
211
|
<% end %>
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
</div>
|
188
|
-
</div>
|
212
|
+
+
|
213
|
+
+ <p><%= cocooned_add_item_link 'Add an item', form, :items %></p>
|
214
|
+
<% end %>
|
189
215
|
|
190
216
|
<%= form.submit "Save" %>
|
191
|
-
|
192
|
-
```
|
217
|
+
<% end %>
|
218
|
+
```
|
193
219
|
|
194
|
-
You'
|
220
|
+
By default, new items will be inserted just before the immediate parent of the 'Add an item' link. You can have a look at the documentation of `cocooned_add_item_link` for more information about how to change that but we'll keep it simple for now.
|
195
221
|
|
196
|
-
###
|
222
|
+
### 4. Add a way to remove an item from the collection
|
197
223
|
|
198
|
-
|
224
|
+
Change your sub form as follow:
|
199
225
|
|
200
|
-
|
226
|
+
```diff
|
227
|
+
<% # `app/views/lists/_item_fields.html.erb` %>
|
228
|
+
<%= cocooned_item do %>
|
229
|
+
<%= f.label :description %>
|
230
|
+
<%= f.text_field :description %>
|
231
|
+
<%= f.check_box :done %>
|
232
|
+
+ <%= cocooned_remove_item_link 'Remove', f %>
|
233
|
+
<% end %>
|
234
|
+
```
|
201
235
|
|
202
|
-
|
203
|
-
* **Reorderable**, that will automatically update `position` fields when you add or remove an item or when you reorder associated items.
|
236
|
+
You're done!
|
204
237
|
|
205
|
-
|
238
|
+
### Gotchas
|
206
239
|
|
207
|
-
|
240
|
+
#### Strong Parameters Gotcha
|
208
241
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
<div class="links">
|
221
|
-
<%= cocooned_add_item_link 'Add an item', form, :items %>
|
222
|
-
</div>
|
223
|
-
</div>
|
224
|
-
|
225
|
-
<%= form.submit "Save" %>
|
226
|
-
<% end %>
|
242
|
+
To destroy nested models, Rails uses a virtual attribute called `_destroy`. When `_destroy` is set, the nested model will be deleted. If a record has previously been persisted, Rails generates and uses an additional `id` field.
|
243
|
+
|
244
|
+
When using Rails > 4.0 (or strong parameters), you need to explicitly add both `:id` and `:_destroy` to the list of permitted parameters in your controller.
|
245
|
+
|
246
|
+
In our example:
|
247
|
+
|
248
|
+
```ruby
|
249
|
+
def list_params
|
250
|
+
params.require(:list).permit(:name, tasks_attributes: [:id, :description, :done, :_destroy])
|
251
|
+
end
|
227
252
|
```
|
228
253
|
|
229
|
-
####
|
254
|
+
#### Has One Gotcha
|
255
|
+
|
256
|
+
If you have a `has_one` association, then you (probably) need to set `force_non_association_create: true` on `cocooned_add_item_link` or the associated object will be destroyed every time the edit form is rendered (which is probably not what you expect).
|
257
|
+
|
258
|
+
See the [original merge request](https://github.com/nathanvda/cocoon/pull/247) for more details.
|
230
259
|
|
231
|
-
|
260
|
+
## Plugins
|
261
|
+
|
262
|
+
Cocooned comes with two built-in plugins:
|
263
|
+
|
264
|
+
* **Limit**, to set a maximum limit of items the association can contain
|
265
|
+
* **Reorderable**, that will automatically update a `position` field in each of your sub forms when you add, remove or move an item.
|
266
|
+
|
267
|
+
### The limit plugin
|
268
|
+
|
269
|
+
The limit plugin requires you specify the maximum number of items allowed in the association. To do so, pass a `:limit` option to the `cocooned_container` helper:
|
232
270
|
|
233
271
|
```erb
|
234
|
-
|
235
|
-
|
236
|
-
<%= form.input :name %>
|
237
|
-
|
238
|
-
<h3>Items</h3>
|
239
|
-
<div id="items" data-cocooned-options="<%= { reorderable: true }.to_json %>">
|
240
|
-
<%= form.fields_for :tasks do |item_form| %>
|
241
|
-
<%= render 'item_fields', f: item_form %>
|
242
|
-
<% end %>
|
243
|
-
|
244
|
-
<div class="links">
|
245
|
-
<%= cocooned_add_item_link 'Add an item', form, :items %>
|
246
|
-
</div>
|
247
|
-
</div>
|
248
|
-
|
249
|
-
<%= form.submit "Save" %>
|
272
|
+
<%= cocooned_container limit: 12 do %>
|
273
|
+
<% # […] %>
|
250
274
|
<% end %>
|
251
275
|
```
|
252
276
|
|
253
|
-
|
277
|
+
### The reorderable plugin
|
254
278
|
|
255
|
-
|
279
|
+
**Important:** To use the reorderable plugin, your model must have a `position` numeric attribute you use to order collections (as in [acts_as_list](https://rubygems.org/gems/acts_as_list)).
|
280
|
+
|
281
|
+
The reorderable plugin can be activated in two ways through the `cocooned_container` helper:
|
282
|
+
|
283
|
+
- With a boolean: `cocooned_container reorderable: true`
|
284
|
+
Will use plugin's defaults (and start counting positions at 1)
|
285
|
+
- With a configuration hash: `cocooned_container reorderable: { startAt: 0 }`
|
286
|
+
Will use given `:startAt` as base position
|
287
|
+
|
288
|
+
To be able to move items up and down in your form and for positions to be saved, you need to change your sub form as follow:
|
289
|
+
|
290
|
+
```diff
|
256
291
|
<% # `app/views/lists/_item_fields.html.erb` %>
|
257
|
-
|
292
|
+
<%= cocooned_item do %>
|
258
293
|
<%= f.label :description %>
|
259
294
|
<%= f.text_field :description %>
|
260
295
|
<%= f.check_box :done %>
|
261
|
-
|
262
|
-
|
263
|
-
|
296
|
+
+ <%= f.hidden_field :position %>
|
297
|
+
+ <%= cocooned_move_item_up_link 'Up', f %>
|
298
|
+
+ <%= cocooned_move_item_down_link 'Down', f %>
|
264
299
|
<%= cocooned_remove_item_link 'Remove', f %>
|
265
|
-
|
300
|
+
<% end %>
|
266
301
|
```
|
267
302
|
|
268
|
-
|
303
|
+
Remember to add `:position` as a permitted parameter in your controller.
|
269
304
|
|
270
|
-
|
305
|
+
## Links or buttons?
|
271
306
|
|
272
|
-
|
307
|
+
Each helper provided by Cocooned with a name ending with `_link` has its `_button` equivalent, to generate a `<button type="button" />` instead of a `<a href="#" />`:
|
273
308
|
|
274
|
-
|
309
|
+
- `cocooned_add_item_link` <=> `cocooned_add_item_button` ([Documentation](https://github.com/notus-sh/cocooned/blob/master/lib/cocooned/helpers/tags/add.rb))
|
310
|
+
- `cocooned_remove_item_link` <=> `cocooned_remove_item_button` ([Documentation](https://github.com/notus-sh/cocooned/blob/master/lib/cocooned/helpers/tags/remove.rb))
|
311
|
+
- `cocooned_move_item_up_link` <=> `cocooned_move_item_up_button` ([Documentation](https://github.com/notus-sh/cocooned/blob/master/lib/cocooned/helpers/tags/up.rb))
|
312
|
+
- `cocooned_move_item_down_link` <=> `cocooned_move_item_down_button` ([Documentation](https://github.com/notus-sh/cocooned/blob/master/lib/cocooned/helpers/tags/down.rb))
|
275
313
|
|
276
|
-
|
277
|
-
* `cocooned_remove_item_link` will build a link that, when clicked, dynamically removes the surrounding partial form. [Have a look at the documentation for available options](https://github.com/notus-sh/cocooned/blob/master/lib/cocooned/helpers.rb#L143).
|
278
|
-
* `cocooned_move_item_up_link` and `cocooned_move_item_down_link` will build links that, when clicked, will move the surrounding partial form one step up or down in the collection. [Have a look at the documentation for available options](https://github.com/notus-sh/cocooned/blob/master/lib/cocooned/helpers.rb#L178).
|
314
|
+
While all `_link` helpers accept and will politely forward any option supported by ActionView's `link_to`, `_button` helpers will do the same with options supported by ActionView's `button_tag`.
|
279
315
|
|
280
|
-
|
316
|
+
## Internationalisation
|
281
317
|
|
282
|
-
|
318
|
+
The label of any action trigger can be given explicitly as helper's first argument or as a block, just as you can do with ActionView's `link_to` or `button_to`.
|
283
319
|
|
284
|
-
|
285
|
-
* `cocooned:after-insert`: called after inserting
|
286
|
-
* `cocooned:before-remove`: called before removing the nested child, can be [canceled](#canceling-an-action)
|
287
|
-
* `cocooned:after-remove`: called after removal
|
320
|
+
Additionally, Cocooned helpers will lookup I18n translations for a default label based on the action name (`add`, `remove`, `up`, `down`) and the association name. For `add` triggers, the association name used is the same as passed as argument. Other triggers extract the association name from form's `#object_name`.
|
288
321
|
|
289
|
-
|
322
|
+
You can declare default labels in your translation files with following keys:
|
290
323
|
|
291
|
-
|
324
|
+
- `cocooned.{association}.{action}` (Ex: `cocooned.items.add`)
|
325
|
+
- `cocooned.defaults.{action}`
|
292
326
|
|
293
|
-
|
327
|
+
If no translation is found, the default label will be the humanized action name.
|
294
328
|
|
295
|
-
|
296
|
-
* `cocooned:after-move`: called after moving
|
297
|
-
* `cocooned:before-reindex`: called before updating the `position` fields of nested items, can be [canceled](#canceling-an-action) (even if I honestly don't know why you would)
|
298
|
-
* `cocooned:after-reindex`: called after `position` fields update
|
329
|
+
## Javascript
|
299
330
|
|
300
|
-
|
331
|
+
For more documentation about the JavaScript bundled in the companion package, please refer to [its own documentation](https://github.com/notus-sh/cocooned/blob/master/npm/README.md).
|
301
332
|
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
333
|
+
## Styling forms
|
334
|
+
|
335
|
+
Cocooned now uses exclusively data-attribute to hook JavaScript methods on but usual classes are still here and will stay so you can style your forms:
|
336
|
+
|
337
|
+
- `.cocooned-container` on a container
|
338
|
+
- `.cocooned-item` on an item
|
339
|
+
- `.cocooned-add` on an add trigger (link or button)
|
340
|
+
- `.cocooned-remove` on a remove trigger (link or button)
|
341
|
+
- `.cocooned-move-up` on a move up trigger (link or button)
|
342
|
+
- `.cocooned-move-down` on a move down trigger (link or button)
|
343
|
+
|
344
|
+
## Migration from a previous version
|
345
|
+
|
346
|
+
These migrations steps only highlight major changes. When upgrading from a previous version, always refer to [the CHANGELOG](https://github.com/notus-sh/cocooned/blob/main/CHANGELOG.md) for new features and breaking changes.
|
347
|
+
|
348
|
+
### From Cocooned ~1.0
|
349
|
+
|
350
|
+
#### Forms markup
|
351
|
+
|
352
|
+
Cocooned 2.0 introduced the `cocooned_container` and `cocooned_item` helpers to respectively wrap the container where items will be added and each of the items.
|
353
|
+
|
354
|
+
If you used Cocooned ~1.0, you should modify your main forms as follow:
|
355
|
+
|
356
|
+
```diff
|
357
|
+
- <div data-cocooned-options="<%= {}.to_json %>">
|
358
|
+
+ <%= cocooned_container do %>
|
359
|
+
<% # […] %>
|
360
|
+
+ <% end %>
|
361
|
+
- </div>
|
306
362
|
```
|
307
363
|
|
308
|
-
|
364
|
+
And your nested partials:
|
365
|
+
|
366
|
+
```diff
|
367
|
+
- <div class="cocooned-item">
|
368
|
+
+ <%= cocooned_item do %>
|
369
|
+
<% # […] %>
|
370
|
+
+ <% end %>
|
371
|
+
- </div>
|
372
|
+
```
|
373
|
+
|
374
|
+
Support for the `data-cocooned-options` attribute to identify a container and the `.cocooned-item` class to identify an item is still here but it is not the recommended way to tag your containers and items anymore.
|
375
|
+
|
376
|
+
**Compatibility with older markup will be dropped in the next major release.**
|
377
|
+
|
378
|
+
#### Bundled styles
|
379
|
+
|
380
|
+
Cocooned ~2.0 does not provide any styles anymore. If you used to require (with Sprockets) or import the cocooned stylesheets into your application, you need to remove it.
|
381
|
+
|
382
|
+
**Empty files are included to not break your assets pipeline but will be removed in the next major release.**
|
309
383
|
|
310
|
-
|
384
|
+
### From Cocoon (any version)
|
311
385
|
|
312
|
-
|
313
|
-
* `event.node`, the nested item that will be added, removed or moved, as a jQuery object. This is null for `cocooned:limit-reached` and `cocooned:*-reindex` events
|
314
|
-
* `event.nodes`, the nested items that will be or just have been reindexed on `cocooned:*-reindex` events, as a jQuery object. Null otherwise.
|
315
|
-
* `event.cocooned`, the Cocooned javascript object instance handling the nested association.
|
316
|
-
* `event.originalEvent`, the original (browser) event.
|
386
|
+
Cocoon uses a `.nested_fields` class to identify items in a nested form and nothing to identify containers new items will be added to.
|
317
387
|
|
318
|
-
|
319
|
-
The `cocooned` argument is the same as `event.cocooned`.
|
388
|
+
If you used Cocoon, you should:
|
320
389
|
|
321
|
-
|
390
|
+
1. Modify your forms and sub forms to use the `cocooned_container` and `cocooned_item` helpers. (See above for examples)
|
391
|
+
2. Replace calls to `link_to_add_association` by `cocooned_add_item_link`
|
392
|
+
3. Replace calls to `link_to_remove_association` by `cocooned_remove_item_link`
|
393
|
+
4. Rename your I18n keys to use the `cocooned` namespace instead of `cocoon`
|
322
394
|
|
323
|
-
|
395
|
+
**Compatibility with the original Cocoon API will be dropped in the next major release.**
|
@@ -1,15 +1,3 @@
|
|
1
|
-
/* globals Cocooned */
|
2
1
|
//= require 'cocooned'
|
3
2
|
|
4
|
-
|
5
|
-
// TODO: Remove in 3.0
|
6
|
-
function initCocoon () {
|
7
|
-
$(Cocooned.prototype.selector('add')).each(function (_i, addLink) {
|
8
|
-
var container = Cocooned.prototype.findContainer(addLink);
|
9
|
-
var limit = parseInt($(addLink).data('limit'), 10) || false;
|
10
|
-
|
11
|
-
container.cocooned({ limit: limit });
|
12
|
-
});
|
13
|
-
}
|
14
|
-
|
15
|
-
$(initCocoon);
|
3
|
+
/* TODO: Remove in 3.0 */
|