@massimo-cassandro/minimo 1.11.1 → 1.12.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.
Files changed (47) hide show
  1. package/charts/src/node-helpers/create-svg-canvas-node.mjs +37 -0
  2. package/dev-tools/README.md +1 -1
  3. package/dev-tools/create-favicons/src/init-start-text.txt +20 -0
  4. package/dev-tools/update-version/index.mjs +1 -1
  5. package/dev-tools/update-version/src/chooser-inquirer.mjs +1 -1
  6. package/dev-tools/webpack-setup/starter-install.sh +149 -0
  7. package/dev-tools/webpack-setup/templates/__project__.code-workspace +93 -0
  8. package/dev-tools/webpack-setup/templates/_browserslistrc +27 -0
  9. package/dev-tools/webpack-setup/templates/_editorconfig +17 -0
  10. package/dev-tools/webpack-setup/templates/_gitignore +21 -0
  11. package/dev-tools/webpack-setup/templates/_prettierrc +9 -0
  12. package/dev-tools/webpack-setup/templates/eslint.config.mjs +31 -0
  13. package/dev-tools/webpack-setup/templates/jsconfig.json +22 -0
  14. package/dev-tools/webpack-setup/templates/package-tpl.json +37 -0
  15. package/dev-tools/webpack-setup/templates/stylelint.config.mjs +32 -0
  16. package/dev-tools/webpack-setup/webpack-modules/css-rules.mjs +177 -0
  17. package/dev-tools/webpack-setup/webpack-modules/get-jsConfig-aliases.mjs +33 -0
  18. package/dev-tools/webpack-setup/webpack-modules/mini-svg-data-uri-loader.cjs +25 -0
  19. package/dev-tools/webpack-setup/webpack-modules/postcss.config.mjs +77 -0
  20. package/dev-tools/webpack-setup/webpack-modules/svg-rules.mjs +154 -0
  21. package/dev-tools/webpack-setup/webpack-modules/svgo.config.mjs +26 -0
  22. package/dev-tools/webpack-setup/webpack-template.ejs +20 -0
  23. package/dev-tools/webpack-setup/webpack.config.mjs +585 -0
  24. package/package.json +5 -4
  25. package/snippets/ImgViewerController.php +403 -0
  26. package/snippets/UnsplashController.php +74 -0
  27. package/snippets/build-chrome-custom-device-list.mjs +101 -0
  28. package/snippets/config-templates/_env.local +13 -0
  29. package/snippets/config-templates/_github/dependabot.yml +10 -0
  30. package/snippets/config-templates/_hintrc.cjs +35 -0
  31. package/snippets/config-templates/_htaccess +69 -0
  32. package/snippets/config-templates/_npmignore +8 -0
  33. package/snippets/config-templates/_npmrc +1 -0
  34. package/snippets/config-templates/_stylelintignore +5 -0
  35. package/snippets/config-templates/babel.config--react.json +20 -0
  36. package/snippets/config-templates/babel.config--solidJS.json +8 -0
  37. package/snippets/config-templates/react/offcanvas/offcanvas.jsx +89 -0
  38. package/snippets/config-templates/react/offcanvas/offcanvas.module.scss +109 -0
  39. package/snippets/config-templates/robots.txt +5 -0
  40. package/snippets/config-templates/rollup.config.mjs +115 -0
  41. package/snippets/controllo-codice-fiscale-IT.js +48 -0
  42. package/snippets/controllo-partita-iva-IT.js +32 -0
  43. package/snippets/email-antispam.js +108 -0
  44. package/snippets/error-pages/bundles/TwigBundle/Exception/error.html.twig +33 -0
  45. package/snippets/error-pages/error-pages.js +37 -0
  46. package/snippets/festivita.js +101 -0
  47. package/snippets/minimo-form-layout.html.twig +446 -0
@@ -0,0 +1,37 @@
1
+
2
+
3
+ import { unsplashPageJS } from '@massimo-cassandro/minimo/index.js';
4
+
5
+ const errCode = document.documentElement.dataset.errCode || '500',
6
+ errText = document.documentElement.dataset.errText,
7
+ errors = {
8
+ '403': {
9
+ title: 'Ops, non puoi accedere a questa pagina'
10
+ },
11
+ '404': {
12
+ title: 'Ops, questa pagina non esiste'
13
+ },
14
+ '500': {
15
+ title: 'Ops, si è verificato un errore'
16
+ },
17
+ '503': {
18
+ title: 'Siamo spiacenti, il sito è temporaneamente in manutenzione'
19
+ }
20
+ }
21
+ ,url = '/get-unsplash'
22
+ ;
23
+
24
+ document.title = `Errore ${errCode}`;
25
+
26
+ unsplashPageJS({
27
+ targetElement : document.getElementById('root'),
28
+ className : 'error-page',
29
+ unsplashDataUrl : url,
30
+ utmSource : 'ictgovernance.bluvacanze.it',
31
+ title : errors[errCode]?.title ?? errText,
32
+ text : `(${errCode} ${errText})`,
33
+ backLink : errCode !== '503'? 'Torna alla <a href="/">Home</a>' : '',
34
+ // hidePhotoLink : true,
35
+ // cssModules : false,
36
+ // cssModulesObj : null
37
+ });
@@ -0,0 +1,101 @@
1
+ // TODO festività locali
2
+ // TODO altre ricorrenze (es. festa della mamma, festa del papà, ecc.)
3
+ export default function (returnMode = 'datesOnly', anno) {
4
+
5
+ /*
6
+ restituisce un array con i giorni di festività per l'anno indicato
7
+ le date sono in formato iso YYYY-MM-DD
8
+
9
+ in base al parametro `returnMode` restituisce:
10
+
11
+ - returnMode == 'datesOnly' => un array di date
12
+ - returnMode == 'fullArray' => un array di array, nella forma [[ data, descrizione ], ...]
13
+ - returnMode == 'obj' => un oggetto, nella forma { data: descrizione, ...}
14
+
15
+ ogni elemento dell'array è a sua forma
16
+ [ data, descrizione ]
17
+ */
18
+
19
+ anno = String(anno || new Date().getFullYear() );
20
+
21
+ let festivi = [
22
+ [anno + '-01-01', 'Capodanno'],
23
+ [anno + '-01-06', 'Epifania'],
24
+ [anno + '-04-25', 'Festa della Liberazione'],
25
+ [anno + '-05-01', 'Festa del Lavoro'],
26
+ [anno + '-06-02', 'Festa della Repubblica'],
27
+ [anno + '-08-15', 'Assunzione'],
28
+ [anno + '-11-01', 'Tutti i Santi'],
29
+ [anno + '-12-08', 'Immacolata Concezione'],
30
+ [anno + '-12-25', 'Natale'],
31
+ [anno + '-12-26', 'Santo Stefano']
32
+ ];
33
+
34
+ // pasqua
35
+ // https://www.irt.org/articles/js052/index.htm
36
+ const getEaster = anno => {
37
+
38
+ anno = Number(anno);
39
+
40
+ let C = Math.floor( anno/100 ),
41
+ N = anno - 19 * Math.floor( anno/19 ),
42
+ K = Math.floor((C - 17)/25),
43
+ I = C - Math.floor(C/4) - Math.floor((C - K)/3) + 19 * N + 15
44
+ ;
45
+
46
+ I = I - 30 * Math.floor((I/30));
47
+ I = I - Math.floor(I/28) * (1 - Math.floor(I/28) *
48
+ Math.floor(29/(I + 1)) * Math.floor((21 - N)/11));
49
+
50
+ let J = anno + Math.floor(anno/4) + I + 2 - C + Math.floor(C/4);
51
+ J = J - 7 * Math.floor(J/7);
52
+
53
+ let L = I - J,
54
+ M = 3 + Math.floor((L + 40)/44), // mese
55
+ D = L + 28 - 31*Math.floor(M/4), // giorno
56
+ pasqua = new Date(anno, M-1, D),
57
+ pasquetta = new Date(anno, M-1, D+1)
58
+ ;
59
+
60
+ return [
61
+ [
62
+ pasqua.getFullYear() + '-' +
63
+ String('00' + (pasqua.getMonth() + 1)).slice(-2) + '-' +
64
+ String('00' + pasqua.getDate()).slice(-2),
65
+ 'Pasqua'
66
+ ],
67
+ [
68
+ pasquetta.getFullYear() + '-' +
69
+ String('00' + (pasquetta.getMonth() + 1)).slice(-2) + '-' +
70
+ String('00' + pasquetta.getDate()).slice(-2),
71
+ 'Lunedì dell’Angelo'
72
+ ]
73
+ ];
74
+ };
75
+
76
+ festivi = festivi.concat( getEaster(anno) );
77
+
78
+ festivi.sort( (a,b) => {
79
+ if(a[0] > b[0]) { return 1; }
80
+ if(a[0] < b[0]) { return -1; }
81
+ return 0;
82
+ });
83
+
84
+
85
+ if (returnMode === 'fullArray') {
86
+ return festivi;
87
+
88
+ } else if (returnMode === 'obj') {
89
+ let obj = {};
90
+ festivi.forEach(item => {
91
+ obj[item[0]] = item[1];
92
+ });
93
+ return obj;
94
+
95
+ } else { //returnMode === 'datesOnly')
96
+
97
+ return festivi.map(item => {
98
+ return item[0];
99
+ });
100
+ }
101
+ }
@@ -0,0 +1,446 @@
1
+ {#
2
+ Bootstrap 5 Symfony form layout
3
+ =======================================
4
+ Massimo Cassandro
5
+ https://github.com/massimo-cassandro/symfony-bootstrap-form-theme
6
+ #}
7
+
8
+ {#
9
+ estende il template form base:
10
+ `/vendor/symfony/twig-bridge/Resources/views/Form/form_div_layout.html.twig`(sf6)
11
+ #}
12
+ {% use "form_div_layout.html.twig" %}
13
+
14
+ {# base #}
15
+ {% block form_widget_simple -%}
16
+ {% if type is not defined or type != 'hidden' %}
17
+ {%- if 'form-control-plaintext' in attr.class|default() -%}
18
+ {% set base_class = '' %}
19
+ {%- else -%}
20
+ {% set base_class = 'form-control' ~ (type|default('') == 'file' ? '-file' : '') %}
21
+ {%- endif -%}
22
+ {%- set attr = attr|merge({class: (attr.class|default('') ~ ' ' ~ base_class)|trim}) -%}
23
+ {% endif %}
24
+
25
+ {%- if type is defined and (type == 'range' or type == 'color') %}
26
+ {# Attribute "required" is not supported #}
27
+ {%- set required = false -%}
28
+ {% endif %}
29
+ {{- parent() -}}
30
+ {%- endblock form_widget_simple %}
31
+
32
+
33
+
34
+ {%- block widget_attributes -%}
35
+ {%- if not valid %}
36
+ {% set attr = attr|merge({class: (attr.class|default('') ~ ' is-invalid')|trim}) %}
37
+ {% endif -%}
38
+ {%- if help is defined and help|trim -%}
39
+ {% set attr = attr|merge({'aria-described-by': 'help-text-' ~ id }) %}
40
+ {%- endif -%}
41
+ {{ parent() }}
42
+ {%- endblock widget_attributes -%}
43
+
44
+ {%- block float_widget -%}
45
+ {%- set type = type|default('number') -%}
46
+ {{ block('form_widget_simple') }}
47
+ {%- endblock float_widget -%}
48
+
49
+ {# added 3.0.4 #}
50
+ {%- block url_widget -%}
51
+ {%- set type = 'url' -%}
52
+ {{ block('form_widget_simple') }}
53
+ {%- endblock url_widget -%}
54
+
55
+ {%- block form_errors -%}
56
+ {%- if errors|length > 0 -%}
57
+ <ul class="sf-error">
58
+ {%- for error in errors -%}
59
+ <li>{{ error.message }}</li>
60
+ {%- endfor -%}
61
+ </ul>
62
+ {%- endif -%}
63
+ {%- endblock form_errors -%}
64
+
65
+ {%- block form_help -%}
66
+ {%- if help is defined and help|trim -%}
67
+ <div class="form-help-text" id="help-text-{{ id }}">{{ help|raw }}</div>
68
+ {%- endif -%}
69
+ {%- endblock form_help -%}
70
+
71
+ {% block form_label -%}
72
+
73
+ {% if label is not same as(false) -%}
74
+ {%- if compound is defined and compound -%}
75
+ {%- set element = 'legend' -%}
76
+ {%- set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' form-label')|trim}) -%}
77
+ {%- else -%}
78
+ {%- set label_attr = label_attr|merge({for: id, class: (label_attr.class|default('') ~ ' form-label')|trim}) -%}
79
+
80
+ {%- endif -%}
81
+
82
+ {% if label is empty -%}
83
+ {%- if label_format is not empty -%}
84
+ {% set label = label_format|replace({
85
+ '%name%': name,
86
+ '%id%': id,
87
+ }) %}
88
+ {%- else -%}
89
+ {% set label = name|humanize %}
90
+ {%- endif -%}
91
+ {%- endif -%}
92
+ <{{ element|default('label') }}{% if label_attr %}{% with { attr: label_attr } %}{{ block('attributes') }}{% endwith %}{% endif %}>
93
+ {%- if params.raw_label|default(false) is same as(false) -%}
94
+ {{ translation_domain is same as(false) ? label : label|trans({}, translation_domain) }}
95
+ {%- else -%}
96
+ {{ translation_domain is same as(false) ? label|raw : label|trans({}, translation_domain)|raw }}
97
+ {%- endif -%}
98
+ {# {% block form_label_errors %}{{- form_errors(form) -}}{% endblock form_label_errors %} #}
99
+ </{{ element|default('label') }}>
100
+ {%- endif -%}
101
+
102
+ {%- endblock form_label %}
103
+
104
+ {# Rows #}
105
+ {% block containers_classes -%}
106
+ {%- if disabled is defined and disabled %} disabled{%- endif -%}
107
+ {# {%- if required is defined and required %} required{%- endif -%} #}
108
+ {%- endblock containers_classes %}
109
+
110
+ {% block containers_attrs -%}
111
+ {%- if params is not defined %}
112
+ {% set params = {} %}
113
+ {%- endif -%}
114
+ {%- if params.container_attr is not defined %}
115
+ {% set params = params|merge({container_attr: {}}) %}
116
+ {%- endif -%}
117
+
118
+ {% set params = params|merge({
119
+ container_attr: params.container_attr|merge({ class: (params.container_attr.class|default('') ~ (compound|default()? ' form-collection-fset form-group' : ' form-group'))|trim })
120
+ }) %}
121
+
122
+ {%- if disabled is defined and disabled %}
123
+ {% set params = params|merge({
124
+ container_attr: params.container_attr|merge({ class: (params.container_attr.class|default('') ~ ' disabled')|trim })
125
+ }) %}
126
+ {%- endif -%}
127
+
128
+ {# {%- if required is defined and required %}
129
+ {% set params = params|merge({
130
+ container_attr: params.container_attr|merge({ class: (params.container_attr.class|default('') ~ ' required')|trim })
131
+ }) %}
132
+ {%- endif -%} #}
133
+
134
+ {%- for attr, val in params.container_attr -%}
135
+ {{- ' ' -}} {{- attr -}}="{{ val }}"
136
+ {%- endfor -%}
137
+ {%- endblock containers_attrs %}
138
+
139
+ {% block form_container_start -%}
140
+ <{{ element|default('div') }} {{- block('containers_attrs') -}}>
141
+ {%- endblock form_container_start %}
142
+
143
+ {% block form_container_end -%}
144
+ {{- form_errors(form) -}}
145
+
146
+ {%- if (not compound) or params.multiselect|default() -%}
147
+ {{- block('form_help') -}}
148
+ {%- endif -%}
149
+
150
+ </{{ element|default('div') }}>
151
+ {%- endblock form_container_end %}
152
+
153
+ {% block input_group_elements -%}
154
+ {% set parsed_input_group = [] %}
155
+ {%- if input_group is not iterable -%} {# single string parameter #}
156
+ {% set parsed_input_group = [{type:'text', content: input_group}] %}
157
+ {%- else -%}
158
+ {%- for item in input_group -%}
159
+ {%- if item is not iterable -%} {# array of strings #}
160
+ {% set parsed_input_group = parsed_input_group|merge([
161
+ {type:'text', content: item}
162
+ ]) %}
163
+ {%- else -%} {# array of arrays #}
164
+ {% set parsed_input_group = parsed_input_group|merge([
165
+ item
166
+ ]) %}
167
+ {%- endif -%}
168
+ {%- endfor -%}
169
+ {%- endif -%}
170
+
171
+ {# <div class="input-group-{{ input_group_mode }}"> #}
172
+ {%- for item in parsed_input_group -%}
173
+ {%- if item.type == 'text' -%}
174
+ <span class="input-group-text">{{ item.content }}</span>
175
+ {%- else -%}
176
+ {{ item.content|raw }}
177
+ {%- endif -%}
178
+ {%- endfor -%}
179
+ {# </div> #}
180
+ {%- endblock input_group_elements %}
181
+
182
+ {% block form_row -%}
183
+ {% set params = {
184
+ container: true,
185
+ container_attr: {},
186
+ collection_container: true,
187
+ before: false,
188
+ after: false,
189
+ raw_label: false
190
+ }|merge(params|default({}))
191
+ %}
192
+
193
+
194
+ {%- if compound is defined and compound and params.collection_container -%}
195
+ {%- set element = 'fieldset' -%}
196
+ {%- endif -%}
197
+
198
+ {%- if params.container == true and params.collection_container == true -%}
199
+ {{- block('form_container_start') -}}
200
+ {% endif %}
201
+
202
+ {{- form_label(form) -}}
203
+
204
+ {%- if compound and not params.multiselect|default() -%}
205
+ {{- block('form_help') -}}
206
+ {%- endif -%}
207
+
208
+ {%- if (not params.before) and (not params.after) -%}
209
+ {{- form_widget(form) -}}
210
+ {%- else -%}
211
+ <div class="input-group">
212
+ {%- if params.before -%}
213
+ {# {% set input_group_mode = 'prepend' %} #}
214
+ {% set input_group = params.before %}
215
+ {{- block('input_group_elements') -}}
216
+ {%- endif -%}
217
+
218
+ {{- form_widget(form) -}}
219
+
220
+ {%- if params.after -%}
221
+ {# {% set input_group_mode = 'append' %} #}
222
+ {% set input_group = params.after %}
223
+ {{- block('input_group_elements') -}}
224
+ {%- endif -%}
225
+ </div>
226
+ {%- endif -%}
227
+
228
+ {%- if params.container == true and params.collection_container == true -%}
229
+ {{- block('form_container_end') -}}
230
+ {%- endif -%}
231
+
232
+ {%- endblock form_row %}
233
+
234
+ {# checkboxes and radios #}
235
+ {% block checkbox_widget -%}
236
+ {{ parent() }}
237
+ {%- endblock checkbox_widget %}
238
+ {% block radio_widget -%}
239
+ {{ parent() }}
240
+ {%- endblock radio_widget %}
241
+
242
+ {% block checkbox_radio_row -%}
243
+
244
+ {% set params = {
245
+ container: true,
246
+ container_attr: {},
247
+ collection_container: true,
248
+ bs_custom_control: false,
249
+ top_label: false,
250
+ inline: false,
251
+ switch: false,
252
+ raw_label: false
253
+ }|merge(params|default({})) %}
254
+
255
+
256
+ {# the `top_label` option requires the container #}
257
+ {% if params.top_label %}
258
+ {% set params = params|merge({container: true}) %}
259
+ {% endif %}
260
+
261
+ {# {%- if params.bs_custom_control -%}
262
+ {%- set attr = attr|merge({class: (attr.class|default('') ~ ' custom-control-input')|trim}) -%}
263
+ <div class="custom-control custom-checkbox{{ params.inline ? ' custom-control-inline' }}">
264
+ {{- block( cbox_radio ~ '_widget') -}}
265
+ {{- form_label(form, null, {label_attr: {class:'custom-control-label' ~ (disabled|default()? ' disabled' :'') }}) -}}
266
+ {% if required %}
267
+ <span class="required"></span>
268
+ {% endif %}
269
+ </div>
270
+ {%- elseif params.switch -%} #}
271
+
272
+ {%- if params.switch -%}
273
+ <div class="form-check form-switch">
274
+ {%- set attr = attr|merge({class: (attr.class|default('') ~ ' form-check-input')|trim, role:'switch' }) -%}
275
+ {{- block('checkbox_widget') -}}
276
+ {{- form_label(form, null, {label_attr: {class:'form-check-label' ~ (disabled|default()? ' disabled' :'') }}) -}}
277
+ </div>
278
+ {{- block('form_help') -}}
279
+ {%- else -%}
280
+ {% if params.container %}
281
+ {{ block('form_container_start') }}
282
+ {% endif %}
283
+
284
+ {% if params.top_label %}
285
+ {%- set attr = attr|merge({class: (attr.class|default('') ~ ' form-check-top-label')|trim}) -%}
286
+ {{- form_label(form) -}}
287
+ {{- block( cbox_radio ~ '_widget') -}}
288
+ {% else %}
289
+ {%- set attr = attr|merge({class: (attr.class|default('') ~ ' form-check-input')|trim}) -%}
290
+ <div class="form-check {{- '' -}}
291
+ {# {%- if params.inline %} form-check-inline{% endif -%} #}
292
+ {%- if not (params.collection is defined and params.collection) -%}
293
+ {{- block('containers_classes') -}}
294
+ {%- endif -%}">
295
+ {{- block( cbox_radio ~ '_widget') -}}
296
+ {# {%- set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' form-check-label')|trim}) -%} #}
297
+ {{- form_label(form) -}}
298
+
299
+ </div>
300
+ {% endif %}
301
+
302
+ {% if params.container %}
303
+ {{ block('form_container_end') }}
304
+ {% endif %}
305
+ {%- endif -%}
306
+ {%- endblock checkbox_radio_row %}
307
+
308
+ {% block checkbox_row -%}
309
+ {% set cbox_radio = 'checkbox' %}
310
+ {{- block('checkbox_radio_row') -}}
311
+ {%- endblock checkbox_row %}
312
+
313
+ {% block radio_row -%}
314
+ {% set cbox_radio = 'radio' %}
315
+ {% set params = params|default({})|merge({switch: false, top_label: false}) %}
316
+ {{- block('checkbox_radio_row') -}}
317
+ {%- endblock radio_row %}
318
+
319
+ {# multiple checkbox / radios #}
320
+ {% block choice_widget_expanded -%}
321
+
322
+ {# the params.collection option tells other widgets that we are creating a series of checkboxes or radios #}
323
+ {% set params = {
324
+ bs_custom_control: false,
325
+ collection_container: true,
326
+ inline: false,
327
+ multiselect: false,
328
+ no_items_mes: null
329
+ }|merge(params|default({}))|merge({
330
+ container: false,
331
+ top_label: false,
332
+ collection: true
333
+ })
334
+ %}
335
+ {% set inner_container_classes = '' %}
336
+ {% if not params.collection_container %}
337
+ {% set inner_container_classes = 'form-group' ~ block('containers_classes') %}
338
+ {% endif %}
339
+
340
+ {%- if params.columns is defined and params.columns is iterable and not params.inline -%}
341
+ {# rcolumns classes come from https://github.com/massimo-cassandro/m-utilities #}
342
+ {% set inner_container_classes = inner_container_classes ~ ' rcolumns' %}
343
+ {%- for brkp, cols in params.columns -%}
344
+ {% set inner_container_classes = inner_container_classes ~ " rcolumns-#{brkp}-#{cols}" %}
345
+ {%- endfor -%}
346
+ {%- endif -%}
347
+
348
+ {%- if params.multiselect != false -%}
349
+
350
+ {# multiselect is not compatible with inline option #}
351
+ {% set params = params|merge({ inline:false }) %}
352
+
353
+ {% set params = params|merge({multiselect:
354
+ {
355
+ placeholder: '&nbsp;',
356
+ button_class: 'btn-multiselect',
357
+ menu_class: ''
358
+ }|merge(params.multiselect is iterable? params.multiselect : {})
359
+ }) %}
360
+
361
+ <div class="btn-group form-multiselect">
362
+ <button type="button" class="btn dropdown-toggle
363
+ {%- if params.multiselect.button_class %} {{ params.multiselect.button_class}}{% endif -%}"
364
+ {{- ' ' -}}
365
+ {# data-bs-toggle="dropdown" data-bs-display="static" #} aria-haspopup="true" aria-expanded="false">
366
+ <span class="form-multiselect-placeholder">{{ params.multiselect.placeholder|raw }}</span>
367
+ </button>
368
+ <div class="dropdown-menu
369
+ {%- if params.multiselect.menu_class %} {{ params.multiselect.menu_class}}{% endif -%}">
370
+ {%- endif -%}
371
+
372
+ {% set child_params = {
373
+ translation_domain: choice_translation_domain,
374
+ valid: valid,
375
+ params: params,
376
+ attr:attr|default({})
377
+ }|merge(
378
+ disabled is defined and disabled? {disabled:true}: {}
379
+ )
380
+ %}
381
+ <div class="form-collection
382
+ {%- if inner_container_classes %} {{ inner_container_classes|trim }}{% endif -%}
383
+ {%- if params.inline %} form-collection-inline{% endif -%}"
384
+ {%- if help is defined and help|trim %} aria-described-by="help-text-{{ id }}"{% endif -%}
385
+ >
386
+
387
+ {%- for child in form %}
388
+ {{- form_row(child, child_params ) -}}
389
+ {% else -%}
390
+ {%- if params.no_items_mes -%}
391
+ {{ params.no_items_mes|raw }}
392
+ {%- endif -%}
393
+ {% endfor -%}
394
+
395
+ </div>
396
+
397
+ {%- if params.multiselect != false -%}
398
+ </div> {# /dropdown-menu #}
399
+ </div> {# /btn-group #}
400
+ {%- endif -%}
401
+
402
+ {%- endblock choice_widget_expanded %}
403
+
404
+ {# select no multiple #}
405
+ {%- block choice_widget_collapsed %}
406
+ {% set params = {
407
+ bs_custom_control: true
408
+ }|merge(params|default({}))
409
+ %}
410
+ {% set attr = attr|merge({class: (attr.class|default('') ~ ' form-control')|trim}) %}
411
+ {{- parent() -}}
412
+ {%- endblock choice_widget_collapsed %}
413
+
414
+ {# textarea #}
415
+ {% block textarea_widget -%}
416
+ {% set attr = attr|merge({class: (attr.class|default('') ~ ' form-control')|trim}) %}
417
+ {{- parent() -}}
418
+ {%- endblock textarea_widget %}
419
+
420
+ {#
421
+ {%- block choice_widget_options -%}
422
+ {% for group_label, choice in options %}
423
+ {%- if c<hoice is iterable -%}
424
+ <optgroup label="{{ choice_translation_domain is same as(false) ? group_label : group_label|trans({}, choice_translation_domain) }}">
425
+ {% set options = choice %}
426
+ {{- block('choice_widget_options') -}}
427
+ </optgroup>
428
+ {%- else -%}
429
+ <option value="{{ choice.value }}"{% if choice.attr %}{% with { attr: choice.attr } %}{{ block('attributes') }}{% endwith %}{% endif %}{% if not render_preferred_choices|default(false) and choice is selectedchoice(value) %} selected="selected"{% endif %}>{{ choice_translation_domain is same as(false) ? choice.label : choice.label|trans(choice.labelTranslationParameters, choice_translation_domain) }}</option>
430
+ {%- endif -%}>
431
+ {% endfor %}
432
+ {%- endblock choice_widget_options -%}
433
+
434
+
435
+ {% block attributes -%}
436
+ {%- for attrname, attrvalue in attr -%}
437
+ {{- " " -}}
438
+ {%- if attrname in ['placeholder', 'title'] -%}
439
+ {{- attrname }}="{{ translation_domain is same as(false) or attrvalue is null ? attrvalue : attrvalue|trans(attr_translation_parameters, translation_domain) }}"
440
+ {%- elseif attrvalue is same as(true) -%}
441
+ {{- attrname }}="{{ attrname }}"
442
+ {%- elseif attrvalue is not same as(false) -%}
443
+ {{- attrname }}="{{ attrvalue }}"
444
+ {%- endif -%}
445
+ {%- endfor -%}
446
+ {%- endblock attributes -%} #}