spina 2.18.0 → 2.19.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.

Potentially problematic release.


This version of spina might be problematic. Click here for more details.

Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/app/assets/javascripts/spina/controllers/data_binding_controller.js +1 -0
  4. data/app/assets/javascripts/spina/controllers/page_select_controller.js +2 -37
  5. data/app/assets/javascripts/spina/controllers/reveal_controller.js +1 -1
  6. data/app/assets/javascripts/spina/controllers/select_controller.js +44 -0
  7. data/app/assets/javascripts/spina/libraries/stimulus-data-bindings@1.3.2.js +234 -0
  8. data/app/assets/javascripts/spina/libraries/stimulus-reveal@1.4.2.js +424 -0
  9. data/app/controllers/spina/admin/resource_select_options_controller.rb +20 -0
  10. data/app/models/spina/navigation_item.rb +5 -1
  11. data/app/models/spina/parts/image_variant.rb +3 -3
  12. data/app/models/spina/parts/page_link.rb +3 -2
  13. data/app/models/spina/parts/resource_link.rb +13 -0
  14. data/app/views/spina/admin/page_select_options/index.html.erb +3 -4
  15. data/app/views/spina/admin/page_select_options/show.html.erb +1 -1
  16. data/app/views/spina/admin/parts/page_links/_form.html.erb +17 -14
  17. data/app/views/spina/admin/parts/resource_links/_form.html.erb +32 -0
  18. data/app/views/spina/admin/resource_select_options/index.html.erb +13 -0
  19. data/app/views/spina/admin/resource_select_options/show.html.erb +3 -0
  20. data/config/locales/da.yml +418 -0
  21. data/config/locales/en.yml +8 -5
  22. data/config/routes.rb +4 -1
  23. data/lib/spina/engine.rb +2 -1
  24. data/lib/spina/theme.rb +8 -6
  25. data/lib/spina/version.rb +1 -1
  26. data/lib/tasks/tailwind.rake +12 -4
  27. metadata +25 -10
  28. data/app/assets/javascripts/spina/libraries/stimulus-reveal@1.2.4.js +0 -388
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spina
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.18.0
4
+ version: 2.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bram Jetten
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-10 00:00:00.000000000 Z
11
+ date: 2025-03-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -17,6 +17,9 @@ dependencies:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '6.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '8.0'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -24,6 +27,9 @@ dependencies:
24
27
  - - ">="
25
28
  - !ruby/object:Gem::Version
26
29
  version: '6.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '8.0'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: sprockets-rails
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -207,7 +213,7 @@ dependencies:
207
213
  version: '0.9'
208
214
  - - "<"
209
215
  - !ruby/object:Gem::Version
210
- version: '2.0'
216
+ version: '3.0'
211
217
  type: :runtime
212
218
  prerelease: false
213
219
  version_requirements: !ruby/object:Gem::Requirement
@@ -217,7 +223,7 @@ dependencies:
217
223
  version: '0.9'
218
224
  - - "<"
219
225
  - !ruby/object:Gem::Version
220
- version: '2.0'
226
+ version: '3.0'
221
227
  - !ruby/object:Gem::Dependency
222
228
  name: stimulus-rails
223
229
  requirement: !ruby/object:Gem::Requirement
@@ -275,19 +281,19 @@ dependencies:
275
281
  - !ruby/object:Gem::Version
276
282
  version: '0'
277
283
  - !ruby/object:Gem::Dependency
278
- name: tailwindcss-rails
284
+ name: tailwindcss-ruby
279
285
  requirement: !ruby/object:Gem::Requirement
280
286
  requirements:
281
287
  - - ">="
282
288
  - !ruby/object:Gem::Version
283
- version: 2.0.0
289
+ version: '0'
284
290
  type: :runtime
285
291
  prerelease: false
286
292
  version_requirements: !ruby/object:Gem::Requirement
287
293
  requirements:
288
294
  - - ">="
289
295
  - !ruby/object:Gem::Version
290
- version: 2.0.0
296
+ version: '0'
291
297
  description: CMS
292
298
  email:
293
299
  - bram@denkgroot.com
@@ -1196,6 +1202,7 @@ files:
1196
1202
  - app/assets/javascripts/spina/controllers/button_controller.js
1197
1203
  - app/assets/javascripts/spina/controllers/confetti_controller.js
1198
1204
  - app/assets/javascripts/spina/controllers/confirm_controller.js
1205
+ - app/assets/javascripts/spina/controllers/data_binding_controller.js
1199
1206
  - app/assets/javascripts/spina/controllers/delegate_click_controller.js
1200
1207
  - app/assets/javascripts/spina/controllers/editor_insert_images_controller.js
1201
1208
  - app/assets/javascripts/spina/controllers/embed_controller.js
@@ -1217,6 +1224,7 @@ files:
1217
1224
  - app/assets/javascripts/spina/controllers/parent_pages_controller.js
1218
1225
  - app/assets/javascripts/spina/controllers/repeater_controller.js
1219
1226
  - app/assets/javascripts/spina/controllers/reveal_controller.js
1227
+ - app/assets/javascripts/spina/controllers/select_controller.js
1220
1228
  - app/assets/javascripts/spina/controllers/select_placeholder_controller.js
1221
1229
  - app/assets/javascripts/spina/controllers/selectable_controller.js
1222
1230
  - app/assets/javascripts/spina/controllers/shortcuts_controller.js
@@ -1235,7 +1243,8 @@ files:
1235
1243
  - app/assets/javascripts/spina/libraries/hotkeys@3.8.7.js
1236
1244
  - app/assets/javascripts/spina/libraries/sortablejs.js
1237
1245
  - app/assets/javascripts/spina/libraries/sortablejs@1.13.0.js
1238
- - app/assets/javascripts/spina/libraries/stimulus-reveal@1.2.4.js
1246
+ - app/assets/javascripts/spina/libraries/stimulus-data-bindings@1.3.2.js
1247
+ - app/assets/javascripts/spina/libraries/stimulus-reveal@1.4.2.js
1239
1248
  - app/assets/javascripts/spina/libraries/trix.js
1240
1249
  - app/assets/javascripts/spina/libraries/trix@1.3.1.esm.js
1241
1250
  - app/assets/stylesheets/spina/animate.css
@@ -1320,6 +1329,7 @@ files:
1320
1329
  - app/controllers/spina/admin/pages_controller.rb
1321
1330
  - app/controllers/spina/admin/parent_pages_controller.rb
1322
1331
  - app/controllers/spina/admin/password_resets_controller.rb
1332
+ - app/controllers/spina/admin/resource_select_options_controller.rb
1323
1333
  - app/controllers/spina/admin/resources_controller.rb
1324
1334
  - app/controllers/spina/admin/sessions_controller.rb
1325
1335
  - app/controllers/spina/admin/settings_controller.rb
@@ -1373,6 +1383,7 @@ files:
1373
1383
  - app/models/spina/parts/page_link.rb
1374
1384
  - app/models/spina/parts/repeater.rb
1375
1385
  - app/models/spina/parts/repeater_content.rb
1386
+ - app/models/spina/parts/resource_link.rb
1376
1387
  - app/models/spina/parts/text.rb
1377
1388
  - app/models/spina/resource.rb
1378
1389
  - app/models/spina/rewrite_rule.rb
@@ -1446,9 +1457,12 @@ files:
1446
1457
  - app/views/spina/admin/parts/page_links/_form.html.erb
1447
1458
  - app/views/spina/admin/parts/repeaters/_fields.html.erb
1448
1459
  - app/views/spina/admin/parts/repeaters/_form.html.erb
1460
+ - app/views/spina/admin/parts/resource_links/_form.html.erb
1449
1461
  - app/views/spina/admin/parts/texts/_form.html.erb
1450
1462
  - app/views/spina/admin/password_resets/edit.html.erb
1451
1463
  - app/views/spina/admin/password_resets/new.html.erb
1464
+ - app/views/spina/admin/resource_select_options/index.html.erb
1465
+ - app/views/spina/admin/resource_select_options/show.html.erb
1452
1466
  - app/views/spina/admin/resources/edit.html.erb
1453
1467
  - app/views/spina/admin/sessions/new.html.erb
1454
1468
  - app/views/spina/admin/settings/_string_field.html.erb
@@ -1481,6 +1495,7 @@ files:
1481
1495
  - config/locales/TH.yml
1482
1496
  - config/locales/bg.yml
1483
1497
  - config/locales/cs.yml
1498
+ - config/locales/da.yml
1484
1499
  - config/locales/de.yml
1485
1500
  - config/locales/en.yml
1486
1501
  - config/locales/es.yml
@@ -1563,7 +1578,7 @@ metadata:
1563
1578
  changelog_uri: https://github.com/SpinaCMS/Spina/blob/main/CHANGELOG.md
1564
1579
  source_code_uri: https://github.com/SpinaCMS/Spina
1565
1580
  post_install_message: "\n Spina v2.16 includes a new migration, don't forget to
1566
- run spina:install:migrations.\n \n For details on this specific release, refer
1581
+ run spina:install:migrations.\n\n For details on this specific release, refer
1567
1582
  to the CHANGELOG file.\n https://github.com/SpinaCMS/Spina/blob/main/CHANGELOG.md#2160-august-23rd-2022\n
1568
1583
  \ "
1569
1584
  rdoc_options: []
@@ -1580,7 +1595,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1580
1595
  - !ruby/object:Gem::Version
1581
1596
  version: '0'
1582
1597
  requirements: []
1583
- rubygems_version: 3.4.18
1598
+ rubygems_version: 3.5.16
1584
1599
  signing_key:
1585
1600
  specification_version: 4
1586
1601
  summary: Spina
@@ -1,388 +0,0 @@
1
- import { Controller } from '@hotwired/stimulus'
2
-
3
- /**
4
- * Stimulus controller to toggle element visibility
5
- * @extends Controller
6
- */
7
- export default class RevealController extends Controller {
8
- static get values() {
9
- return {
10
- open: Boolean,
11
- transitioning: Boolean,
12
- targetSelector: String,
13
- toggleKeys: String,
14
- showKeys: String,
15
- hideKeys: String,
16
- away: Boolean,
17
- debug: Boolean,
18
- }
19
- }
20
-
21
- connect() {
22
- this._initCloseKeypressListener()
23
- this._initToggleKeypressListener()
24
- this._initShowKeypressListener()
25
- }
26
-
27
- /**
28
- * Shows elements connected to the controller.
29
- * @param {Event} event - an event with a currentTarget DOMElement
30
- */
31
- show(event) {
32
- if (this.openValue || this.transitioningValue) return
33
-
34
- this._init(event, true)
35
- }
36
-
37
- /**
38
- * Hides elements connected to the controller.
39
- * @param {Event} event - an event with a currentTarget DOMElement
40
- */
41
- hide(event) {
42
- if (!this.openValue || this.transitioningValue) return
43
-
44
- this._init(event, false)
45
- }
46
-
47
- /**
48
- * Toggles elements connected to the controller.
49
- * @param {Event} event - an event with a currentTarget DOMElement
50
- */
51
- toggle(event) {
52
- if (this.transitioningValue) return
53
-
54
- this._init(event, !this.openValue)
55
- }
56
-
57
- // Private methods
58
-
59
- /**
60
- * @private
61
- * @param {Event} event
62
- * @param {Event} shouldOpen
63
- */
64
- async _init(event, shouldOpen) {
65
- if (event && event.currentTarget && event.currentTarget.dataset) {
66
- if ('revealPreventDefault' in event.currentTarget.dataset) { event.preventDefault() }
67
- if ('revealStopPropagation' in event.currentTarget.dataset) { event.stopPropagation() }
68
- }
69
- // start stuff
70
- const startSelector = `${this.selector}[data-${shouldOpen ? 'enter' : 'leave'
71
- }-start]`
72
- const startPromises = this._didInitWithPromise(startSelector, shouldOpen)
73
- await Promise.all(startPromises)
74
-
75
- const defaultSelector = `${this.selector}:not([data-${shouldOpen ? 'enter' : 'leave'
76
- }-start]):not([data-${shouldOpen ? 'enter' : 'leave'}-end])`
77
- const defaultPromises = this._didInitWithPromise(
78
- defaultSelector,
79
- shouldOpen
80
- )
81
- await Promise.all(defaultPromises)
82
-
83
- // end stuff
84
- const endSelector = `${this.selector}[data-${shouldOpen ? 'enter' : 'leave'
85
- }-end]`
86
- const endPromises = this._didInitWithPromise(endSelector, shouldOpen)
87
- await Promise.all(endPromises)
88
- }
89
-
90
- _didInitWithPromise(selector, shouldOpen) {
91
- this._debug('selecting', selector, this.element.querySelectorAll(selector))
92
- return Array.from(this.element.querySelectorAll(selector)).map(
93
- (element) => {
94
- return this._doInitTransition(element, shouldOpen)
95
- }
96
- )
97
- }
98
-
99
- /**
100
- * @private
101
- */
102
- _initCloseKeypressListener() {
103
- if (this.hasHideKeysValue) {
104
- document.addEventListener('keydown', (event) => {
105
- if (!this.openValue) return
106
- if (!this.hideKeysValue.split(',').includes(event.key.toLowerCase())) {
107
- return
108
- }
109
-
110
- event.stopPropagation()
111
- this.toggle(event)
112
- })
113
- }
114
- }
115
-
116
- /**
117
- * @private
118
- */
119
- _initToggleKeypressListener() {
120
- if (this.hasToggleKeysValue) {
121
- document.addEventListener('keydown', (event) => {
122
- if (
123
- !this.toggleKeysValue.split(',').includes(event.key.toLowerCase())
124
- ) {
125
- return
126
- }
127
-
128
- event.stopPropagation()
129
-
130
- this.toggle(event)
131
- })
132
- }
133
- }
134
-
135
- /**
136
- * @private
137
- */
138
- _initShowKeypressListener() {
139
- if (this.hasShowKeysValue) {
140
- document.addEventListener('keydown', (event) => {
141
- if (this.openValue) return
142
- if (!this.showKeysValue.split(',').includes(event.key.toLowerCase())) {
143
- return
144
- }
145
-
146
- event.stopPropagation()
147
-
148
- this.toggle(event)
149
- })
150
- }
151
- }
152
-
153
- /**
154
- * @private
155
- */
156
- _awayHandler(event) {
157
- if (!this.element.contains(event.target)) {
158
- this.hide(event)
159
- }
160
- return true
161
- }
162
-
163
- /**
164
- * @private
165
- * @param {DOMElement} target
166
- * @param {boolean} openState
167
- */
168
- _doInitTransition(target, openState) {
169
- this._debug('init transition', `${openState ? 'open' : 'closed'}`, target)
170
- this._debug('dispatching event', `reveal:${openState ? 'show' : 'hide'}`, target)
171
- target.dispatchEvent(
172
- new Event(`reveal:${openState ? 'show' : 'hide'}`, {
173
- bubbles: true,
174
- cancelable: false,
175
- })
176
- )
177
-
178
- return new Promise((resolve, reject) => {
179
- if (
180
- 'transition' in target.dataset &&
181
- this.element.offsetParent !== null
182
- ) {
183
- requestAnimationFrame(() => {
184
- this._transitionSetup(target, openState)
185
- const _didEndTransition = this._didEndTransition.bind(this)
186
-
187
- target.addEventListener(
188
- 'transitionend',
189
- function _didEndTransitionHandler() {
190
- _didEndTransition(target, openState)
191
- target.removeEventListener(
192
- 'transitionend',
193
- _didEndTransitionHandler
194
- )
195
- resolve()
196
- }
197
- )
198
-
199
- requestAnimationFrame(() => {
200
- this._doStartTransition(target, openState)
201
- })
202
- })
203
- } else {
204
- if (openState) {
205
- this._debug(
206
- 'force hidden - init',
207
- `${openState ? 'open' : 'closed'}`,
208
- target
209
- )
210
- target.hidden = !target.hidden
211
- }
212
- this._doCompleteTransition(target, openState)
213
- resolve()
214
- }
215
- })
216
- }
217
-
218
- /**
219
- * @private
220
- * @param {DOMElement} target
221
- */
222
- _doStartTransition(target, openState) {
223
- this._debug('start transition', `${openState ? 'open' : 'closed'}`, target)
224
- this.transitioningValue = true
225
- if (target.dataset.useTransitionClasses === 'true') {
226
- const transitionClasses = this._transitionClasses(
227
- target,
228
- this.transitionType
229
- )
230
- target.classList.add(...transitionClasses.end.split(' '))
231
- target.classList.remove(...transitionClasses.start.split(' '))
232
- } else {
233
- const transitions = this._transitionDefaults(openState)
234
- target.style.transformOrigin = transitions.origin
235
- target.style.transitionProperty = 'opacity transform'
236
- target.style.transitionDuration = `${transitions.duration / 1000}s`
237
- target.style.transitionTimingFunction = 'cubic-bezier(0.4, 0.0, 0.2, 1)'
238
-
239
- target.style.opacity = transitions.to.opacity
240
- target.style.transform = `scale(${transitions.to.scale / 100})`
241
- }
242
- }
243
-
244
- /**
245
- * @private
246
- * @param {DOMElement} target
247
- * @param {boolean} openState
248
- */
249
- _didEndTransition(target, openState) {
250
- this._debug('end transition', `${openState ? 'open' : 'closed'}`, target)
251
- if (target.dataset.useTransitionClasses === 'true') {
252
- const transitionClasses = this._transitionClasses(
253
- target,
254
- this.transitionType
255
- )
256
- target.classList.remove(...transitionClasses.before.split(' '))
257
- } else {
258
- target.style.opacity = target.dataset.opacityCache
259
- target.style.transform = target.dataset.transformCache
260
- target.style.transformOrigin = target.dataset.transformOriginCache
261
- }
262
- this._doCompleteTransition(target, openState)
263
- }
264
-
265
- /**
266
- * @private
267
- * @param {DOMElement} target
268
- * @param {boolean} openState
269
- */
270
- _doCompleteTransition(target, openState) {
271
- this._debug(
272
- 'complete transition',
273
- `${openState ? 'open' : 'closed'}`,
274
- target
275
- )
276
- this.transitioningValue = false
277
-
278
- if (!openState) {
279
- this._debug(
280
- 'force hidden - complete',
281
- `${openState ? 'open' : 'closed'}`,
282
- target
283
- )
284
- target.hidden = !target.hidden
285
- }
286
- this.openValue = openState
287
-
288
- this._debug('dispatching event', `reveal:${openState ? 'shown' : 'hidden'}`, target)
289
- target.dispatchEvent(
290
- new Event(`reveal:${openState ? 'shown' : 'hidden'}`, {
291
- bubbles: true,
292
- cancelable: false,
293
- })
294
- )
295
-
296
- if (this.hasAwayValue) {
297
- if (openState) {
298
- this.awayHandler = this._awayHandler.bind(this)
299
- document.addEventListener('click', this.awayHandler)
300
- } else {
301
- document.removeEventListener('click', this.awayHandler)
302
- }
303
- }
304
-
305
- this._debug('dispatching event', 'reveal:complete', target)
306
- target.dispatchEvent(
307
- new Event('reveal:complete', { bubbles: true, cancelable: false })
308
- )
309
- }
310
-
311
- /**
312
- * @private
313
- * @param {DOMElement} target
314
- * @param {boolean} openState
315
- */
316
- _transitionSetup(target, openState) {
317
- this.transitionType = openState ? 'transitionEnter' : 'transitionLeave'
318
-
319
- if (this.transitionType in target.dataset) {
320
- target.dataset.useTransitionClasses = true
321
- const transitionClasses = this._transitionClasses(
322
- target,
323
- this.transitionType
324
- )
325
- target.classList.add(...transitionClasses.before.split(' '))
326
- target.classList.add(...transitionClasses.start.split(' '))
327
- } else {
328
- target.dataset.useTransitionClasses = false
329
- const transitions = this._transitionDefaults(openState)
330
- target.dataset.opacityCache = target.style.opacity
331
- target.dataset.transformCache = target.style.transform
332
- target.dataset.transformOriginCache = target.style.transformOrigin
333
-
334
- target.style.opacity = transitions.from.opacity
335
- target.style.transform = `scale(${transitions.from.scale / 100})`
336
- }
337
- if (openState) {
338
- this._debug('opening with transition', target)
339
- target.hidden = !target.hidden
340
- }
341
- }
342
-
343
- /**
344
- * @private
345
- * @param {boolean} openState
346
- */
347
- _transitionDefaults(openState) {
348
- return {
349
- duration: openState ? 200 : 150,
350
- origin: 'center',
351
- from: {
352
- opacity: openState ? 0 : 1,
353
- scale: openState ? 95 : 100,
354
- },
355
- to: {
356
- opacity: openState ? 1 : 0,
357
- scale: openState ? 100 : 95,
358
- },
359
- }
360
- }
361
-
362
- /**
363
- * @private
364
- * @param {DOMElement} target
365
- * @param {string} transitionType
366
- */
367
- _transitionClasses(target, transitionType) {
368
- return {
369
- before: target.dataset[transitionType],
370
- start: target.dataset[`${transitionType}Start`],
371
- end: target.dataset[`${transitionType}End`],
372
- }
373
- }
374
-
375
- _debug(...args) {
376
- if (this.debugValue) console.log(...args)
377
- }
378
-
379
- get selector() {
380
- return this.hasTargetSelectorValue
381
- ? this.targetSelectorValue
382
- : '[data-reveal]'
383
- }
384
- }
385
-
386
- export {
387
- RevealController
388
- }