hot-glue 0.6.15 → 0.6.17
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 +2 -2
- data/README.md +221 -0
- data/lib/generators/hot_glue/field_factory.rb +23 -22
- data/lib/generators/hot_glue/fields/association_field.rb +14 -14
- data/lib/generators/hot_glue/fields/attachment_field.rb +1 -20
- data/lib/generators/hot_glue/fields/boolean_field.rb +13 -13
- data/lib/generators/hot_glue/fields/date_field.rb +4 -2
- data/lib/generators/hot_glue/fields/enum_field.rb +7 -1
- data/lib/generators/hot_glue/fields/field.rb +48 -47
- data/lib/generators/hot_glue/fields/related_set_field.rb +4 -9
- data/lib/generators/hot_glue/layout/builder.rb +19 -7
- data/lib/generators/hot_glue/layout_strategy/bootstrap.rb +6 -6
- data/lib/generators/hot_glue/layout_strategy/hot_glue.rb +3 -3
- data/lib/generators/hot_glue/layout_strategy/tailwind.rb +3 -3
- data/lib/generators/hot_glue/markup_templates/erb.rb +40 -21
- data/lib/generators/hot_glue/scaffold_generator.rb +33 -18
- data/lib/generators/hot_glue/templates/controller.rb.erb +36 -18
- data/lib/generators/hot_glue/templates/erb/_edit.erb +3 -1
- data/lib/generators/hot_glue/templates/erb/_form.erb +2 -1
- data/lib/generators/hot_glue/templates/erb/_new_form.erb +3 -1
- data/lib/generators/hot_glue/templates/erb/edit.erb +23 -13
- data/lib/hot-glue.rb +12 -0
- 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: a6abeaf2b7456e5f554928c58bb5deae7fb01a0c664ad0d717572f20c6185537
|
4
|
+
data.tar.gz: da58696031065cf910116374477ce9f8f3b388bef0a2ad756289953b70a31d8b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 626a8d361bef7d74109406ba5beae46b0daf4db297c2f95fcd92431bc1b6f9ea97d224acb8ef898bb0281b8cb3bc369d5507f6956751da137c4e5ecb4e3a93d5
|
7
|
+
data.tar.gz: 3a646740022a5c699051ad99c400178f1abdafc911a9c1e40c400b52a16458f3181e98ed73e0e6db8fc64fdaa8829b93f8432efcf4026873dbb2236708c2308e
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
hot-glue (0.6.
|
4
|
+
hot-glue (0.6.17)
|
5
5
|
ffaker (~> 2.16)
|
6
6
|
kaminari (~> 1.2)
|
7
7
|
rails (> 5.1)
|
@@ -140,7 +140,7 @@ GEM
|
|
140
140
|
mini_mime (1.1.2)
|
141
141
|
mini_portile2 (2.8.4)
|
142
142
|
minitest (5.16.3)
|
143
|
-
net-imap (0.5.
|
143
|
+
net-imap (0.5.8)
|
144
144
|
date
|
145
145
|
net-protocol
|
146
146
|
net-pop (0.1.2)
|
data/README.md
CHANGED
@@ -790,6 +790,23 @@ end
|
|
790
790
|
Because Hot Glue detects the `*_able?` methods at build time, if you add them to your policy, you will have to rebuild your scaffold.
|
791
791
|
|
792
792
|
|
793
|
+
### `--pundit-policy-override`
|
794
|
+
if you use the flag `--pundit-policy-override` your controller operations will bypass the invisible (pundit provided) access control and use the pundit policy you specify.
|
795
|
+
|
796
|
+
example
|
797
|
+
|
798
|
+
`rails generate hot_glue:scaffold Invoice --gd --pundit-policy-override='UniqueInvoicePolicy'`
|
799
|
+
|
800
|
+
You will implement a Pundit policy for `UniqueInvoicePolicy` and it should implement actions with question mark `?` endings corresponding to the same actions you are building, `new?`, `create?`, `edit?`, `update?`, and `destroy?`
|
801
|
+
|
802
|
+
If provided, the output code looks something like (in this example, showing the `edit?` method)
|
803
|
+
|
804
|
+
```
|
805
|
+
skip_authorization
|
806
|
+
raise Pundit::NotAuthorizedError if ! UniqueInvoicePolicy.edit?
|
807
|
+
```
|
808
|
+
|
809
|
+
|
793
810
|
### `--show-only=`
|
794
811
|
(separate field names by COMMA)
|
795
812
|
|
@@ -851,6 +868,92 @@ Remember, if there's a corresponding `*_able?` method on the policy, it will be
|
|
851
868
|
As shown in the method `name_able?` of the example ThingPolicy above, if this field on your policy returns true, the field will be editable. If it returns false, the field will be viewable (read-only).
|
852
869
|
|
853
870
|
|
871
|
+
### `--hidden`
|
872
|
+
|
873
|
+
Separate list of fields.
|
874
|
+
|
875
|
+
These fields will be hidden from the form but will exist as hidden_field, and so the update will still work.
|
876
|
+
|
877
|
+
|
878
|
+
EXAMPLE:
|
879
|
+
|
880
|
+
```
|
881
|
+
bin/rails generate hot_glue:scaffold Wrapper --namespace='account_dashboard' --no-nav-menu --big-edit --smart-layout --stimmify --hidden=raw_source
|
882
|
+
```
|
883
|
+
|
884
|
+
In the `wrappers` folder, I am using a special sticky partial `_edit_within_form.html.erb`, which contains code preserved from build-to-build and included in the form:
|
885
|
+
|
886
|
+
|
887
|
+
```
|
888
|
+
<div class="row" style="position: relative; width: 100%; overflow: auto;">
|
889
|
+
<div class="col-md-12">
|
890
|
+
<div id="wrapper__raw_source"
|
891
|
+
style="position: static">
|
892
|
+
|
893
|
+
<div id="wrapper__raw_source-toolbar">
|
894
|
+
|
895
|
+
</div>
|
896
|
+
|
897
|
+
|
898
|
+
<div cols="60"
|
899
|
+
data-wrapper-form-target="editor"
|
900
|
+
id="wrapper__raw_source-editor" >
|
901
|
+
</div>
|
902
|
+
</div>
|
903
|
+
|
904
|
+
|
905
|
+
</div>
|
906
|
+
</div>
|
907
|
+
<div class="col-md-2">
|
908
|
+
</div>
|
909
|
+
```
|
910
|
+
|
911
|
+
|
912
|
+
Then, create a `app/javascript/controllers/wrapper_form_controller.js` file with the following code:
|
913
|
+
|
914
|
+
```javascript
|
915
|
+
|
916
|
+
|
917
|
+
import { Controller } from "@hotwired/stimulus"
|
918
|
+
|
919
|
+
import {basicSetup} from "codemirror"
|
920
|
+
import {EditorView} from "@codemirror/view"
|
921
|
+
|
922
|
+
// Connects to data-controller="wrapper-form"
|
923
|
+
export default class extends Controller {
|
924
|
+
static targets = ['rawSource', 'name', 'nameWrapper', 'editor'];
|
925
|
+
|
926
|
+
connect() {
|
927
|
+
console.log("WrapperFormController connected")
|
928
|
+
this.account_id = this.element.dataset['accountId']
|
929
|
+
this.crusade_id = this.element.dataset['crusadeId']
|
930
|
+
this.wrapper_id = this.element.dataset['wrapperId']
|
931
|
+
|
932
|
+
const view = new EditorView({
|
933
|
+
doc: this.rawSourceTarget.value,
|
934
|
+
parent: this.editorTarget,
|
935
|
+
extensions: [basicSetup]
|
936
|
+
})
|
937
|
+
|
938
|
+
this.view = view;
|
939
|
+
this.element.addEventListener('submit', this.formSubmit.bind(this))
|
940
|
+
// this.previewButtonTarget.addEventListener('click', this.previewClick.bind(this))
|
941
|
+
}
|
942
|
+
|
943
|
+
formSubmit(event) {
|
944
|
+
this.rawSourceTarget.value = this.view.state.doc.toString();
|
945
|
+
}
|
946
|
+
}
|
947
|
+
```
|
948
|
+
|
949
|
+
Notice we are also using `--stimmify` to decorate the form with a Stimulus controller.
|
950
|
+
|
951
|
+
The code above uses Code Mirror to act as a code editor, which requires pulling the value off the hidden form element (putting it into the code mirror interface) and pushing it back into the hidden form element when the Submit button is clicked.
|
952
|
+
|
953
|
+
|
954
|
+
|
955
|
+
|
956
|
+
|
854
957
|
### `--ujs_syntax=true` (Default is set automatically based on whether you have turbo-rails installed)
|
855
958
|
|
856
959
|
If you are pre-Turbo (UJS), your delete buttons will come out like this:
|
@@ -1364,6 +1467,54 @@ Then run:
|
|
1364
1467
|
This will 1) copy the dropzone_controller.js file into your app and 2) add the dropzone css into your app's application.css or application.bootstrap.css file.
|
1365
1468
|
|
1366
1469
|
|
1470
|
+
### Attach Stimulus JS Controllers to Your Forms with `--stimmify` or `--stimmify=xyz`
|
1471
|
+
|
1472
|
+
Automatically build the new and edit form with `data-controller='xyz'` to attach cooresponding stimulus controllers.
|
1473
|
+
|
1474
|
+
If you use the shorthand (specify no `=`) your stimulus controller's name will be inferred from the Singular form of the scaffolding beild built, with dashes for underscores, and ending with `-form`
|
1475
|
+
|
1476
|
+
`@singular.gsub("_", "-") + "-form"`
|
1477
|
+
|
1478
|
+
(For example, `rails g hot_glue:scaffold Thing --stimmy` generates a form that looks like
|
1479
|
+
|
1480
|
+
```
|
1481
|
+
<%= form_with model: thing,
|
1482
|
+
url: things_path(account,crusade,email_template),
|
1483
|
+
html: {
|
1484
|
+
'data-controller': "thing-form"
|
1485
|
+
}
|
1486
|
+
%>
|
1487
|
+
...
|
1488
|
+
|
1489
|
+
```
|
1490
|
+
|
1491
|
+
Note that your fields also appended with `data-thing-target=abc` and also `data-thing-target=abcWrapper`
|
1492
|
+
(assuming `thing` is the scaffold being built and abc is the field name)
|
1493
|
+
|
1494
|
+
|
1495
|
+
Here, we are building a `thing` scaffold. The field `name` is decorated twice: once for the wrapper span and again for the specific form element itself.
|
1496
|
+
```
|
1497
|
+
<span class="" data-thing-form-target="nameWrapper">
|
1498
|
+
<input value="asdfadf" autocomplete="off" size="40" class="form-control" type="" data-thing-form-target="name" name="thing[name]" id="thing_name">
|
1499
|
+
|
1500
|
+
|
1501
|
+
<label class="text-muted small form-text" for="">Name</label>
|
1502
|
+
</span>
|
1503
|
+
```
|
1504
|
+
|
1505
|
+
Your stimulus controller will need two targets for each field:
|
1506
|
+
|
1507
|
+
```
|
1508
|
+
static targets = ['name', 'nameWrapper'];
|
1509
|
+
```
|
1510
|
+
You can interact with the wrapper for things like clicks or hovers, or to hide/show the entire box surrounding the form element.
|
1511
|
+
|
1512
|
+
Use the form field element itself to affect things like enabled or the value of the field.
|
1513
|
+
|
1514
|
+
|
1515
|
+
For a crash course on Stimulus, see
|
1516
|
+
https://jasonfleetwoodboldt.com/courses/rails-7-crash-course/rails-7-stimulus-js-basics-with-importmap-rails/
|
1517
|
+
|
1367
1518
|
|
1368
1519
|
|
1369
1520
|
### `--factory-creation={ ... }`
|
@@ -1751,6 +1902,76 @@ These automatic pickups for partials are detected at build time. This means that
|
|
1751
1902
|
|
1752
1903
|
# VERSION HISTORY
|
1753
1904
|
|
1905
|
+
#### 2025-05-0097 - v0.6.17
|
1906
|
+
|
1907
|
+
|
1908
|
+
• Adds Stimulus JS & `--stimmify` or `--stimmify=xyz`
|
1909
|
+
|
1910
|
+
Automatically build the new and edit form with `data-controller='xyz'` to attach stimulus
|
1911
|
+
|
1912
|
+
If you use the shorthand (specify no `=`) your stimulus controller's name will be inferred from the Singular form of the scaffolding beild built, with dashes for underscores, and ending with `-form`
|
1913
|
+
|
1914
|
+
(For example, `rails g hot_glue:scaffold Thing --stimmy` generates a form that looks like
|
1915
|
+
|
1916
|
+
```
|
1917
|
+
<%= form_with model: thing,
|
1918
|
+
url: things_path(account,crusade,email_template),
|
1919
|
+
html: {
|
1920
|
+
'data-controller': "thing-form"
|
1921
|
+
}
|
1922
|
+
%>
|
1923
|
+
...
|
1924
|
+
|
1925
|
+
```
|
1926
|
+
|
1927
|
+
Note that your fields also appended with `data-thing-target=abc` and also `data-thing-target=abcWrapper`
|
1928
|
+
|
1929
|
+
See section "Attach Stimulus JS Controllers to Your Forms with `--stimmify` or `--stimmify=xyz`"
|
1930
|
+
|
1931
|
+
For a crash course on Stimulus, see
|
1932
|
+
https://jasonfleetwoodboldt.com/courses/rails-7-crash-course/rails-7-stimulus-js-basics-with-importmap-rails/
|
1933
|
+
|
1934
|
+
|
1935
|
+
• Adds `--hidden` option
|
1936
|
+
Pass a list of fields, like include or show-only. This will make the field hidden on the form *but still updated via its submission*
|
1937
|
+
|
1938
|
+
|
1939
|
+
|
1940
|
+
|
1941
|
+
|
1942
|
+
#### 2025-03-31 v0.6.16
|
1943
|
+
|
1944
|
+
• Bootstrap Tab Panes For Downnested Portals
|
1945
|
+
Downnested portals are now built with bootstrap tab panes (always) and are no longer stacked on top of one another.
|
1946
|
+
|
1947
|
+
It looks like this:
|
1948
|
+
https://getbootstrap.com/docs/5.0/components/navs-tabs/#javascript-behavior
|
1949
|
+
|
1950
|
+
• inline_list_labels can be set in hot_glue.yml
|
1951
|
+
• typeaheads nested inside of routes are fixed
|
1952
|
+
• switches back to current_timezone implementation, displaying times relative to the user's set timezone
|
1953
|
+
• load all code now sets query parameters
|
1954
|
+
|
1955
|
+
• Pundit Policy Override
|
1956
|
+
if you use the flag `--pundit-policy-override` your controller operations will bypass the invisible (pundit provided) access control and use the pundit policy you specify.
|
1957
|
+
|
1958
|
+
example
|
1959
|
+
|
1960
|
+
`rails generate hot_glue:scaffold Invoice --gd --pundit-policy-override='UniqueInvoicePolicy'`
|
1961
|
+
|
1962
|
+
Implement `UniqueInvoicePolicy` using actions with question mark `?` endings corresponding to the same actions you are building, `new?`, `create?`, `edit?`, `update?`, and `destroy?`
|
1963
|
+
|
1964
|
+
|
1965
|
+
• Bootstrap column builder has been changed.
|
1966
|
+
The bootstrap column bulder previously defaulted all real columns to col-sm-2 (or whichever bootstrap column with you set)
|
1967
|
+
|
1968
|
+
The builder has been refactored to allow for a per-column width generated automatically by the builder. If there are unused bootstrap columns, the builder will add width to the first columns in your layout, making them wider.
|
1969
|
+
|
1970
|
+
|
1971
|
+
|
1972
|
+
|
1973
|
+
|
1974
|
+
|
1754
1975
|
#### 2025-03-17 - v0.6.15
|
1755
1976
|
|
1756
1977
|
• now store on your current_user model (this is automatically passed into the method modify_date_inputs_on_params). HG will set user-inputted values correctly to daylight savings time during April-Nov months only (#195)
|
@@ -12,8 +12,6 @@ require_relative "fields/uuid_field"
|
|
12
12
|
require_relative "fields/attachment_field"
|
13
13
|
require_relative "fields/related_set_field"
|
14
14
|
|
15
|
-
|
16
|
-
|
17
15
|
class FieldFactory
|
18
16
|
attr_accessor :field, :class_name
|
19
17
|
def initialize(type: , name: , generator: )
|
@@ -51,26 +49,29 @@ class FieldFactory
|
|
51
49
|
end
|
52
50
|
@class_name = class_name
|
53
51
|
|
52
|
+
if field_class.nil?
|
53
|
+
raise "Field type could be identified #{name} "
|
54
|
+
end
|
54
55
|
|
55
|
-
@field = field_class.new(name: name
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
56
|
+
@field = field_class.new(scaffold: generator, name: name)
|
57
|
+
# layout_strategy: generator.layout_strategy,
|
58
|
+
# form_placeholder_labels: generator.form_placeholder_labels,
|
59
|
+
# form_labels_position: generator.form_labels_position,
|
60
|
+
# ownership_field: generator.ownership_field,
|
61
|
+
# hawk_keys: generator.hawk_keys,
|
62
|
+
# auth: generator.auth,
|
63
|
+
# class_name: generator.singular_class,
|
64
|
+
# alt_lookup: generator.alt_lookups[name] || nil,
|
65
|
+
# singular: generator.singular,
|
66
|
+
# self_auth: generator.self_auth,
|
67
|
+
# update_show_only: generator.update_show_only,
|
68
|
+
# attachment_data: generator.attachments[name.to_sym],
|
69
|
+
# sample_file_path: generator.sample_file_path,
|
70
|
+
# modify_as: generator.modify_as[name.to_sym] || nil,
|
71
|
+
# plural: generator.plural,
|
72
|
+
# display_as: generator.display_as[name.to_sym] || nil,
|
73
|
+
# default_boolean_display: generator.default_boolean_display,
|
74
|
+
# namespace: generator.namespace_value,
|
75
|
+
# pundit: generator.pundit )
|
75
76
|
end
|
76
77
|
end
|
@@ -5,17 +5,8 @@ class AssociationField < Field
|
|
5
5
|
|
6
6
|
attr_accessor :assoc_name, :assoc_class, :assoc, :alt_lookup
|
7
7
|
|
8
|
-
def initialize(
|
9
|
-
class_name: ,
|
10
|
-
default_boolean_display:, display_as: ,
|
11
|
-
name: , singular: ,
|
12
|
-
update_show_only: ,
|
13
|
-
hawk_keys: , auth: , sample_file_path:, ownership_field: ,
|
14
|
-
attachment_data: nil , layout_strategy: , form_placeholder_labels: nil,
|
15
|
-
form_labels_position:, modify_as: , self_auth: , namespace:, pundit: , plural: )
|
8
|
+
def initialize(scaffold: , name: )
|
16
9
|
super
|
17
|
-
|
18
|
-
|
19
10
|
@assoc_model = eval("#{class_name}.reflect_on_association(:#{assoc})")
|
20
11
|
|
21
12
|
if assoc_model.nil?
|
@@ -97,14 +88,14 @@ class AssociationField < Field
|
|
97
88
|
def form_field_output
|
98
89
|
assoc_name = name.to_s.gsub("_id","")
|
99
90
|
assoc = eval("#{class_name}.reflect_on_association(:#{assoc_name})")
|
100
|
-
|
101
|
-
if alt_lookup
|
91
|
+
if alt_lookup.keys.include?(name.to_sym)
|
102
92
|
alt = alt_lookup[:lookup_as]
|
103
93
|
assoc_name = name.to_s.gsub("_id","")
|
104
94
|
assoc = eval("#{class_name}.reflect_on_association(:#{assoc_name})")
|
105
95
|
|
106
96
|
alt = alt_lookup[:lookup_as]
|
107
|
-
|
97
|
+
parts = name.split('_')
|
98
|
+
"<%= f.text_field :__lookup_#{alt}, value: @#{singular}.#{assoc_name}.try(:#{alt}), placeholder: \"search by #{alt}\" " + (stimmify ? ", 'data-#{@stimmify}-target': '#{camelcase_name}' " : "") + "%>"
|
108
99
|
|
109
100
|
# if modify_as
|
110
101
|
# modified_display_output
|
@@ -156,8 +147,17 @@ class AssociationField < Field
|
|
156
147
|
end
|
157
148
|
|
158
149
|
|
150
|
+
if @stimmify
|
151
|
+
col_target = HotGlue.to_camel_case(name.to_s.gsub("_", " "))
|
152
|
+
data_attr = ", data: {'#{@stimmify}-target': '#{col_target}'} "
|
153
|
+
els
|
154
|
+
data_attr = ""
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
|
159
159
|
(is_owner ? "<% unless @#{assoc_name} %>\n" : "") +
|
160
|
-
" <%= f.collection_select(:#{name}, #{hawked_association}, :id, :#{display_column}, {prompt: true, selected: #{singular}.#{name} }, class: 'form-control') %>\n" +
|
160
|
+
" <%= f.collection_select(:#{name}, #{hawked_association}, :id, :#{display_column}, { prompt: true, selected: #{singular}.#{name} }, class: 'form-control'#{data_attr}) %>\n" +
|
161
161
|
(is_owner ? "<% else %>\n <%= @#{assoc_name}.#{display_column} %>" : "") +
|
162
162
|
(is_owner ? "\n<% end %>" : "")
|
163
163
|
end
|
@@ -1,25 +1,6 @@
|
|
1
1
|
class AttachmentField < Field
|
2
2
|
attr_accessor :attachment_data
|
3
|
-
def initialize(
|
4
|
-
attachment_data:,
|
5
|
-
plural:,
|
6
|
-
auth:,
|
7
|
-
class_name:,
|
8
|
-
display_as:, singular:,
|
9
|
-
default_boolean_display: ,
|
10
|
-
form_placeholder_labels: ,
|
11
|
-
form_labels_position:,
|
12
|
-
hawk_keys:,
|
13
|
-
layout_strategy: ,
|
14
|
-
name:,
|
15
|
-
namespace:,
|
16
|
-
modify_as:,
|
17
|
-
ownership_field:,
|
18
|
-
pundit: ,
|
19
|
-
sample_file_path: nil,
|
20
|
-
self_auth:,
|
21
|
-
update_show_only:
|
22
|
-
)
|
3
|
+
def initialize(scaffold:, name:)
|
23
4
|
super
|
24
5
|
|
25
6
|
@attachment_data = attachment_data
|
@@ -23,9 +23,9 @@ class BooleanField < Field
|
|
23
23
|
|
24
24
|
def radio_button_display
|
25
25
|
" <%= f.radio_button(:#{name}, '0', checked: #{singular}.#{name} ? '' : 'checked', class: '#{@layout_strategy.form_checkbox_input_class}') %>\n" +
|
26
|
-
" <%= f.label(:#{name}, value: '#{modify_binary? && modify_as[:binary][:falsy] || 'No'}', for: '#{singular}_#{name}_0') %>\n" +
|
26
|
+
" <%= f.label(:#{name}, value: '#{modify_binary? && modify_as[name.to_sym][:binary][:falsy] || 'No'}', for: '#{singular}_#{name}_0') %>\n" +
|
27
27
|
" <br /> <%= f.radio_button(:#{name}, '1', checked: #{singular}.#{name} ? 'checked' : '' , class: '#{@layout_strategy.form_checkbox_input_class}') %>\n" +
|
28
|
-
" <%= f.label(:#{name}, value: '#{modify_binary? && modify_as[:binary][:truthy] || 'Yes'}', for: '#{singular}_#{name}_1') %>\n"
|
28
|
+
" <%= f.label(:#{name}, value: '#{modify_binary? && modify_as[name.to_sym][:binary][:truthy] || 'Yes'}', for: '#{singular}_#{name}_1') %>\n"
|
29
29
|
end
|
30
30
|
|
31
31
|
def checkbox_display
|
@@ -38,16 +38,16 @@ class BooleanField < Field
|
|
38
38
|
|
39
39
|
def form_field_display
|
40
40
|
if display_boolean_as.nil?
|
41
|
-
|
42
41
|
end
|
42
|
+
|
43
43
|
"<span class='#{@layout_strategy.form_checkbox_wrapper_class} #{'form-switch' if display_boolean_as == 'switch'}'>\n" +
|
44
44
|
(if display_boolean_as == 'radio'
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
45
|
+
radio_button_display
|
46
|
+
elsif display_boolean_as == 'checkbox'
|
47
|
+
checkbox_display
|
48
|
+
elsif display_boolean_as == 'switch'
|
49
|
+
switch_display
|
50
|
+
end) + "</span> \n"
|
51
51
|
end
|
52
52
|
|
53
53
|
def form_field_output
|
@@ -59,9 +59,9 @@ class BooleanField < Field
|
|
59
59
|
"<% if #{singular}.#{name}.nil? %>
|
60
60
|
<span class=''>MISSING</span>
|
61
61
|
<% elsif #{singular}.#{name} %>
|
62
|
-
#{modify_as[:binary][:truthy]}
|
62
|
+
#{modify_as[name.to_sym][:binary][:truthy]}
|
63
63
|
<% else %>
|
64
|
-
#{modify_as[:binary][:falsy]}
|
64
|
+
#{modify_as[name.to_sym][:binary][:falsy]}
|
65
65
|
<% end %>"
|
66
66
|
else
|
67
67
|
"<% if #{singular}.#{name}.nil? %>
|
@@ -75,11 +75,11 @@ class BooleanField < Field
|
|
75
75
|
end
|
76
76
|
|
77
77
|
def truthy_value
|
78
|
-
modify_as[:binary][:truthy] || 'Yes'
|
78
|
+
modify_as[name.to_sym][:binary][:truthy] || 'Yes'
|
79
79
|
end
|
80
80
|
|
81
81
|
def falsy_value
|
82
|
-
modify_as[:binary][:falsy] || 'No'
|
82
|
+
modify_as[name.to_sym][:binary][:falsy] || 'No'
|
83
83
|
end
|
84
84
|
|
85
85
|
def label_class
|
@@ -10,8 +10,10 @@ class DateField < Field
|
|
10
10
|
|
11
11
|
|
12
12
|
def form_field_output
|
13
|
-
|
14
|
-
|
13
|
+
parts = name.to_s.split('_')
|
14
|
+
camelcase_name = parts.map(&:capitalize).join
|
15
|
+
"<%= date_field_localized(f, :#{name}, #{singular}.#{name}, label: '#{ name.to_s.humanize }'" + (stimmify ? ", html: {'data-#{@stimmify}-target': '#{camelcase_name}'}" : "") + ") %>"
|
16
|
+
end
|
15
17
|
|
16
18
|
def line_field_output
|
17
19
|
"<% unless #{singular}.#{name}.nil? %>
|
@@ -31,14 +31,20 @@ class EnumField < Field
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def form_field_output
|
34
|
+
if @stimmify
|
35
|
+
col_target = HotGlue.to_camel_case(name.to_s.gsub("_", " "))
|
36
|
+
data_attr = ", data: {'#{@stimmify}-target': '#{col_target}'} "
|
37
|
+
end
|
38
|
+
|
34
39
|
enum_type = eval("#{class_name}.columns.select{|x| x.name == '#{name}'}[0].sql_type")
|
40
|
+
|
35
41
|
if eval("defined? #{class_name}.#{enum_type}_labels") == "method"
|
36
42
|
enum_definer = "#{class_name}.#{enum_type}_labels"
|
37
43
|
else
|
38
44
|
enum_definer = "#{class_name}.defined_enums['#{name}']"
|
39
45
|
end
|
40
46
|
|
41
|
-
res = "<%= f.collection_select(:#{name},
|
47
|
+
res = "<%= f.collection_select(:#{name}, enum_to_collection_select(#{enum_definer}), :key, :value, {include_blank: true, selected: #{singular}.#{name} }, class: 'form-control' #{data_attr} )%>"
|
42
48
|
|
43
49
|
|
44
50
|
if modify_as && modify_as[:enum] == :partials
|
@@ -5,50 +5,37 @@ class Field
|
|
5
5
|
:hawk_keys, :layout_strategy, :limit, :modify_as, :name, :object, :sample_file_path,
|
6
6
|
:self_auth,
|
7
7
|
:singular_class, :singular, :sql_type, :ownership_field,
|
8
|
-
:update_show_only, :namespace, :pundit, :plural
|
8
|
+
:update_show_only, :namespace, :pundit, :plural,
|
9
|
+
:stimmify, :hidden, :attachment_data
|
10
|
+
|
9
11
|
|
10
12
|
def initialize(
|
11
|
-
|
12
|
-
|
13
|
-
class_name: ,
|
14
|
-
alt_lookup: ,
|
15
|
-
default_boolean_display: ,
|
16
|
-
display_as: ,
|
17
|
-
form_labels_position:,
|
18
|
-
form_placeholder_labels: ,
|
19
|
-
hawk_keys: nil,
|
20
|
-
layout_strategy: ,
|
21
|
-
modify_as: , #note non-standard naming as to avoid collision with Ruby reserved word modify
|
22
|
-
name: ,
|
23
|
-
ownership_field: ,
|
24
|
-
sample_file_path: nil,
|
25
|
-
singular: ,
|
26
|
-
update_show_only:,
|
27
|
-
self_auth:,
|
28
|
-
namespace:,
|
29
|
-
pundit: ,
|
30
|
-
plural:
|
13
|
+
scaffold:, name:
|
14
|
+
|
31
15
|
)
|
32
16
|
@name = name
|
33
|
-
@layout_strategy = layout_strategy
|
34
|
-
@alt_lookup =
|
35
|
-
@singular = singular
|
36
|
-
@class_name =
|
37
|
-
@update_show_only = update_show_only
|
38
|
-
@hawk_keys = hawk_keys
|
39
|
-
@auth = auth
|
40
|
-
@sample_file_path = sample_file_path
|
41
|
-
@form_placeholder_labels = form_placeholder_labels
|
42
|
-
@ownership_field = ownership_field
|
43
|
-
@form_labels_position = form_labels_position
|
44
|
-
@modify_as = modify_as
|
45
|
-
@display_as = display_as
|
46
|
-
@pundit = pundit
|
47
|
-
@plural = plural
|
48
|
-
|
49
|
-
@
|
50
|
-
@
|
51
|
-
@
|
17
|
+
@layout_strategy = scaffold.layout_strategy
|
18
|
+
@alt_lookup = scaffold.alt_lookups
|
19
|
+
@singular = scaffold.singular
|
20
|
+
@class_name = scaffold.singular_class
|
21
|
+
@update_show_only = scaffold.update_show_only
|
22
|
+
@hawk_keys = scaffold.hawk_keys
|
23
|
+
@auth = scaffold.auth
|
24
|
+
@sample_file_path = scaffold.sample_file_path
|
25
|
+
@form_placeholder_labels = scaffold.form_placeholder_labels
|
26
|
+
@ownership_field = scaffold.ownership_field
|
27
|
+
@form_labels_position = scaffold.form_labels_position
|
28
|
+
@modify_as = scaffold.modify_as
|
29
|
+
@display_as = scaffold.display_as
|
30
|
+
@pundit = scaffold.pundit
|
31
|
+
@plural = scaffold.plural
|
32
|
+
@self_auth = scaffold.self_auth
|
33
|
+
@default_boolean_display = scaffold.default_boolean_display
|
34
|
+
@namespace = scaffold.namespace_value
|
35
|
+
@stimmify = scaffold.stimmify
|
36
|
+
@hidden = scaffold.hidden
|
37
|
+
@attachment_data = scaffold.attachments[name.to_sym]
|
38
|
+
|
52
39
|
|
53
40
|
# TODO: remove knowledge of subclasses from Field
|
54
41
|
unless self.class == AttachmentField || self.class == RelatedSetField
|
@@ -125,7 +112,7 @@ class Field
|
|
125
112
|
end
|
126
113
|
|
127
114
|
def viewable_output
|
128
|
-
if modify_as
|
115
|
+
if modify_as[:modify]
|
129
116
|
modified_display_output(show_only: true)
|
130
117
|
else
|
131
118
|
field_view_output
|
@@ -179,20 +166,34 @@ class Field
|
|
179
166
|
if modify_as && modify_as[:timezone]
|
180
167
|
"<%= f.time_zone_select :#{name}, ActiveSupport::TimeZone.all, {}, {class: 'form-control'} %>"
|
181
168
|
else
|
182
|
-
|
169
|
+
parts = name.split('_')
|
170
|
+
camelcase_name = parts.first + parts[1..].map(&:capitalize).join
|
171
|
+
" <%= f.text_field :#{name}, value: #{singular}.#{name}, autocomplete: 'off', size: #{width}, class: 'form-control', type: '#{type}'" + (form_placeholder_labels ? ", placeholder: '#{name.to_s.humanize}'" : "") + (stimmify ? ", 'data-#{@stimmify}-target': '#{camelcase_name}' " : "") + " %>\n " + "\n"
|
183
172
|
end
|
184
173
|
end
|
185
174
|
|
175
|
+
def hidden_output
|
176
|
+
parts = name.split('_')
|
177
|
+
camelcase_name = parts.first + parts[1..].map(&:capitalize).join
|
178
|
+
"<%= f.hidden_field :#{name}, value: #{singular}.#{name} " +
|
179
|
+
(@stimmify ? ", 'data-#{@stimmify}-target': '#{camelcase_name}' " : "") +
|
180
|
+
" %>"
|
181
|
+
end
|
182
|
+
|
186
183
|
def text_area_output(field_length, extra_classes: "")
|
187
184
|
lines = field_length % 40
|
188
185
|
if lines > 5
|
189
186
|
lines = 5
|
190
187
|
end
|
191
|
-
|
188
|
+
|
189
|
+
parts = name.split('_')
|
190
|
+
camelcase_name = parts.first + parts[1..].map(&:capitalize).join
|
191
|
+
"<%= f.text_area :#{name}, class: 'form-control#{extra_classes}', autocomplete: 'off', cols: 40, rows: '#{lines}'" + ( form_placeholder_labels ? ", placeholder: '#{name.to_s.humanize}'" : "") +
|
192
|
+
(@stimmify ? ", 'data-#{@stimmify}-target': '#{camelcase_name}' " : "") + " %>"
|
192
193
|
end
|
193
194
|
|
194
|
-
def modify_binary?
|
195
|
-
!!(modify_as && modify_as[:binary])
|
195
|
+
def modify_binary?
|
196
|
+
!!(modify_as && modify_as[name.to_sym] && modify_as[name.to_sym][:binary])
|
196
197
|
end
|
197
198
|
|
198
199
|
def display_boolean_as
|
@@ -201,8 +202,8 @@ class Field
|
|
201
202
|
@default_boolean_display = "radio"
|
202
203
|
end
|
203
204
|
|
204
|
-
if
|
205
|
-
return display_as[:boolean] || "radio"
|
205
|
+
if display_as[name.to_sym]
|
206
|
+
return display_as[name.to_sym][:boolean] || "radio"
|
206
207
|
else
|
207
208
|
return @default_boolean_display
|
208
209
|
end
|