base_editing_bootstrap 1.13.0 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +37 -5
- data/app/assets/config/base_editing_bootstrap_manifest.js +1 -0
- data/app/assets/javascripts/nested_form_controller.js +48 -0
- data/app/controllers/base_editing_controller.rb +11 -0
- data/app/helpers/utilities/form_helper.rb +7 -3
- data/app/helpers/utilities/template_helper.rb +11 -3
- data/app/policies/base_model_policy.rb +21 -1
- data/app/views/base_editing/_form_field.html.erb +2 -3
- data/app/views/base_editing/_form_full_components.html.erb +2 -2
- data/app/views/base_editing/_nested_row_form.html.erb +1 -1
- data/app/views/base_editing/_nested_row_form_readonly.html.erb +8 -0
- data/app/views/base_editing/form_field/_accept_has_many_nested_field.html.erb +21 -1
- data/app/views/base_editing/form_field/_accept_has_many_nested_field_readonly.html.erb +22 -0
- data/app/views/base_editing/form_field/_accept_has_one_nested_field_readonly.html.erb +4 -0
- data/app/views/base_editing/form_field/_base_readonly.html.erb +8 -0
- data/app/views/base_editing/form_field/_belongs_to_select.html.erb +2 -2
- data/app/views/base_editing/form_field/_belongs_to_select_readonly.html.erb +6 -0
- data/app/views/base_editing/form_field/_boolean.html.erb +1 -1
- data/app/views/base_editing/form_field/_boolean_readonly.html.erb +2 -0
- data/app/views/base_editing/form_field/_date_readonly.html.erb +2 -0
- data/app/views/base_editing/form_field/_datetime_readonly.html.erb +2 -0
- data/app/views/base_editing/form_field/_decimal_readonly.html.erb +2 -0
- data/app/views/base_editing/form_field/_enum_readonly.html.erb +2 -0
- data/app/views/base_editing/form_field/_has_one_attachment.html.erb +16 -12
- data/app/views/base_editing/form_field/_has_one_attachment_readonly.html.erb +12 -0
- data/app/views/base_editing/form_field/_integer_readonly.html.erb +2 -0
- data/app/views/base_editing/form_field/_textarea_readonly.html.erb +7 -0
- data/config/importmap.rb +2 -0
- data/lib/base_editing_bootstrap/VERSION +1 -1
- data/lib/base_editing_bootstrap/engine.rb +8 -0
- data/lib/generators/base_editing_bootstrap/field_override/field_override_generator.rb +5 -2
- data/lib/generators/base_editing_bootstrap/install/install_generator.rb +3 -3
- data/spec/support/external_shared/pundit.rb +1 -0
- metadata +17 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d69ef1800e2eece675666b76837ae189f47c6f054031c12990a4b36181fca951
|
|
4
|
+
data.tar.gz: e345a8d8545068e50128afe6e55d212fe5f6e87555309898fb72ed0add5e0d69
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 37e059fd372aeb9ef27780523d13d336e4815c6afb8792990b6a375f1c60a1dfb951d48ea2231045a2715de8022138eb8732dfaa313b2e06d77ed23e1a4ee731
|
|
7
|
+
data.tar.gz: 4e8778eefe88514f17133dab5c96d5d8eaad61cb71bdf82b5ace11226af0f737a8e4ff15dd1609efd7555610aeaaec8e4783175103f4ad2e0323acd69ee6e2dd
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
All notable changes to this project will be documented in this file. See [conventional commits](https://www.conventionalcommits.org/) for commit guidelines.
|
|
3
3
|
|
|
4
4
|
- - -
|
|
5
|
+
## 1.15.0 - 2026-04-09
|
|
6
|
+
#### Features
|
|
7
|
+
- Add Read only mode (#25) - (0ba3da2) - Marino Bonetti
|
|
8
|
+
|
|
9
|
+
- - -
|
|
10
|
+
|
|
11
|
+
## 1.14.0 - 2026-03-19
|
|
12
|
+
#### Features
|
|
13
|
+
- Nested elements with limit from rails config (#24) - (f003ce4) - Marino Bonetti
|
|
14
|
+
#### Bug Fixes
|
|
15
|
+
- Correct nested_form when elements are marked for destruction - (9fd6544) - Marino Bonetti
|
|
16
|
+
|
|
17
|
+
- - -
|
|
18
|
+
|
|
5
19
|
## 1.13.0 - 2026-02-03
|
|
6
20
|
#### Features
|
|
7
21
|
- Form submit button inheritance value - (00b04b1) - Marino Bonetti
|
data/README.md
CHANGED
|
@@ -35,16 +35,34 @@ $ bundle exec rails g base_editing_bootstrap:install
|
|
|
35
35
|
|
|
36
36
|
**Si presume quindi che ActiveStorage sia correttamente installato, completo del javascript per il direct upload**
|
|
37
37
|
|
|
38
|
+
### Upgrade Notes
|
|
39
|
+
- From <= 1.13:
|
|
40
|
+
In `app/javascript/controllers/application.js` replace:
|
|
41
|
+
```js
|
|
42
|
+
import RailsNestedForm from '@stimulus-components/rails-nested-form'
|
|
43
|
+
application.register('nested-form', RailsNestedForm)
|
|
44
|
+
```
|
|
45
|
+
with:
|
|
46
|
+
```js
|
|
47
|
+
import NestedForm from 'nested_form_controller';
|
|
48
|
+
application.register('nested-form', NestedForm);
|
|
49
|
+
```
|
|
50
|
+
in `config/importmap.rb` remove:
|
|
51
|
+
```ruby
|
|
52
|
+
pin "@stimulus-components/rails-nested-form"
|
|
53
|
+
```
|
|
54
|
+
and finaly remove in vendor/javascript the `@stimulus-components/rails-nested-form` downloaded dependencies
|
|
55
|
+
|
|
38
56
|
### Note for NestedAttributes
|
|
39
57
|
|
|
40
|
-
|
|
58
|
+
Il controller nested attributes viene importato da importmaps dell'engine.
|
|
59
|
+
E' necessagio registrare il nuovo controller in app/javascript/application.js
|
|
41
60
|
|
|
42
|
-
```
|
|
43
|
-
|
|
61
|
+
```js
|
|
62
|
+
import NestedForm from 'nested_form_controller'; // Mappato con import maps locale
|
|
63
|
+
application.register('nested-form', NestedForm); // Utilizzato nell'interfaccia della form.
|
|
44
64
|
```
|
|
45
65
|
|
|
46
|
-
e seguire installazione https://www.stimulus-components.com/docs/stimulus-rails-nested-form
|
|
47
|
-
|
|
48
66
|
### Generators
|
|
49
67
|
|
|
50
68
|
Then Install dependency (if you run base_editing_bootstrap:install you are good to go):
|
|
@@ -274,6 +292,20 @@ Note:
|
|
|
274
292
|
|
|
275
293
|
Fai riferimento all'implementazione di esempio del dummy `Company->addresses`
|
|
276
294
|
|
|
295
|
+
### ReadOnly
|
|
296
|
+
E' possibile renderizzare i campi di un modello in sola lettura, andando a ridefinire nella policy
|
|
297
|
+
il metodo `attribute_is_readonly(attribute_name)`.
|
|
298
|
+
Per ogni campo abbiamo la versione NOME_CAMPO_readonly.html.erb che viene renderizzato quando il metodo
|
|
299
|
+
precedente restituisce true.
|
|
300
|
+
I nested attributes verranno renderizzati rispetto a quanto definito dal
|
|
301
|
+
campo padre.
|
|
302
|
+
La ricerca dei partial avviene nella stessa modalità dei campi sopra definiti.
|
|
303
|
+
Al generator per i campi standard basta aggiungere il parametro `--readonly` per avere la versione NOME_CAMPO_readonly.html.erb:
|
|
304
|
+
```shell
|
|
305
|
+
rails g base_editing_bootstrap:field_override ModelName field1 field2:type --readonly
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
|
|
277
309
|
### Translations
|
|
278
310
|
|
|
279
311
|
#### Index buttons:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//= link nested_form_controller.js
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import NestedForm from "@stimulus-components/rails-nested-form"
|
|
2
|
+
|
|
3
|
+
// Connects to data-controller="nested-form"
|
|
4
|
+
export default class extends NestedForm {
|
|
5
|
+
|
|
6
|
+
static values = {
|
|
7
|
+
limit: Number,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
add(e) {
|
|
11
|
+
super.add(e);
|
|
12
|
+
this.check_for_enabling_add_button(e);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
remove(e) {
|
|
16
|
+
super.remove(e);
|
|
17
|
+
this.check_for_enabling_add_button(e);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Elenco elementi presenti visibili (e quindi non settati per essere cancellati)
|
|
21
|
+
total_active_elements() {
|
|
22
|
+
let count = 0;
|
|
23
|
+
|
|
24
|
+
this.targetTarget.parentElement.querySelectorAll(this.wrapperSelectorValue).forEach((ele) => {
|
|
25
|
+
if (ele.checkVisibility()) {
|
|
26
|
+
count += 1;
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
return count;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
check_for_enabling_add_button(e) {
|
|
33
|
+
if (this.hasLimitValue) {
|
|
34
|
+
if (this.total_active_elements() >= this.limitValue) {
|
|
35
|
+
// Aggiungiamo classe disable sull'elemento che ha lanciato questo evento
|
|
36
|
+
this.add_button().disabled = "disabled";
|
|
37
|
+
} else {
|
|
38
|
+
this.add_button().removeAttribute("disabled");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
add_button() {
|
|
44
|
+
return this.element.querySelector('[data-action="nested-form#add"]')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
}
|
|
@@ -5,6 +5,7 @@ class BaseEditingController < RestrictedAreaController
|
|
|
5
5
|
:edit_custom_polymorphic_path,
|
|
6
6
|
:form_attributes,
|
|
7
7
|
:form_builder,
|
|
8
|
+
:readonly_attribute?,
|
|
8
9
|
:index_custom_polymorphic_path,
|
|
9
10
|
:new_custom_polymorphic_path,
|
|
10
11
|
:show_custom_polymorphic_path
|
|
@@ -131,6 +132,16 @@ class BaseEditingController < RestrictedAreaController
|
|
|
131
132
|
policy.public_send(method_name)
|
|
132
133
|
end
|
|
133
134
|
|
|
135
|
+
def readonly_attribute?(attribute, model = base_class.new, action = override_pundit_action_name)
|
|
136
|
+
policy = policy(model)
|
|
137
|
+
method_name = if policy.respond_to?("attribute_is_readonly_for_#{action}")
|
|
138
|
+
"attribute_is_readonly_for_#{action}"
|
|
139
|
+
else
|
|
140
|
+
"attribute_is_readonly"
|
|
141
|
+
end
|
|
142
|
+
policy.public_send(method_name, attribute)
|
|
143
|
+
end
|
|
144
|
+
|
|
134
145
|
def load_object
|
|
135
146
|
@object = base_class.find(params[:id])
|
|
136
147
|
|
|
@@ -19,10 +19,13 @@ module Utilities
|
|
|
19
19
|
#
|
|
20
20
|
# @param [Forms::Base] form
|
|
21
21
|
# @param [Symbol] field
|
|
22
|
-
|
|
22
|
+
# @param [Boolean] readonly -> rende possibile nelle nested form, nel caso arrivi da un field padre che definisce
|
|
23
|
+
# il campo come readonly di non controllare nemmeno la policy(il padre ha priorità su figlio)
|
|
24
|
+
# @return [ActiveSupport::SafeBuffer]
|
|
25
|
+
def form_print_field(form, field, readonly: nil)
|
|
23
26
|
locals = {form:, field:}
|
|
24
27
|
if form.object.class.respond_to?(:field_to_form_partial) and (generic_field = form.object.class.field_to_form_partial(field))
|
|
25
|
-
type= :custom
|
|
28
|
+
type = :custom
|
|
26
29
|
elsif form.object.class.respond_to?(:defined_enums) && form.object.class.defined_enums.key?(field.to_s)
|
|
27
30
|
type = :enum
|
|
28
31
|
generic_field = "enum"
|
|
@@ -89,7 +92,8 @@ module Utilities
|
|
|
89
92
|
form.object,
|
|
90
93
|
field,
|
|
91
94
|
"form_field",
|
|
92
|
-
generic_field
|
|
95
|
+
generic_field,
|
|
96
|
+
readonly: (readonly.nil? ? readonly_attribute?(field, form.object) : readonly)
|
|
93
97
|
)
|
|
94
98
|
bs_logger.debug do
|
|
95
99
|
<<~TEXT
|
|
@@ -12,7 +12,8 @@ module Utilities::TemplateHelper
|
|
|
12
12
|
# @param [Symbol] field
|
|
13
13
|
# @param [String] base_path
|
|
14
14
|
# @param [String] generic_field
|
|
15
|
-
|
|
15
|
+
# @param [Boolean] readonly #aggiunge nella ricerca del template la versione readonly
|
|
16
|
+
def find_template_with_fallbacks(obj, field, base_path, generic_field, readonly: false)
|
|
16
17
|
# nei casi in cui passiamo la classe e non l'oggetto, dobbiamo utilizzare un metodo interno a rails per
|
|
17
18
|
# avere la partial_path
|
|
18
19
|
|
|
@@ -31,7 +32,7 @@ module Utilities::TemplateHelper
|
|
|
31
32
|
end
|
|
32
33
|
|
|
33
34
|
bs_logger.tagged(field) do
|
|
34
|
-
[
|
|
35
|
+
casistiche = [
|
|
35
36
|
# Precedenza modello e campo specifico
|
|
36
37
|
["Campo SPECIFICO + inheritance tra modelli", field, obj_base_paths],
|
|
37
38
|
# cerco tramite nome modello semplice, con namespace della risorsa (cell_field,header_field,form_field) e nome del campo specifico
|
|
@@ -42,7 +43,14 @@ module Utilities::TemplateHelper
|
|
|
42
43
|
["Campo GENERICO + inheritance controllers", "#{base_path}/#{generic_field}", lookup_context.prefixes],
|
|
43
44
|
["Campo GENERICO + inheritance tra modelli", generic_field, obj_base_paths],
|
|
44
45
|
["Default BaseEditingController", "base_editing/#{base_path}/#{generic_field}", []],
|
|
45
|
-
]
|
|
46
|
+
]
|
|
47
|
+
# In caso di readonly andremo a ricercare solamente la versione di quel tipo
|
|
48
|
+
if readonly
|
|
49
|
+
casistiche = casistiche.collect do |desc, partial, prefixes|
|
|
50
|
+
[desc, "#{partial}_readonly", prefixes]
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
casistiche.each do |desc, partial, prefixes|
|
|
46
54
|
bs_logger.debug { "#{desc} - partial:`#{partial}` in #{prefixes.inspect}" }
|
|
47
55
|
if lookup_context.exists?(partial, prefixes, true)
|
|
48
56
|
return lookup_context.find(partial, prefixes, true)
|
|
@@ -9,13 +9,33 @@ class BaseModelPolicy < ApplicationPolicy
|
|
|
9
9
|
|
|
10
10
|
def show? = general_rule
|
|
11
11
|
|
|
12
|
-
# Questo metodo può essere
|
|
12
|
+
# Questo metodo può essere richiamato specifico per azione:
|
|
13
13
|
# - permitted_attributes_for_create
|
|
14
14
|
# - permitted_attributes_for_update
|
|
15
|
+
# - permitted_attributes_for_ACTION_NAME
|
|
16
|
+
# Quindi nella policy possiamo differenziare le due situazioni
|
|
15
17
|
def permitted_attributes = []
|
|
16
18
|
|
|
19
|
+
# Questo metodo può essere richiamato specifico per azione:
|
|
20
|
+
# - editable_attributes_for_create
|
|
21
|
+
# - editable_attributes_for_update
|
|
22
|
+
# - editable_attributes_for_ACTION_NAME
|
|
23
|
+
# Quindi nella policy possiamo differenziare le due situazioni
|
|
17
24
|
def editable_attributes = []
|
|
18
25
|
|
|
26
|
+
##
|
|
27
|
+
# Permette di specificare se un attributo è di sola lettura durante il rendering della form.
|
|
28
|
+
# Oltre alla versione standard è possibile definire il metodo specificando il tipo di azione con il
|
|
29
|
+
# medesimo formato utilizzato negli altri metodi:
|
|
30
|
+
# - attribute_is_readonly_for_create?
|
|
31
|
+
# - attribute_is_readonly_for_update?
|
|
32
|
+
# - attribute_is_readonly_for_ACTION_NAME?
|
|
33
|
+
#
|
|
34
|
+
# @param attribute [Symbol] nome dell'attributo
|
|
35
|
+
# @param action_name [String] nome dell'azione
|
|
36
|
+
# @return [Boolean] true se l'attributo è di sola lettura, false altrimenti
|
|
37
|
+
def attribute_is_readonly(_attribute) = false
|
|
38
|
+
|
|
19
39
|
def permitted_attributes_for_ransack
|
|
20
40
|
record.class.column_names + record.class._ransackers.keys
|
|
21
41
|
end
|
|
@@ -4,11 +4,10 @@
|
|
|
4
4
|
# - form -> FormBuilder
|
|
5
5
|
# - form_field -> String
|
|
6
6
|
%>
|
|
7
|
-
<%# locals: (form:, form_field:) -%>
|
|
7
|
+
<%# locals: (form:, form_field:,readonly:nil) -%>
|
|
8
8
|
<%
|
|
9
9
|
input_group_classes = ["mb-1"]
|
|
10
|
-
|
|
11
|
-
content = form_print_field(form, form_field)
|
|
10
|
+
content = form_print_field(form, form_field, readonly: readonly)
|
|
12
11
|
unless content.match "checkbox"
|
|
13
12
|
input_group_classes << "input-group"
|
|
14
13
|
end
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
Questo partial è il raggruppamento di tutti gli elementi tranne il footer del form.
|
|
3
3
|
Serve per riutilizzarlo anche nel nested attributes come base per costruire tutti gli elementi
|
|
4
4
|
%>
|
|
5
|
-
<%# locals: (form:) -%>
|
|
5
|
+
<%# locals: (form:,readonly:nil) -%>
|
|
6
6
|
<%= render layout: "form_body_container" do %>
|
|
7
7
|
<%= render partial: "form_field_header", locals: {form:} %>
|
|
8
8
|
<%= render partial: "form_base_errors", locals: {form:} if form.object.errors.key?(:base) %>
|
|
9
9
|
<%= render layout: "form_fields_container" do %>
|
|
10
10
|
<%= render collection: form_attributes(form.object),
|
|
11
11
|
layout: "form_field_container",
|
|
12
|
-
partial: "form_field", locals: {form:} %>
|
|
12
|
+
partial: "form_field", locals: {form:, readonly: readonly} %>
|
|
13
13
|
<% end %>
|
|
14
14
|
<% end %>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<tr class="nested-form-wrapper" data-new-record="<%= form.object.new_record? %>" id="<%= dom_id(form.object) %>">
|
|
1
|
+
<tr class="nested-form-wrapper <%= (form.object.marked_for_destruction? ? "d-none" : "") %>" data-new-record="<%= form.object.new_record? %>" id="<%= dom_id(form.object) %>">
|
|
2
2
|
|
|
3
3
|
<% policy(form.object).editable_attributes.each do |field| %>
|
|
4
4
|
<td>
|
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
<%# locals: (form:, field:,new_object:) -%>
|
|
2
|
-
|
|
2
|
+
<%
|
|
3
|
+
|
|
4
|
+
##
|
|
5
|
+
# Costruisco le opzioni per limitare tramite interfaccia (ricevuta da configurazione di Rails nested_attributes_for)
|
|
6
|
+
# il numero di nested elements
|
|
7
|
+
controller_data = {controller: 'nested-form'}
|
|
8
|
+
if (limit = form.object.class.nested_attributes_options[field].dig(:limit))
|
|
9
|
+
controller_data["nested-form-limit-value"] = \
|
|
10
|
+
case limit
|
|
11
|
+
when Symbol #TODO add tests
|
|
12
|
+
form.object.class.send(limit)
|
|
13
|
+
when Proc #TODO add tests
|
|
14
|
+
limit.call
|
|
15
|
+
else
|
|
16
|
+
limit
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
%>
|
|
21
|
+
|
|
22
|
+
<%= content_tag :table, class: "table", data: controller_data do %>
|
|
3
23
|
|
|
4
24
|
<thead>
|
|
5
25
|
<tr>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<%# locals: (form:, field:,new_object:) -%>
|
|
2
|
+
<%= content_tag :table, class: "table read-only" do %>
|
|
3
|
+
<thead>
|
|
4
|
+
<tr>
|
|
5
|
+
<% policy(new_object).editable_attributes.each do |field| %>
|
|
6
|
+
<th>
|
|
7
|
+
<%= new_object.class.human_attribute_name(field) %>
|
|
8
|
+
</th>
|
|
9
|
+
<% end %>
|
|
10
|
+
</tr>
|
|
11
|
+
</thead>
|
|
12
|
+
|
|
13
|
+
<tbody>
|
|
14
|
+
|
|
15
|
+
<%= form.fields_for field do |form_for_sections| %>
|
|
16
|
+
<%= render "nested_row_form_readonly", form: form_for_sections %>
|
|
17
|
+
<% end %>
|
|
18
|
+
|
|
19
|
+
</tbody>
|
|
20
|
+
|
|
21
|
+
<% end %>
|
|
22
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<%# locals: (form:, field:,relation_class:,foreign_key:,value_method: :id, label_method: :option_label) -%>
|
|
2
2
|
<%= form.select(foreign_key, options_from_collection_for_select(policy_scope(relation_class),
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
value_method, label_method,
|
|
4
|
+
selected: form.object.send(foreign_key)),
|
|
5
5
|
include_blank: true
|
|
6
6
|
) %>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<%# locals: (form:, field:,relation_class:,foreign_key:,value_method: :id, label_method: :option_label) -%>
|
|
2
|
+
<%= form.select(foreign_key, options_from_collection_for_select(policy_scope(relation_class),
|
|
3
|
+
value_method, label_method,
|
|
4
|
+
selected: form.object.send(foreign_key)),
|
|
5
|
+
{include_blank: true}, {disabled: true, readonly: true, name: "READONLY"}
|
|
6
|
+
) %>
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
<%# locals: (form:, field:) -%>
|
|
2
|
-
<%= form.switch_box(field,label: field) %>
|
|
2
|
+
<%= form.switch_box(field, label: field) %>
|
|
@@ -13,19 +13,23 @@
|
|
|
13
13
|
JAVASCRIPT
|
|
14
14
|
|
|
15
15
|
%>
|
|
16
|
-
|
|
16
|
+
<div class="d-flex">
|
|
17
|
+
<%= form.hidden_field field, value: form.object.send(field).signed_id, id: hidden_field_id if is_attached %>
|
|
17
18
|
|
|
18
|
-
<%= form.file_field field, direct_upload: true %>
|
|
19
|
+
<%= form.file_field field, direct_upload: true %>
|
|
19
20
|
|
|
20
|
-
<% if is_attached %>
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
<% if is_attached %>
|
|
22
|
+
|
|
23
|
+
<%= content_tag :span, form.object.send(field).attachment.blob.filename, class: "input-group-text flex-grow-1", id: filename_id %>
|
|
24
|
+
<%= content_tag :button, icon(:trash),
|
|
25
|
+
onclick: javascript_clear_event,
|
|
26
|
+
class: "btn btn-outline-secondary rounded-0" %>
|
|
27
|
+
<%= link_to icon(:download), form.object.send(field), class: "btn btn-outline-secondary", target: :_blank %>
|
|
28
|
+
|
|
29
|
+
<% if form.object.send(field).representable? %>
|
|
30
|
+
<% content_for :form_field_ending, flush: true do %>
|
|
31
|
+
<%= content_tag :div, image_tag(form.object.send(field).representation(resize_to_limit: [100, 100])), id: preview_image_id %>
|
|
32
|
+
<% end %>
|
|
29
33
|
<% end %>
|
|
30
34
|
<% end %>
|
|
31
|
-
|
|
35
|
+
</div>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<%# locals: (form:, field:) -%>
|
|
2
|
+
<% if form.object.send(field).attached? %>
|
|
3
|
+
<div class="d-flex">
|
|
4
|
+
<%= content_tag :span, form.object.send(field).attachment.blob.filename, class: "input-group-text flex-grow-1" %>
|
|
5
|
+
<%= link_to icon(:download), form.object.send(field), class: "btn btn-outline-secondary ms-1", target: :_blank %>
|
|
6
|
+
</div>
|
|
7
|
+
<% if form.object.send(field).representable? %>
|
|
8
|
+
<% content_for :form_field_ending, flush: true do %>
|
|
9
|
+
<%= content_tag :div, image_tag(form.object.send(field).representation(resize_to_limit: [100, 100])) %>
|
|
10
|
+
<% end %>
|
|
11
|
+
<% end %>
|
|
12
|
+
<% end %>
|
data/config/importmap.rb
ADDED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.
|
|
1
|
+
1.15.0
|
|
@@ -5,5 +5,13 @@ module BaseEditingBootstrap
|
|
|
5
5
|
app.deprecators[:base_editing_bootstrap] = BaseEditingBootstrap.deprecator
|
|
6
6
|
end
|
|
7
7
|
|
|
8
|
+
initializer "base_editing_bootstrap.importmap", before: "importmap" do |app|
|
|
9
|
+
app.config.importmap.paths << Engine.root.join("config/importmap.rb")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
initializer "base_editing_bootstrap.assets.precompile" do |app|
|
|
13
|
+
app.config.assets.precompile << "nested_form_controller.js"
|
|
14
|
+
end
|
|
15
|
+
|
|
8
16
|
end
|
|
9
17
|
end
|
|
@@ -6,7 +6,8 @@ module BaseEditingBootstrap
|
|
|
6
6
|
include BaseEditingBootstrap::GeneratorsHelpers
|
|
7
7
|
source_root File.expand_path("../../../../app/views/base_editing", __dir__)
|
|
8
8
|
argument :name, type: :string, banner: "Post", required: true
|
|
9
|
-
argument :attributes, type: :array, default: [], banner: "field field:type"
|
|
9
|
+
argument :attributes, type: :array, default: [], banner: "field field[:type]"
|
|
10
|
+
class_option :readonly, type: :boolean, default: false, banner: "--readonly"
|
|
10
11
|
|
|
11
12
|
TYPES = %i[base date datetime decimal integer enum boolean]
|
|
12
13
|
|
|
@@ -24,13 +25,15 @@ module BaseEditingBootstrap
|
|
|
24
25
|
|
|
25
26
|
base_path = class_to_view_path(name)
|
|
26
27
|
|
|
28
|
+
readonly_suffix = options[:readonly] ? "_readonly" : ""
|
|
29
|
+
|
|
27
30
|
attributes.each do |a|
|
|
28
31
|
attr_name, type = a.split(":")
|
|
29
32
|
|
|
30
33
|
type = :base if type.nil?
|
|
31
34
|
type = type.to_sym
|
|
32
35
|
raise "Type #{type} not found in #{TYPES}" unless TYPES.include?(type)
|
|
33
|
-
copy_file "form_field/_#{type}.html.erb", File.join(*base_path,"form_field", "_#{attr_name}.html.erb")
|
|
36
|
+
copy_file "form_field/_#{type}#{readonly_suffix}.html.erb", File.join(*base_path,"form_field", "_#{attr_name}#{readonly_suffix}.html.erb")
|
|
34
37
|
end
|
|
35
38
|
end
|
|
36
39
|
|
|
@@ -35,9 +35,9 @@ module BaseEditingBootstrap
|
|
|
35
35
|
# attualmente penso sia più sensato semplicemente scrivere a video i passaggi necessari, dato che
|
|
36
36
|
# potrebbe essere già presente importmap, nested_attribute_controller e le varie configurazioni
|
|
37
37
|
|
|
38
|
-
say "Install
|
|
39
|
-
say "
|
|
40
|
-
|
|
38
|
+
say "Install nested attributes controller, add to application.js:"
|
|
39
|
+
say " import NestedForm from 'nested_form_controller' \n
|
|
40
|
+
application.register('nested-form', NestedForm)"
|
|
41
41
|
|
|
42
42
|
end
|
|
43
43
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: base_editing_bootstrap
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.15.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Marino Bonetti
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-04-09 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -320,6 +320,7 @@ files:
|
|
|
320
320
|
- README.md
|
|
321
321
|
- Rakefile
|
|
322
322
|
- app/assets/config/base_editing_bootstrap_manifest.js
|
|
323
|
+
- app/assets/javascripts/nested_form_controller.js
|
|
323
324
|
- app/controllers/.keep
|
|
324
325
|
- app/controllers/base_editing_controller.rb
|
|
325
326
|
- app/controllers/restricted_area_controller.rb
|
|
@@ -352,6 +353,7 @@ files:
|
|
|
352
353
|
- app/views/base_editing/_index_title_header.html.erb
|
|
353
354
|
- app/views/base_editing/_navbar.html.erb
|
|
354
355
|
- app/views/base_editing/_nested_row_form.html.erb
|
|
356
|
+
- app/views/base_editing/_nested_row_form_readonly.html.erb
|
|
355
357
|
- app/views/base_editing/_new_page_title_header.html.erb
|
|
356
358
|
- app/views/base_editing/_search.html.erb
|
|
357
359
|
- app/views/base_editing/_search_field.erb
|
|
@@ -366,17 +368,29 @@ files:
|
|
|
366
368
|
- app/views/base_editing/cell_field/_timestamps.html.erb
|
|
367
369
|
- app/views/base_editing/edit.html.erb
|
|
368
370
|
- app/views/base_editing/form_field/_accept_has_many_nested_field.html.erb
|
|
371
|
+
- app/views/base_editing/form_field/_accept_has_many_nested_field_readonly.html.erb
|
|
369
372
|
- app/views/base_editing/form_field/_accept_has_one_nested_field.html.erb
|
|
373
|
+
- app/views/base_editing/form_field/_accept_has_one_nested_field_readonly.html.erb
|
|
370
374
|
- app/views/base_editing/form_field/_base.html.erb
|
|
375
|
+
- app/views/base_editing/form_field/_base_readonly.html.erb
|
|
371
376
|
- app/views/base_editing/form_field/_belongs_to_select.html.erb
|
|
377
|
+
- app/views/base_editing/form_field/_belongs_to_select_readonly.html.erb
|
|
372
378
|
- app/views/base_editing/form_field/_boolean.html.erb
|
|
379
|
+
- app/views/base_editing/form_field/_boolean_readonly.html.erb
|
|
373
380
|
- app/views/base_editing/form_field/_date.html.erb
|
|
381
|
+
- app/views/base_editing/form_field/_date_readonly.html.erb
|
|
374
382
|
- app/views/base_editing/form_field/_datetime.html.erb
|
|
383
|
+
- app/views/base_editing/form_field/_datetime_readonly.html.erb
|
|
375
384
|
- app/views/base_editing/form_field/_decimal.html.erb
|
|
385
|
+
- app/views/base_editing/form_field/_decimal_readonly.html.erb
|
|
376
386
|
- app/views/base_editing/form_field/_enum.html.erb
|
|
387
|
+
- app/views/base_editing/form_field/_enum_readonly.html.erb
|
|
377
388
|
- app/views/base_editing/form_field/_has_one_attachment.html.erb
|
|
389
|
+
- app/views/base_editing/form_field/_has_one_attachment_readonly.html.erb
|
|
378
390
|
- app/views/base_editing/form_field/_integer.html.erb
|
|
391
|
+
- app/views/base_editing/form_field/_integer_readonly.html.erb
|
|
379
392
|
- app/views/base_editing/form_field/_textarea.html.erb
|
|
393
|
+
- app/views/base_editing/form_field/_textarea_readonly.html.erb
|
|
380
394
|
- app/views/base_editing/header_field/_base.html.erb
|
|
381
395
|
- app/views/base_editing/index.html.erb
|
|
382
396
|
- app/views/base_editing/new.html.erb
|
|
@@ -389,6 +403,7 @@ files:
|
|
|
389
403
|
- app/views/kaminari/_paginator.html.erb
|
|
390
404
|
- app/views/kaminari/_prev_page.html.erb
|
|
391
405
|
- base_editing_bootstrap.gemspec
|
|
406
|
+
- config/importmap.rb
|
|
392
407
|
- config/initializers/base_field_error_proc.rb
|
|
393
408
|
- config/locales/it.yml
|
|
394
409
|
- config/routes.rb
|