hot-glue 0.6.31 → 0.7.1
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/Gemfile.lock +1 -1
- data/README.md +152 -11
- data/lib/generators/hot_glue/fields/association_field.rb +1 -1
- data/lib/generators/hot_glue/fields/string_field.rb +2 -2
- data/lib/generators/hot_glue/fields/text_field.rb +3 -3
- data/lib/generators/hot_glue/layout/builder.rb +79 -19
- data/lib/generators/hot_glue/markup_templates/erb.rb +93 -70
- data/lib/generators/hot_glue/scaffold_generator.rb +41 -8
- data/lib/generators/hot_glue/templates/controller.rb.erb +3 -2
- data/lib/generators/hot_glue/templates/erb/_edit.erb +5 -1
- data/lib/generators/hot_glue/templates/erb/_line.erb +4 -1
- data/lib/generators/hot_glue/templates/erb/_list.erb +10 -5
- data/lib/generators/hot_glue/templates/erb/_new_form.erb +5 -2
- data/lib/generators/hot_glue/templates/erb/create.turbo_stream.erb +9 -3
- data/lib/generators/hot_glue/templates/erb/destroy.turbo_stream.erb +5 -2
- data/lib/generators/hot_glue/templates/erb/edit.erb +3 -3
- data/lib/generators/hot_glue/templates/erb/new.erb +1 -1
- data/lib/generators/hot_glue/templates/javascript/search_form_controller.js +54 -3
- data/lib/hotglue/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 62c0a8b7999c39d4d93ece238d6447baa2ecdf34613d9fb11b5fe49842919424
|
|
4
|
+
data.tar.gz: c0a2d741d113fe2d3a366b5f33f110fc5aa8956a1b52af7ea2deb56085e76a4b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dd02b7553a585535eb7eb2ac195ce55eb0192151edccfb41cb9f3b4c8110ed125096200bbe3442cdc79dbb27db48cc0b8a10fdbc3366c9c0371f7ba46dc3684f
|
|
7
|
+
data.tar.gz: 235257f2f9150c0ac038fd7b11d4ac0551d4a224213e5cf244311ed43ca4cbdc02e25bf6427090213e30abde0de7289a0b01b887e265f0e2496a63c9fc9b12e0
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -655,7 +655,16 @@ If you specify an include list, it will be treated as a whitelist: no fields wil
|
|
|
655
655
|
|
|
656
656
|
You may not specify both include and exclude.
|
|
657
657
|
|
|
658
|
-
|
|
658
|
+
Many options allow you to specify fields in multiple modes:
|
|
659
|
+
• Standard
|
|
660
|
+
• Smart layout
|
|
661
|
+
• Specified grouping
|
|
662
|
+
|
|
663
|
+
see "Layout & Manipulation features" for details on how to build your `--include` statement, including how to use `:` and `,`
|
|
664
|
+
|
|
665
|
+
Also review Omitted Fields (`-` and `=`), Dynamic Blocks (`**`), Omitted Dynamic Blocks (`**-` and `**=`)
|
|
666
|
+
|
|
667
|
+
Also see Set Column Widths ( `(` ... `)` ) to set the column widths explicitly in your `--include`
|
|
659
668
|
|
|
660
669
|
|
|
661
670
|
### `--exclude=`
|
|
@@ -665,7 +674,6 @@ By default, all fields are included unless they are on the default exclude list.
|
|
|
665
674
|
|
|
666
675
|
If you specify any exclude list, those excluded **and** the default exclude list will be excluded. (If you need any of the fields on the default exclude list, you must use `--include` instead.)
|
|
667
676
|
|
|
668
|
-
|
|
669
677
|
`./bin/rails generate hot_glue:scaffold Account --exclude=password`
|
|
670
678
|
|
|
671
679
|
|
|
@@ -1059,10 +1067,72 @@ This is what would happen if 9 fields, specified in the order A,B,C,D,E,F,G,H,I,
|
|
|
1059
1067
|
(If you had a number of fields that wasn't easily divisible by the number of columns, it would leave the final column one or a few fields short of the others.)
|
|
1060
1068
|
|
|
1061
1069
|
|
|
1062
|
-
### `--new-button-position` (above, below; default: above)
|
|
1063
|
-
Show the new button above or below the list.
|
|
1064
1070
|
|
|
1071
|
+
### Omitted fields
|
|
1072
|
+
|
|
1073
|
+
Note that these additions all affect how you write your `--include` setting, but they operate in addition to all of the field visibility rules above. Notice that omitting a form means we by design omit it on both the new and edit actions. If you want to determine if it shows up on new vs. edit granularly, use a different approach.
|
|
1074
|
+
|
|
1075
|
+
Generally, you will only omit a field in special cases. To omit a field, prefix either `-` (omit on list) or `=` to omit on form (new & edit), like so :
|
|
1076
|
+
|
|
1077
|
+
`--include=-abd,=dfg`
|
|
1078
|
+
|
|
1079
|
+
Here, the abc field will be omitted on the list and the dfg will be omitted on the form (new & edit)
|
|
1080
|
+
|
|
1081
|
+
|
|
1082
|
+
This works for any include setting type, whether the grouping mode is specified or not.
|
|
1083
|
+
|
|
1084
|
+
`--include=-abd,=dfg`
|
|
1085
|
+
`--include=-abd:=dfg` # same as above but builder will use specified grouping mode
|
|
1086
|
+
|
|
1087
|
+
### Dynamic Blocks
|
|
1088
|
+
|
|
1089
|
+
Next, you can now dynamically pull any partials from the view folder (of the name of your choosing) into your object's field display- before, between, or after any part of the column groupings using the `:` and `,` characters. (Review specified grouping mode in "Layout & Manipulation Features.")
|
|
1090
|
+
|
|
1091
|
+
You simply make up any partial name, treat it as if it is one of the fields in the field list, and prefix it with `**`. (When specified, don't use `_` but remember to use the `_` in the file name.)
|
|
1092
|
+
|
|
1093
|
+
It looks like this (let's assume I've made an arbitrary partial called `_jello.erb` in my build folder, which expects to be passed a `thing` local variable)
|
|
1094
|
+
|
|
1095
|
+
`rails generate hot_glue:scaffold Thing --include='**jello:name:birthday:gender'`
|
|
1096
|
+
|
|
1097
|
+
Here, you'll get four columns:
|
|
1098
|
+
|
|
1099
|
+
The first column will pull a partial from the same folder being built. You build this partial, not Hot Glue.
|
|
1065
1100
|
|
|
1101
|
+
```
|
|
1102
|
+
<%= render partial: 'jello', locals: {thing: thing } %>
|
|
1103
|
+
```
|
|
1104
|
+
|
|
1105
|
+
(Remember, the partial file name begins with `_` but is referenced without the underscore)
|
|
1106
|
+
|
|
1107
|
+
Because you separated that first column using `:` from the other three, the partial will take up the whole column.
|
|
1108
|
+
The next 3 columns will contain name, birthday & gender, respectively.
|
|
1109
|
+
|
|
1110
|
+
If you specify it this way:
|
|
1111
|
+
rails generate hot_glue:scaffold Thing --include='**jello,name:birthday:gender'
|
|
1112
|
+
|
|
1113
|
+
Notice that between **jello and name is now a comma, putting the jello partial and name into the same column. Now the partial will be displayed before the name in that column.
|
|
1114
|
+
|
|
1115
|
+
You can mix & match any number of partials inserted anywhere into the field layout.
|
|
1116
|
+
|
|
1117
|
+
|
|
1118
|
+
### Omitted Dynamic Blocks
|
|
1119
|
+
|
|
1120
|
+
Dynamic blocks respond to the new `-` and `=` settings for omitting fields the same way fields do. Prefixing a dynamic partial with `**-` will mean it will be omitted from the list, and `**=` will omit it from the form (new & edit)
|
|
1121
|
+
|
|
1122
|
+
This way, the omitted syntax is parallel to the dynamic block structure. No other tye-in is made with the other field visibility settings.
|
|
1123
|
+
|
|
1124
|
+
|
|
1125
|
+
### Set Column Widths
|
|
1126
|
+
|
|
1127
|
+
In other modes, Hot Glue decides how many bootstrap columns each column should span, defaulting to 2 unless using `--smart-layout`, in which case it ranges from 2 to 5 depending on how many fields you have. Generally, I start my scaffolds using either standard or smart, but soon, I'm often upgrading to specified grouping mode for fine-grained control.
|
|
1128
|
+
|
|
1129
|
+
When using specified group mode (activated when a `:` character appears in the `--include` list), you can append to the end of EACH COLUMN (not each field) a parenthetical setting for the number of bootstrap columns.
|
|
1130
|
+
|
|
1131
|
+
(When the setting includes this special character, you'll need `'` to wrap the entire setting for `--include` on the command line.)
|
|
1132
|
+
|
|
1133
|
+
|
|
1134
|
+
### `--new-button-position` (above, below; default: above)
|
|
1135
|
+
Show the new button above or below the list.
|
|
1066
1136
|
|
|
1067
1137
|
### `--button-icons` (default is no icons)
|
|
1068
1138
|
You can specify this either as builder flag or as a config setting (in `config/hot_glue.yml`)
|
|
@@ -1075,8 +1145,6 @@ Can also be specified globally in `config/hot_glue.yml`
|
|
|
1075
1145
|
|
|
1076
1146
|
|
|
1077
1147
|
### `--modify=field1{...},field2{...}`
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
1148
|
You can apply modification to the viewable (non-edit) display of field using the `--modify` switch.
|
|
1081
1149
|
|
|
1082
1150
|
The syntax is `--modify=cost{$},price{$}`
|
|
@@ -1179,7 +1247,7 @@ In these contexts, the lookup must be exact match to the text entered (no partia
|
|
|
1179
1247
|
|
|
1180
1248
|
Use `+` to map to the `find_or_create_by` method. (Without `+` it will use `find_by`.)
|
|
1181
1249
|
|
|
1182
|
-
This is
|
|
1250
|
+
This is accomplished using a little magic of a lookup field called `__lookup_X_Y` passed in the form parameters.
|
|
1183
1251
|
|
|
1184
1252
|
The lookup field is used to look up the associated record, then deleted from the params.
|
|
1185
1253
|
|
|
@@ -1443,10 +1511,15 @@ As shown in the method `name_able?` of the example ThingPolicy above, if this fi
|
|
|
1443
1511
|
### `--hidden=` (affects both create + update actions)
|
|
1444
1512
|
### `--create-hidden=`
|
|
1445
1513
|
### `--update-hidden=`
|
|
1446
|
-
TODO: RENAME ME TO INVISIBLE
|
|
1447
1514
|
Separate list of fields.
|
|
1448
1515
|
|
|
1449
|
-
These fields will exist on the create or update form exist as
|
|
1516
|
+
These fields will exist on the create or update form exist as `<input type='hidden'>` (html) field and so the *actual update or create action will continue to expect data from the front end.**
|
|
1517
|
+
|
|
1518
|
+
(The data, being in a hidden field, is not visible to the user but it is in the browser's form, available to a hacker, and passed to the back-end for updating.)
|
|
1519
|
+
|
|
1520
|
+
You do your own javascript here to insert/set the value programmatically. The example below uses a library called EditorView to create a HTML editor.
|
|
1521
|
+
|
|
1522
|
+
The dynamic interface's value from the edited html gets stuffed back into the form by Javascript before the form is updated
|
|
1450
1523
|
|
|
1451
1524
|
|
|
1452
1525
|
EXAMPLE:
|
|
@@ -1539,10 +1612,9 @@ Like show only, these will check for `*_able?` methods on the object or Policy a
|
|
|
1539
1612
|
|
|
1540
1613
|
It will also block the field from being updated on the backend, so don't use this if you want to create a hidden_field tag but still allow the controller to update it. (For that, see `--hidden=`.)
|
|
1541
1614
|
|
|
1542
|
-
|
|
1543
1615
|
Like show-only, note special behavior with pundit.
|
|
1544
1616
|
|
|
1545
|
-
A field can be marked invisible and show-only, in which case the invisible rule take
|
|
1617
|
+
A field can be marked invisible and show-only, in which case the invisible rule take precedence when the access control is denied (field removed from form) but the show-only rule takes precedence when the access control is granted.
|
|
1546
1618
|
|
|
1547
1619
|
Hidden can be used with invisible. In this case, the access control will be applied to the field. When editable, the hidden field output will be used.
|
|
1548
1620
|
|
|
@@ -1598,6 +1670,12 @@ If thing is not a Thing, then it is active relation (so this applies to the colu
|
|
|
1598
1670
|
Remember, since the `_able?` methods are not otherwise called during Pundit's index cycle, this applies only to the list column headings and has no bearing on create, update, read, delete for which the access control can be anything you want that is available to the Poilcy.
|
|
1599
1671
|
|
|
1600
1672
|
|
|
1673
|
+
###
|
|
1674
|
+
|
|
1675
|
+
|
|
1676
|
+
|
|
1677
|
+
|
|
1678
|
+
|
|
1601
1679
|
|
|
1602
1680
|
## Code Insertion Features
|
|
1603
1681
|
'
|
|
@@ -1639,6 +1717,7 @@ This is a good place to set your created_by user id, like so
|
|
|
1639
1717
|
|
|
1640
1718
|
|
|
1641
1719
|
|
|
1720
|
+
|
|
1642
1721
|
```
|
|
1643
1722
|
def new
|
|
1644
1723
|
@email_template = EmailTemplate.new(crusade: crusade)
|
|
@@ -1670,6 +1749,16 @@ def create
|
|
|
1670
1749
|
```
|
|
1671
1750
|
TODO: build a solution for inserting code only in the `new` action but NOT the create action
|
|
1672
1751
|
|
|
1752
|
+
#### `--code-in-controller=''` (escape newlines with `;` )
|
|
1753
|
+
|
|
1754
|
+
This code will be inserted directly into your controller (as a class-level definition)
|
|
1755
|
+
|
|
1756
|
+
|
|
1757
|
+
```
|
|
1758
|
+
--code-in-controller="before_action -> { @thing = 'abc' }"
|
|
1759
|
+
```
|
|
1760
|
+
A one-liner hook works well for these. if you define an entire method, be sure to use `;` to separate line breaks
|
|
1761
|
+
|
|
1673
1762
|
|
|
1674
1763
|
|
|
1675
1764
|
## Searching
|
|
@@ -2331,6 +2420,58 @@ These automatic pickups for partials are detected at build time. This means that
|
|
|
2331
2420
|
|
|
2332
2421
|
# VERSION HISTORY
|
|
2333
2422
|
|
|
2423
|
+
#### 2025-11-12 - v0.7.1
|
|
2424
|
+
- in set searches, automatically sets the match field if the search text is input, removes match field (back to default) when search text is removed;
|
|
2425
|
+
-
|
|
2426
|
+
- also removes search text if you change the match selector back to empty
|
|
2427
|
+
-
|
|
2428
|
+
- removes vestiges of `.merge` from old implementation (#236)
|
|
2429
|
+
|
|
2430
|
+
- `--code-in-controller` option for inserting controller code directly into your controller
|
|
2431
|
+
|
|
2432
|
+
|
|
2433
|
+
#### 2025-11-05 - v0.7
|
|
2434
|
+
|
|
2435
|
+
Hot Glue already has a robust set of tools to provide field-by-field access control, hiding or turning visible-only fields by multiple methods, described under Access Control & Field Visibility Features.
|
|
2436
|
+
|
|
2437
|
+
Remember that Hot Glue's opinionated design has two ways a field is displayed: show (which appears on the list view and is always just viewable), and form (which is usees by both the new and edit actions to display a form). Within the `form` output, the form might be used for either new or edit, and further refinements can be applied to new or edit.
|
|
2438
|
+
|
|
2439
|
+
Here's a quick review those methods now:
|
|
2440
|
+
|
|
2441
|
+
--pundit
|
|
2442
|
+
• No distinction is made between the new and edit contexts
|
|
2443
|
+
• If policy says not able (_able? method returns false), the field is shown as viewable-only. That is, a user with access to the controller but not the field-level access granted by Pundit will see the field's value but cannot edit it. If you want instead the Policy to determine if the field is editable or completely invisible (not shown to the user), use invible below
|
|
2444
|
+
|
|
2445
|
+
--show-only=
|
|
2446
|
+
• Turns fields on this list viewable only for both create & edit actions
|
|
2447
|
+
• overrides what's on the policy, but asks the policy if not on this list
|
|
2448
|
+
|
|
2449
|
+
--update-show-only=
|
|
2450
|
+
• Turns fields on this list viewable only for the edit action
|
|
2451
|
+
• overrides what's on the policy, but asks the policy if not on this list
|
|
2452
|
+
|
|
2453
|
+
|
|
2454
|
+
--hidden=, --create-hidden=, --update-hidden=
|
|
2455
|
+
• Creates <input type='hidden'> fields on the form, not seen by the user but available to a hacker in the browser, and submitted to the back end.
|
|
2456
|
+
|
|
2457
|
+
--invisible=, --create-invisible=, --update-invisible=
|
|
2458
|
+
• Must be used with Pundit.
|
|
2459
|
+
• If policy returns true, the field is viewable on list & editable as normal.
|
|
2460
|
+
• If the policy return false, the field is taken away (invisible) for that user
|
|
2461
|
+
|
|
2462
|
+
|
|
2463
|
+
|
|
2464
|
+
Today, with v0.7 of this gem, I'm introducing three more features that are all available from within the `--include` setting.
|
|
2465
|
+
|
|
2466
|
+
• Omitted fields: using `-` is omit on list & show; use `=` to omit the field on the form (new & edit)
|
|
2467
|
+
• Dynamic blocks (which can also be omitted using
|
|
2468
|
+
• Set column widths when using specified grouping made (--include contains `:`)
|
|
2469
|
+
|
|
2470
|
+
For details, see "Layout & Manipulation Features"
|
|
2471
|
+
|
|
2472
|
+
|
|
2473
|
+
|
|
2474
|
+
|
|
2334
2475
|
#### 2025-10-28 - v0.6.31
|
|
2335
2476
|
|
|
2336
2477
|
- new modification directive: `urlwrap`: use to wrap the field contents in a clickable link.
|
|
@@ -219,7 +219,7 @@ class AssociationField < Field
|
|
|
219
219
|
autofocus: true,
|
|
220
220
|
autocomplete: 'off',
|
|
221
221
|
value: @q['0']['#{name}'].present? ? #{assoc.class_name}.find(@q['0']['#{name}']).try(:name) : \"\" %>
|
|
222
|
-
<%= f.hidden_field \'q[0][#{name}]\', value: @q['0']['#{name}
|
|
222
|
+
<%= f.hidden_field \'q[0][#{name}]\', value: @q['0']['#{name}'], 'data-typeahead-target': 'hiddenFormValue' %>
|
|
223
223
|
<div data-typeahead-target='results'></div>
|
|
224
224
|
<div data-typeahead-target='classIdentifier' data-id=\"typeahead--q_0_#{name}_search\"></div>
|
|
225
225
|
</div>"
|
|
@@ -49,8 +49,8 @@ class StringField < Field
|
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
def search_field_output
|
|
52
|
-
"<%= f.select 'q[0][#{name}_match]', options_for_select([['', ''], ['contains', 'contains'], ['is exactly', 'is_exactly'], ['starts with', 'starts_with'], ['ends with', 'ends_with']], @q[\'0\']['#{name}_match'] ), {} , { class: 'form-control match' } %>"+
|
|
53
|
-
"<%= f.text_field 'q[0][#{name}_search]', value: @q[\'0\'][:#{name}_search], autocomplete: 'off', size: 40, class: 'form-control', type: 'text' %>"
|
|
52
|
+
"<%= f.select 'q[0][#{name}_match]', options_for_select([['', ''], ['contains', 'contains'], ['is exactly', 'is_exactly'], ['starts with', 'starts_with'], ['ends with', 'ends_with']], @q[\'0\']['#{name}_match'] ), {} , { class: 'form-control match' , 'data-search-form-target': \"textMatch\"} %>"+
|
|
53
|
+
"<%= f.text_field 'q[0][#{name}_search]', value: @q[\'0\'][:#{name}_search], autocomplete: 'off', size: 40, class: 'form-control', type: 'text' , 'data-search-form-target': \"textSearch\" %>"
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
|
|
@@ -31,8 +31,8 @@ class TextField < Field
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
def search_field_output
|
|
34
|
-
"<%= f.select 'q[0][#{name}_match]', options_for_select([['', ''], ['contains', 'contains'], ['is exactly', 'is_exactly'], ['starts with', 'starts_with'], ['ends with', 'ends_with']], @q[\'0\']['#{name}_match'] ), {} , { class: 'form-control match' } %>"+
|
|
35
|
-
"<%= f.text_field 'q[0][#{name}_search]', value: @q[\'0\'][:#{name}_search], autocomplete: 'off', size: 40, class: 'form-control', type: 'text' %>"
|
|
34
|
+
"<%= f.select 'q[0][#{name}_match]', options_for_select([['', ''], ['contains', 'contains'], ['is exactly', 'is_exactly'], ['starts with', 'starts_with'], ['ends with', 'ends_with']], @q[\'0\']['#{name}_match'] ), {} , { class: 'form-control match', 'data-search-form-target': \"textMatch\" } %>"+
|
|
35
|
+
"<%= f.text_field 'q[0][#{name}_search]', value: @q[\'0\'][:#{name}_search], autocomplete: 'off', size: 40, class: 'form-control', type: 'text', 'data-search-form-target': \"textSearch\" %>"
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
|
|
@@ -45,7 +45,7 @@ class TextField < Field
|
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
def code_to_reset_match_if_search_is_blank
|
|
48
|
-
" @q['0'][:#{name}_match] = '' if @q['0'][:#{name}_search] == ''"
|
|
48
|
+
# " @q['0'][:#{name}_match] = '' if @q['0'][:#{name}_search] == ''"
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
end
|
|
@@ -11,8 +11,8 @@ module HotGlue
|
|
|
11
11
|
:stacked_downnesting, :bootstrap_column_width
|
|
12
12
|
|
|
13
13
|
def initialize(generator: ,
|
|
14
|
-
include_setting
|
|
15
|
-
buttons_width:
|
|
14
|
+
include_setting:,
|
|
15
|
+
buttons_width: )
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
@generator = generator
|
|
@@ -41,7 +41,11 @@ module HotGlue
|
|
|
41
41
|
columns: {
|
|
42
42
|
size_each: smart_layout ? bootstrap_column_width : (specified_grouping_mode ? nil : 1),
|
|
43
43
|
container: [] , # array of arrays,
|
|
44
|
-
bootstrap_column_width: []
|
|
44
|
+
bootstrap_column_width: [],
|
|
45
|
+
column_custom_widths: [],
|
|
46
|
+
fields: {
|
|
47
|
+
|
|
48
|
+
}, # hash of fields
|
|
45
49
|
},
|
|
46
50
|
portals: {
|
|
47
51
|
|
|
@@ -103,15 +107,21 @@ module HotGlue
|
|
|
103
107
|
}
|
|
104
108
|
layout_object[:columns][:container] = (0..available_columns-1).collect { |x| [columns[x]] }
|
|
105
109
|
layout_object[:columns][:container].reject!{|x| x == [nil]}
|
|
106
|
-
|
|
110
|
+
|
|
107
111
|
end
|
|
112
|
+
|
|
108
113
|
elsif ! specified_grouping_mode
|
|
109
114
|
# not smart and no specified grouping
|
|
110
115
|
layout_object[:columns][:button_columns] = bootstrap_column_width
|
|
111
116
|
|
|
112
117
|
layout_object[:columns][:container] = columns.collect{|col| [col]}
|
|
113
118
|
|
|
114
|
-
|
|
119
|
+
if include_setting.split(",").any?{|col| col.include?("(")}
|
|
120
|
+
raise "Your include list has a ( character; to specify a column width, use specified grouping mode only"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
else # specified grouping mode -- the builder is given control unless a column width is explicitly set using (..)
|
|
115
125
|
layout_object[:columns][:button_columns] = bootstrap_column_width
|
|
116
126
|
|
|
117
127
|
(0..available_columns-1).each do |int|
|
|
@@ -121,16 +131,22 @@ module HotGlue
|
|
|
121
131
|
# input control
|
|
122
132
|
|
|
123
133
|
user_layout_columns = @include_setting.split(":")
|
|
134
|
+
fixed_widths = {}
|
|
135
|
+
|
|
136
|
+
user_layout_columns.each_with_index do |column_data,i |
|
|
137
|
+
if column_data.include?("(")
|
|
138
|
+
column_data =~ /(.*)\((.*)\)/
|
|
139
|
+
column_fields = $1
|
|
140
|
+
fixed_col_width = $2
|
|
141
|
+
fixed_widths[i] = fixed_col_width
|
|
142
|
+
else
|
|
143
|
+
column_fields = column_data
|
|
144
|
+
end
|
|
145
|
+
user_layout_columns[i] = column_fields
|
|
146
|
+
end
|
|
124
147
|
|
|
125
|
-
extra_columns = available_columns - user_layout_columns.size
|
|
126
|
-
# size_each = (bootstrap_columns / user_layout_columns.count).floor # this is the bootstrap size
|
|
127
|
-
#
|
|
128
|
-
# layout_object[:columns][:size_each] = size_each
|
|
129
|
-
|
|
130
|
-
# if user_layout_columns.size > available_columns
|
|
131
|
-
# raise "Your include statement #{@include_setting } has #{user_layout_columns.size} columns, but I can only construct up to #{available_columns}"
|
|
132
|
-
# end
|
|
133
148
|
|
|
149
|
+
extra_columns = available_columns - user_layout_columns.size
|
|
134
150
|
|
|
135
151
|
columns_to_work_with = (12 - @buttons_width)
|
|
136
152
|
|
|
@@ -142,10 +158,22 @@ module HotGlue
|
|
|
142
158
|
extra_columns = columns_to_work_with % user_layout_columns.size
|
|
143
159
|
|
|
144
160
|
|
|
145
|
-
user_layout_columns.each_with_index do |column,i|
|
|
146
|
-
|
|
147
|
-
layout_object[:columns][:
|
|
148
|
-
|
|
161
|
+
user_layout_columns.each_with_index do |column, i|
|
|
162
|
+
|
|
163
|
+
layout_object[:columns][:container][i] = column.split(",").collect{|x|
|
|
164
|
+
x.gsub("-","").gsub("=","")
|
|
165
|
+
if x.include?("(")
|
|
166
|
+
x =~ /(.*)\((.*)\)/
|
|
167
|
+
x = $1
|
|
168
|
+
|
|
169
|
+
end
|
|
170
|
+
x
|
|
171
|
+
}.collect(&:to_sym)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
layout_object[:columns][:bootstrap_column_width][i] = fixed_widths[i] || target_col_size
|
|
175
|
+
|
|
176
|
+
if i < extra_columns && ! fixed_widths[i]
|
|
149
177
|
layout_object[:columns][:bootstrap_column_width][i] += 1
|
|
150
178
|
end
|
|
151
179
|
end
|
|
@@ -153,14 +181,46 @@ module HotGlue
|
|
|
153
181
|
if user_layout_columns.size < layout_object[:columns][:container].size
|
|
154
182
|
layout_object[:columns][:container].reject!{|x| x == []}
|
|
155
183
|
end
|
|
184
|
+
end
|
|
156
185
|
|
|
186
|
+
# go through the columns and build the split visibility (show / form)
|
|
187
|
+
|
|
188
|
+
columns.each do |col|
|
|
189
|
+
layout_object[:columns][:fields][col] = {show: true, form: true}
|
|
157
190
|
end
|
|
158
191
|
|
|
192
|
+
@include_setting.split(":").collect { |column_list|
|
|
193
|
+
column_list.split(",").collect do |field|
|
|
194
|
+
if field.include?("(")
|
|
195
|
+
field =~ /(.*)\((.*)\)/
|
|
196
|
+
field_short = $1
|
|
197
|
+
else
|
|
198
|
+
field_short = field
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
field_short = field_short.gsub("-", "").gsub("=", "")
|
|
202
|
+
|
|
203
|
+
layout_object[:columns][:fields][field_short.to_sym] = {
|
|
204
|
+
show: true,
|
|
205
|
+
form: true
|
|
206
|
+
}
|
|
159
207
|
|
|
160
|
-
|
|
208
|
+
if field.starts_with?("**")
|
|
209
|
+
nil
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
if field.include?("-")
|
|
213
|
+
layout_object[:columns][:fields][field_short.to_sym][:show] = false;
|
|
214
|
+
end
|
|
215
|
+
if field.include?("=")
|
|
216
|
+
layout_object[:columns][:fields][field_short.to_sym][:form] = false;
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
end
|
|
220
|
+
}
|
|
221
|
+
puts "*** SPECIFIED GROUPING SETTINGS: #{layout_object.inspect}"
|
|
161
222
|
layout_object
|
|
162
223
|
end
|
|
163
|
-
|
|
164
224
|
end
|
|
165
225
|
end
|
|
166
226
|
end
|
|
@@ -98,11 +98,15 @@ module HotGlue
|
|
|
98
98
|
size = layout_object[:columns][:bootstrap_column_width][i]
|
|
99
99
|
"<div class='#{layout_strategy.column_classes_for_column_headings(size)} hg-heading-row heading--#{singular}--#{column.join("-")}' " + col_style + ">" +
|
|
100
100
|
column.map(&:to_s).map{|col_name|
|
|
101
|
-
|
|
101
|
+
unless col_name.starts_with?("**")
|
|
102
|
+
the_output = "#{col_name.humanize}"
|
|
103
|
+
else
|
|
104
|
+
the_output = ""
|
|
105
|
+
end
|
|
102
106
|
if invisible_update.include?(col_name.to_sym)
|
|
103
107
|
if_statements = []
|
|
104
108
|
if_statements << "false" if invisible_update.include?(col_name.to_sym)
|
|
105
|
-
|
|
109
|
+
|
|
106
110
|
the_output = "<% if ( " + if_statements.join(" || ") + " || policy(#{@plural}).#{col_name}_able? ) %>" +
|
|
107
111
|
+ the_output + "<% end %>"
|
|
108
112
|
|
|
@@ -158,7 +162,7 @@ module HotGlue
|
|
|
158
162
|
dom_label = choice[:label].downcase.gsub(" ","_")
|
|
159
163
|
if data[:type] == "radio"
|
|
160
164
|
res << "\n<input type='radio'
|
|
161
|
-
id='#{search_field}_search__#{dom_label}
|
|
165
|
+
id='#{search_field}_search__#{dom_label}'
|
|
162
166
|
name='q[0][#{search_field}_search]' value='#{dom_label}'
|
|
163
167
|
<%= 'checked' if @q['0'][:#{search_field}_search] == \"#{dom_label}\" %> />"
|
|
164
168
|
elsif data[:type] == "checkboxes"
|
|
@@ -195,66 +199,75 @@ module HotGlue
|
|
|
195
199
|
size = layout_object[:columns][:bootstrap_column_width][columns.index(column)]
|
|
196
200
|
|
|
197
201
|
" <div class='#{layout_strategy.column_classes_for_form_fields(size)} cell--#{singular}--#{column.join("-")}' >" +
|
|
198
|
-
column.map { |
|
|
202
|
+
column.map { |full_col|
|
|
199
203
|
|
|
200
|
-
|
|
204
|
+
col = full_col.to_s.gsub("=", "").gsub("-", "").to_sym
|
|
201
205
|
|
|
202
|
-
|
|
203
|
-
|
|
206
|
+
if col.to_s.starts_with?("**") && layout_object[:columns][:fields][col][:form]
|
|
207
|
+
the_output = "<%= render partial: '#{col.to_s.gsub!("**","")}', locals: {#{singular}: #{singular} } %>"
|
|
208
|
+
elsif ! layout_object[:columns][:fields][col][:form]
|
|
209
|
+
# omit from show action
|
|
210
|
+
else
|
|
204
211
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
field_result =
|
|
209
|
-
if show_only.include?(col)
|
|
210
|
-
columns_map[col].form_show_only_output
|
|
211
|
-
elsif update_show_only.include?(col) && !@pundit
|
|
212
|
-
"<% if @action == 'edit' %>" + columns_map[col].form_show_only_output + "<% else %>" + columns_map[col].form_field_output + "<% end %>"
|
|
213
|
-
elsif update_show_only.include?(col) && @pundit && eval("defined? #{singular_class}Policy") && eval("#{singular_class}Policy").instance_methods.include?("#{col}_able?".to_sym)
|
|
214
|
-
"<% if @action == 'new' && policy(@#{singular}).#{col}_able? %>" + columns_map[col].form_field_output + "<% else %>" + columns_map[col].form_show_only_output + "<% end %>"
|
|
215
|
-
# show only on the update action overrides any pundit policy
|
|
216
|
-
elsif @pundit && eval("defined? #{singular_class}Policy") && eval("#{singular_class}Policy").instance_methods.include?("#{col}_able?".to_sym)
|
|
217
|
-
"<% if policy(@#{singular}).#{col}_able? %>" + columns_map[col].form_field_output + "<% else %>" + columns_map[col].form_show_only_output + "<% end %>"
|
|
218
|
-
elsif update_show_only.include?(col)
|
|
219
|
-
"<% if @action == 'edit' %>" + columns_map[col].form_show_only_output + "<% else %>" + columns_map[col].form_field_output + "<% end %>"
|
|
220
|
-
else
|
|
221
|
-
columns_map[col].form_field_output
|
|
222
|
-
end
|
|
212
|
+
field_error_name = columns_map[col].field_error_name
|
|
223
213
|
|
|
214
|
+
label_class = columns_map[col].label_class
|
|
215
|
+
label_for = columns_map[col].label_for
|
|
224
216
|
|
|
225
|
-
|
|
217
|
+
the_label = "\n<label class='#{label_class}' for='#{label_for}'>#{col.to_s.humanize}</label>"
|
|
226
218
|
|
|
227
|
-
if @stimmify
|
|
228
|
-
col_target = HotGlue.to_camel_case(col.to_s.gsub("_", " "))
|
|
229
|
-
data_attr = " data-#{@stimmify}-target='#{col_target}Wrapper'"
|
|
230
|
-
end
|
|
231
219
|
|
|
220
|
+
field_result =
|
|
221
|
+
if show_only.include?(col)
|
|
222
|
+
columns_map[col].form_show_only_output
|
|
223
|
+
elsif update_show_only.include?(col) && !@pundit
|
|
224
|
+
"<% if @action == 'edit' %>" + columns_map[col].form_show_only_output + "<% else %>" + columns_map[col].form_field_output + "<% end %>"
|
|
225
|
+
elsif update_show_only.include?(col) && @pundit && eval("defined? #{singular_class}Policy") && eval("#{singular_class}Policy").instance_methods.include?("#{col}_able?".to_sym)
|
|
226
|
+
"<% if @action == 'new' && policy(@#{singular}).#{col}_able? %>" + columns_map[col].form_field_output + "<% else %>" + columns_map[col].form_show_only_output + "<% end %>"
|
|
227
|
+
# show only on the update action overrides any pundit policy
|
|
228
|
+
elsif @pundit && eval("defined? #{singular_class}Policy") && eval("#{singular_class}Policy").instance_methods.include?("#{col}_able?".to_sym)
|
|
229
|
+
"<% if policy(@#{singular}).#{col}_able? %>" + columns_map[col].form_field_output + "<% else %>" + columns_map[col].form_show_only_output + "<% end %>"
|
|
230
|
+
elsif update_show_only.include?(col)
|
|
231
|
+
"<% if @action == 'edit' %>" + columns_map[col].form_show_only_output + "<% else %>" + columns_map[col].form_field_output + "<% end %>"
|
|
232
|
+
else
|
|
233
|
+
columns_map[col].form_field_output
|
|
234
|
+
end
|
|
232
235
|
|
|
233
|
-
the_output = add_spaces_each_line( "\n <div #{@tinymce_stimulus_controller}class='<%= \"alert alert-danger\" if #{singular}.errors.details.keys.include?(:#{field_error_name}) %>' #{data_attr} >\n" +
|
|
234
|
-
add_spaces_each_line( (form_labels_position == 'before' ? (the_label || "") + "<br />\n" : "") +
|
|
235
|
-
+ field_result +
|
|
236
|
-
(form_labels_position == 'after' ? ( columns_map[col].newline_after_field? ? "<br />\n" : "") + (the_label || "") : "") , 4) +
|
|
237
|
-
"\n </div>\n ", 2)
|
|
238
236
|
|
|
237
|
+
@tinymce_stimulus_controller = (columns_map[col].modify_as == {tinymce: 1} ? "data-controller='tiny-mce' " : "")
|
|
239
238
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
239
|
+
if @stimmify
|
|
240
|
+
col_target = HotGlue.to_camel_case(col.to_s.gsub("_", " "))
|
|
241
|
+
data_attr = " data-#{@stimmify}-target='#{col_target}Wrapper'"
|
|
242
|
+
end
|
|
244
243
|
|
|
245
|
-
the_output = "<% if " + if_statements.join(" || ") + " %>" +
|
|
246
|
-
columns_map[col].hidden_output + "<% else %>" + the_output + "<% end %>"
|
|
247
|
-
end
|
|
248
244
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
245
|
+
the_output = add_spaces_each_line( "\n <div #{@tinymce_stimulus_controller}class='<%= \"alert alert-danger\" if #{singular}.errors.details.keys.include?(:#{field_error_name}) %>' #{data_attr} >\n" +
|
|
246
|
+
add_spaces_each_line( (form_labels_position == 'before' ? (the_label || "") + "<br />\n" : "") +
|
|
247
|
+
+ field_result +
|
|
248
|
+
(form_labels_position == 'after' ? ( columns_map[col].newline_after_field? ? "<br />\n" : "") + (the_label || "") : "") , 4) +
|
|
249
|
+
"\n </div>\n ", 2)
|
|
253
250
|
|
|
254
|
-
the_output = "<% if !(" + if_statements.join(" || ") + ") || policy(@#{singular}).#{col}_able? %>" +
|
|
255
|
-
+ the_output + "<% end %>"
|
|
256
|
-
end
|
|
257
251
|
|
|
252
|
+
if hidden_create.include?(col.to_sym) || hidden_update.include?(col.to_sym)
|
|
253
|
+
if_statements = []
|
|
254
|
+
if_statements << "@action == 'edit'" if hidden_update.include?(col.to_sym)
|
|
255
|
+
if_statements << "@action == 'new'" if hidden_create.include?(col.to_sym)
|
|
256
|
+
|
|
257
|
+
the_output = "<% if " + if_statements.join(" || ") + " %>" +
|
|
258
|
+
columns_map[col].hidden_output + "<% else %>" + the_output + "<% end %>"
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
if invisible_create.include?(col) || invisible_update.include?(col)
|
|
262
|
+
if_statements = []
|
|
263
|
+
if_statements << "@action == 'edit'" if invisible_update.include?(col.to_sym)
|
|
264
|
+
if_statements << "@action == 'new'" if invisible_create.include?(col.to_sym)
|
|
265
|
+
|
|
266
|
+
the_output = "<% if !(" + if_statements.join(" || ") + ") || policy(@#{singular}).#{col}_able? %>" +
|
|
267
|
+
+ the_output + "<% end %>"
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
end # end of if col.to_s.starts_with?("**")
|
|
258
271
|
|
|
259
272
|
|
|
260
273
|
the_output
|
|
@@ -298,35 +311,45 @@ module HotGlue
|
|
|
298
311
|
style_with_flex_basis = layout_strategy.style_with_flex_basis(perc_width)
|
|
299
312
|
|
|
300
313
|
result = columns.map.with_index{ |column,i|
|
|
301
|
-
|
|
302
314
|
size = layout_object[:columns][:bootstrap_column_width][i]
|
|
303
|
-
|
|
304
315
|
"<div class='hg-col #{layout_strategy.column_classes_for_line_fields(size)} #{singular}--#{column.join("-")}'#{style_with_flex_basis}> " +
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
316
|
+
|
|
317
|
+
column.map { |full_col|
|
|
318
|
+
col = full_col.to_s.gsub("=", "").gsub("-","").to_sym
|
|
319
|
+
|
|
320
|
+
if layout_object[:columns][:fields][col].nil?
|
|
321
|
+
raise "column #{col} not found on the layout data"
|
|
308
322
|
end
|
|
323
|
+
if col.starts_with?("**") && layout_object[:columns][:fields][col][:show]
|
|
324
|
+
the_output = "<%= render partial: '#{col.to_s.gsub!("**","")}', locals: {#{singular}: #{singular} } %>"
|
|
325
|
+
elsif ! layout_object[:columns][:fields][col][:show]
|
|
326
|
+
the_output = ""
|
|
327
|
+
elsif eval("#{singular_class}.columns_hash['#{col}']").nil? && !attachments.keys.include?(col) && !related_sets.include?(col)
|
|
328
|
+
raise "Can't find column '#{col}' on #{singular_class}, are you sure that is the column name?"
|
|
329
|
+
# omit from show action
|
|
330
|
+
else
|
|
309
331
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
label = "<label class='small form-text text-muted'>#{col.to_s.humanize}</label>"
|
|
332
|
+
field_output = columns_map[col].line_field_output
|
|
313
333
|
|
|
314
|
-
|
|
315
|
-
if invisible_create.include?(col) || invisible_update.include?(col)
|
|
316
|
-
if_statements = []
|
|
317
|
-
if invisible_update.include?(col.to_sym) && invisible_create.include?(col.to_sym)
|
|
318
|
-
# elsif invisible_create.include?(col.to_sym)
|
|
319
|
-
# if_statements << "!(@action == 'new')"
|
|
320
|
-
else
|
|
321
|
-
if_statements << "@action == 'edit'"
|
|
322
|
-
end
|
|
334
|
+
label = "<label class='small form-text text-muted'>#{col.to_s.humanize}</label>"
|
|
323
335
|
|
|
324
|
-
|
|
325
|
-
the_output
|
|
326
|
-
|
|
336
|
+
the_output = "#{inline_list_labels == 'before' ? label + "<br/>" : ''}#{field_output}#{inline_list_labels == 'after' ? "<br/>" + label : ''}"
|
|
337
|
+
the_output += "\n"
|
|
338
|
+
if invisible_create.include?(col) || invisible_update.include?(col)
|
|
339
|
+
if_statements = []
|
|
340
|
+
if invisible_update.include?(col.to_sym) && invisible_create.include?(col.to_sym)
|
|
341
|
+
else
|
|
342
|
+
if_statements << "@action == 'edit'"
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
if_statements << " policy(#{singular}).#{col}_able?"
|
|
346
|
+
the_output = "<% if " + if_statements.join(" || ") + " %>" +
|
|
347
|
+
+ the_output + "<% end %>"
|
|
348
|
+
end
|
|
327
349
|
end
|
|
350
|
+
|
|
328
351
|
the_output
|
|
329
|
-
}.join( "<br
|
|
352
|
+
}.join( "<br />\n") + "</div>"
|
|
330
353
|
}.join("\n")
|
|
331
354
|
return result
|
|
332
355
|
|
|
@@ -117,6 +117,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
117
117
|
class_option :phantom_create_params, type: :string, default: nil
|
|
118
118
|
class_option :phantom_update_params, type: :string, default: nil
|
|
119
119
|
class_option :controller_prefix, type: :string, default: nil
|
|
120
|
+
class_option :code_in_controller, type: :string, default: nil
|
|
120
121
|
|
|
121
122
|
# SEARCH OPTIONS
|
|
122
123
|
class_option :search, default: nil # set or predicate
|
|
@@ -256,11 +257,26 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
256
257
|
@include_fields = []
|
|
257
258
|
|
|
258
259
|
# semicolon to denote layout columns; commas separate fields
|
|
259
|
-
|
|
260
|
+
#
|
|
261
|
+
@include_fields += options['include'].split(":").collect { |column_list|
|
|
262
|
+
column_list.split(",").collect do |field|
|
|
263
|
+
if field.include?("(")
|
|
264
|
+
field =~ /(.*)\((.*)\)/
|
|
265
|
+
field_short = $1
|
|
266
|
+
else
|
|
267
|
+
field_short = field
|
|
268
|
+
end
|
|
269
|
+
if field_short.starts_with?("**")
|
|
270
|
+
nil
|
|
271
|
+
else
|
|
272
|
+
field_short.gsub("-", "").gsub("=", "")
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
}.flatten.compact.collect(&:to_sym)
|
|
276
|
+
puts "INCLUDED FIELDS: #{@include_fields}"
|
|
260
277
|
end
|
|
261
278
|
|
|
262
279
|
|
|
263
|
-
|
|
264
280
|
@show_only = options['show_only'].split(",").collect(&:to_sym)
|
|
265
281
|
if @show_only.any?
|
|
266
282
|
puts "show only field #{@show_only}}"
|
|
@@ -424,6 +440,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
424
440
|
@phantom_create_params = options['phantom_create_params'] || ""
|
|
425
441
|
@phantom_update_params = options['phantom_update_params'] || ""
|
|
426
442
|
|
|
443
|
+
|
|
427
444
|
if get_default_from_config(key: :pundit_default)
|
|
428
445
|
raise "please note the config setting `pundit_default` has been renamed `pundit`. please update your hot_glue.yml file"
|
|
429
446
|
end
|
|
@@ -630,6 +647,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
630
647
|
@code_before_update = options['code_before_update']
|
|
631
648
|
@code_after_update = options['code_after_update']
|
|
632
649
|
@code_after_new = options['code_after_new']
|
|
650
|
+
@code_in_controller = options['code_in_controller'] || ""
|
|
633
651
|
|
|
634
652
|
buttons_width = ((!@no_edit && 1) || 0) + ((!@no_delete && 1) || 0) + (@magic_buttons.any? ? 1 : 0)
|
|
635
653
|
|
|
@@ -672,6 +690,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
672
690
|
# build a new polymorphic object
|
|
673
691
|
@associations = []
|
|
674
692
|
@columns_map = {}
|
|
693
|
+
|
|
675
694
|
@columns.each do |col|
|
|
676
695
|
# if !(@the_object.columns_hash.keys.include?(col.to_s) || @attachments.keys.include?(col))
|
|
677
696
|
# raise "couldn't find #{col} in either field list or attachments list"
|
|
@@ -1062,6 +1081,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
1062
1081
|
@columns = @the_object.columns.map(&:name).map(&:to_sym).reject { |field| !@include_fields.include?(field) }
|
|
1063
1082
|
end
|
|
1064
1083
|
|
|
1084
|
+
|
|
1065
1085
|
@columns = @columns - @nested_set.collect { |set| (set[:singular] + "_id").to_sym }
|
|
1066
1086
|
|
|
1067
1087
|
if @attachments.any?
|
|
@@ -1084,6 +1104,19 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
1084
1104
|
end
|
|
1085
1105
|
end
|
|
1086
1106
|
|
|
1107
|
+
# def omit_fields_show
|
|
1108
|
+
#
|
|
1109
|
+
# layout_object[:columns][:fields].each { |key, value|
|
|
1110
|
+
# value[:show] == false
|
|
1111
|
+
# }.reduce(:&)
|
|
1112
|
+
# end
|
|
1113
|
+
|
|
1114
|
+
def omit_fields_form
|
|
1115
|
+
layout_object[:columns][:fields].collect { |key, value| value[:form] == false ? key : nil }.compact.reject!{|x| x.starts_with?("**")} || []
|
|
1116
|
+
end
|
|
1117
|
+
|
|
1118
|
+
|
|
1119
|
+
|
|
1087
1120
|
def check_if_sample_file_is_present
|
|
1088
1121
|
if sample_file_path.nil?
|
|
1089
1122
|
puts "you have no sample file path set in config/hot_glue.yml"
|
|
@@ -1616,12 +1649,12 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
1616
1649
|
append_text = " <li class='nav-item'>
|
|
1617
1650
|
<%= link_to '#{@list_label_heading.humanize}', #{path_helper_plural(@nested_set.any? ? true: false)}, class: \"nav-link \#{'active' if nav == '#{plural_name}'}\" %>
|
|
1618
1651
|
</li>"
|
|
1619
|
-
alt_append_text = "
|
|
1620
|
-
|
|
1621
|
-
|
|
1652
|
+
alt_append_text = "<%= link_to '#{@list_label_heading.humanize.upcase}', #{path_helper_plural(@nested_set.any? ? true: false)}, class: \"nav-link \#{'active' if nav == '#{plural_name}'}\" %>"
|
|
1653
|
+
|
|
1654
|
+
check_for_existing_append = "<%= link_to '#{@list_label_heading.humanize}', #{path_helper_plural(@nested_set.any? ? true: false)}, class: \"nav-link \#{'active' if nav == '#{plural_name}'}\" %>"
|
|
1622
1655
|
|
|
1623
1656
|
text = File.read(nav_file)
|
|
1624
|
-
if text.include?(
|
|
1657
|
+
if text.include?(check_for_existing_append) || text.include?(alt_append_text)
|
|
1625
1658
|
puts "SKIPPING: Nav link for #{singular_name} already exists in #{nav_file}"
|
|
1626
1659
|
else
|
|
1627
1660
|
puts "APPENDING: nav link for #{singular_name} #{nav_file}"
|
|
@@ -1892,7 +1925,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
1892
1925
|
if phantom_data[:type] == "radio"
|
|
1893
1926
|
phantom_data[:choices].each do |choice|
|
|
1894
1927
|
unless choice[:scope] == ".all"
|
|
1895
|
-
res << "\n @#{plural} = @#{plural}#{choice[:scope]} if @q['0'][:#{phantom_key}_search] == \"#{choice[:label]}\""
|
|
1928
|
+
res << "\n @#{plural} = @#{plural}#{choice[:scope]} if @q['0'][:#{phantom_key}_search] == \"#{choice[:label].downcase.gsub(" ","_")}\""
|
|
1896
1929
|
end
|
|
1897
1930
|
end
|
|
1898
1931
|
elsif phantom_data[:type] == "checkboxes"
|
|
@@ -1903,7 +1936,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
1903
1936
|
res << "\n @#{plural} = @#{plural}#{choice[:scope]} if @q['0'][:#{phantom_key}_search__#{choice[:label].gsub(" ", "_").downcase}] == \"1\""
|
|
1904
1937
|
end
|
|
1905
1938
|
unless choice[:scope_negative] == ".all"
|
|
1906
|
-
res << "\n @#{plural} = @#{plural}#{choice[:scope_negative]} if @q['0'][:#{phantom_key}
|
|
1939
|
+
res << "\n @#{plural} = @#{plural}#{choice[:scope_negative]} if @q['0'][:#{phantom_key}_search__#{choice[:label].gsub(" ", "_").downcase}] != \"1\""
|
|
1907
1940
|
end
|
|
1908
1941
|
end
|
|
1909
1942
|
end
|
|
@@ -8,6 +8,7 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
|
8
8
|
|
|
9
9
|
helper :hot_glue
|
|
10
10
|
include HotGlue::ControllerHelper
|
|
11
|
+
<%= @code_in_controller.gsub(";", "\n") %>
|
|
11
12
|
|
|
12
13
|
<% unless @god %>before_action :<%= "authenticate_" + @auth_identifier.split(".")[0] + "!" %><% end %><% if any_nested? %>
|
|
13
14
|
<% nest_chain = [] %> <% @nested_set.each { |arg|
|
|
@@ -288,13 +289,13 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
|
288
289
|
end<% end %><% end %>
|
|
289
290
|
|
|
290
291
|
def <%=singular_name%>_params
|
|
291
|
-
fields = <%= ((fields_filtered_for_strong_params - @show_only) + @magic_buttons.collect{|x| "__#{x}"} + @phantom_create_params.split(",")).collect{|sym| ":#{sym}"}.join(", ") %><%= ", " + @related_sets.collect{|key, rs| "{#{rs[:association_ids_method]}: []}"}.join(", ") if @related_sets.any? %><%= ", " + @alt_lookups.collect{|k,v| ":__lookup_#{v[:assoc].downcase}_#{v[:lookup_as]}" }.join(", ") if @alt_lookups.any? %>
|
|
292
|
+
fields = <%= ((fields_filtered_for_strong_params - @show_only - omit_fields_form) + @magic_buttons.collect{|x| "__#{x}"} + @phantom_create_params.split(",")).collect{|sym| ":#{sym}"}.join(", ") %><%= ", " + @related_sets.collect{|key, rs| "{#{rs[:association_ids_method]}: []}"}.join(", ") if @related_sets.any? %><%= ", " + @alt_lookups.collect{|k,v| ":__lookup_#{v[:assoc].downcase}_#{v[:lookup_as]}" }.join(", ") if @alt_lookups.any? %>
|
|
292
293
|
params.require(:<%= testing_name %>).permit(fields)
|
|
293
294
|
end<% if @update_show_only %>
|
|
294
295
|
|
|
295
296
|
<% unless @no_edit %>
|
|
296
297
|
def update_<%=singular_name%>_params
|
|
297
|
-
fields = <%= ((fields_filtered_for_strong_params - @update_show_only) + @magic_buttons.collect{|x| "__#{x}"} + @phantom_update_params.split(",")).collect{|sym| ":#{sym}"}.join(", ") %><%= ", " + @related_sets.collect{|key, rs| "{#{rs[:association_ids_method]}: []}"}.join(", ") if @related_sets.any? %><%= ", " + @alt_lookups.collect{|k,v| ":__lookup_#{v[:assoc].downcase}_#{v[:lookup_as]}" }.join(", ") if @alt_lookups.any? %>
|
|
298
|
+
fields = <%= ((fields_filtered_for_strong_params - @update_show_only - omit_fields_form) + @magic_buttons.collect{|x| "__#{x}"} + @phantom_update_params.split(",")).collect{|sym| ":#{sym}"}.join(", ") %><%= ", " + @related_sets.collect{|key, rs| "{#{rs[:association_ids_method]}: []}"}.join(", ") if @related_sets.any? %><%= ", " + @alt_lookups.collect{|k,v| ":__lookup_#{v[:assoc].downcase}_#{v[:lookup_as]}" }.join(", ") if @alt_lookups.any? %>
|
|
298
299
|
<%= (fields_filtered_for_strong_params - @update_show_only).collect{|col|
|
|
299
300
|
# TODO : fields not on show only also not invisible should be checked here
|
|
300
301
|
# for _able? methods and added only when able
|
|
@@ -7,7 +7,11 @@
|
|
|
7
7
|
<\%= form_with model: <%= singular %>,
|
|
8
8
|
<% if @stimmify %> data: {controller: '<%= @stimmify %>' },
|
|
9
9
|
<% end %>url: <%= form_path_edit_helper %><%= ", html: {'data-turbo': false}" if @big_edit %> do |f| %>
|
|
10
|
-
<\%= render partial: "<%= namespace_with_trailing_dash + @controller_build_folder + "/" %>form", locals: {
|
|
10
|
+
<\%= render partial: "<%= namespace_with_trailing_dash + @controller_build_folder + "/" %>form", locals: {
|
|
11
|
+
<%= singular %>: <%= singular %>,
|
|
12
|
+
f: f,
|
|
13
|
+
<%= @nested_set.collect{|arg| "#{arg[:singular]}: #{arg[:singular]}" }.join(",\n ") %>
|
|
14
|
+
} \%>
|
|
11
15
|
<% if @edit_within_form_partial %><\%= render partial: "edit_within_form", locals: {f: f, <%= singular %>: <%= singular %>}<%= @nested_set.collect{|arg| ".merge(#{arg[:singular]} ? {#{arg[:singular]}: #{arg[:singular]}} : {})" }.join %> %><% end %>
|
|
12
16
|
<\% end %>
|
|
13
17
|
<% if @edit_after_form_partial %><\%= render partial: "edit_after_form", locals: {<%= singular %>: <%= singular %>}<%= @nested_set.collect{|arg| ".merge(#{arg[:singular]} ? {#{arg[:singular]}: #{arg[:singular]}} : {})" }.join %> %><% end %>
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
<% if @turbo_streams %><\%= turbo_stream_from <%= singular %> %>
|
|
2
2
|
<% end %><\%= turbo_frame_tag "<%= @namespace %>__#{ dom_id(<%= singular %>) }" do %>
|
|
3
3
|
<div class='<%= @layout_strategy.row_classes %>' data-id='<\%= <%= singular %>.id %>' data-edit='false'>
|
|
4
|
-
|
|
4
|
+
<\%= render partial: '<%= show_path_partial %>', locals: {
|
|
5
|
+
<%= singular %>: <%= singular %><% if @nested_set.any? %>,
|
|
6
|
+
<%= @nested_set.collect{|nest_arg| "#{nest_arg[:singular]}: #{ nest_arg[:singular] }"}.join(",\n ") %>,
|
|
7
|
+
nested_for: "<%= @nested_set.collect{|nest_arg| nest_arg[:singular] + "-\#{#{nest_arg[:singular]}.id}"}.join("__") %>"<% end %> } %>
|
|
5
8
|
</div>
|
|
6
9
|
<\% end %>
|
|
7
10
|
|
|
@@ -8,7 +8,14 @@
|
|
|
8
8
|
<% end %>
|
|
9
9
|
|
|
10
10
|
<% if @new_button_position == 'above' %>
|
|
11
|
-
<% unless @no_create
|
|
11
|
+
<% unless @no_create %>
|
|
12
|
+
<%= '<%= render partial: "' + ((@namespace+"/" if @namespace) || "") +
|
|
13
|
+
@controller_build_folder +
|
|
14
|
+
"/new_button\", locals: {
|
|
15
|
+
#{@nested_set.collect{|arg| arg[:singular] + ": " + arg[:singular]}.join(",\n ")} }" +
|
|
16
|
+
' %\>'.gsub('\\',"") %>
|
|
17
|
+
<br />
|
|
18
|
+
<% end %>
|
|
12
19
|
<% end %>
|
|
13
20
|
|
|
14
21
|
<% unless @no_list %>
|
|
@@ -58,10 +65,8 @@
|
|
|
58
65
|
</div>
|
|
59
66
|
<\% end %>
|
|
60
67
|
<\% <%= plural %>.each do |<%= singular %>| %>
|
|
61
|
-
<\%= render partial: '<%= line_path_partial %>', locals: {<%= singular %>: <%= singular
|
|
62
|
-
|
|
63
|
-
<%= @nested_set.collect{|arg| " .merge(defined?(#{arg[:singular]}) ? {#{arg[:singular]}: #{arg[:singular]}} : {})"}.join("\n") %>
|
|
64
|
-
%>
|
|
68
|
+
<\%= render partial: '<%= line_path_partial %>', locals: {<%= singular %>: <%= singular %>,
|
|
69
|
+
<% if @nested_set.any? %>nested_for: nested_for, <%= @nested_set.collect{|arg| "#{arg[:singular]}: #{arg[:singular]}" }.join(", ") %><% end %> } \%>
|
|
65
70
|
<\% end %>
|
|
66
71
|
<% if @paginate_per_page_selector %>
|
|
67
72
|
<\%= form_with url: '<%= path_helper_plural(top_level: false) %>', method: :get do |f| %>
|
|
@@ -5,8 +5,11 @@
|
|
|
5
5
|
<\%= form_with model: <%= singular %>,
|
|
6
6
|
<% if @stimmify %>data: {controller: '<%= @stimmify %>' },
|
|
7
7
|
<% end %>url: <%= form_path_new_helper %>, method: :post<%= @display_edit_after_create ? ", html: {'data-turbo': false}" : "" %> do |f| \%>
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
<\%= render partial: "<%= namespace_with_slash + @controller_build_folder %>/form", locals: {
|
|
9
|
+
<%= singular %>: <%= singular %>,
|
|
10
|
+
f: f,
|
|
11
|
+
<%= @nested_set.collect{|arg| "#{arg[:singular]}: #{arg[:singular]}" }.join(",\n ") %>
|
|
12
|
+
} \%>
|
|
10
13
|
|
|
11
14
|
<% if @new_within_form_partial %><\%= render partial: "new_within_form", locals: {f: f, <%= singular %>: <%= singular %>}<%= @nested_set.collect{|arg| ".merge(#{arg[:singular]} ? {#{arg[:singular]}: #{arg[:singular]}} : {})" }.join %> %><% end %>
|
|
12
15
|
<\% end %>
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
<\% if @<%= singular %>.errors.none? %>
|
|
2
2
|
<\%= turbo_stream.replace "<%= @namespace %>__<%= plural %>-list" + <%= nested_for_turbo_nested_constructor %> do %>
|
|
3
|
-
<\%= render partial: "list", locals: {<%= plural %>: @<%= plural
|
|
3
|
+
<\%= render partial: "list", locals: {<%= plural %>: @<%= plural %>,
|
|
4
|
+
<% if @nested_set.any? %> <%= @nested_set.collect{|arg| "#{arg[:singular]}: @#{arg[:singular]}"}.join(", ") %>,
|
|
5
|
+
nested_for: "<%= @nested_set.collect{|arg| "#{arg[:singular]}-\#{@#{arg[:singular]}.id}"}.join("__") %>" <% end %>
|
|
6
|
+
} %>
|
|
4
7
|
|
|
5
8
|
<\% end %>
|
|
6
9
|
<\% end %>
|
|
@@ -9,9 +12,12 @@
|
|
|
9
12
|
<!-- errors -->
|
|
10
13
|
<\%= turbo_stream.replace "<%= @namespace %>__<%= singular %>-new" do %>
|
|
11
14
|
<\% if @<%= singular %>.errors.none? %>
|
|
12
|
-
<\%= render partial: "new_button", locals: {
|
|
15
|
+
<\%= render partial: "new_button", locals: {
|
|
16
|
+
<%= @nested_set.collect{|arg| "#{arg[:singular]}: @#{arg[:singular] }"}.join(", \n") %>
|
|
17
|
+
|
|
18
|
+
} %>
|
|
13
19
|
<\% else %>
|
|
14
|
-
<\%= render partial: "new_form", locals: {<%= singular %>: @<%= singular
|
|
20
|
+
<\%= render partial: "new_form", locals: {<%= singular %>: @<%= singular %>, <%= @nested_set.collect{|arg| arg[:singular] + ": @" + arg[:singular]}.join(",\n ") %> } %>
|
|
15
21
|
<\% end %>
|
|
16
22
|
<\% end %>
|
|
17
23
|
<\%= turbo_stream.replace "flash_notices" do %>
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
<%= turbo_parental_updates %>
|
|
2
2
|
|
|
3
3
|
<\%= turbo_stream.update "<%= @namespace %>__<%= plural %>-list" + <%= nested_for_turbo_nested_constructor %> do %>
|
|
4
|
-
<\%= render partial: "list", locals: {<%=plural%>: @<%=plural%>
|
|
4
|
+
<\%= render partial: "list", locals: {<%=plural%>: @<%=plural %> ,
|
|
5
|
+
<% if @nested_set.any? %>nested_for: "<%= @nested_set.collect{|arg| arg[:singular] + "-\#{@#{arg[:singular]}.id}" }.join("__") %>",
|
|
6
|
+
<%= @nested_set.collect{|arg| arg[:singular] + ": @" + arg[:singular] }.join(", ") %><% end %>
|
|
7
|
+
} \%>
|
|
5
8
|
<\% end %>
|
|
6
9
|
|
|
7
10
|
<\%= turbo_stream.update "flash_notices" do %>
|
|
8
11
|
<\%= render partial: "layouts/flash_notices", locals: {resource: @<%= singular %>} %>
|
|
9
|
-
<\% end %>
|
|
12
|
+
<\% end %>
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
<% if @big_edit %>
|
|
2
|
-
|
|
2
|
+
<% if include_nav_template %><%= @layout_strategy.page_begin %><\%= render partial: "<%= nav_template %>", locals: {nav: "<%= @plural %>"} %><%= @layout_strategy.page_end %><% end %>
|
|
3
|
+
|
|
4
|
+
<div class="container">
|
|
3
5
|
<div class="row">
|
|
4
6
|
<div class="col-md-12">
|
|
5
7
|
<\%= link_to "<% if @button_icons == 'font-awesome' %><i class='fa fa-arrow-circle-left 2x'></i><% end %> Back to list".html_safe, <%= path_helper_plural(true) %> %>
|
|
@@ -10,8 +12,6 @@
|
|
|
10
12
|
</div>
|
|
11
13
|
</div>
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
15
|
<% if @downnest_children.any? && @big_edit %>
|
|
16
16
|
<div class="container" data-controller="bootstrap-tabbed-nav">
|
|
17
17
|
<ul class="nav nav-tabs" id="<%= singular + "_downnest_portals" %>" role="tablist">
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<\%= render partial: "new_form", locals: {<%= singular %>: @<%=singular
|
|
1
|
+
<\%= render partial: "new_form", locals: {<%= singular %>: @<%=singular%>, <%= @nested_set.collect{|arg| "#{arg[:singular]}: @#{arg[:singular]}" }.join(", ") %>} %>
|
|
@@ -1,16 +1,67 @@
|
|
|
1
1
|
import { Controller } from "@hotwired/stimulus"
|
|
2
2
|
|
|
3
|
-
// Connects to data-controller="search_form"
|
|
4
3
|
export default class extends Controller {
|
|
5
|
-
static targets = ["clearButton"]
|
|
4
|
+
static targets = ["clearButton", "textSearch", "textMatch"]
|
|
6
5
|
|
|
7
6
|
connect() {
|
|
8
|
-
|
|
9
7
|
if (this.hasClearButtonTarget) {
|
|
10
8
|
this.clearButtonTarget.addEventListener("click", (event) => {
|
|
11
9
|
event.preventDefault()
|
|
12
10
|
this.element.reset()
|
|
13
11
|
})
|
|
14
12
|
}
|
|
13
|
+
|
|
14
|
+
// watch match selects
|
|
15
|
+
this.textMatchTargets.forEach(target => {
|
|
16
|
+
target.addEventListener("change", this.handleMatchChange)
|
|
17
|
+
})
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
textSearchTargetConnected(target) {
|
|
21
|
+
target.addEventListener("input", this.handleSearchInput)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
disconnect() {
|
|
25
|
+
this.textSearchTargets.forEach(target => {
|
|
26
|
+
target.removeEventListener("input", this.handleSearchInput)
|
|
27
|
+
})
|
|
28
|
+
this.textMatchTargets.forEach(target => {
|
|
29
|
+
target.removeEventListener("change", this.handleMatchChange)
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
handleSearchInput = (event) => {
|
|
34
|
+
const searchEl = event.target
|
|
35
|
+
const matchEl = this.findMatchFor(searchEl)
|
|
36
|
+
if (!matchEl) return
|
|
37
|
+
|
|
38
|
+
const val = searchEl.value.trim()
|
|
39
|
+
const resettable = ["contains", "starts_with", "ends_with"]
|
|
40
|
+
|
|
41
|
+
if (val.length > 0 && matchEl.value === "") {
|
|
42
|
+
matchEl.value = "contains"
|
|
43
|
+
} else if (val === "" && resettable.includes(matchEl.value)) {
|
|
44
|
+
matchEl.value = ""
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
handleMatchChange = (event) => {
|
|
49
|
+
const matchEl = event.target
|
|
50
|
+
if (matchEl.value !== "") return
|
|
51
|
+
|
|
52
|
+
const searchEl = this.findSearchFor(matchEl)
|
|
53
|
+
if (!searchEl) return
|
|
54
|
+
|
|
55
|
+
searchEl.value = ""
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
findMatchFor(searchEl) {
|
|
59
|
+
const matchName = searchEl.name.replace("search", "match")
|
|
60
|
+
return this.textMatchTargets.find(t => t.name === matchName)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
findSearchFor(matchEl) {
|
|
64
|
+
const searchName = matchEl.name.replace("match", "search")
|
|
65
|
+
return this.textSearchTargets.find(t => t.name === searchName)
|
|
15
66
|
}
|
|
16
67
|
}
|
data/lib/hotglue/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hot-glue
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jason Fleetwood-Boldt
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-
|
|
11
|
+
date: 2025-11-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|