_field_repeater.blade.php 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. {{--
  2. Partial: поле типа repeater — динамический список строк с sub-полями
  3. Переменные из родителя: $field, $prefix, $values, $imageUrl
  4. --}}
  5. @php $repName = $field['name']; $subFields = $field['sub_fields']; @endphp
  6. <div class="form-group">
  7. <label class="font-weight-bold d-block mb-2">{{ $field['label'] }}</label>
  8. <div class="repeater-wrap" data-repeater="{{ $repName }}">
  9. {{-- ── Существующие строки (с данными) ──────────────────── --}}
  10. <div class="repeater-rows" id="repeater-rows-{{ $repName }}">
  11. @foreach($values[$repName] ?? [] as $i => $row)
  12. <div class="repeater-row card card-secondary mb-2" data-index="{{ $i }}">
  13. <div class="card-body py-2 px-3">
  14. <div class="d-flex align-items-start">
  15. <span class="repeater-handle text-muted mr-2 mt-1">&#9776;</span>
  16. <div class="flex-grow-1">
  17. @foreach($subFields as $sub)
  18. <div class="form-group mb-2">
  19. <label class="small text-muted mb-0">{{ $sub['label'] }}</label>
  20. @if($sub['type'] === 'textarea')
  21. <textarea name="{{ $prefix }}[{{ $repName }}][{{ $i }}][{{ $sub['name'] }}]"
  22. class="form-control form-control-sm" rows="2">{{ $row[$sub['name']] ?? '' }}</textarea>
  23. @elseif($sub['type'] === 'image')
  24. @php
  25. $subCurVal = $row[$sub['name']] ?? '';
  26. $subCurUrl = $imageUrl($subCurVal);
  27. @endphp
  28. <input type="hidden"
  29. name="{{ $prefix }}[{{ $repName }}][{{ $i }}][{{ $sub['name'] }}]"
  30. value="{{ $subCurVal }}"
  31. class="js-img-current">
  32. @if($subCurVal)
  33. <div class="mb-1 js-img-preview-current">
  34. <img src="{{ $subCurUrl }}"
  35. class="img-thumbnail d-block"
  36. style="max-height:80px;max-width:120px;object-fit:cover">
  37. </div>
  38. @endif
  39. <div class="custom-file" style="max-width:300px">
  40. <input type="file"
  41. name="uploads[{{ $repName }}][{{ $i }}][{{ $sub['name'] }}]"
  42. class="custom-file-input js-img-upload"
  43. accept="image/*"
  44. id="upload-{{ $repName }}-{{ $i }}-{{ $sub['name'] }}">
  45. <label class="custom-file-label" for="upload-{{ $repName }}-{{ $i }}-{{ $sub['name'] }}">
  46. {{ $subCurVal ? 'Заменить' : 'Выбрать' }}
  47. </label>
  48. </div>
  49. <div class="js-img-preview-new mt-1" style="display:none">
  50. <img src="" class="img-thumbnail d-block" style="max-height:80px;max-width:120px;object-fit:cover">
  51. <small class="js-img-new-name text-muted"></small>
  52. </div>
  53. @else
  54. <input type="text"
  55. name="{{ $prefix }}[{{ $repName }}][{{ $i }}][{{ $sub['name'] }}]"
  56. class="form-control form-control-sm"
  57. value="{{ $row[$sub['name']] ?? '' }}">
  58. @endif
  59. </div>
  60. @endforeach
  61. </div>
  62. <button type="button" class="btn btn-sm btn-outline-danger ml-2 flex-shrink-0 btn-remove-repeater-row" title="Удалить строку">
  63. <i class="fas fa-times"></i>
  64. </button>
  65. </div>
  66. </div>
  67. </div>
  68. @endforeach
  69. </div>
  70. {{-- ── Шаблон новой строки (JS-клонирование, __IDX__ → реальный индекс) ── --}}
  71. <script type="text/template" id="repeater-tpl-{{ $repName }}">
  72. <div class="repeater-row card card-secondary mb-2" data-index="__IDX__">
  73. <div class="card-body py-2 px-3">
  74. <div class="d-flex align-items-start">
  75. <span class="repeater-handle text-muted mr-2 mt-1">&#9776;</span>
  76. <div class="flex-grow-1">
  77. @foreach($subFields as $sub)
  78. <div class="form-group mb-2">
  79. <label class="small text-muted mb-0">{{ $sub['label'] }}</label>
  80. @if($sub['type'] === 'textarea')
  81. <textarea name="{{ $prefix }}[{{ $repName }}][__IDX__][{{ $sub['name'] }}]"
  82. class="form-control form-control-sm" rows="2"></textarea>
  83. @elseif($sub['type'] === 'image')
  84. <input type="hidden"
  85. name="{{ $prefix }}[{{ $repName }}][__IDX__][{{ $sub['name'] }}]"
  86. value=""
  87. class="js-img-current">
  88. <div class="custom-file" style="max-width:300px">
  89. <input type="file"
  90. name="uploads[{{ $repName }}][__IDX__][{{ $sub['name'] }}]"
  91. class="custom-file-input js-img-upload"
  92. accept="image/*"
  93. id="upload-{{ $repName }}-__IDX__-{{ $sub['name'] }}">
  94. <label class="custom-file-label" for="upload-{{ $repName }}-__IDX__-{{ $sub['name'] }}">
  95. Выбрать изображение
  96. </label>
  97. </div>
  98. <div class="js-img-preview-new mt-1" style="display:none">
  99. <img src="" class="img-thumbnail d-block" style="max-height:80px;max-width:120px;object-fit:cover">
  100. <small class="js-img-new-name text-muted"></small>
  101. </div>
  102. @else
  103. <input type="text"
  104. name="{{ $prefix }}[{{ $repName }}][__IDX__][{{ $sub['name'] }}]"
  105. class="form-control form-control-sm">
  106. @endif
  107. </div>
  108. @endforeach
  109. </div>
  110. <button type="button" class="btn btn-sm btn-outline-danger ml-2 flex-shrink-0 btn-remove-repeater-row" title="Удалить строку">
  111. <i class="fas fa-times"></i>
  112. </button>
  113. </div>
  114. </div>
  115. </div>
  116. </script>
  117. <button type="button"
  118. class="btn btn-sm btn-outline-primary btn-add-repeater-row"
  119. data-repeater="{{ $repName }}">
  120. <i class="fas fa-plus"></i> Добавить строку
  121. </button>
  122. </div>
  123. </div>