3 * Copyright © 2003-2024 The Galette Team
5 * This file is part of Galette (https://galette.eu).
7 * Galette is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * Galette is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Galette. If not, see <http://www.gnu.org/licenses/>.
21 {% if object.getDynamicFields() is not empty %}
22 {% set fields = object.getDynamicFields().getFields() %}
23 {% set masschange = masschange ?? false %}
25 {% if fields is not empty %}
27 {% macro draw_field(field, field_data, disabled, loop, object, masschange) %}
28 {% set valuedata = field_data.field_val|escape %}
29 {% if get_class(field) == 'Galette\\DynamicFields\\File' %}
30 <label>{{ field.getName()|escape }}</label>
32 <label for="info_field_{{ field.getId() }}_{{ loop }}">
34 {# Add a checkbox for fields to change on mass edition #}
35 <input type="checkbox" name="mass_info_field_{{ field.getId() }}" class="mass_checkbox"/>
37 {{ field.getName()|escape }}
40 {% if field.getInformation() and field.hasInformationAbove() %}
41 <div class="exemple">{{ field.getInformation()|raw }}</div>
43 {% if get_class(field) == 'Galette\\DynamicFields\\Text' %}
44 <textarea name="info_field_{{ field.getId() }}_{{ loop }}" id="info_field_{{ field.getId() }}_{{ loop }}"
45 cols="{% if field.getWidth() > 0 %}{{ field.getWidth() }}{% else %}61{% endif %}"
46 rows="{% if field.getHeight() > 0 %}{{ field.getHeight() }}{% else %}6{% endif %}"
47 {% if field.isRepeatable() %} data-maxrepeat="{{ field.getRepeat() }}"{% endif %}
48 {% if not masschange %}
49 {% if field.isRequired() %} required="required"{% endif %}
51 {% if disabled %} disabled="disabled"{% endif %}>{{ valuedata|raw }}</textarea>
52 {% elseif get_class(field) == 'Galette\\DynamicFields\\Line' %}
53 <input type="text" name="info_field_{{ field.getId() }}_{{ loop }}" id="info_field_{{ field.getId() }}_{{ loop }}"
54 {% if field.getWidth() > 0 %}size="{{ field.getWidth() }}"{% endif %}
55 {% if field.getSize() > 0 %}maxlength="{{ field.getSize() }}"{% endif %}
56 {% if field.getMinSize() > 0 %}minlength="{{ field.getMinSize() }}"{% endif %}
57 value="{{ valuedata|raw }}"
58 {% if not masschange %}
59 {% if field.isRequired() %} required="required"{% endif %}
61 {% if field.isRepeatable() or field.getRepeat() == 0 %}data-maxrepeat="{{ field.getRepeat() }}"{% endif %}
62 {% if disabled %} disabled="disabled"{% endif %}
64 {% elseif get_class(field) == 'Galette\\DynamicFields\\Choice' %}
65 <select name="info_field_{{ field.getId() }}_{{ loop }}" id="info_field_{{ field.getId() }}_{{ loop }}"
66 {% if not masschange %}
67 {% if field.isRequired() %} required="required"{% endif %}
69 {% if field.isRepeatable() %} data-maxrepeat="{{ field.getRepeat() }}"{% endif %}
70 {% if disabled %} disabled="disabled"{% endif %}
72 <!-- If no option is present, page is not XHTML compliant -->
73 <option value="">{{ _T("Select an option") }}</option>
74 {% for key, value in field.getValues() %}
75 <option value="{{ key }}"{% if key == valuedata %} selected="selected"{% endif %}>{{ value }}</option>
78 {% elseif get_class(field) == 'Galette\\DynamicFields\\Date' %}
79 <div id="dynamic_date_{{ field.getId() }}_rangestart" class="ui calendar">
80 <div class="ui fluid input left icon">
81 <i class="calendar icon" aria-hidden="true"></i>
82 <input type="text" name="info_field_{{ field.getId() }}_{{ loop }}" id="info_field_{{ field.getId() }}_{{ loop }}" maxlength="10"
83 value="{{ valuedata }}" class="dynamic_date modif_date" placeholder="{{ _T("yyyy-mm-dd format") }}"
84 {% if field.isRepeatable() %} data-maxrepeat="{field.getRepeat()}"{% endif %}
85 {% if not masschange %}
86 {% if field.isRequired() %} required="required"{% endif %}
88 {% if disabled %} disabled="disabled"{% endif %}
92 {% elseif get_class(field) == 'Galette\\DynamicFields\\Boolean' %}
93 <div class="ui toggle checkbox">
94 <input type="checkbox" name="info_field_{{ field.getId() }}_{{ loop }}" id="info_field_{{ field.getId() }}_{{ loop }}" value="1"
95 {% if valuedata == 1%} checked="checked"{% endif %}
96 {% if field.isRepeatable() %} data-maxrepeat="{{ field.getRepeat() }}"{% endif %}
97 {% if not masschange %}
98 {% if field.isRequired() %} required="required"{% endif %}
100 {% if disabled %} disabled="disabled"{% endif %}
103 {% elseif get_class(field) == 'Galette\\DynamicFields\\File' %}
104 {% if object.id and valuedata %}
105 <a href="{{ url_for("getDynamicFile", {"form_name": object.getFormName(), "id": object.id, "fid": field.getId(), "pos": loop, "name": valuedata}) }}">
107 <i class="external alternate icon" aria-hidden="true"></i>
110 <div class="extra ui basic fitted segment">
111 <div class="ui file action input">
114 name="info_field_{{ field.getId() }}_{{ loop }}"
115 id="info_field_{{ field.getId() }}_{{ loop }}_new"
116 {% if field.isRequired() and valuedata == '' %} required="required"{% endif %}
117 {% if disabled %} disabled="disabled"{% endif %}
119 <label for="info_field_{{ field.getId() }}_{{ loop }}_new" class="ui button">
120 <i class="blue upload icon" aria-hidden="true"></i>
121 {% if object.id and valuedata %}{{ _T("Choose another file") }}{% else %}{{ _T("Choose a file") }}{% endif %}
125 {% if object.id and valuedata %}
126 <div class="extra ui basic fitted segment">
127 <div class="ui toggle checkbox">
130 name="info_field_{{ field.getId() }}_{{ loop }}"
131 id="info_field_{{ field.getId() }}_{{ loop }}_delete"
132 onclick="this.form.info_field_{{ field.getId() }}_{{ loop }}_new.disabled = this.checked;"
134 <label class="labelalign" for="info_field_{{ field.getId() }}_{{ loop }}_delete">
141 {% if field.getInformation() and not field.hasInformationAbove() %}
142 <div class="exemple">{{ field.getInformation()|raw }}</div>
146 <div class="ui styled fluid accordion field">
147 <div class="active title">
148 <i class="jsonly displaynone icon dropdown" aria-hidden="true"></i>
149 {{ _T("Additionnal fields:") }}
151 <div class="active content field">
152 <div class="ui{% if preferences.pref_member_form_grid is defined %} {{ preferences.pref_member_form_grid }}{% endif %} column stackable grid">
153 {% set access_level = login.getAccessLevel() %}
154 {% for field in fields %}
155 {% set perm = field.getPermission() %}
156 {% if get_class(field) == 'Galette\\DynamicFields\\Separator' %}
157 <div class="sixteen wide column">
158 <div class="ui horizontal divider">{{ field.getName()|escape }}</div>
160 {% elseif (get_class(field) == 'Galette\\DynamicFields\\File' or field.isRepeatable()) and masschange %}
161 <!-- File and repeatable fields not shown in mass changes form -->
163 {% set disabled = false %}
164 {% if perm == constant('Galette\\Entity\\FieldsConfig::USER_READ') and access_level == constant('Galette\\Core\\Authentication::ACCESS_USER') %}
165 {% set disabled = true %}
167 {% set values = object.getDynamicFields().getValues(field.getId()) %}
168 {# set can_add = false %}
169 {% if field.getRepeat() == 0 or values is not iterable or values|length < field.getRepeat() or values|length == 0 %}
170 {% set can_add = true %}
172 {% if get_class(field) == 'Galette\\DynamicFields\\File' or (field.isRepeatable() and field.getRepeat() > 1) or (field.isMultiValued() and field.getRepeat() == 0) %}
173 {% set columns = 'sixteen wide ' %}
174 {% elseif field.getWidthInForms() == 1 or (preferences.pref_member_form_grid == 'two' and field.getWidthInForms() == 3) %}
175 {% set columns = '' %}
177 {% set columns = (field.getWidthInForms() == 3) ? 'eight wide ' : 'sixteen wide ' %}
180 {% if get_class(field) == 'Galette\\DynamicFields\\File' or (field.isRepeatable() and field.getRepeat() > 1) or (field.isMultiValued() and field.getRepeat() == 0) %}
181 repetable {% endif %}{{ columns }}column">
182 {% for field_data in values %}
183 <div class="field{% if field.isRequired() %} required{% endif %}{% if get_class(field) == 'Galette\\DynamicFields\\File' %} wide{% endif %}">
184 {{ _self.draw_field(field, field_data, disabled, loop.index, object, masschange) }}
187 {% if values is not iterable or values|length == 0 %}
188 {% set field_data = {'field_val': ''} %}
189 {% if values is iterable %}
190 {% set current_count = values|length %}
192 {% set current_count = 0 %}
194 {{ _self.draw_field(field, field_data, disabled, current_count + 1, object, masschange) }}
196 {% if field.isRepeatable() %}
197 {% if field.getRepeat() == 0 %}
198 <p class="exemple" id="repeat_msg">{{ _T("Enter as many occurences you want.") }}</p>
199 {% elseif values is not iterable or values|length < field.getRepeat() or values|length == 0 %}
200 {% if values is iterable %}
201 {% set current_count = values|length %}
203 {% set current_count = 1 %}
205 {% set remaining = field.getRepeat() - current_count %}
206 <p class="exemple" id="repeat_msg">{{ _T("Enter up to %count more occurences.")|replace({"%count": remaining}) }}</p>
215 {% if not masschange %}
216 <script type="text/javascript">
217 var _addLnk = function(){
218 return $('<a class="ui tiny green labeled icon button" href="#"><i class="plus icon" aria-hidden="true"></i> {{ _T("Add") }}</a>');
221 var _lnkEvent = function(_a, _input, _parent) {
222 var _vals = _input[0].id.split(/_/);
223 var _total = $(_input[0]).data('maxrepeat'); //max number of occurrences
224 var _current = _vals[_vals.length-1]; //current occurrence
226 _a.click(function(e) {
227 var _new = _input.clone();
231 for ( var i = 0 ; i < _vals.length -1 ; i++ ) {
232 _id += _vals[i] + '_';
235 _current = Number(_current) + 1;
236 _new.attr('id', _id + _current);
237 _new.attr('name', _id + _current);
240 _parent.append(_new);
241 _parent.append('<br/><br/>');
243 if( _total == '0' || _current < _total ) {
245 _lnkEvent(_b, _new, _parent);
247 if (_current < _total) {
248 $('#repeat_msg').html('{{ _T("Enter up to %count more occurrences.")|replace({"%count": "COUNT"})|e('js') }}'.replace(/COUNT/, _total - _current));
250 } else if (_current == _total) {
251 $('#repeat_msg').remove();
258 $('.repetable').each(function(){
261 var _parent = $(this);
263 var _input = $(this).find('.field:last input');
264 if ( _input.length > 0 ) {
265 while ( $(this).find('.field').length > 1 && _input.val() == '' ) {
267 _input = $(this).find('.field:last input')
269 var _vals = _input[0].id.split(/_/);
270 var _total = $(_input[0]).data('maxrepeat'); //max number of occurrences
271 var _current = _vals[_vals.length-1]; //current occurrence
273 if ( _total == '0' || _current < _total ) {
276 _lnkEvent(_a, _input, _parent);