|
@@ -34,7 +34,25 @@
|
|
|
<form action="{{ route('responsible.store') }}" method="post">
|
|
<form action="{{ route('responsible.store') }}" method="post">
|
|
|
@csrf
|
|
@csrf
|
|
|
|
|
|
|
|
- @include('partials.select', ['name' => 'area_id', 'title' => 'Район', 'options' => $areas])
|
|
|
|
|
|
|
+ <div class="row mb-2">
|
|
|
|
|
+ <label for="area_search" class="col-form-label small col-md-4 text-md-end">
|
|
|
|
|
+ Район
|
|
|
|
|
+ <sup>*</sup>
|
|
|
|
|
+ </label>
|
|
|
|
|
+ <div class="col-md-8">
|
|
|
|
|
+ <div class="position-relative">
|
|
|
|
|
+ <input type="text"
|
|
|
|
|
+ class="form-control form-control-sm"
|
|
|
|
|
+ id="area_search"
|
|
|
|
|
+ placeholder="Введите район..."
|
|
|
|
|
+ autocomplete="off"
|
|
|
|
|
+ required>
|
|
|
|
|
+ <input type="hidden" name="area_id" id="area_id" value="{{ old('area_id', '') }}" required>
|
|
|
|
|
+ <div class="autocomplete-dropdown autocomplete-dropdown--order" id="area_dropdown"></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="form-text" id="area_hint"></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
@include('partials.input', ['name' => 'name', 'title' => 'ФИО', 'required' => true])
|
|
@include('partials.input', ['name' => 'name', 'title' => 'ФИО', 'required' => true])
|
|
|
@include('partials.input', ['name' => 'phone', 'title' => 'Телефон', 'required' => true])
|
|
@include('partials.input', ['name' => 'phone', 'title' => 'Телефон', 'required' => true])
|
|
|
@include('partials.input', ['name' => 'post', 'title' => 'Должность'])
|
|
@include('partials.input', ['name' => 'post', 'title' => 'Должность'])
|
|
@@ -48,12 +66,170 @@
|
|
|
</div>
|
|
</div>
|
|
|
@endsection
|
|
@endsection
|
|
|
@push('scripts')
|
|
@push('scripts')
|
|
|
-{{-- <script type="module">--}}
|
|
|
|
|
-{{-- $('#select_maf').on('change', function () {--}}
|
|
|
|
|
-{{-- $('#product_id').val($(this).val());--}}
|
|
|
|
|
-{{-- $('#product_name').val($('#select_maf option:selected').text()).slideDown();--}}
|
|
|
|
|
-{{-- $('#select_maf_form').slideUp();--}}
|
|
|
|
|
-{{-- $('#sku_form').slideDown();--}}
|
|
|
|
|
-{{-- });--}}
|
|
|
|
|
-{{-- </script>--}}
|
|
|
|
|
|
|
+ <script>
|
|
|
|
|
+ waitForJQuery(function () {
|
|
|
|
|
+ const $modal = $('#addModal');
|
|
|
|
|
+ const $input = $modal.find('#area_search');
|
|
|
|
|
+ const $dropdown = $modal.find('#area_dropdown');
|
|
|
|
|
+ const $hiddenInput = $modal.find('#area_id');
|
|
|
|
|
+ const $hint = $modal.find('#area_hint');
|
|
|
|
|
+ const $form = $modal.find('form');
|
|
|
|
|
+ let currentFocus = -1;
|
|
|
|
|
+
|
|
|
|
|
+ const areas = @json($areasForSearch ?? []);
|
|
|
|
|
+
|
|
|
|
|
+ function escapeHtml(text) {
|
|
|
|
|
+ return String(text)
|
|
|
|
|
+ .replace(/&/g, '&')
|
|
|
|
|
+ .replace(/</g, '<')
|
|
|
|
|
+ .replace(/>/g, '>')
|
|
|
|
|
+ .replace(/"/g, '"')
|
|
|
|
|
+ .replace(/'/g, ''');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function escapeRegex(str) {
|
|
|
|
|
+ return String(str).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function highlightMatch(text, query) {
|
|
|
|
|
+ if (!text || !query) {
|
|
|
|
|
+ return escapeHtml(text || '');
|
|
|
|
|
+ }
|
|
|
|
|
+ const safeText = escapeHtml(text);
|
|
|
|
|
+ const regex = new RegExp('(' + escapeRegex(query) + ')', 'gi');
|
|
|
|
|
+ return safeText.replace(regex, '<strong>$1</strong>');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function showDropdown(items, query) {
|
|
|
|
|
+ $dropdown.empty();
|
|
|
|
|
+ currentFocus = -1;
|
|
|
|
|
+
|
|
|
|
|
+ if (!items.length) {
|
|
|
|
|
+ $dropdown.html('<div class="autocomplete-item text-muted">Ничего не найдено</div>');
|
|
|
|
|
+ $dropdown.show();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ items.forEach(function (item) {
|
|
|
|
|
+ const html = '<div class="autocomplete-item" data-id="' + item.id + '" data-name="' + escapeHtml(item.name) + '">' +
|
|
|
|
|
+ '<div class="article">' + highlightMatch(item.name, query) + '</div>' +
|
|
|
|
|
+ '</div>';
|
|
|
|
|
+ $dropdown.append(html);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ $dropdown.show();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function hideDropdown() {
|
|
|
|
|
+ $dropdown.hide();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function selectItem($item) {
|
|
|
|
|
+ const id = String($item.data('id') || '');
|
|
|
|
|
+ const name = String($item.data('name') || '');
|
|
|
|
|
+
|
|
|
|
|
+ $input.val(name);
|
|
|
|
|
+ $hiddenInput.val(id);
|
|
|
|
|
+ $hint.html('<i class="bi bi-check-circle text-success"></i> Выбрано: ' + name);
|
|
|
|
|
+ $input.removeClass('is-invalid');
|
|
|
|
|
+ hideDropdown();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function setActive($items) {
|
|
|
|
|
+ $items.removeClass('active');
|
|
|
|
|
+ if (currentFocus >= 0 && currentFocus < $items.length) {
|
|
|
|
|
+ const $active = $items.eq(currentFocus);
|
|
|
|
|
+ $active.addClass('active');
|
|
|
|
|
+ $active[0].scrollIntoView({block: 'nearest'});
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function searchAreas(query) {
|
|
|
|
|
+ const normalized = String(query || '').trim().toLowerCase();
|
|
|
|
|
+ if (normalized.length < 1) {
|
|
|
|
|
+ hideDropdown();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const items = areas.filter(function (item) {
|
|
|
|
|
+ return String(item.name).toLowerCase().includes(normalized);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ showDropdown(items.slice(0, 50), normalized);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $input.on('input', function () {
|
|
|
|
|
+ $hiddenInput.val('');
|
|
|
|
|
+ $hint.html('');
|
|
|
|
|
+ $input.removeClass('is-invalid');
|
|
|
|
|
+ searchAreas($(this).val());
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ $input.on('focus', function () {
|
|
|
|
|
+ if (!$hiddenInput.val()) {
|
|
|
|
|
+ searchAreas($(this).val());
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ $input.on('keydown', function (e) {
|
|
|
|
|
+ const $items = $dropdown.find('.autocomplete-item:not(.text-muted)');
|
|
|
|
|
+
|
|
|
|
|
+ if (e.key === 'ArrowDown') {
|
|
|
|
|
+ e.preventDefault();
|
|
|
|
|
+ currentFocus++;
|
|
|
|
|
+ if (currentFocus >= $items.length) {
|
|
|
|
|
+ currentFocus = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ setActive($items);
|
|
|
|
|
+ } else if (e.key === 'ArrowUp') {
|
|
|
|
|
+ e.preventDefault();
|
|
|
|
|
+ currentFocus--;
|
|
|
|
|
+ if (currentFocus < 0) {
|
|
|
|
|
+ currentFocus = $items.length - 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ setActive($items);
|
|
|
|
|
+ } else if (e.key === 'Enter') {
|
|
|
|
|
+ if ($items.length > 0 && currentFocus > -1) {
|
|
|
|
|
+ e.preventDefault();
|
|
|
|
|
+ selectItem($items.eq(currentFocus));
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if (e.key === 'Escape') {
|
|
|
|
|
+ hideDropdown();
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ $dropdown.on('click', '.autocomplete-item:not(.text-muted)', function () {
|
|
|
|
|
+ selectItem($(this));
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ $(document).on('click', function (e) {
|
|
|
|
|
+ if (!$(e.target).closest('#area_search, #area_dropdown').length) {
|
|
|
|
|
+ hideDropdown();
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ $form.on('submit', function (e) {
|
|
|
|
|
+ if (!$hiddenInput.val()) {
|
|
|
|
|
+ e.preventDefault();
|
|
|
|
|
+ $input.addClass('is-invalid').focus();
|
|
|
|
|
+ $hint.html('<span class="text-danger">Выберите район из списка</span>');
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ @if(old('area_id'))
|
|
|
|
|
+ const oldAreaId = '{{ old('area_id') }}';
|
|
|
|
|
+ const oldArea = areas.find(function (item) {
|
|
|
|
|
+ return String(item.id) === String(oldAreaId);
|
|
|
|
|
+ });
|
|
|
|
|
+ if (oldArea) {
|
|
|
|
|
+ $input.val(oldArea.name);
|
|
|
|
|
+ $hint.html('<i class="bi bi-check-circle text-success"></i> Выбрано: ' + oldArea.name);
|
|
|
|
|
+ }
|
|
|
|
|
+ @endif
|
|
|
|
|
+
|
|
|
|
|
+ $modal.on('hidden.bs.modal', function () {
|
|
|
|
|
+ hideDropdown();
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ </script>
|
|
|
@endpush
|
|
@endpush
|