b4um_generators 0.2.14 → 0.2.16
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/README.de.md +39 -8
- data/README.md +37 -8
- data/lib/b4um_generators/version.rb +1 -1
- data/lib/generators/b4um/bento/bento_generator.rb +24 -0
- data/lib/generators/b4um/help/help_generator.rb +48 -8
- data/lib/generators/b4um/install/templates/b4um/tables.css +49 -0
- data/lib/generators/b4um/install/templates/image_lightbox_controller.js +5 -1
- data/lib/generators/b4um/table/table_generator.rb +187 -5
- data/lib/generators/b4um/table/templates/_table.html.erb.tt +286 -0
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3872ce0dc22b0119d636611c3948c941da818ed3c8ee65301da95c0570ba677d
|
|
4
|
+
data.tar.gz: 77a2d8228dddbb5852325b81c1e1cc65482dc429912629884cf7c580438dac4e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1e44802b32dc4e9ee22c7bd2b4507a34a692777ca0a940b904f0403223b0d36b7bbd9c403579a13cd2fe9409d76f86fd21cc487022d13b4abd7de0ef600f4e6a
|
|
7
|
+
data.tar.gz: 1a20c4ba742c086c788c5426085724d3bea2a3a01e30229ea1dc0f190b6ad4d2819a5c5609e326dd95fdfc4b70beb728260ded64a26416d0725322144e7f6b1b
|
data/README.de.md
CHANGED
|
@@ -302,16 +302,34 @@ Das Partial verwendet eine lokale Collection und kann daher auch mit einer ander
|
|
|
302
302
|
Erzeuge eine wiederverwendbare b4um-Tabelle für ein bestehendes Modell:
|
|
303
303
|
|
|
304
304
|
```bash
|
|
305
|
-
bin/rails generate b4um:table MODEL FIELDS
|
|
305
|
+
bin/rails generate b4um:table MODEL [FIELDS]
|
|
306
306
|
```
|
|
307
307
|
|
|
308
|
-
|
|
308
|
+
Das Modell muss bereits vorhanden sein.
|
|
309
|
+
|
|
310
|
+
Die Felder sind optional. Werden keine Felder angegeben, erkennt der Generator automatisch die Datenbankfelder des
|
|
311
|
+
Modells, Action-Text-Felder und Active-Storage-Anhänge. `id`, `created_at` und `updated_at` werden automatisch
|
|
312
|
+
ausgeschlossen.
|
|
313
|
+
|
|
314
|
+
Empfohlen:
|
|
309
315
|
|
|
310
316
|
```bash
|
|
311
|
-
bin/rails generate b4um:table Product
|
|
317
|
+
bin/rails generate b4um:table Product
|
|
312
318
|
```
|
|
313
319
|
|
|
314
|
-
|
|
320
|
+
Felder können weiterhin ausdrücklich angegeben werden:
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
bin/rails generate b4um:table Product name price status
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Konfigurierte Select- und Radio-Werte können mit ihren Beschriftungen dargestellt werden:
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
bin/rails generate b4um:table Product \
|
|
330
|
+
--select="status:active=Aktiv,inactive=Inaktiv" \
|
|
331
|
+
--radio="condition:new=Neu,used=Gebraucht"
|
|
332
|
+
```
|
|
315
333
|
|
|
316
334
|
Für ein `Product`-Modell wird das generierte Partial hier gespeichert:
|
|
317
335
|
|
|
@@ -321,20 +339,33 @@ app/views/products/_table.html.erb
|
|
|
321
339
|
|
|
322
340
|
Die generierte Tabelle bietet:
|
|
323
341
|
|
|
342
|
+
- Automatische Felderkennung aus dem bestehenden Modell
|
|
324
343
|
- Responsives Tabellenlayout
|
|
325
|
-
-
|
|
344
|
+
- Erkennung der tatsächlichen Feldtypen des Modells
|
|
326
345
|
- Kürzung von Textfeldern auf 100 Zeichen
|
|
346
|
+
- Formatierung von Dezimalwerten mit zwei Nachkommastellen
|
|
327
347
|
- Darstellung von Statusfeldern als b4um-Badges
|
|
348
|
+
- Beschriftungen für konfigurierte `--select`- und `--radio`-Werte
|
|
349
|
+
- Action-Text-/Trix-Inhalte
|
|
350
|
+
- Lightbox für Bilder innerhalb von Rich Text
|
|
351
|
+
- Übernahme von Trix-Bildbeschriftungen in die Lightbox
|
|
352
|
+
- Active-Storage-`has_one_attached`-Bilder
|
|
353
|
+
- Active-Storage-`has_many_attached`-Galerien
|
|
354
|
+
- Vorschaubilder, Lightbox-Navigation und Ziehen/Wischen
|
|
328
355
|
- Aktionsspalte mit Show-Button
|
|
329
356
|
- Empty-State-Darstellung
|
|
330
357
|
|
|
331
|
-
|
|
358
|
+
Beim Aufruf des Tabellen-Generators wird eine vorhandene b4um-Index-Ansicht automatisch auf das Tabellen-Partial
|
|
359
|
+
umgestellt:
|
|
332
360
|
|
|
333
361
|
```erb
|
|
334
362
|
<%= render "table", products: @products %>
|
|
335
363
|
```
|
|
336
364
|
|
|
337
|
-
|
|
365
|
+
Wird später `b4um:bento Product` ausgeführt, stellt der Generator den Index wieder auf das Bento-Partial zurück. Das
|
|
366
|
+
gilt auch für die Bento-Layouts `grid`, `list` und `alternating`.
|
|
367
|
+
|
|
368
|
+
Das Tabellen-Partial kann auch mit einer anderen Collection verwendet werden:
|
|
338
369
|
|
|
339
370
|
```erb
|
|
340
371
|
<%= render "products/table", products: @featured_products %>
|
|
@@ -1104,7 +1135,7 @@ wird.
|
|
|
1104
1135
|
|
|
1105
1136
|
## Version
|
|
1106
1137
|
|
|
1107
|
-
Aktuelle Version: `0.2.
|
|
1138
|
+
Aktuelle Version: `0.2.16`
|
|
1108
1139
|
|
|
1109
1140
|
## Autor
|
|
1110
1141
|
|
data/README.md
CHANGED
|
@@ -299,16 +299,33 @@ The partial uses a local collection and can therefore also be reused with anothe
|
|
|
299
299
|
Generate a reusable b4um table for an existing model:
|
|
300
300
|
|
|
301
301
|
```bash
|
|
302
|
-
bin/rails generate b4um:table MODEL FIELDS
|
|
302
|
+
bin/rails generate b4um:table MODEL [FIELDS]
|
|
303
303
|
```
|
|
304
304
|
|
|
305
|
-
|
|
305
|
+
The model must already exist.
|
|
306
|
+
|
|
307
|
+
Fields are optional. If no fields are supplied, the generator automatically detects the model's database fields, Action
|
|
308
|
+
Text fields and Active Storage attachments. `id`, `created_at` and `updated_at` are excluded automatically.
|
|
309
|
+
|
|
310
|
+
Recommended:
|
|
306
311
|
|
|
307
312
|
```bash
|
|
308
|
-
bin/rails generate b4um:table Product
|
|
313
|
+
bin/rails generate b4um:table Product
|
|
309
314
|
```
|
|
310
315
|
|
|
311
|
-
|
|
316
|
+
Fields can also be specified explicitly:
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
bin/rails generate b4um:table Product name price status
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
Configured select and radio values can be displayed using their labels:
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
bin/rails generate b4um:table Product \
|
|
326
|
+
--select="status:active=Active,inactive=Inactive" \
|
|
327
|
+
--radio="condition:new=New,used=Used"
|
|
328
|
+
```
|
|
312
329
|
|
|
313
330
|
For a `Product` model, the generated partial is stored at:
|
|
314
331
|
|
|
@@ -318,20 +335,32 @@ app/views/products/_table.html.erb
|
|
|
318
335
|
|
|
319
336
|
The generated table provides:
|
|
320
337
|
|
|
338
|
+
- Automatic field detection from the existing model
|
|
321
339
|
- Responsive table layout
|
|
322
|
-
-
|
|
340
|
+
- Model-aware field types
|
|
323
341
|
- Text fields shortened to 100 characters
|
|
342
|
+
- Decimal values formatted with two decimal places
|
|
324
343
|
- Status fields displayed as b4um badges
|
|
344
|
+
- Labels for configured `--select` and `--radio` values
|
|
345
|
+
- Action Text / Trix content
|
|
346
|
+
- Lightbox support for images embedded in rich text
|
|
347
|
+
- Trix image captions in the Lightbox
|
|
348
|
+
- Active Storage `has_one_attached` images
|
|
349
|
+
- Active Storage `has_many_attached` galleries
|
|
350
|
+
- Thumbnails, Lightbox navigation and drag/swipe support
|
|
325
351
|
- Actions column with a Show button
|
|
326
352
|
- Empty-state handling
|
|
327
353
|
|
|
328
|
-
|
|
354
|
+
Running the Table generator automatically switches an existing b4um index view to the table partial:
|
|
329
355
|
|
|
330
356
|
```erb
|
|
331
357
|
<%= render "table", products: @products %>
|
|
332
358
|
```
|
|
333
359
|
|
|
334
|
-
|
|
360
|
+
Running `b4um:bento Product` later switches the index back to the Bento partial. This also applies to the `grid`, `list`
|
|
361
|
+
and `alternating` Bento layouts.
|
|
362
|
+
|
|
363
|
+
The table partial can also be reused with another collection:
|
|
335
364
|
|
|
336
365
|
```erb
|
|
337
366
|
<%= render "products/table", products: @featured_products %>
|
|
@@ -1095,7 +1124,7 @@ The gem can be tested locally by referencing the repository with `path:` from a
|
|
|
1095
1124
|
|
|
1096
1125
|
## Version
|
|
1097
1126
|
|
|
1098
|
-
Current version: `0.2.
|
|
1127
|
+
Current version: `0.2.16`
|
|
1099
1128
|
|
|
1100
1129
|
## Author
|
|
1101
1130
|
|
|
@@ -45,6 +45,21 @@ module B4um
|
|
|
45
45
|
)
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
+
def update_index_layout
|
|
49
|
+
return unless File.exist?(index_path)
|
|
50
|
+
|
|
51
|
+
index = File.read(index_path)
|
|
52
|
+
|
|
53
|
+
updated_index = index.sub(
|
|
54
|
+
/render\s+["'](?:bento|table|list|alternating)["']/,
|
|
55
|
+
'render "bento"'
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
return if updated_index == index
|
|
59
|
+
|
|
60
|
+
File.write(index_path, updated_index)
|
|
61
|
+
end
|
|
62
|
+
|
|
48
63
|
private
|
|
49
64
|
|
|
50
65
|
def model_path
|
|
@@ -55,6 +70,15 @@ module B4um
|
|
|
55
70
|
)
|
|
56
71
|
end
|
|
57
72
|
|
|
73
|
+
def index_path
|
|
74
|
+
File.join(
|
|
75
|
+
destination_root,
|
|
76
|
+
"app/views",
|
|
77
|
+
plural_table_name,
|
|
78
|
+
"index.html.erb"
|
|
79
|
+
)
|
|
80
|
+
end
|
|
81
|
+
|
|
58
82
|
def resource_partial_path
|
|
59
83
|
File.join(
|
|
60
84
|
destination_root,
|
|
@@ -758,15 +758,39 @@ module B4um
|
|
|
758
758
|
|
|
759
759
|
TABLE
|
|
760
760
|
|
|
761
|
-
bin/rails generate b4um:table MODEL FIELDS
|
|
761
|
+
bin/rails generate b4um:table MODEL [FIELDS]
|
|
762
762
|
|
|
763
763
|
Generates a reusable b4um table partial for an existing model.
|
|
764
764
|
|
|
765
|
-
|
|
765
|
+
The model must already exist.
|
|
766
766
|
|
|
767
|
-
|
|
767
|
+
Fields are optional. If no fields are supplied, the generator
|
|
768
|
+
automatically detects:
|
|
768
769
|
|
|
769
|
-
|
|
770
|
+
- Database fields
|
|
771
|
+
- Action Text rich text fields
|
|
772
|
+
- Active Storage single attachments
|
|
773
|
+
- Active Storage multiple attachments
|
|
774
|
+
|
|
775
|
+
id, created_at and updated_at are excluded automatically.
|
|
776
|
+
|
|
777
|
+
Recommended:
|
|
778
|
+
|
|
779
|
+
bin/rails generate b4um:table Product
|
|
780
|
+
|
|
781
|
+
Fields can also be specified explicitly:
|
|
782
|
+
|
|
783
|
+
bin/rails generate b4um:table Product name price status
|
|
784
|
+
|
|
785
|
+
Select fields can be configured with --select:
|
|
786
|
+
|
|
787
|
+
bin/rails generate b4um:table Product --select='status:active=Active,inactive=Inactive'
|
|
788
|
+
|
|
789
|
+
Radio fields can be configured with --radio:
|
|
790
|
+
|
|
791
|
+
bin/rails generate b4um:table Product --radio='condition:new=New,used=Used'
|
|
792
|
+
|
|
793
|
+
The configured database values are displayed using their labels.
|
|
770
794
|
|
|
771
795
|
The generated partial is created at:
|
|
772
796
|
|
|
@@ -774,18 +798,34 @@ module B4um
|
|
|
774
798
|
|
|
775
799
|
Table features:
|
|
776
800
|
|
|
801
|
+
- Automatic field detection from the existing model
|
|
777
802
|
- Responsive b4um table component
|
|
778
|
-
-
|
|
803
|
+
- Model-aware field types
|
|
779
804
|
- Text fields shortened to 100 characters
|
|
780
|
-
-
|
|
805
|
+
- Decimal values formatted with two decimal places
|
|
806
|
+
- Status fields displayed as b4um badges
|
|
807
|
+
- Select and radio labels
|
|
808
|
+
- Action Text / Trix content
|
|
809
|
+
- Lightbox for images embedded in rich text
|
|
810
|
+
- Trix image captions in the lightbox
|
|
811
|
+
- Active Storage single images
|
|
812
|
+
- Active Storage multiple image galleries
|
|
813
|
+
- Image thumbnails and lightbox navigation
|
|
814
|
+
- Mouse and touch drag / swipe
|
|
781
815
|
- Actions column with a Show button
|
|
816
|
+
- Empty-state handling
|
|
782
817
|
- No migrations, routes or controllers are generated
|
|
783
818
|
|
|
784
|
-
|
|
819
|
+
Running the Table generator automatically switches an existing
|
|
820
|
+
b4um index view to the table partial:
|
|
785
821
|
|
|
786
822
|
<%= render "table", products: @products %>
|
|
787
823
|
|
|
788
|
-
|
|
824
|
+
Running b4um:bento later switches the index back to the Bento
|
|
825
|
+
partial. This also applies to the grid, list and alternating
|
|
826
|
+
Bento layouts.
|
|
827
|
+
|
|
828
|
+
The table partial uses a local collection, so it can also be
|
|
789
829
|
reused with another collection:
|
|
790
830
|
|
|
791
831
|
<%= render "products/table", products: @featured_products %>
|
|
@@ -65,3 +65,52 @@
|
|
|
65
65
|
.b4um-table td:last-child {
|
|
66
66
|
padding-right: 1.25rem;
|
|
67
67
|
}
|
|
68
|
+
|
|
69
|
+
/* -------------------------------------------------------
|
|
70
|
+
Table media
|
|
71
|
+
------------------------------------------------------- */
|
|
72
|
+
|
|
73
|
+
.b4um-table__media {
|
|
74
|
+
display: flex;
|
|
75
|
+
flex-wrap: wrap;
|
|
76
|
+
gap: 0.5rem;
|
|
77
|
+
|
|
78
|
+
min-width: 100px;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.b4um-table__image-button {
|
|
82
|
+
display: block;
|
|
83
|
+
|
|
84
|
+
width: 100px;
|
|
85
|
+
height: 75px;
|
|
86
|
+
|
|
87
|
+
flex: 0 0 100px;
|
|
88
|
+
|
|
89
|
+
padding: 0;
|
|
90
|
+
|
|
91
|
+
border: 0;
|
|
92
|
+
border-radius: 8px;
|
|
93
|
+
|
|
94
|
+
overflow: hidden;
|
|
95
|
+
|
|
96
|
+
background: transparent;
|
|
97
|
+
|
|
98
|
+
cursor: zoom-in;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.b4um-table__image {
|
|
102
|
+
display: block;
|
|
103
|
+
|
|
104
|
+
width: 100%;
|
|
105
|
+
height: 100%;
|
|
106
|
+
|
|
107
|
+
border: 0;
|
|
108
|
+
border-radius: 8px;
|
|
109
|
+
|
|
110
|
+
object-fit: cover;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.b4um-table__media-empty {
|
|
114
|
+
color: var(--b4um-text-muted);
|
|
115
|
+
font-style: italic;
|
|
116
|
+
}
|
|
@@ -32,10 +32,14 @@ export default class extends Controller {
|
|
|
32
32
|
if (image.closest('[data-image-lightbox-target="item"]')) return
|
|
33
33
|
|
|
34
34
|
const item = image.closest('a') || image
|
|
35
|
+
const figure = image.closest('figure.attachment')
|
|
36
|
+
const figcaption = figure?.querySelector('figcaption')
|
|
37
|
+
const caption = figcaption?.textContent?.trim() || ''
|
|
35
38
|
|
|
36
39
|
item.dataset.imageLightboxTarget = 'item'
|
|
37
40
|
item.dataset.imageLightboxUrl = image.currentSrc || image.src
|
|
38
41
|
item.dataset.imageLightboxAlt = image.alt || ''
|
|
42
|
+
item.dataset.imageLightboxCaption = caption
|
|
39
43
|
|
|
40
44
|
const actions = [item.dataset.action, 'click->image-lightbox#open']
|
|
41
45
|
|
|
@@ -487,7 +491,7 @@ export default class extends Controller {
|
|
|
487
491
|
if (!item) return
|
|
488
492
|
|
|
489
493
|
if (this.hasCaptionTarget) {
|
|
490
|
-
this.captionTarget.textContent = item.dataset.imageLightboxAlt || ''
|
|
494
|
+
this.captionTarget.textContent = item.dataset.imageLightboxCaption || item.dataset.imageLightboxAlt || ''
|
|
491
495
|
}
|
|
492
496
|
|
|
493
497
|
if (this.hasCounterTarget) {
|
|
@@ -14,6 +14,14 @@ module B4um
|
|
|
14
14
|
default: [],
|
|
15
15
|
banner: "field:type field:type"
|
|
16
16
|
|
|
17
|
+
class_option :select,
|
|
18
|
+
type: :string,
|
|
19
|
+
desc: "Renders a field as a select value. Example: status:Active=Aktiv,Inactive=Inaktiv"
|
|
20
|
+
|
|
21
|
+
class_option :radio,
|
|
22
|
+
type: :string,
|
|
23
|
+
desc: "Renders a field as a radio value. Example: condition:new=Neu,used=Gebraucht"
|
|
24
|
+
|
|
17
25
|
class << self
|
|
18
26
|
def desc(_description = nil)
|
|
19
27
|
"Generates a B4UM table partial for an existing model."
|
|
@@ -27,6 +35,22 @@ module B4um
|
|
|
27
35
|
"Model not found: app/models/#{file_name}.rb"
|
|
28
36
|
end
|
|
29
37
|
|
|
38
|
+
def validate_editor_configurations
|
|
39
|
+
configurations = {
|
|
40
|
+
select: select_configuration,
|
|
41
|
+
radio: radio_configuration
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
configurations.each do |option_name, configuration|
|
|
45
|
+
validate_editor_configuration(
|
|
46
|
+
option_name,
|
|
47
|
+
configuration
|
|
48
|
+
)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
validate_editor_configuration_conflict(configurations)
|
|
52
|
+
end
|
|
53
|
+
|
|
30
54
|
def create_table_partial
|
|
31
55
|
template(
|
|
32
56
|
"_table.html.erb.tt",
|
|
@@ -38,19 +62,177 @@ module B4um
|
|
|
38
62
|
)
|
|
39
63
|
end
|
|
40
64
|
|
|
65
|
+
def update_index_layout
|
|
66
|
+
return unless File.exist?(index_path)
|
|
67
|
+
|
|
68
|
+
index = File.read(index_path)
|
|
69
|
+
|
|
70
|
+
updated_index = index.sub(
|
|
71
|
+
/render\s+["'](?:bento|table|list|alternating)["']/,
|
|
72
|
+
'render "table"'
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
return if updated_index == index
|
|
76
|
+
|
|
77
|
+
File.write(index_path, updated_index)
|
|
78
|
+
end
|
|
79
|
+
|
|
41
80
|
private
|
|
42
81
|
|
|
43
|
-
def
|
|
44
|
-
|
|
45
|
-
|
|
82
|
+
def model_class
|
|
83
|
+
class_name.constantize
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def database_columns
|
|
87
|
+
model_class.columns.index_by(&:name)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def rich_text_fields
|
|
91
|
+
model_class.reflect_on_all_associations(:has_one)
|
|
92
|
+
.filter_map do |association|
|
|
93
|
+
association.name.to_s.delete_prefix("rich_text_") if
|
|
94
|
+
association.name.to_s.start_with?("rich_text_")
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def single_attachment_fields
|
|
99
|
+
model_class.reflect_on_all_attachments
|
|
100
|
+
.select { |reflection| reflection.macro == :has_one_attached }
|
|
101
|
+
.map { |reflection| reflection.name.to_s }
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def multiple_attachment_fields
|
|
105
|
+
model_class.reflect_on_all_attachments
|
|
106
|
+
.select { |reflection| reflection.macro == :has_many_attached }
|
|
107
|
+
.map { |reflection| reflection.name.to_s }
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def available_field_names
|
|
111
|
+
(
|
|
112
|
+
database_field_names +
|
|
113
|
+
rich_text_fields +
|
|
114
|
+
single_attachment_fields +
|
|
115
|
+
multiple_attachment_fields
|
|
116
|
+
).uniq
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def database_field_names
|
|
120
|
+
database_columns.keys - %w[id created_at updated_at]
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def field_type(field)
|
|
124
|
+
return :rich_text if rich_text_fields.include?(field)
|
|
125
|
+
return :attachment if single_attachment_fields.include?(field)
|
|
126
|
+
return :attachments if multiple_attachment_fields.include?(field)
|
|
127
|
+
|
|
128
|
+
database_columns.fetch(field).type
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def table_field_names
|
|
132
|
+
return available_field_names if fields.empty?
|
|
133
|
+
|
|
134
|
+
fields.map { |field| field.split(":", 2).first }
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def validate_editor_configuration(option_name, configuration)
|
|
138
|
+
return unless options[option_name].present?
|
|
139
|
+
|
|
140
|
+
unless configuration
|
|
141
|
+
raise Thor::Error,
|
|
142
|
+
"Invalid --#{option_name} configuration. " \
|
|
143
|
+
"Expected FIELD:VALUE[,VALUE...]"
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
return if table_field_names.include?(configuration[:field])
|
|
147
|
+
|
|
148
|
+
raise Thor::Error,
|
|
149
|
+
"--#{option_name} field #{configuration[:field]} " \
|
|
150
|
+
"must be one of the generated fields: #{fields.join(", ")}"
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def validate_editor_configuration_conflict(configurations)
|
|
154
|
+
select = configurations[:select]
|
|
155
|
+
radio = configurations[:radio]
|
|
156
|
+
|
|
157
|
+
return unless select && radio
|
|
158
|
+
return unless select[:field] == radio[:field]
|
|
159
|
+
|
|
160
|
+
raise Thor::Error,
|
|
161
|
+
"Field #{select[:field]} cannot use both --select and --radio"
|
|
162
|
+
end
|
|
46
163
|
|
|
164
|
+
def select_configuration
|
|
165
|
+
field_configuration(:select)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def radio_configuration
|
|
169
|
+
field_configuration(:radio)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def field_configuration(option_name)
|
|
173
|
+
value = options[option_name]
|
|
174
|
+
return unless value.present?
|
|
175
|
+
|
|
176
|
+
field, values = value.split(":", 2)
|
|
177
|
+
|
|
178
|
+
return unless field.present? && values.present?
|
|
179
|
+
|
|
180
|
+
choices = field_choices(values)
|
|
181
|
+
return if choices.empty?
|
|
182
|
+
|
|
183
|
+
{
|
|
184
|
+
field: field,
|
|
185
|
+
values: choices
|
|
186
|
+
}
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def field_choices(values)
|
|
190
|
+
values.split(",").filter_map do |choice|
|
|
191
|
+
value, label = choice.strip.split("=", 2)
|
|
192
|
+
|
|
193
|
+
next if value.blank?
|
|
194
|
+
|
|
195
|
+
{
|
|
196
|
+
value: value,
|
|
197
|
+
label: label.presence || value
|
|
198
|
+
}
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def select_field?(field)
|
|
203
|
+
configuration = select_configuration
|
|
204
|
+
|
|
205
|
+
configuration &&
|
|
206
|
+
configuration[:field] == field &&
|
|
207
|
+
configuration[:values].any?
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def radio_field?(field)
|
|
211
|
+
configuration = radio_configuration
|
|
212
|
+
|
|
213
|
+
configuration &&
|
|
214
|
+
configuration[:field] == field &&
|
|
215
|
+
configuration[:values].any?
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def table_attributes
|
|
219
|
+
table_field_names.map do |field|
|
|
47
220
|
TableAttribute.new(
|
|
48
|
-
|
|
49
|
-
(
|
|
221
|
+
field,
|
|
222
|
+
field_type(field)
|
|
50
223
|
)
|
|
51
224
|
end
|
|
52
225
|
end
|
|
53
226
|
|
|
227
|
+
def index_path
|
|
228
|
+
File.join(
|
|
229
|
+
destination_root,
|
|
230
|
+
"app/views",
|
|
231
|
+
plural_table_name,
|
|
232
|
+
"index.html.erb"
|
|
233
|
+
)
|
|
234
|
+
end
|
|
235
|
+
|
|
54
236
|
def model_path
|
|
55
237
|
File.join(
|
|
56
238
|
destination_root,
|
|
@@ -14,12 +14,298 @@
|
|
|
14
14
|
<tr>
|
|
15
15
|
<% table_attributes.each do |attribute| -%>
|
|
16
16
|
<td>
|
|
17
|
+
<% if select_field?(attribute.name) -%>
|
|
17
18
|
<% if attribute.name == "status" -%>
|
|
19
|
+
<span class="b4um-badge">
|
|
20
|
+
<%%=
|
|
21
|
+
<%= select_configuration[:values].inspect %>.to_h {
|
|
22
|
+
|choice| [choice[:value], choice[:label]]
|
|
23
|
+
}.fetch(
|
|
24
|
+
<%= file_name %>.<%= attribute.name %>,
|
|
25
|
+
<%= file_name %>.<%= attribute.name %>
|
|
26
|
+
)
|
|
27
|
+
%>
|
|
28
|
+
</span>
|
|
29
|
+
<% else -%>
|
|
30
|
+
<%%=
|
|
31
|
+
<%= select_configuration[:values].inspect %>.to_h {
|
|
32
|
+
|choice| [choice[:value], choice[:label]]
|
|
33
|
+
}.fetch(
|
|
34
|
+
<%= file_name %>.<%= attribute.name %>,
|
|
35
|
+
<%= file_name %>.<%= attribute.name %>
|
|
36
|
+
)
|
|
37
|
+
%>
|
|
38
|
+
<% end -%>
|
|
39
|
+
<% elsif radio_field?(attribute.name) -%>
|
|
40
|
+
<%%=
|
|
41
|
+
<%= radio_configuration[:values].inspect %>.to_h {
|
|
42
|
+
|choice| [choice[:value], choice[:label]]
|
|
43
|
+
}.fetch(
|
|
44
|
+
<%= file_name %>.<%= attribute.name %>,
|
|
45
|
+
<%= file_name %>.<%= attribute.name %>
|
|
46
|
+
)
|
|
47
|
+
%>
|
|
48
|
+
<% elsif attribute.type == :rich_text -%>
|
|
49
|
+
<div
|
|
50
|
+
class="b4um-table__rich-text trix-content"
|
|
51
|
+
data-controller="image-lightbox rich-text"
|
|
52
|
+
data-action="keydown->image-lightbox#keydown"
|
|
53
|
+
>
|
|
54
|
+
<%%= <%= file_name %>.<%= attribute.name %> %>
|
|
55
|
+
|
|
56
|
+
<div
|
|
57
|
+
class="image-lightbox"
|
|
58
|
+
data-image-lightbox-target="overlay"
|
|
59
|
+
data-action="click->image-lightbox#closeOnBackground"
|
|
60
|
+
tabindex="-1"
|
|
61
|
+
role="dialog"
|
|
62
|
+
aria-modal="true"
|
|
63
|
+
aria-label="Image preview"
|
|
64
|
+
hidden
|
|
65
|
+
>
|
|
66
|
+
<div
|
|
67
|
+
class="image-lightbox__counter"
|
|
68
|
+
data-image-lightbox-target="counter"
|
|
69
|
+
></div>
|
|
70
|
+
|
|
71
|
+
<button
|
|
72
|
+
type="button"
|
|
73
|
+
class="image-lightbox__close"
|
|
74
|
+
aria-label="Close image"
|
|
75
|
+
data-action="click->image-lightbox#close"
|
|
76
|
+
>
|
|
77
|
+
×
|
|
78
|
+
</button>
|
|
79
|
+
|
|
80
|
+
<button
|
|
81
|
+
type="button"
|
|
82
|
+
class="image-lightbox__navigation image-lightbox__navigation--previous"
|
|
83
|
+
aria-label="Previous image"
|
|
84
|
+
data-action="click->image-lightbox#previous"
|
|
85
|
+
>
|
|
86
|
+
‹
|
|
87
|
+
</button>
|
|
88
|
+
|
|
89
|
+
<div
|
|
90
|
+
class="image-lightbox__stage"
|
|
91
|
+
data-image-lightbox-target="stage"
|
|
92
|
+
data-action="
|
|
93
|
+
pointerdown->image-lightbox#pointerDown
|
|
94
|
+
pointermove->image-lightbox#pointerMove
|
|
95
|
+
pointerup->image-lightbox#pointerUp
|
|
96
|
+
pointercancel->image-lightbox#pointerCancel
|
|
97
|
+
"
|
|
98
|
+
>
|
|
99
|
+
<img
|
|
100
|
+
class="image-lightbox__image"
|
|
101
|
+
data-image-lightbox-target="image"
|
|
102
|
+
alt=""
|
|
103
|
+
>
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<button
|
|
107
|
+
type="button"
|
|
108
|
+
class="image-lightbox__navigation image-lightbox__navigation--next"
|
|
109
|
+
aria-label="Next image"
|
|
110
|
+
data-action="click->image-lightbox#next"
|
|
111
|
+
>
|
|
112
|
+
›
|
|
113
|
+
</button>
|
|
114
|
+
|
|
115
|
+
<div
|
|
116
|
+
class="image-lightbox__thumbnails"
|
|
117
|
+
data-image-lightbox-target="thumbnails"
|
|
118
|
+
></div>
|
|
119
|
+
|
|
120
|
+
<div
|
|
121
|
+
class="image-lightbox__caption"
|
|
122
|
+
data-image-lightbox-target="caption"
|
|
123
|
+
></div>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
<% elsif attribute.type == :attachment -%>
|
|
127
|
+
<%% if <%= file_name %>.<%= attribute.name %>.attached? %>
|
|
128
|
+
<div
|
|
129
|
+
class="b4um-table__media"
|
|
130
|
+
data-controller="image-lightbox"
|
|
131
|
+
data-action="keydown->image-lightbox#keydown"
|
|
132
|
+
>
|
|
133
|
+
<button
|
|
134
|
+
type="button"
|
|
135
|
+
class="b4um-table__image-button"
|
|
136
|
+
data-image-lightbox-target="item"
|
|
137
|
+
data-image-lightbox-url="<%%= url_for(<%= file_name %>.<%= attribute.name %>) %>"
|
|
138
|
+
data-image-lightbox-alt="<%%= <%= file_name %>.<%= attribute.name %>.filename.to_s %>"
|
|
139
|
+
data-action="click->image-lightbox#open"
|
|
140
|
+
>
|
|
141
|
+
<%%= image_tag <%= file_name %>.<%= attribute.name %>,
|
|
142
|
+
class: "b4um-table__image",
|
|
143
|
+
alt: <%= file_name %>.<%= attribute.name %>.filename.to_s %>
|
|
144
|
+
</button>
|
|
145
|
+
|
|
146
|
+
<div
|
|
147
|
+
class="image-lightbox"
|
|
148
|
+
data-image-lightbox-target="overlay"
|
|
149
|
+
data-action="click->image-lightbox#closeOnBackground"
|
|
150
|
+
tabindex="-1"
|
|
151
|
+
role="dialog"
|
|
152
|
+
aria-modal="true"
|
|
153
|
+
aria-label="Image preview"
|
|
154
|
+
hidden
|
|
155
|
+
>
|
|
156
|
+
<div
|
|
157
|
+
class="image-lightbox__counter"
|
|
158
|
+
data-image-lightbox-target="counter"
|
|
159
|
+
></div>
|
|
160
|
+
|
|
161
|
+
<button
|
|
162
|
+
type="button"
|
|
163
|
+
class="image-lightbox__close"
|
|
164
|
+
aria-label="Close image"
|
|
165
|
+
data-action="click->image-lightbox#close"
|
|
166
|
+
>
|
|
167
|
+
×
|
|
168
|
+
</button>
|
|
169
|
+
|
|
170
|
+
<div
|
|
171
|
+
class="image-lightbox__stage"
|
|
172
|
+
data-image-lightbox-target="stage"
|
|
173
|
+
data-action="
|
|
174
|
+
pointerdown->image-lightbox#pointerDown
|
|
175
|
+
pointermove->image-lightbox#pointerMove
|
|
176
|
+
pointerup->image-lightbox#pointerUp
|
|
177
|
+
pointercancel->image-lightbox#pointerCancel
|
|
178
|
+
"
|
|
179
|
+
>
|
|
180
|
+
<img
|
|
181
|
+
class="image-lightbox__image"
|
|
182
|
+
data-image-lightbox-target="image"
|
|
183
|
+
alt=""
|
|
184
|
+
>
|
|
185
|
+
</div>
|
|
186
|
+
|
|
187
|
+
<div
|
|
188
|
+
class="image-lightbox__thumbnails"
|
|
189
|
+
data-image-lightbox-target="thumbnails"
|
|
190
|
+
></div>
|
|
191
|
+
|
|
192
|
+
<div
|
|
193
|
+
class="image-lightbox__caption"
|
|
194
|
+
data-image-lightbox-target="caption"
|
|
195
|
+
></div>
|
|
196
|
+
</div>
|
|
197
|
+
</div>
|
|
198
|
+
<%% else %>
|
|
199
|
+
<span class="b4um-table__media-empty">No image</span>
|
|
200
|
+
<%% end %>
|
|
201
|
+
<% elsif attribute.type == :attachments -%>
|
|
202
|
+
<%% if <%= file_name %>.<%= attribute.name %>.attached? %>
|
|
203
|
+
<div
|
|
204
|
+
class="b4um-table__media"
|
|
205
|
+
data-controller="image-lightbox"
|
|
206
|
+
data-action="keydown->image-lightbox#keydown"
|
|
207
|
+
>
|
|
208
|
+
<%% <%= file_name %>.<%= attribute.name %>.each do |image| %>
|
|
209
|
+
<button
|
|
210
|
+
type="button"
|
|
211
|
+
class="b4um-table__image-button"
|
|
212
|
+
data-image-lightbox-target="item"
|
|
213
|
+
data-image-lightbox-url="<%%= url_for(image) %>"
|
|
214
|
+
data-image-lightbox-alt="<%%= image.filename.to_s %>"
|
|
215
|
+
data-action="click->image-lightbox#open"
|
|
216
|
+
>
|
|
217
|
+
<%%= image_tag image,
|
|
218
|
+
class: "b4um-table__image",
|
|
219
|
+
alt: image.filename.to_s %>
|
|
220
|
+
</button>
|
|
221
|
+
<%% end %>
|
|
222
|
+
|
|
223
|
+
<div
|
|
224
|
+
class="image-lightbox"
|
|
225
|
+
data-image-lightbox-target="overlay"
|
|
226
|
+
data-action="click->image-lightbox#closeOnBackground"
|
|
227
|
+
tabindex="-1"
|
|
228
|
+
role="dialog"
|
|
229
|
+
aria-modal="true"
|
|
230
|
+
aria-label="Image gallery"
|
|
231
|
+
hidden
|
|
232
|
+
>
|
|
233
|
+
<div
|
|
234
|
+
class="image-lightbox__counter"
|
|
235
|
+
data-image-lightbox-target="counter"
|
|
236
|
+
></div>
|
|
237
|
+
|
|
238
|
+
<button
|
|
239
|
+
type="button"
|
|
240
|
+
class="image-lightbox__close"
|
|
241
|
+
aria-label="Close image"
|
|
242
|
+
data-action="click->image-lightbox#close"
|
|
243
|
+
>
|
|
244
|
+
×
|
|
245
|
+
</button>
|
|
246
|
+
|
|
247
|
+
<button
|
|
248
|
+
type="button"
|
|
249
|
+
class="image-lightbox__navigation image-lightbox__navigation--previous"
|
|
250
|
+
aria-label="Previous image"
|
|
251
|
+
data-action="click->image-lightbox#previous"
|
|
252
|
+
>
|
|
253
|
+
‹
|
|
254
|
+
</button>
|
|
255
|
+
|
|
256
|
+
<div
|
|
257
|
+
class="image-lightbox__stage"
|
|
258
|
+
data-image-lightbox-target="stage"
|
|
259
|
+
data-action="
|
|
260
|
+
pointerdown->image-lightbox#pointerDown
|
|
261
|
+
pointermove->image-lightbox#pointerMove
|
|
262
|
+
pointerup->image-lightbox#pointerUp
|
|
263
|
+
pointercancel->image-lightbox#pointerCancel
|
|
264
|
+
"
|
|
265
|
+
>
|
|
266
|
+
<img
|
|
267
|
+
class="image-lightbox__image"
|
|
268
|
+
data-image-lightbox-target="image"
|
|
269
|
+
alt=""
|
|
270
|
+
>
|
|
271
|
+
</div>
|
|
272
|
+
|
|
273
|
+
<button
|
|
274
|
+
type="button"
|
|
275
|
+
class="image-lightbox__navigation image-lightbox__navigation--next"
|
|
276
|
+
aria-label="Next image"
|
|
277
|
+
data-action="click->image-lightbox#next"
|
|
278
|
+
>
|
|
279
|
+
›
|
|
280
|
+
</button>
|
|
281
|
+
|
|
282
|
+
<div
|
|
283
|
+
class="image-lightbox__thumbnails"
|
|
284
|
+
data-image-lightbox-target="thumbnails"
|
|
285
|
+
></div>
|
|
286
|
+
|
|
287
|
+
<div
|
|
288
|
+
class="image-lightbox__caption"
|
|
289
|
+
data-image-lightbox-target="caption"
|
|
290
|
+
></div>
|
|
291
|
+
</div>
|
|
292
|
+
</div>
|
|
293
|
+
<%% else %>
|
|
294
|
+
<span class="b4um-table__media-empty">No images</span>
|
|
295
|
+
<%% end %>
|
|
296
|
+
<% elsif attribute.name == "status" -%>
|
|
18
297
|
<span class="b4um-badge">
|
|
19
298
|
<%%= <%= file_name %>.<%= attribute.name %> %>
|
|
20
299
|
</span>
|
|
21
300
|
<% elsif attribute.type == :text -%>
|
|
22
301
|
<%%= truncate(<%= file_name %>.<%= attribute.name %>, length: 100) %>
|
|
302
|
+
<% elsif attribute.type == :decimal -%>
|
|
303
|
+
<%%= number_with_precision(
|
|
304
|
+
<%= file_name %>.<%= attribute.name %>,
|
|
305
|
+
precision: 2,
|
|
306
|
+
delimiter: ".",
|
|
307
|
+
separator: ","
|
|
308
|
+
) %>
|
|
23
309
|
<% else -%>
|
|
24
310
|
<%%= <%= file_name %>.<%= attribute.name %> %>
|
|
25
311
|
<% end -%>
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: b4um_generators
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.16
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alexander Baum
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 2026-10-09 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: railties
|
|
@@ -171,7 +171,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
171
171
|
- !ruby/object:Gem::Version
|
|
172
172
|
version: '0'
|
|
173
173
|
requirements: []
|
|
174
|
-
rubygems_version: 3.6.
|
|
174
|
+
rubygems_version: 3.6.2
|
|
175
175
|
specification_version: 4
|
|
176
176
|
summary: Rails generators for b4um applications
|
|
177
177
|
test_files: []
|