cocooned 2.5.0 → 3.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 +19 -0
- data/app/assets/javascripts/cocoon.js +1 -1
- data/app/assets/javascripts/cocooned.js +214 -135
- data/app/assets/stylesheets/cocoon.css +1 -1
- data/app/assets/stylesheets/cocooned.css +1 -1
- data/cocooned.gemspec +3 -3
- data/lib/cocooned/deprecation.rb +6 -6
- data/lib/cocooned/helpers/containers.rb +19 -8
- data/lib/cocooned/version.rb +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4452a44114a2a49166816f4966764b27cccf5de838568acb29fc68544fb96878
|
|
4
|
+
data.tar.gz: 7d28fe11d1d06bb28433be2587411471ce79db0983347de07acf40a2e62bc3d7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8af0b42463b95aac1f4bf2c1f290a75735a1ebb304fe333f79124da55bb2f0d694c05e23292b3328accb0b70c596205b918a6912757f2e8dbddcd5101f6df4bc
|
|
7
|
+
data.tar.gz: e95c020441e9c26e4941d49ec7e202dc22af173b02af6bf2023a46260004dceee1e0ca9f352bed232a80b085c819a35f26d9994013a21a76ed65f669d2f4f471
|
data/CHANGELOG.md
CHANGED
|
@@ -6,8 +6,27 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## Version 3.0.0 (2026-01-27)
|
|
10
|
+
|
|
11
|
+
## Breaking changes
|
|
12
|
+
|
|
13
|
+
* Respect browser accessibility settings on reduced motion to determinate the default value of the `animate` option (#120)
|
|
14
|
+
`animate` will be set to false by default if the `(prefers-reduced-motion: reduce)` media query matches.
|
|
15
|
+
* Proper instances cleanup through [explicit resource management](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Resource_management) (#115)
|
|
16
|
+
Introduce a `dispose` method on Cocooned instances to clean up what was done in the `start` method: remove event listeners and delete references to the disposed instance, so it can be cleanly garbage collected.
|
|
17
|
+
This may require you to install a polyfill for `DisposableStack` and `[Symbol.dispose]()` to support older browsers.
|
|
18
|
+
|
|
19
|
+
To not introduce too many breaking changes in a single release, removal of long-time deprecated features have been postponed to Cocooned 4.0 (#122)
|
|
20
|
+
|
|
21
|
+
## Added
|
|
22
|
+
|
|
23
|
+
* Optional Stimulus integration (#119)
|
|
24
|
+
Introduce two ways to integrate Cocooned with Stimulus: `registerCocoonedContainer` and `useCocooned`. See documentation for details.
|
|
25
|
+
|
|
9
26
|
### Changed
|
|
10
27
|
|
|
28
|
+
* Add Ruby 4.0 to the test matrix (#112)
|
|
29
|
+
|
|
11
30
|
## Version 2.5.0 (2025-10-23)
|
|
12
31
|
|
|
13
32
|
* Upgrade to use `eslint ~> 9` (#103)
|
|
@@ -36,6 +36,153 @@
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
class Traverser {
|
|
40
|
+
constructor (origin, traversal) {
|
|
41
|
+
this.#origin = origin;
|
|
42
|
+
this.#traversal = traversal;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
resolve (selector) {
|
|
46
|
+
if (this.#traversal in this.#origin && typeof this.#origin[this.#traversal] === 'function') {
|
|
47
|
+
return this._tryMethod(this.#traversal, selector)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (this.#traversal in this.#origin) {
|
|
51
|
+
return this._tryProperty(this.#traversal)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const method = `_${this.#traversal}`;
|
|
55
|
+
if (method in this) {
|
|
56
|
+
return this[method](selector)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return null
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* Protected and private attributes and methods */
|
|
63
|
+
#origin
|
|
64
|
+
#traversal
|
|
65
|
+
|
|
66
|
+
_tryMethod (method, selector) {
|
|
67
|
+
try {
|
|
68
|
+
const resolved = this.#origin[method](selector);
|
|
69
|
+
if (resolved instanceof HTMLElement) {
|
|
70
|
+
return resolved
|
|
71
|
+
}
|
|
72
|
+
} catch (e) {}
|
|
73
|
+
|
|
74
|
+
return null
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
_tryProperty (property) {
|
|
78
|
+
const resolved = this.#origin[property];
|
|
79
|
+
if (resolved instanceof HTMLElement) {
|
|
80
|
+
return resolved
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return null
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
_parent (selector) {
|
|
87
|
+
if (this.#origin.parentElement.matches(selector)) {
|
|
88
|
+
return this.#origin.parentElement
|
|
89
|
+
}
|
|
90
|
+
return null
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
_prev (selector) {
|
|
94
|
+
if (this.#origin.previousElementSibling.matches(selector)) {
|
|
95
|
+
return this.#origin.previousElementSibling
|
|
96
|
+
}
|
|
97
|
+
return null
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
_next (selector) {
|
|
101
|
+
if (this.#origin.nextElementSibling.matches(selector)) {
|
|
102
|
+
return this.#origin.nextElementSibling
|
|
103
|
+
}
|
|
104
|
+
return null
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
_siblings (selector) {
|
|
108
|
+
return this.#origin.parentElement.querySelector(selector)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
class Deprecator {
|
|
113
|
+
logger
|
|
114
|
+
package
|
|
115
|
+
version
|
|
116
|
+
|
|
117
|
+
constructor (version, packageName, logger) {
|
|
118
|
+
this.version = version;
|
|
119
|
+
this.package = packageName;
|
|
120
|
+
this.logger = logger;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
warn (message, replacement = null) {
|
|
124
|
+
if (message in this.#emitted) {
|
|
125
|
+
return
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const warning = `${message}. It will be removed from ${this.package} ${this.version}`;
|
|
129
|
+
const alternative = (replacement !== null ? `, use ${replacement} instead` : '');
|
|
130
|
+
this.logger.warn(`DEPRECATION WARNING: ${warning}${alternative}.`);
|
|
131
|
+
|
|
132
|
+
this.#emitted[message] = true;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* Protected and private attributes and methods */
|
|
136
|
+
#emitted = Object.create(null)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const deprecators = Object.create(null);
|
|
140
|
+
|
|
141
|
+
function deprecator (version, packageName = 'Cocooned', logger = console) {
|
|
142
|
+
const hash = [version, packageName].join('#');
|
|
143
|
+
if (!(hash in deprecators)) {
|
|
144
|
+
deprecators[hash] = new Deprecator(version, packageName, logger);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return deprecators[hash]
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
class Listener {
|
|
151
|
+
constructor (eventTarget, type, listener) {
|
|
152
|
+
this.#eventTarget = eventTarget;
|
|
153
|
+
this.#type = type;
|
|
154
|
+
this.#listener = listener;
|
|
155
|
+
|
|
156
|
+
this.#eventTarget.addEventListener(this.#type, this.#listener);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
dispose () {
|
|
160
|
+
this.#eventTarget.removeEventListener(this.#type, this.#listener);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/* Protected and private attributes and methods */
|
|
164
|
+
#eventTarget
|
|
165
|
+
#type
|
|
166
|
+
#listener
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
disposable(Listener);
|
|
170
|
+
|
|
171
|
+
if (typeof Symbol.dispose !== "symbol") {
|
|
172
|
+
console.warn(`
|
|
173
|
+
Cocooned use Disposable objects but they are not supported by your browser.
|
|
174
|
+
See Cocooned documentation for polyfill options.
|
|
175
|
+
`);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function disposable(klass) {
|
|
179
|
+
if (typeof Symbol.dispose !== "symbol") {
|
|
180
|
+
return
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
klass.prototype[Symbol.dispose] = klass.prototype.dispose;
|
|
184
|
+
}
|
|
185
|
+
|
|
39
186
|
// Borrowed from <https://stackoverflow.com/a/2117523>
|
|
40
187
|
function uuidv4 () {
|
|
41
188
|
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
|
|
@@ -69,13 +216,22 @@
|
|
|
69
216
|
]
|
|
70
217
|
}
|
|
71
218
|
|
|
219
|
+
const canAnimate = (
|
|
220
|
+
'animate' in document.createElement('div') &&
|
|
221
|
+
typeof document.createElement('div').animate === 'function'
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
const shouldAnimate = (
|
|
225
|
+
'matchMedia' in window &&
|
|
226
|
+
!window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
|
227
|
+
);
|
|
228
|
+
|
|
72
229
|
const instances = Object.create(null);
|
|
73
230
|
|
|
74
231
|
class Base {
|
|
75
232
|
static get defaultOptions () {
|
|
76
|
-
const element = document.createElement('div');
|
|
77
233
|
return {
|
|
78
|
-
animate:
|
|
234
|
+
animate: canAnimate && shouldAnimate,
|
|
79
235
|
animator: defaultAnimator,
|
|
80
236
|
duration: 450
|
|
81
237
|
}
|
|
@@ -98,7 +254,7 @@
|
|
|
98
254
|
|
|
99
255
|
constructor (container, options) {
|
|
100
256
|
this._container = container;
|
|
101
|
-
this.
|
|
257
|
+
this.__uuid = uuidv4();
|
|
102
258
|
this._options = this.constructor._normalizeOptions({
|
|
103
259
|
...this.constructor.defaultOptions,
|
|
104
260
|
...('cocoonedOptions' in container.dataset ? JSON.parse(container.dataset.cocoonedOptions) : {}),
|
|
@@ -115,16 +271,31 @@
|
|
|
115
271
|
}
|
|
116
272
|
|
|
117
273
|
start () {
|
|
118
|
-
this.container.dataset
|
|
119
|
-
|
|
120
|
-
|
|
274
|
+
if (!('cocoonedContainer' in this.container.dataset)) {
|
|
275
|
+
deprecator('4.0').warn(
|
|
276
|
+
'CSS classes based detection is deprecated',
|
|
277
|
+
'cocooned_container Rails helper to declare containers'
|
|
278
|
+
);
|
|
279
|
+
this.container.dataset.cocoonedContainer = true;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
this.container.dataset.cocoonedUuid = this.__uuid;
|
|
283
|
+
this._onDispose(() => delete this.container.dataset.cocoonedUuid);
|
|
284
|
+
|
|
285
|
+
instances[this.__uuid] = this;
|
|
286
|
+
this._onDispose(() => delete instances[this.__uuid]);
|
|
121
287
|
|
|
122
288
|
const hideDestroyed = () => { hideMarkedForDestruction(this, this.items); };
|
|
123
289
|
|
|
124
290
|
hideDestroyed();
|
|
125
|
-
this.container.ownerDocument
|
|
126
|
-
this.container.ownerDocument
|
|
127
|
-
this.container.ownerDocument
|
|
291
|
+
this._addEventListener(this.container.ownerDocument, 'page:load', hideDestroyed);
|
|
292
|
+
this._addEventListener(this.container.ownerDocument, 'turbo:load', hideDestroyed);
|
|
293
|
+
this._addEventListener(this.container.ownerDocument, 'turbolinks:load', hideDestroyed);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
dispose () {
|
|
297
|
+
this._disposer.dispose();
|
|
298
|
+
this._container = null;
|
|
128
299
|
}
|
|
129
300
|
|
|
130
301
|
notify (node, eventType, eventData) {
|
|
@@ -180,8 +351,21 @@
|
|
|
180
351
|
|
|
181
352
|
_container
|
|
182
353
|
_options
|
|
183
|
-
|
|
354
|
+
__disposer
|
|
184
355
|
__emitter
|
|
356
|
+
__uuid
|
|
357
|
+
|
|
358
|
+
_addEventListener (target, type, listener) {
|
|
359
|
+
this._disposer.use(new Listener(target, type, listener));
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
get _disposer () {
|
|
363
|
+
if (typeof this.__disposer === 'undefined') {
|
|
364
|
+
this.__disposer = new DisposableStack();
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return this.__disposer
|
|
368
|
+
}
|
|
185
369
|
|
|
186
370
|
get _emitter () {
|
|
187
371
|
if (typeof this.__emitter === 'undefined') {
|
|
@@ -191,6 +375,10 @@
|
|
|
191
375
|
return this.__emitter
|
|
192
376
|
}
|
|
193
377
|
|
|
378
|
+
_onDispose (callback) {
|
|
379
|
+
this._disposer.defer(callback);
|
|
380
|
+
}
|
|
381
|
+
|
|
194
382
|
_selectors (name) {
|
|
195
383
|
return this.constructor.selectors[name]
|
|
196
384
|
}
|
|
@@ -205,6 +393,8 @@
|
|
|
205
393
|
}
|
|
206
394
|
}
|
|
207
395
|
|
|
396
|
+
disposable(Base);
|
|
397
|
+
|
|
208
398
|
class Trigger {
|
|
209
399
|
constructor (trigger, cocooned) {
|
|
210
400
|
this._trigger = trigger;
|
|
@@ -277,117 +467,6 @@
|
|
|
277
467
|
}
|
|
278
468
|
}
|
|
279
469
|
|
|
280
|
-
class Traverser {
|
|
281
|
-
constructor (origin, traversal) {
|
|
282
|
-
this.#origin = origin;
|
|
283
|
-
this.#traversal = traversal;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
resolve (selector) {
|
|
287
|
-
if (this.#traversal in this.#origin && typeof this.#origin[this.#traversal] === 'function') {
|
|
288
|
-
return this._tryMethod(this.#traversal, selector)
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
if (this.#traversal in this.#origin) {
|
|
292
|
-
return this._tryProperty(this.#traversal)
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
const method = `_${this.#traversal}`;
|
|
296
|
-
if (method in this) {
|
|
297
|
-
return this[method](selector)
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
return null
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
/* Protected and private attributes and methods */
|
|
304
|
-
#origin
|
|
305
|
-
#traversal
|
|
306
|
-
|
|
307
|
-
_tryMethod (method, selector) {
|
|
308
|
-
try {
|
|
309
|
-
const resolved = this.#origin[method](selector);
|
|
310
|
-
if (resolved instanceof HTMLElement) {
|
|
311
|
-
return resolved
|
|
312
|
-
}
|
|
313
|
-
} catch (e) {}
|
|
314
|
-
|
|
315
|
-
return null
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
_tryProperty (property) {
|
|
319
|
-
const resolved = this.#origin[property];
|
|
320
|
-
if (resolved instanceof HTMLElement) {
|
|
321
|
-
return resolved
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
return null
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
_parent (selector) {
|
|
328
|
-
if (this.#origin.parentElement.matches(selector)) {
|
|
329
|
-
return this.#origin.parentElement
|
|
330
|
-
}
|
|
331
|
-
return null
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
_prev (selector) {
|
|
335
|
-
if (this.#origin.previousElementSibling.matches(selector)) {
|
|
336
|
-
return this.#origin.previousElementSibling
|
|
337
|
-
}
|
|
338
|
-
return null
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
_next (selector) {
|
|
342
|
-
if (this.#origin.nextElementSibling.matches(selector)) {
|
|
343
|
-
return this.#origin.nextElementSibling
|
|
344
|
-
}
|
|
345
|
-
return null
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
_siblings (selector) {
|
|
349
|
-
return this.#origin.parentElement.querySelector(selector)
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
class Deprecator {
|
|
354
|
-
logger
|
|
355
|
-
package
|
|
356
|
-
version
|
|
357
|
-
|
|
358
|
-
constructor (version, packageName, logger) {
|
|
359
|
-
this.version = version;
|
|
360
|
-
this.package = packageName;
|
|
361
|
-
this.logger = logger;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
warn (message, replacement = null) {
|
|
365
|
-
if (message in this.#emitted) {
|
|
366
|
-
return
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
const warning = `${message}. It will be removed from ${this.package} ${this.version}`;
|
|
370
|
-
const alternative = (replacement !== null ? `, use ${replacement} instead` : '');
|
|
371
|
-
this.logger.warn(`DEPRECATION WARNING: ${warning}${alternative}.`);
|
|
372
|
-
|
|
373
|
-
this.#emitted[message] = true;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
/* Protected and private attributes and methods */
|
|
377
|
-
#emitted = Object.create(null)
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
const deprecators = Object.create(null);
|
|
381
|
-
|
|
382
|
-
function deprecator (version, packageName = 'Cocooned', logger = console) {
|
|
383
|
-
const hash = [version, packageName].join('#');
|
|
384
|
-
if (!(hash in deprecators)) {
|
|
385
|
-
deprecators[hash] = new Deprecator(version, packageName, logger);
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
return deprecators[hash]
|
|
389
|
-
}
|
|
390
|
-
|
|
391
470
|
class Extractor {
|
|
392
471
|
constructor (trigger, cocooned) {
|
|
393
472
|
this.#trigger = trigger;
|
|
@@ -466,7 +545,7 @@
|
|
|
466
545
|
return this.#trigger.ownerDocument.querySelector(node)
|
|
467
546
|
}
|
|
468
547
|
|
|
469
|
-
deprecator('
|
|
548
|
+
deprecator('4.0').warn('associationInsertionTraversal is deprecated');
|
|
470
549
|
const traverser = new Traverser(this.#trigger, this.#dataset.associationInsertionTraversal);
|
|
471
550
|
|
|
472
551
|
return traverser.resolve(node)
|
|
@@ -736,12 +815,12 @@
|
|
|
736
815
|
.map(element => Add.create(element, this))
|
|
737
816
|
.filter(trigger => this.toContainer(trigger.insertionNode) === this.container);
|
|
738
817
|
|
|
739
|
-
this.addTriggers.forEach(add =>
|
|
740
|
-
'click',
|
|
741
|
-
|
|
742
|
-
));
|
|
818
|
+
this.addTriggers.forEach(add => {
|
|
819
|
+
this._addEventListener(add.trigger, 'click', clickHandler$1((e) => add.handle(e)));
|
|
820
|
+
});
|
|
743
821
|
|
|
744
|
-
this.
|
|
822
|
+
this._addEventListener(
|
|
823
|
+
this.container,
|
|
745
824
|
'click',
|
|
746
825
|
itemDelegatedClickHandler(this, this._selector('triggers.remove'), (e) => {
|
|
747
826
|
const trigger = new Remove(e.target, this);
|
|
@@ -795,7 +874,7 @@
|
|
|
795
874
|
return
|
|
796
875
|
}
|
|
797
876
|
|
|
798
|
-
this.container
|
|
877
|
+
this._addEventListener(this.container, 'cocooned:before-insert', e => {
|
|
799
878
|
if (this.items.length < this.options.limit) {
|
|
800
879
|
return
|
|
801
880
|
}
|
|
@@ -943,16 +1022,16 @@
|
|
|
943
1022
|
return
|
|
944
1023
|
}
|
|
945
1024
|
|
|
946
|
-
this.container
|
|
947
|
-
this.container
|
|
948
|
-
this.container
|
|
1025
|
+
this._addEventListener(this.container, 'cocooned:after-insert', e => this._reindexer.reindex(e));
|
|
1026
|
+
this._addEventListener(this.container, 'cocooned:after-remove', e => this._reindexer.reindex(e));
|
|
1027
|
+
this._addEventListener(this.container, 'cocooned:after-move', e => this._reindexer.reindex(e));
|
|
949
1028
|
const form = this.container.closest('form');
|
|
950
1029
|
if (form !== null) {
|
|
951
|
-
|
|
1030
|
+
this._addEventListener(form, 'submit', e => this._reindexer.reindex(e));
|
|
952
1031
|
}
|
|
953
1032
|
|
|
954
|
-
this.container
|
|
955
|
-
this.container
|
|
1033
|
+
this._addEventListener(this.container, 'click', clickHandler(this, this._selector('triggers.up'), Up));
|
|
1034
|
+
this._addEventListener(this.container, 'click', clickHandler(this, this._selector('triggers.down'), Down));
|
|
956
1035
|
}
|
|
957
1036
|
|
|
958
1037
|
/* Protected and private attributes and methods */
|
|
@@ -1051,7 +1130,7 @@
|
|
|
1051
1130
|
|
|
1052
1131
|
$(() => cocoonAutoStart($));
|
|
1053
1132
|
|
|
1054
|
-
deprecator('
|
|
1133
|
+
deprecator('4.0').warn(
|
|
1055
1134
|
'Loading @notus.sh/cocooned/cocooned is deprecated',
|
|
1056
1135
|
'@notus.sh/cocooned/jquery, @notus.sh/cocooned or `@notus.sh/cocooned/src/cocooned/cocooned`'
|
|
1057
1136
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
/* TODO: Remove in
|
|
1
|
+
/* TODO: Remove in 4.0 */
|
data/cocooned.gemspec
CHANGED
|
@@ -13,8 +13,8 @@ Gem::Specification.new do |spec|
|
|
|
13
13
|
|
|
14
14
|
spec.summary = 'Form builder agnostic handling of Rails nested forms'
|
|
15
15
|
spec.description = <<-DESC.gsub(/\s+/, ' ')
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
Rails nested form made easy, with standard Rails form builder, Formtastic or SimpleForm.
|
|
17
|
+
Unobtrusive and zero-dependencies JavaScript included, with optional integration with jQuery and Stimulus.
|
|
18
18
|
DESC
|
|
19
19
|
spec.homepage = 'https://github.com/notus-sh/cocooned'
|
|
20
20
|
|
|
@@ -42,7 +42,7 @@ Gem::Specification.new do |spec|
|
|
|
42
42
|
|
|
43
43
|
spec.add_dependency 'rails', '>= 7.2', '< 8.2'
|
|
44
44
|
|
|
45
|
-
spec.add_development_dependency 'bundler', '
|
|
45
|
+
spec.add_development_dependency 'bundler', '>= 2.1'
|
|
46
46
|
spec.add_development_dependency 'rake', '~> 13.0'
|
|
47
47
|
spec.add_development_dependency 'rspec', '~> 3.11'
|
|
48
48
|
end
|
data/lib/cocooned/deprecation.rb
CHANGED
|
@@ -26,14 +26,14 @@ module Cocooned
|
|
|
26
26
|
cocooned_add_item_link(...)
|
|
27
27
|
end
|
|
28
28
|
deprecate link_to_add_association: 'Use :cocooned_add_link instead',
|
|
29
|
-
deprecator: Deprecation['
|
|
29
|
+
deprecator: Deprecation['4.0']
|
|
30
30
|
|
|
31
31
|
# @deprecated: Please use {#cocooned_remove_item_link} instead
|
|
32
32
|
def link_to_remove_association(...)
|
|
33
33
|
cocooned_remove_item_link(...)
|
|
34
34
|
end
|
|
35
35
|
deprecate link_to_remove_association: 'Use :cocooned_remove_item_link instead',
|
|
36
|
-
deprecator: Deprecation['
|
|
36
|
+
deprecator: Deprecation['4.0']
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
|
|
@@ -44,7 +44,7 @@ module Cocooned
|
|
|
44
44
|
def i18n_namespaces
|
|
45
45
|
return super unless I18n.exists?(:cocoon)
|
|
46
46
|
|
|
47
|
-
Deprecation['
|
|
47
|
+
Deprecation['4.0'].warn 'Support for the :cocoon i18n namespace will be removed in 4.0', caller_locations(3)
|
|
48
48
|
super + %w[cocoon]
|
|
49
49
|
end
|
|
50
50
|
end
|
|
@@ -57,7 +57,7 @@ module Cocooned
|
|
|
57
57
|
def html_data
|
|
58
58
|
return super unless data_keys.size.positive?
|
|
59
59
|
|
|
60
|
-
Deprecation['
|
|
60
|
+
Deprecation['4.0'].warn 'Compatibility with options named data-* will be removed in 4.0', caller_locations(3)
|
|
61
61
|
html_data_normalize super.merge(data_options)
|
|
62
62
|
end
|
|
63
63
|
|
|
@@ -78,7 +78,7 @@ module Cocooned
|
|
|
78
78
|
|
|
79
79
|
def association_options
|
|
80
80
|
if options.key? :insertion_traversal
|
|
81
|
-
Deprecation['
|
|
81
|
+
Deprecation['4.0'].warn 'Support for the :insertion_traversal will be removed in 4.0', caller_locations(3)
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
super
|
|
@@ -91,7 +91,7 @@ module Cocooned
|
|
|
91
91
|
def renderer_options
|
|
92
92
|
return super unless options.key?(:render_options)
|
|
93
93
|
|
|
94
|
-
Deprecation['
|
|
94
|
+
Deprecation['4.0'].warn 'Support for :render_options will be removed in 4.0', caller_locations(3)
|
|
95
95
|
legacy_options = options.delete(:render_options)
|
|
96
96
|
|
|
97
97
|
super.tap do |opts|
|
|
@@ -32,10 +32,8 @@ module Cocooned
|
|
|
32
32
|
def cocooned_container(*args, &)
|
|
33
33
|
options = args.extract_options!.dup
|
|
34
34
|
name = args.shift || :div
|
|
35
|
-
defaults = cocooned_wrapper_defaults(options, %w[cocooned-container], :'cocooned-container')
|
|
36
|
-
defaults[:data][:cocooned_options] = options.extract!(:limit, :reorderable).to_json
|
|
37
35
|
|
|
38
|
-
content_tag(name, *args, **options
|
|
36
|
+
content_tag(name, *args, **cocooned_container_options(options), &)
|
|
39
37
|
end
|
|
40
38
|
|
|
41
39
|
# Wrap content with the expected markup for a Cocooned item.
|
|
@@ -56,17 +54,30 @@ module Cocooned
|
|
|
56
54
|
def cocooned_item(*args, &)
|
|
57
55
|
options = args.extract_options!.dup
|
|
58
56
|
name = args.shift || :div
|
|
59
|
-
defaults = cocooned_wrapper_defaults(options, %w[cocooned-item nested-fields], :'cocooned-item')
|
|
60
57
|
|
|
61
|
-
content_tag(name, *args, **options
|
|
58
|
+
content_tag(name, *args, **cocooned_item_options(options), &)
|
|
62
59
|
end
|
|
63
60
|
|
|
64
61
|
protected
|
|
65
62
|
|
|
66
|
-
def
|
|
67
|
-
|
|
63
|
+
def cocooned_container_options(options)
|
|
64
|
+
options.deep_merge(
|
|
65
|
+
class: token_list(options.delete(:class), %w[cocooned-container]),
|
|
66
|
+
data: {
|
|
67
|
+
controller: [options.dig(:data, :controller), :cocooned].compact_blank.map(&:to_s).join(' '),
|
|
68
|
+
cocooned_container: true,
|
|
69
|
+
cocooned_options: options.extract!(:limit, :reorderable).to_json
|
|
70
|
+
}
|
|
71
|
+
)
|
|
72
|
+
end
|
|
68
73
|
|
|
69
|
-
|
|
74
|
+
def cocooned_item_options(options)
|
|
75
|
+
options.deep_merge(
|
|
76
|
+
class: token_list(options.delete(:class), %w[cocooned-item nested-fields]),
|
|
77
|
+
data: {
|
|
78
|
+
cocooned_item: true
|
|
79
|
+
}
|
|
80
|
+
)
|
|
70
81
|
end
|
|
71
82
|
end
|
|
72
83
|
end
|
data/lib/cocooned/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cocooned
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 3.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gaël-Ian Havard
|
|
@@ -34,14 +34,14 @@ dependencies:
|
|
|
34
34
|
name: bundler
|
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
|
-
- - "
|
|
37
|
+
- - ">="
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
39
|
version: '2.1'
|
|
40
40
|
type: :development
|
|
41
41
|
prerelease: false
|
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
|
43
43
|
requirements:
|
|
44
|
-
- - "
|
|
44
|
+
- - ">="
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
46
|
version: '2.1'
|
|
47
47
|
- !ruby/object:Gem::Dependency
|
|
@@ -72,9 +72,9 @@ dependencies:
|
|
|
72
72
|
- - "~>"
|
|
73
73
|
- !ruby/object:Gem::Version
|
|
74
74
|
version: '3.11'
|
|
75
|
-
description: "
|
|
76
|
-
or
|
|
77
|
-
|
|
75
|
+
description: " Rails nested form made easy, with standard Rails form builder, Formtastic
|
|
76
|
+
or SimpleForm. Unobtrusive and zero-dependencies JavaScript included, with optional
|
|
77
|
+
integration with jQuery and Stimulus. "
|
|
78
78
|
email:
|
|
79
79
|
- gael-ian@notus.sh
|
|
80
80
|
- nathan@dixis.com
|
|
@@ -136,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
136
136
|
- !ruby/object:Gem::Version
|
|
137
137
|
version: '0'
|
|
138
138
|
requirements: []
|
|
139
|
-
rubygems_version:
|
|
139
|
+
rubygems_version: 4.0.3
|
|
140
140
|
specification_version: 4
|
|
141
141
|
summary: Form builder agnostic handling of Rails nested forms
|
|
142
142
|
test_files: []
|