vendor/easycorp/easyadmin-bundle/src/Resources/views/crud/form_theme.html.twig line 737

Open in your IDE?
  1. {# @var ea \EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext #}
  2. {% use '@EasyAdmin/symfony-form-themes/bootstrap_5_layout.html.twig' %}
  3. {% block form_start %}
  4.     {% if form.vars.errors|length > 0 and 'ea_crud' in form.vars.block_prefixes|default([]) %}
  5.         {{ form_errors(form, {attr: { class: 'global-invalid-feedback' }}) }}
  6.     {% endif %}
  7.     {{ parent() }}
  8.     {% if ea.request.query.get('referrer')  %}
  9.         <input type="hidden" name="referrer" value="{{ ea.request.query.get('referrer') }}">
  10.     {% endif %}
  11. {% endblock form_start %}
  12. {% block form_end %}
  13.         {% if not render_rest is defined or render_rest %}
  14.             {{ form_rest(form) }}
  15.         {% endif %}
  16.     </form>
  17. {% endblock %}
  18. {% block form_errors %}
  19.     {% if errors|length > 0 %}
  20.         {% for error in errors %}
  21.             <div class="{{ attr.class|default('') }} invalid-feedback d-block">{{ error.message }}</div>
  22.         {% endfor %}
  23.     {% endif %}
  24. {% endblock form_errors %}
  25. {# Widgets #}
  26. {% block form_widget_simple -%}
  27.     {% if type is not defined or type not in ['file', 'hidden'] %}
  28.         {%- set attr = attr|merge({class: (attr.class|default(''))|trim}) -%}
  29.     {% endif %}
  30.     {%- if type is defined and (type == 'range' or type == 'color') %}
  31.         {# Attribute "required" is not supported #}
  32.         {%- set required = false -%}
  33.     {% endif %}
  34.     {{- parent() -}}
  35. {%- endblock form_widget_simple %}
  36. {% block datetime_widget %}
  37.     {% set attr = attr|merge({class: (attr.class|default('') ~ ' form-inline')|trim}) %}
  38.     <div class="datetime-widget datetime-widget-datetime">
  39.         {{- parent() -}}
  40.     </div>
  41. {% endblock datetime_widget %}
  42. {% block date_widget -%}
  43.     <div class="datetime-widget datetime-widget-date">
  44.         {{- parent() -}}
  45.     </div>
  46. {%- endblock date_widget %}
  47. {% block time_widget -%}
  48.     <div class="datetime-widget datetime-widget-time">
  49.         {{- parent() -}}
  50.     </div>
  51. {%- endblock time_widget %}
  52. {% block file_widget -%}
  53.     {% if vich|default(false) %}
  54.         {%- set type = type|default('file') -%}
  55.         {{- block('form_widget_simple') -}}
  56.     {% else %}
  57.         {{- block('form_widget_simple') -}}
  58.     {% endif %}
  59. {%- endblock %}
  60. {# Rows #}
  61. {% block form_row %}
  62.     {% set row_attr = row_attr|merge({
  63.         class: row_attr.class|default('') ~ ' form-group'
  64.     }) %}
  65.     {%  set field = form.vars.ea_vars.field %}
  66.     <div class="{{ field.columns ?? field.defaultColumns ?? '' }}">
  67.         <div {% with { attr: row_attr } %}{{ block('attributes') }}{% endwith %}>
  68.             {{- form_label(form) -}}
  69.             <div class="form-widget">
  70.                 {% set has_prepend_html = field.prepend_html|default(null) is not null %}
  71.                 {% set has_append_html = field.append_html|default(null) is not null %}
  72.                 {% set has_input_groups = has_prepend_html or has_append_html %}
  73.                 {% if has_input_groups %}<div class="input-group">{% endif %}
  74.                     {% if has_prepend_html %}
  75.                         <div class="input-group-prepend">
  76.                             <span class="input-group-text">{{ field.prepend_html|raw }}</span>
  77.                         </div>
  78.                     {% endif %}
  79.                     {{ form_widget(form) }}
  80.                     {% if has_append_html %}
  81.                         <span class="input-group-text">{{ field.append_html|raw }}</span>
  82.                     {% endif %}
  83.                 {% if has_input_groups %}</div>{% endif %}
  84.                 {% if field.help ?? false %}
  85.                     <small class="form-text form-help">{{ field.help|trans(label_translation_parameters, translation_domain)|raw }}</small>
  86.                 {% elseif form.vars.help ?? false %}
  87.                     <small class="form-text form-help">{{ form.vars.help|trans(form.vars.help_translation_parameters, form.vars.translation_domain)|raw }}</small>
  88.                 {% endif %}
  89.                 {{- form_errors(form) -}}
  90.             </div>
  91.         </div>
  92.     </div>
  93.     {# if a field doesn't define its columns explicitly, insert a fill element to make the field take the entire row space #}
  94.     {% if field.columns|default(null) is null %}
  95.         <div class="flex-fill"></div>
  96.     {% endif %}
  97. {% endblock form_row %}
  98. {% block choice_widget_collapsed %}
  99.     {% if 'ea-autocomplete' == attr['data-ea-widget']|default(false) %}
  100.         {% set attr = attr|merge({
  101.             'data-ea-i18n-no-results-found': 'autocomplete.no-results-found'|trans({}, 'EasyAdminBundle'),
  102.             'data-ea-i18n-no-more-results': 'autocomplete.no-more-results'|trans({}, 'EasyAdminBundle'),
  103.             'data-ea-i18n-loading-more-results': 'autocomplete.loading-more-results'|trans({}, 'EasyAdminBundle'),
  104.         }) %}
  105.     {% endif %}
  106.     {{ parent() }}
  107. {% endblock choice_widget_collapsed %}
  108. {% block collection_row %}
  109.     {% if prototype is defined and not prototype.rendered %}
  110.         {% set row_attr = row_attr|merge({ 'data-prototype': form_row(prototype) }) %}
  111.     {% endif %}
  112.     {% set row_attr = row_attr|merge({
  113.         'data-ea-collection-field': 'true',
  114.         'data-entry-is-complex': form.vars.ea_vars.field and form.vars.ea_vars.field.customOptions.get('entryIsComplex') ? 'true' : 'false',
  115.         'data-allow-add': allow_add ? 'true' : 'false',
  116.         'data-allow-delete': allow_delete ? 'true' : 'false',
  117.         'data-num-items': form.children is empty ? 0 : max(form.children|keys) + 1,
  118.         'data-form-type-name-placeholder': prototype is defined ? prototype.vars.name : '',
  119.     }) %}
  120.     {{ block('form_row') }}
  121. {% endblock collection_row %}
  122. {% block collection_widget %}
  123.     {# the "is iterable" check is needed because if an object implements __toString() and
  124.                returns an empty string, "is empty" returns true even if it's not a collection #}
  125.     {% set isEmptyCollection = value is null or (value is iterable and value is empty) %}
  126.     {% set is_array_field = 'EasyCorp\\Bundle\\EasyAdminBundle\\Field\\ArrayField' == form.vars.ea_vars.field.fieldFqcn ?? false %}
  127.     <div class="ea-form-collection-items">
  128.         {% if isEmptyCollection %}
  129.             {{ block('empty_collection') }}
  130.         {% elseif is_array_field %}
  131.             {{ block('form_widget') }}
  132.         {% else %}
  133.             <div class="accordion">
  134.                 {{ block('form_widget') }}
  135.             </div>
  136.         {% endif %}
  137.     </div>
  138.     {% if isEmptyCollection or form.vars.prototype is defined %}
  139.         {% set attr = attr|merge({'data-empty-collection': block('empty_collection') }) %}
  140.     {% endif %}
  141.     {% if allow_add|default(false) and not disabled %}
  142.         <button type="button" class="btn btn-link field-collection-add-button">
  143.             <i class="fa fa-plus pr-1"></i>
  144.             {{ 'action.add_new_item'|trans({}, 'EasyAdminBundle') }}
  145.         </button>
  146.     {% endif %}
  147. {% endblock collection_widget %}
  148. {% block collection_entry_row %}
  149.     {% set is_array_field = 'EasyCorp\\Bundle\\EasyAdminBundle\\Field\\ArrayField' == form_parent(form).vars.ea_vars.field.fieldFqcn ?? false %}
  150.     {% set is_complex = form_parent(form).vars.ea_vars.field.customOptions.get('entryIsComplex') ?? false %}
  151.     {% set allows_deleting_items = form_parent(form).vars.allow_delete|default(false) %}
  152.     {% set render_expanded = form_parent(form).vars.ea_vars.field.customOptions.get('renderExpanded') ?? false %}
  153.     {% set delete_item_button %}
  154.         <button type="button" class="btn btn-link btn-link-danger field-collection-delete-button"
  155.                 title="{{ 'action.remove_item'|trans({}, 'EasyAdminBundle') }}">
  156.             <i class="far fa-trash-alt"></i>
  157.         </button>
  158.     {% endset %}
  159.     <div class="field-collection-item {{ is_complex ? 'field-collection-item-complex' }} {{ not form.vars.valid ? 'is-invalid' }}">
  160.         {% if is_array_field|default(false) %}
  161.             {{ form_label(form) }}
  162.             {{ form_widget(form) }}
  163.             {% if allows_deleting_items and not disabled %}
  164.                 {{ delete_item_button }}
  165.             {% endif %}
  166.         {% else %}
  167.             <div class="accordion-item">
  168.                 <h2 class="accordion-header">
  169.                     <button class="accordion-button {{ render_expanded ? '' : 'collapsed' }}" type="button" data-bs-toggle="collapse" data-bs-target="#{{ id }}-contents">
  170.                         <i class="fas fw fa-chevron-right form-collection-item-collapse-marker"></i>
  171.                         {{ value|ea_as_string }}
  172.                     </button>
  173.                     {% if allows_deleting_items and not disabled %}
  174.                         {{ delete_item_button }}
  175.                     {% endif %}
  176.                 </h2>
  177.                 <div id="{{ id }}-contents" class="accordion-collapse collapse {{ render_expanded ? 'show' }}">
  178.                     <div class="accordion-body">
  179.                         <div class="row">
  180.                             {{ form_widget(form) }}
  181.                         </div>
  182.                     </div>
  183.                 </div>
  184.             </div>
  185.         {% endif %}
  186.     </div>
  187. {% endblock collection_entry_row %}
  188. {% block form_widget_compound %}
  189.     <div class="form-widget-compound">
  190.         {% if 'collection' in block_prefixes %}
  191.             {# the "is iterable" check is needed because if an object implements __toString() and
  192.                returns an empty string, "is empty" returns true even if it's not a collection #}
  193.             {% set isEmptyCollection = value is null or (value is iterable and value is empty) %}
  194.             {% if isEmptyCollection %}
  195.                 {{ block('empty_collection') }}
  196.             {% endif %}
  197.             {% if isEmptyCollection or form.vars.prototype is defined %}
  198.                 {% set attr = attr|merge({'data-empty-collection': block('empty_collection') }) %}
  199.             {% endif %}
  200.         {% endif %}
  201.         {{ parent() }}
  202.     </div>
  203. {% endblock form_widget_compound %}
  204. {% block button_row -%}
  205.     <div class="form-group field-{{ block_prefixes|slice(-2)|first }} {{ ea.field.css_class|default('') }}">
  206.         {{- form_widget(form) -}}
  207.     </div>
  208. {%- endblock button_row %}
  209. {# Labels #}
  210. {% block form_label -%}
  211.     {% if label is same as(false) -%}
  212.         {# don't display anything, not even an empty <label> element; if you want to not display
  213.            any label contents but keep the form layout, use an empty string as the field label #}
  214.     {%- else -%}
  215.         {%- if compound is defined and compound -%}
  216.             {%- set element = 'legend' -%}
  217.             {%- set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' col-form-label')|trim}) -%}
  218.         {%- else -%}
  219.             {%- set label_attr = label_attr|merge({for: id, class: (label_attr.class|default('') ~ ' form-control-label')|trim}) -%}
  220.         {%- endif -%}
  221.         {% if required -%}
  222.             {% set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' required')|trim}) %}
  223.         {%- endif -%}
  224.         {% if label is same as('') -%}
  225.             {# don't process the label; this is used to not display any label content
  226.                but render an empty <label> element keep the form layout #}
  227.         {%- elseif label is null -%}
  228.             {%- if label_format is not empty -%}
  229.                 {% set label = label_format|replace({
  230.                     '%name%': name,
  231.                     '%id%': id,
  232.                 }) %}
  233.             {%- else -%}
  234.                 {% set label = name|humanize %}
  235.             {%- endif -%}
  236.         {%- endif -%}
  237.         <{{ element|default('label') }}{% if label_attr %}{% with { attr: label_attr } %}{{ block('attributes') }}{% endwith %}{% endif %}>
  238.         {%- if translation_domain is same as(false) -%}
  239.             {%- if label_html|default(false) is same as(false) -%}
  240.                 {{- label -}}
  241.             {%- else -%}
  242.                 {{- label|raw -}}
  243.             {%- endif -%}
  244.         {%- else -%}
  245.             {%- if label_html|default(false) is same as(false) -%}
  246.                 {{- label|trans(label_translation_parameters, translation_domain) -}}
  247.             {%- else -%}
  248.                 {{- label|trans(label_translation_parameters, translation_domain)|raw -}}
  249.             {%- endif -%}
  250.         {%- endif -%}
  251.         </{{ element|default('label') }}>
  252.     {%- endif -%}
  253. {%- endblock form_label %}
  254. {# Errors #}
  255. {% block empty_collection %}
  256.     <div class="empty collection-empty">
  257.         {{ include(ea.templatePath('label/empty')) }}
  258.     </div>
  259. {% endblock empty_collection %}
  260. {% block vich_file_row %}
  261.     {% set force_error = true %}
  262.     {{ block('form_row') }}
  263. {% endblock %}
  264. {% block vich_file_widget %}
  265.     <div class="ea-vich-file">
  266.         {% if download_uri|default('') is not empty %}
  267.             {% set file_extension = download_uri|split('.')|last %}
  268.             {% set extension_icons = {
  269.                 'gif': 'fa-file-image-o',
  270.                 'jpg': 'fa-file-image-o',
  271.                 'pdf': 'fa-file-pdf-o',
  272.                 'png': 'fa-file-image-o',
  273.                 'zip': 'fa-file-archive-o'
  274.             } %}
  275.             <a class="ea-vich-file-name" href="{{ asset_helper is same as(true) ? asset(download_uri) : download_uri }}">
  276.                 <i class="fa fa-fw {{ extension_icons[file_extension] ?? 'fa-file-o' }}"></i>
  277.                 {%- if download_label|default(false) -%}
  278.                     {{ download_label|trans({}, 'VichUploaderBundle') }}
  279.                 {%- else -%}
  280.                     {{ download_uri|split('/')|last ?: 'download'|trans({}, 'VichUploaderBundle') }}
  281.                 {%- endif -%}
  282.             </a>
  283.         {% endif %}
  284.         {% set file_upload_js %}
  285.             var newFile = document.getElementById('{{ form.file.vars.id }}').files[0];
  286.             var fileSizeInMegabytes = newFile.size > 1024 * 1024;
  287.             var fileSize = fileSizeInMegabytes ? newFile.size / (1024 * 1024) : newFile.size / 1024;
  288.             document.getElementById('{{ form.file.vars.id }}_new_file_name').innerText = newFile.name + ' (' + fileSize.toFixed(2) + ' ' + (fileSizeInMegabytes ? 'MB' : 'KB') + ')';
  289.         {% endset %}
  290.         <div class="ea-vich-file-actions">
  291.             {# the container element is needed to allow customizing the <input type="file" /> #}
  292.             <div class="btn btn-secondary input-file-container">
  293.                 <i class="fa fa-fw fa-upload"></i> {{ 'action.choose_file'|trans({}, 'EasyAdminBundle') }}
  294.                 {{ form_widget(form.file, { 'attr': { 'onchange': file_upload_js }, vich: true}) }}
  295.             </div>
  296.             {% if form.delete is defined %}
  297.                 {{ form_row(form.delete) }}
  298.             {% endif %}
  299.         </div>
  300.         <div class="small" id="{{ form.file.vars.id }}_new_file_name"></div>
  301.     </div>
  302. {% endblock %}
  303. {% block vich_image_row %}
  304.     {% set force_error = true %}
  305.     {{ block('form_row') }}
  306. {% endblock %}
  307. {% block vich_image_widget %}
  308.     {% set formTypeOptions = ea_vars.field.formTypeOptions|default('') %}
  309.     <div class="ea-vich-image">
  310.         {% if image_uri|default('') is not empty %}
  311.             {% if download_uri|default('') is empty %}
  312.                 <div class="ea-lightbox-thumbnail">
  313.                     {% if formTypeOptions.imagine_pattern is defined and formTypeOptions.imagine_pattern is not empty %}
  314.                         <img style="cursor: initial" src="{{ (asset_helper is same as(true) ? asset(image_uri) : image_uri)|ea_apply_filter_if_exists('imagine_filter', formTypeOptions.imagine_pattern) }}">
  315.                     {% else %}
  316.                         <img style="cursor: initial" src="{{ asset_helper is same as(true) ? asset(image_uri) : image_uri }}">
  317.                     {% endif %}
  318.                 </div>
  319.             {% else %}
  320.                 {% set _lightbox_id = 'ea-lightbox-' ~ id %}
  321.                 <a href="#" class="ea-lightbox-thumbnail" data-ea-lightbox-content-selector="#{{ _lightbox_id }}">
  322.                     {% if formTypeOptions.imagine_pattern is defined and formTypeOptions.imagine_pattern is not empty %}
  323.                         <img src="{{ (asset_helper is same as(true) ? asset(download_uri) : download_uri)|ea_apply_filter_if_exists('imagine_filter', formTypeOptions.imagine_pattern) }}">
  324.                     {% else %}
  325.                         <img src="{{ asset_helper is same as(true) ? asset(download_uri) : download_uri }}">
  326.                     {% endif %}
  327.                 </a>
  328.                 <div id="{{ _lightbox_id }}" class="ea-lightbox">
  329.                     {% if formTypeOptions.imagine_pattern is defined and formTypeOptions.imagine_pattern is not empty %}
  330.                         <img src="{{ (asset_helper is same as(true) ? asset(download_uri) : download_uri)|ea_apply_filter_if_exists('imagine_filter', formTypeOptions.imagine_pattern) }}">
  331.                     {% else %}
  332.                         <img src="{{ asset_helper is same as(true) ? asset(download_uri) : download_uri }}">
  333.                     {% endif %}
  334.                 </div>
  335.             {% endif %}
  336.         {% endif %}
  337.         {% set file_upload_js %}
  338.             var newFile = document.getElementById('{{ form.file.vars.id }}').files[0];
  339.             var fileSizeInMegabytes = newFile.size > 1024 * 1024;
  340.             var fileSize = fileSizeInMegabytes ? newFile.size / (1024 * 1024) : newFile.size / 1024;
  341.             document.getElementById('{{ form.file.vars.id }}_new_file_name').innerText = newFile.name + ' (' + fileSize.toFixed(2) + ' ' + (fileSizeInMegabytes ? 'MB' : 'KB') + ')';
  342.         {% endset %}
  343.         <div class="ea-vich-image-actions">
  344.             {# the container element is needed to allow customizing the <input type="file" /> #}
  345.             <div class="btn btn-secondary input-file-container">
  346.                 <i class="fa fa-fw fa-upload"></i> {{ 'action.choose_file'|trans({}, 'EasyAdminBundle') }}
  347.                 {{ form_widget(form.file, { 'attr': { 'onchange': file_upload_js }, vich: true}) }}
  348.             </div>
  349.             {% if form.delete is defined %}
  350.                 {{ form_row(form.delete) }}
  351.             {% endif %}
  352.         </div>
  353.         <div class="small" id="{{ form.file.vars.id }}_new_file_name"></div>
  354.     </div>
  355. {% endblock %}
  356. {% block ea_crud_rest %}
  357.     {{ form_rest(form) }}
  358. {% endblock ea_crud_rest %}
  359. {# EasyAdmin form type #}
  360. {% block ea_crud_widget %}
  361.     {% for field in form %}
  362.         {{ form_row(field) }}
  363.     {% endfor %}
  364. {% endblock ea_crud_widget %}
  365. {# TODO: remove this when "form panels" are removed #}
  366. {% block ea_crud_widget_panels %}
  367.     {% deprecated 'The "ea_crud_widget_panels" block is deprecated because the form layout building logic has been revamped. Check "ea_crud_widget" block in `form_theme.html.page` for more details.' %}
  368.     {{ block('ea_crud_widget_fieldsets') }}
  369. {% endblock ea_crud_widget_panels %}
  370. {% block ea_crud_widget_fieldsets %}
  371.     {% deprecated 'The "ea_crud_widget_fieldsets" block is deprecated because the form layout building logic has been revamped. Check "ea_crud_widget" block in `form_theme.html.page` for more details.' %}
  372.     {% for fieldset_name, fieldset_config in field.vars.ea_crud_form.form_fieldsets|filter(fieldset_config => not fieldset_config.form_tab or fieldset_config.form_tab == tab_name) %}
  373.         {% set fieldset_has_header = fieldset_config.label|default(false) or fieldset_config.icon|default(false) or fieldset_config.help|default(false) %}
  374.         {% set collapsible = fieldset_config.collapsible %}
  375.         {% set collapsed = fieldset_config.collapsed %}
  376.         <div class="{{ fieldset_config.css_class ?? '' }}">
  377.             <fieldset class="form-fieldset">
  378.                 {% if fieldset_has_header %}
  379.                     <div class="form-fieldset-header {{ collapsible ? 'collapsible' }} {{ fieldset_config.help|default(false) is not empty ? 'with-help' }}">
  380.                         <div class="form-fieldset-title">
  381.                             <a {% if not collapsible %}
  382.                                 href="#" class="not-collapsible"
  383.                             {% else %}
  384.                                 href="#content-{{ fieldset_name }}" data-bs-toggle="collapse"
  385.                                 class="form-fieldset-collapse {{ collapsed ? 'collapsed' }}"
  386.                                 aria-expanded="{{ collapsed ? 'false' : 'true' }}" aria-controls="content-{{ fieldset_name }}"
  387.                             {% endif %}
  388.                             >
  389.                                 {% if collapsible %}
  390.                                     <i class="fas fw fa-chevron-right form-fieldset-collapse-marker"></i>
  391.                                 {% endif %}
  392.                                 {% if fieldset_config.icon|default(false) %}
  393.                                     <i class="form-fieldset-icon {{ fieldset_config.icon }}"></i>
  394.                                 {% endif %}
  395.                                 {{ fieldset_config.label|trans|raw }}
  396.                             </a>
  397.                             {% if fieldset_config.help|default(false) %}
  398.                                 <div class="form-fieldset-help">{{ fieldset_config.help|trans|raw }}</div>
  399.                             {% endif %}
  400.                         </div>
  401.                     </div>
  402.                 {% endif %}
  403.                 <div id="content-{{ fieldset_name }}" class="form-fieldset-body {{ not fieldset_has_header ? 'without-header' }} {{ collapsible ? 'collapse' }} {{ not collapsed ? 'show'}}">
  404.                     <div class="row">
  405.                         {% for field in form|filter(field => 'hidden' not in field.vars.block_prefixes and field.vars.ea_crud_form.form_fieldset == fieldset_name) %}
  406.                             {% if not field.vars.ea_crud_form.form_tab or field.vars.ea_crud_form.form_tab == tab_name %}
  407.                                 {{ form_row(field) }}
  408.                             {% endif %}
  409.                         {% endfor %}
  410.                     </div>
  411.                 </div>
  412.             </fieldset>
  413.         </div>
  414.     {% else %}
  415.         {% macro recursiveFieldsetForm(form) %}
  416.             {% for field in form|filter(field => 'hidden' not in field.vars.block_prefixes and ((field.vars.ea_crud_form.form_tab is defined and not field.vars.ea_crud_form.form_tab) or field.vars.ea_crud_form.form_tabs is defined)) %}
  417.                 {% if field.vars.ea_crud_form.form_tabs is defined %}
  418.                     {# If the field is a nested CRUD form then only render its children #}
  419.                     {{ _self.recursiveFieldsetForm(field) }}
  420.                 {% else %}
  421.                     {# Render all other fields #}
  422.                     {{ form_row(field) }}
  423.                 {% endif %}
  424.             {% endfor %}
  425.         {% endmacro %}
  426.         {{ _self.recursiveFieldsetForm(form) }}
  427.     {% endfor %}
  428. {% endblock ea_crud_widget_fieldsets %}
  429. {# EasyAdminAutocomplete form type #}
  430. {% block ea_autocomplete_widget %}
  431.     {{ form_widget(form.autocomplete, { attr: attr|merge({ required: required }) }) }}
  432. {% endblock ea_autocomplete_widget %}
  433. {% block ea_autocomplete_inner_label %}
  434.     {% set name = form_parent(form).vars.name %}
  435.     {{ block('form_label') }}
  436. {% endblock ea_autocomplete_inner_label %}
  437. {# EasyAdmin's CodeEditor form type #}
  438. {% block ea_code_editor_widget %}
  439.     {{ form_widget(form, { attr: attr|merge({
  440.         'data-ea-code-editor-field': 'true',
  441.         'data-language': form.vars.ea_vars.field.customOptions.get('language'),
  442.         'data-tab-size': form.vars.ea_vars.field.customOptions.get('tabSize'),
  443.         'data-indent-with-tabs': form.vars.ea_vars.field.customOptions.get('indentWithTabs') ? 'true' : 'false',
  444.         'data-show-line-numbers': form.vars.ea_vars.field.customOptions.get('showLineNumbers') ? 'true' : 'false',
  445.         'data-number-of-rows': form.vars.ea_vars.field.customOptions.get('numOfRows'),
  446.     }) }) }}
  447. {% endblock ea_code_editor_widget %}
  448. {# EasyAdmin's TextEditor form type #}
  449. {% block ea_text_editor_widget %}
  450.     {{ form_widget(form, { attr: attr|merge({
  451.         class: 'ea-text-editor-content d-none',
  452.         'data-number-of-rows': form.vars.ea_vars.field.customOptions.get('numOfRows')|default(5),
  453.         'data-trix-editor-config': form.vars.ea_vars.field.customOptions.get('trixEditorConfig')|default(null)|json_encode,
  454.     }) }) }}
  455.     <div class="ea-text-editor-wrapper">
  456.         <trix-editor input="{{ id }}" class="trix-content"></trix-editor>
  457.     </div>
  458. {% endblock ea_text_editor_widget %}
  459. {# EasyAdminSection form type #}
  460. {% block ea_form_row_row %}
  461.     <div class="{{ form.vars.row_attr.class }}"></div>
  462. {% endblock %}
  463. {% block ea_form_column_group_open_row %}
  464.     {# if columns are inside tabs, don't add a '.row' element because the tab pane already opens it #}
  465.     {% if not form.vars.ea_is_inside_tab|default(false) %}
  466.         <div class="row">
  467.     {% endif %}
  468. {% endblock ea_form_column_group_open_row %}
  469. {% block ea_form_column_group_close_row %}
  470.     {# if columns are inside tabs, we don't add a '.row' element because
  471.        the tab pane already opens it; so, don't close it here #}
  472.     {% if not form.vars.ea_is_inside_tab|default(false) %}
  473.         </div>
  474.     {% endif %}
  475. {% endblock ea_form_column_group_close_row %}
  476. {% block ea_form_column_open_row %}
  477.     {% set field = form.vars.ea_vars.field %}
  478.     {% set field_icon = field.getCustomOption('icon') %}
  479.     {% set column_has_title = field_icon != null or field.label != false or field.label != null or field.label != '' or field.help != null %}
  480.     <div class="form-column {{ not column_has_title ? 'form-column-no-header' }} {{ field.cssClass }}">
  481.         {% if column_has_title %}
  482.             <div class="form-column-title">
  483.                 <div class="form-column-title-content">
  484.                     {% if field_icon %}<i class="form-column-icon fa fa-fw fa-{{ field_icon }}"></i>{% endif %}
  485.                     {% if field.label %}{{ field.label|default('')|trans(domain = ea.i18n.translationDomain)|raw }}{% endif %}
  486.                 </div>
  487.                 {% if field.help %}
  488.                     <div class="form-column-help">{{ field.help|trans(domain = ea.i18n.translationDomain)|raw }}</div>
  489.                 {% endif %}
  490.             </div>
  491.         {% endif %}
  492. {% endblock ea_form_column_open_row %}
  493. {% block ea_form_column_close_row %}
  494.     </div>
  495. {% endblock ea_form_column_close_row %}
  496. {% block ea_form_fieldset_open_row %}
  497.     {% set fieldset_has_header = form.vars.label or ea_icon or ea_help %}
  498.     <div class="form-fieldset {{ not fieldset_has_header ? 'form-fieldset-no-header' }} {{ ea_css_class }}">
  499.         <fieldset>
  500.             {% if fieldset_has_header %}
  501.                 <div class="form-fieldset-header {{ ea_is_collapsible ? 'collapsible' }} {{ ea_help is not empty ? 'with-help' }}">
  502.                     <div class="form-fieldset-title">
  503.                         {% set fieldset_title_contents %}
  504.                             {% if ea_is_collapsible %}
  505.                                 <i class="fas fw fa-chevron-right form-fieldset-collapse-marker"></i>
  506.                             {% endif %}
  507.                             {% if ea_icon %}
  508.                                 <i class="form-fieldset-icon {{ ea_icon }}"></i>
  509.                             {% endif %}
  510.                             {{ form.vars.label|trans|raw }}
  511.                         {% endset %}
  512.                         {% if ea_is_collapsible %}
  513.                             <a href="#content-{{ form.vars.name }}" data-bs-toggle="collapse"
  514.                                class="form-fieldset-title-content form-fieldset-collapse {{ ea_is_collapsed ? 'collapsed' }}"
  515.                                aria-expanded="{{ ea_is_collapsed ? 'false' : 'true' }}" aria-controls="content-{{ form.vars.name }}">
  516.                                 {{ fieldset_title_contents|raw }}
  517.                             </a>
  518.                         {% else %}
  519.                             <span class="not-collapsible form-fieldset-title-content">
  520.                                 {{ fieldset_title_contents|raw }}
  521.                             </span>
  522.                         {% endif %}
  523.                         {% if ea_help %}
  524.                             <div class="form-fieldset-help">{{ ea_help|trans|raw }}</div>
  525.                         {% endif %}
  526.                     </div>
  527.                 </div>
  528.             {% endif %}
  529.             <div id="content-{{ form.vars.name }}" class="form-fieldset-body {{ not fieldset_has_header ? 'without-header' }} {{ ea_is_collapsible ? 'collapse' }} {{ not ea_is_collapsed ? 'show'}}">
  530.                 <div class="row">
  531. {% endblock ea_form_fieldset_open_row %}
  532. {% block ea_form_fieldset_close_row %}
  533.                 </div>
  534.             </div>
  535.         </fieldset>
  536.     </div>
  537. {% endblock ea_form_fieldset_close_row %}
  538. {% block ea_form_tablist_row %}
  539.     {% set tab_id_option_name = constant('EasyCorp\\Bundle\\EasyAdminBundle\\Field\\FormField::OPTION_TAB_ID') %}
  540.     {% set tab_is_active_option_name = constant('EasyCorp\\Bundle\\EasyAdminBundle\\Field\\FormField::OPTION_TAB_IS_ACTIVE') %}
  541.     {% set tab_error_count_option_name = constant('EasyCorp\\Bundle\\EasyAdminBundle\\Field\\FormField::OPTION_TAB_ERROR_COUNT') %}
  542.     {% set field = form.vars.ea_vars.field %}
  543.     <div class="nav-tabs-custom form-tabs-tablist">
  544.         <ul class="nav nav-tabs">
  545.             {% for tab in field.getCustomOption('tabs') %}
  546.                 <li class="nav-item">
  547.                     <a class="nav-link {% if tab.getCustomOption(tab_is_active_option_name) %}active{% endif %}" href="#{{ tab.getCustomOption(tab_id_option_name) }}" id="tablist-{{ tab.getCustomOption(tab_id_option_name) }}" data-bs-toggle="tab">
  548.                         {%- if tab.getCustomOption('icon')|default(false) -%}
  549.                             <i class="tab-nav-item-icon fa-fw {{ tab.getCustomOption('icon') }}"></i>
  550.                         {%- endif -%}
  551.                         {{ tab.label|trans(domain = ea.i18n.translationDomain)|raw }}
  552.                         {% set tab_error_count = tab.getCustomOption(tab_error_count_option_name)  %}
  553.                         {%- if tab_error_count > 0 -%}
  554.                             <span class="badge badge-danger" title="{{ 'form.tab.error_badge_title'|trans({'%count%': tab_error_count}, 'EasyAdminBundle') }}">
  555.                                 {{- tab_error_count -}}
  556.                             </span>
  557.                         {%- endif -%}
  558.                     </a>
  559.                 </li>
  560.             {% endfor %}
  561.         </ul>
  562.     </div>
  563. {% endblock ea_form_tablist_row %}
  564. {% block ea_form_tabpane_group_open_row %}
  565.     <div class="nav-tabs-custom form-tabs-content">
  566.         <div class="tab-content">
  567. {% endblock ea_form_tabpane_group_open_row %}
  568. {% block ea_form_tabpane_group_close_row %}
  569.         </div>
  570.     </div>
  571. {% endblock ea_form_tabpane_group_close_row %}
  572. {% block ea_form_tabpane_open_row %}
  573.     {% set tab_is_active_option_name = constant('EasyCorp\\Bundle\\EasyAdminBundle\\Field\\FormField::OPTION_TAB_IS_ACTIVE') %}
  574.     {% set field = form.vars.ea_vars.field %}
  575.     <div id="{{ ea_tab_id }}" class="tab-pane {% if field.getCustomOption(tab_is_active_option_name) %}active{% endif %} {{ ea_css_class }}" {% for key, value in form.vars.attr %}{{ key }}={{ value|e('html_attr') }}{% endfor %}>
  576.         {% if ea_help %}
  577.             <div class="content-header-help tab-help">
  578.                 {{ ea_help|trans(domain = ea.i18n.translationDomain)|raw }}
  579.             </div>
  580.         {% endif %}
  581.         <div class="row">
  582. {% endblock ea_form_tabpane_open_row %}
  583. {% block ea_form_tabpane_close_row %}
  584.         </div>
  585.     </div>
  586. {% endblock ea_form_tabpane_close_row %}
  587. {# EasyAdminFilters form type #}
  588. {% block ea_filters_widget %}
  589.     {% set applied_filters = ea.request.query.all()['filters']|default([])|keys %}
  590.     {% for field in form %}
  591.         <div class="col-12">
  592.             <div class="filter-field px-3" data-filter-property="{{ field.vars.name }}">
  593.                 <div class="filter-heading" id="filter-heading-{{ loop.index }}">
  594.                     <input type="checkbox" class="filter-checkbox" {% if field.vars.name in applied_filters %}checked{% endif %}>
  595.                     <a data-bs-toggle="collapse" href="#filter-content-{{ loop.index }}" aria-expanded="{{ field.vars.name in applied_filters ? 'true' : 'false' }}" aria-controls="filter-content-{{ loop.index }}"
  596.                         {% for name, value in field.vars.label_attr|default([]) %}{{ name }}="{{ value|e('html_attr') }}" {% endfor %}>
  597.                         {{ field.vars.label|default(field.vars.name|humanize)|trans(domain = ea.i18n.translationDomain) }}
  598.                     </a>
  599.                 </div>
  600.                 <div id="filter-content-{{ loop.index }}" class="filter-content collapse {% if field.vars.name in applied_filters %}show{% endif %}" aria-labelledby="filter-heading-{{ loop.index }}">
  601.                     <div class="form-widget">
  602.                         {{ form_widget(field) }}
  603.                     </div>
  604.                 </div>
  605.             </div>
  606.         </div>
  607.     {% endfor %}
  608. {% endblock ea_filters_widget %}
  609. {% block comparison_widget %}
  610.     {{ form_widget(form, { attr: form.vars.attr|merge({'data-ea-comparison-id': form.vars.id}) }) }}
  611. {% endblock comparison_widget %}
  612. {% block ea_numeric_filter_widget %}
  613.     <div class="form-widget-compound">
  614.         {{ form_row(form.comparison) }}
  615.         {{ form_row(form.value) }}
  616.         <div data-ea-value2-of-comparison-id="{{ form.comparison.vars.id }}" class="{{ form.comparison.vars.value != 'between' ? 'd-none' }}">
  617.             {{ form_row(form.value2) }}
  618.         </div>
  619.     </div>
  620.     {{- form_errors(form) -}}
  621. {% endblock ea_numeric_filter_widget %}
  622. {% block ea_datetime_filter_widget %}
  623.     {{ block('ea_numeric_filter_widget') }}
  624. {% endblock ea_datetime_filter_widget %}
  625. {% block ea_fileupload_widget %}
  626.     <div class="ea-fileupload">
  627.         <div class="input-group">
  628.             {% set placeholder = t('action.choose_file', {}, 'EasyAdminBundle') %}
  629.             {% set title = '' %}
  630.             {% set filesLabel = 'files'|trans({}, 'EasyAdminBundle') %}
  631.             {% if currentFiles %}
  632.                 {% if multiple %}
  633.                     {% set placeholder = currentFiles|length ~ ' ' ~ filesLabel %}
  634.                 {% else %}
  635.                     {% set placeholder = (currentFiles|first).filename %}
  636.                     {% set title = (currentFiles|first).mTime|date %}
  637.                 {% endif %}
  638.             {% endif %}
  639.             <div class="custom-file">
  640.                 {{ form_widget(form.file, { attr: form.file.vars.attr|merge({ placeholder: placeholder, title: title, 'data-files-label': filesLabel, class: 'd-none' }) }) }}
  641.                 {{ form_label(form.file, placeholder, { label_attr: { class: 'custom-file-label' }}) }}
  642.             </div>
  643.             <div class="input-group-text">
  644.                 {%- if currentFiles -%}
  645.                     {% if multiple %}
  646.                         {{ (currentFiles|reduce((carry, file) => carry + file.size))|ea_filesize }}
  647.                     {% else %}
  648.                         {{ (currentFiles|first).size|ea_filesize }}
  649.                     {% endif %}
  650.                 {%- endif -%}
  651.                 {% if allow_delete %}
  652.                     <label class="btn ea-fileupload-delete-btn {{ currentFiles is empty ? 'd-none' }}" for="{{ form.delete.vars.id }}">
  653.                         <i class="fa fa-trash-o"></i>
  654.                     </label>
  655.                 {% endif %}
  656.                 <label class="btn" for="{{ form.file.vars.id }}">
  657.                     <i class="fa fa-folder-open-o"></i>
  658.                 </label>
  659.             </div>
  660.         </div>
  661.         {% if multiple and currentFiles %}
  662.             <div class="form-control fileupload-list">
  663.                 <table class="fileupload-table">
  664.                     <tbody>
  665.                     {% for file in currentFiles %}
  666.                         <tr>
  667.                             <td>
  668.                                 {% if download_path %}<a href="{{ asset(download_path ~ file.filename) }}">{% endif %}
  669.                                     <span title="{{ file.mTime|date }}">
  670.                                         <i class="fa fa-file-o"></i> {{ file.filename }}
  671.                                     </span>
  672.                                 {% if download_path %}</a>{% endif %}
  673.                             </td>
  674.                             <td class="text-right file-size">{{ file.size|ea_filesize }}</td>
  675.                         </tr>
  676.                     {% endfor %}
  677.                     </tbody>
  678.                 </table>
  679.             </div>
  680.         {% endif %}
  681.         {% if allow_delete %}
  682.             <div class="d-none">{{ form_widget(form.delete, { label: false }) }}</div>
  683.         {% endif %}
  684.     </div>
  685.     {{ form_errors(form.file) }}
  686. {% endblock %}
  687. {% block TODO_ea_fileupload_widget %}
  688.     {% set placeholder = '' %}
  689.     {% set title = '' %}
  690.     {% set filesLabel = 'files'|trans({}, 'EasyAdminBundle') %}
  691.     {% if currentFiles %}
  692.         {% if multiple %}
  693.             {% set placeholder = currentFiles|length ~ ' ' ~ filesLabel %}
  694.         {% else %}
  695.             {% set placeholder = (currentFiles|first).filename %}
  696.             {% set title = (currentFiles|first).mTime|date %}
  697.         {% endif %}
  698.     {% endif %}
  699.     <div class="ea-fileupload">
  700.         <div class="input-group">
  701.             {{ form_widget(form.file, { attr: form.file.vars.attr|merge({ placeholder: placeholder, title: title, 'data-files-label': filesLabel, class: 'form-control' }) }) }}
  702.             {% if currentFiles %}
  703.                 <span class="input-group-text">
  704.                     {% if multiple %}
  705.                         {{ (currentFiles|reduce((carry, file) => carry + file.size))|ea_filesize }}
  706.                     {% else %}
  707.                         {{ (currentFiles|first).size|ea_filesize }}
  708.                     {% endif %}
  709.                 </span>
  710.             {% endif %}
  711.             {% if currentFiles and allow_delete %}
  712.                 <button class="btn ea-fileupload-delete-btn">
  713.                     <i class="fa fa-trash-o"></i>
  714.                 </button>
  715.             {% endif %}
  716.             {% if currentFiles %}
  717.                 <button class="btn">
  718.                     <i class="fa fa-folder-open-o"></i>
  719.                 </button>
  720.             {% endif %}
  721.         </div>
  722.         {% if multiple and currentFiles %}
  723.             <div class="form-control fileupload-list">
  724.                 <table class="fileupload-table">
  725.                     <tbody>
  726.                     {% for file in currentFiles %}
  727.                         <tr>
  728.                             <td>
  729.                                 {% if download_path %}<a href="{{ asset(download_path ~ file.filename) }}">{% endif %}
  730.                                     <span title="{{ file.mTime|date }}">
  731.                                         <i class="fa fa-file-o"></i> {{ file.filename }}
  732.                                     </span>
  733.                                     {% if download_path %}</a>{% endif %}
  734.                             </td>
  735.                             <td class="text-right file-size">{{ file.size|ea_filesize }}</td>
  736.                         </tr>
  737.                     {% endfor %}
  738.                     </tbody>
  739.                 </table>
  740.             </div>
  741.         {% endif %}
  742.         {% if allow_delete %}
  743.             <div class="d-none">{{ form_widget(form.delete, { label: false }) }}</div>
  744.         {% endif %}
  745.     </div>
  746.     {{ form_errors(form.file) }}
  747. {% endblock %}
  748. {% block ea_slug_widget %}
  749.     {% set attr = attr|merge({
  750.         'data-ea-slug-field': '',
  751.         'data-target': target|split('|')|map(name => form.parent.children[name].vars.id)|json_encode
  752.     }) %}
  753.     {% if attr['data-confirm-text'] is defined %}
  754.         {% set attr = attr|merge({
  755.             'data-confirm-text': attr['data-confirm-text']|trans
  756.         }) %}
  757.     {% endif %}
  758.     <div class="input-group">
  759.         {{ block('form_widget') }}
  760.         <button type="button" class="btn">
  761.             <i class="fas fa-lock fa-fw"></i>
  762.         </button>
  763.     </div>
  764. {% endblock %}