PageSourceSearch

https://akvastom-group.ru/local/templates/aspro-premier/js/custom.js?178537905423120

js akvastom-group.ru collected 2026-10-07 10:49:56 UTC 23,120 bytes, 673 lines download raw bytes

1/*
2You can use this file with your scripts.
3It will not be overwritten when you upgrade solution.
4*/
5
6document.addEventListener("DOMContentLoaded", function() {
7    var btn = document.getElementById("cookie-accept");
8    if (btn) {
9        btn.addEventListener("click", function(e) {
10            e.preventDefault();
11            fetch('/local/ajax/cookie_accept.php', {
12                method: "POST",
13                headers: {
14                    "Content-Type": "application/x-www-form-urlencoded"
15                },
16                body: "cookie_accept=1",
17                credentials: 'same-origin'
18            }).then(response => response.json()).then(data => {
19                    if (data.status === "ok") {
20                        document.getElementById("cookie-consent").style.display = "none";
21                    }
22                }
23            );
24        });
25    }
26});
27
28$(function(){
29    // Функция инициализации автоподстановки для поля города в быстром заказе
30    function initOcbCityAutocomplete() {
31        var $cityInput = $('#one_click_buy_id_CITY');
32
33        if (!$cityInput.length) return;
34        if ($cityInput.data('autocomplete-inited')) return;
35
36        // Добавляем контейнер для подсказок
37        var $wrap = $cityInput.closest('.input');
38        if (!$wrap.length) {
39            $cityInput.wrap('<div class="input" style="position:relative;"></div>');
40            $wrap = $cityInput.parent();
41        }
42
43        // Создаем контейнер для результатов
44        var $suggestions = $cityInput.siblings('.city-suggestions');
45        if (!$suggestions.length) {
46            $suggestions = $('<div class="city-suggestions" style="display:none; position:absolute; z-index:9999; background:#fff; border:1px solid #ddd; border-radius:4px; max-height:200px; overflow-y:auto; width:100%; margin-top:2px;"></div>');
47            $wrap.css('position', 'relative');
48            $wrap.append($suggestions);
49        }
50
51        var currentRequest = null;
52        var lastQuery = '';
53
54        // Функция поиска - без задержки, сразу
55        function performSearch(query) {
56            lastQuery = query;
57
58            // Отменяем предыдущий запрос
59            if (currentRequest) {
60                currentRequest.abort();
61                currentRequest = null;
62            }
63
64            if (!query || query.length < 2) {
65                $suggestions.hide().empty();
66                return;
67            }
68
69            // Показываем индикатор
70            $suggestions.html('<div style="padding:8px 12px; color:#999;">Поиск...</div>').show();
71
72            currentRequest = $.ajax({
73                url: '/local/ajax/shipping_cities.php',
74                method: 'GET',
75                dataType: 'json',
76                data: { q: query },
77                success: function(response) {
78                    currentRequest = null;
79
80                    // Проверяем актуальность
81                    if (lastQuery !== query) {
82                        return;
83                    }
84
85                    var cities = response && response.cities ? response.cities : [];
86
87                    if (!cities.length) {
88                        $suggestions.html('<div style="padding:8px 12px; color:#999;">Ничего не найдено</div>').show();
89                        return;
90                    }
91
92                    var html = '';
93                    $.each(cities, function(index, city) {
94                        var cityName = city.name || city;
95                        html += '<div class="city-suggestion-item" data-city-name="' + cityName + '" style="padding:8px 12px; cursor:pointer; border-bottom:1px solid #f0f0f0;">';
96                        html += cityName;
97                        html += '</div>';
98                    });
99
100                    $suggestions.html(html).show();
101
102                    // Обработчики кликов
103                    $suggestions.find('.city-suggestion-item').on('click', function() {
104                        var cityName = $(this).data('city-name');
105                        $cityInput.val(cityName);
106                        $suggestions.hide().empty();
107                        $cityInput.trigger('change');
108                        lastQuery = cityName;
109                    }).on('mouseenter', function() {
110                        $(this).css('background', '#f5f5f5');
111                    }).on('mouseleave', function() {
112                        $(this).css('background', '');
113                    });
114                },
115                error: function() {
116                    currentRequest = null;
117                    if (lastQuery === query) {
118                        $suggestions.hide().empty();
119                    }
120                }
121            });
122        }
123
124        // Обработчик ввода - с минимальной задержкой
125        var searchTimer = null;
126        $cityInput.on('input.ocbCity', function() {
127            var query = $.trim($(this).val());
128
129            // Сбрасываем таймер
130            clearTimeout(searchTimer);
131
132            // Если запрос изменился
133            if (query !== lastQuery) {
134                if (query.length < 2) {
135                    $suggestions.hide().empty();
136                    lastQuery = query;
137                    return;
138                }
139
140                // Маленькая задержка для плавности
141                searchTimer = setTimeout(function() {
142                    performSearch(query);
143                }, 150);
144            }
145        });
146
147        // При потере фокуса - скрываем
148        $cityInput.on('blur.ocbCity', function() {
149            setTimeout(function() {
150                $suggestions.hide().empty();
151            }, 300);
152        });
153
154        // Клавиши
155        $cityInput.on('keydown.ocbCity', function(e) {
156            var $items = $suggestions.find('.city-suggestion-item');
157            if (!$items.length || !$suggestions.is(':visible')) return;
158
159            var $active = $items.filter('[style*="background: rgb(245, 245, 245)"]');
160
161            if (e.key === 'ArrowDown') {
162                e.preventDefault();
163                if ($active.length) {
164                    var next = $active.next();
165                    if (next.length) {
166                        $active.css('background', '');
167                        next.css('background', '#f5f5f5');
168                    }
169                } else {
170                    $items.first().css('background', '#f5f5f5');
171                }
172            } else if (e.key === 'ArrowUp') {
173                e.preventDefault();
174                if ($active.length) {
175                    var prev = $active.prev();
176                    if (prev.length) {
177                        $active.css('background', '');
178                        prev.css('background', '#f5f5f5');
179                    }
180                } else {
181                    $items.last().css('background', '#f5f5f5');
182                }
183            } else if (e.key === 'Enter') {
184                if ($active.length) {
185                    e.preventDefault();
186                    $active.trigger('click');
187                }
188            } else if (e.key === 'Escape') {
189                $suggestions.hide().empty();
190            }
191        });
192
193        // Закрываем при клике вне
194        $(document).on('click.ocbCity', function(e) {
195            if (!$(e.target).closest('.input').length) {
196                $suggestions.hide().empty();
197            }
198        });
199
200        $cityInput.data('autocomplete-inited', true);
201    }
202
203// Инициализируем при загрузке модалки быстрого заказа
204    $(document).on('click', '*[data-event="jqm"][data-name="ocb"]', function() {
205        // Инициализируем через некоторое время после открытия
206        setTimeout(initOcbCityAutocomplete, 500);
207    });
208
209// Также инициализируем через onLoadjqm
210    var originalOnLoadjqm = window.onLoadjqm || function() {};
211    window.onLoadjqm = function(name, hash, _this) {
212        // Вызываем оригинальную функцию
213        if (typeof originalOnLoadjqm === 'function') {
214            originalOnLoadjqm(name, hash, _this);
215        }
216
217        // Инициализируем автоподстановку для быстрого заказа
218        if (name === 'ocb') {
219            setTimeout(initOcbCityAutocomplete, 400);
220        }
221    };
222
223// Инициализация при загрузке AJAX-контента
224    BX.addCustomEvent('onCompleteAction', function(eventdata) {
225        if (eventdata.action === 'loadForm' && eventdata.container) {
226            var $container = $(eventdata.container);
227            if ($container.closest('.ocb_frame').length || $container.find('.ocb_frame').length) {
228                setTimeout(initOcbCityAutocomplete, 500);
229            }
230        }
231    });
232
233// Инициализация при успешной загрузке формы
234    BX.addCustomEvent('onAjaxSuccess', function(data, config) {
235        if (config && config.url && config.url.indexOf('oneclickbuy') !== -1) {
236            setTimeout(initOcbCityAutocomplete, 500);
237        }
238    });
239
240// Вызываем при загрузке страницы (на случай если модалка уже открыта)
241    $(document).ready(function() {
242        setTimeout(initOcbCityAutocomplete, 1000);
243    });
244
245
246
247    var shippingCitySearchXhr = null;
248    var shippingCitySearchTimer = null;
249
250    function normalizeShippingCity(value) {
251        return $.trim(value || '')
252            .toUpperCase()
253            .replace(/^Г\.\s*/i, '')
254            .replace(/\s+/g, ' ');
255    }
256
257    function getShippingCityName($input) {
258        var storedName = $.trim($input.attr('data-city-name') || '');
259
260        if (storedName) {
261            return normalizeShippingCity(storedName);
262        }
263
264        var value = $.trim($input.val() || '');
265
266        if (value.indexOf(',') !== -1) {
267            return normalizeShippingCity(value.split(',')[0]);
268        }
269
270        return normalizeShippingCity(value);
271    }
272
273    function getShippingDeliveryText($input) {
274        var city = getShippingCityName($input);
275        var deliveryText = 'Бесплатная доставка <br> от 30 000р. до 5кг';
276
277        if (city === 'САНКТ-ПЕТЕРБУРГ') {
278            deliveryText = $input.attr('data-default-text');
279        }
280
281        if (city === 'МОСКВА') {
282            deliveryText = 'Бесплатная доставка <br> от 20 000р. до 5кг';
283        }
284
285        return deliveryText;
286    }
287
288    function getShippingCityTargetLine($input) {
289        var $target = $('.js-shipping-city-target').first();
290
291        if ($input && $input.length) {
292            var $scoped = $input.closest('#bx-soa-total, .card-order-registr').find('.js-shipping-city-target').first();
293            if ($scoped.length) {
294                $target = $scoped;
295            }
296        }
297
298        return $target.length ? $target.closest('.card-order-registr__line') : $();
299    }
300
301    function toggleShippingCityTargetLine(show) {
302        var $line = getShippingCityTargetLine();
303
304        if (!$line.length) {
305            return;
306        }
307
308        $line.addClass('akvastom-shipping-city-line');
309        $line.toggleClass('akvastom-shipping-city-line--hidden', !show);
310    }
311
312    function updateAkvastomCityDependentUi() {
313        if (
314            window.BX &&
315            BX.Sale &&
316            BX.Sale.OrderAjaxComponent &&
317            typeof BX.Sale.OrderAjaxComponent.updateAkvastomCityDependentUi === 'function'
318        ) {
319            BX.Sale.OrderAjaxComponent.updateAkvastomCityDependentUi();
320        }
321    }
322
323    function clearShippingCityTarget() {
324        if (!$('.js-shipping-city-target').length) {
325            return;
326        }
327
328        $('.js-shipping-city-target').html('');
329        toggleShippingCityTargetLine(false);
330    }
331
332    function updateShippingCityTarget($input) {
333        if (!$('.js-shipping-city-target').length) {
334            return;
335        }
336
337        if (!$input || !$input.length || $input.attr('data-city-selected') !== '1') {
338            clearShippingCityTarget();
339            return;
340        }
341
342        $('.js-shipping-city-target').html(getShippingDeliveryText($input));
343        toggleShippingCityTargetLine(true);
344    }
345
346    function syncShippingCityTargetSidebar($input) {
347        if ($input && $input.length && $input.attr('data-city-selected') === '1') {
348            updateShippingCityTarget($input);
349        } else {
350            clearShippingCityTarget();
351        }
352    }
353
354    var shippingCityOrderRefreshTimer = null;
355
356    function requestOrderRefreshAfterCityChange() {
357        if (!window.BX || !BX.Sale || !BX.Sale.OrderAjaxComponent) {
358            return;
359        }
360
361        var component = BX.Sale.OrderAjaxComponent;
362
363        clearTimeout(shippingCityOrderRefreshTimer);
364        shippingCityOrderRefreshTimer = setTimeout(function tryRefresh() {
365            if (component.BXFormPosting) {
366                shippingCityOrderRefreshTimer = setTimeout(tryRefresh, 200);
367                return;
368            }
369
370            if (component.markAkvastomCityChange) {
371                component.markAkvastomCityChange();
372            }
373            if (component.syncAkvastomCityToOrderProps) {
374                component.syncAkvastomCityToOrderProps();
375            }
376            if (component.saveAkvastomCityState) {
377                component.saveAkvastomCityState();
378            }
379
380            component.deliveryCachedInfo = [];
381            component.initialized.delivery = false;
382            component.initialized.paySystem = false;
383            component.sendRequest();
384        }, 350);
385    }
386
387    function setOrderLocationId(locationId) {
388        if (!locationId) {
389            return;
390        }
391
392        var cityFields = document.getElementById('bx-soa-city-fields');
393        if (!cityFields) {
394            return;
395        }
396
397        var locHidden = cityFields.querySelector('.js-akvastom-location-id');
398        var prevValue = locHidden ? String(locHidden.value || '') : '';
399        var nextValue = String(locationId);
400
401        if (locHidden) {
402            locHidden.value = locationId;
403        } else {
404            cityFields.querySelectorAll('input[type="hidden"]').forEach(function (input) {
405                if (input.name && input.name.indexOf('ORDER_PROP') !== -1) {
406                    input.value = locationId;
407                }
408            });
409        }
410
411        var recentInput = document.querySelector('input[name="RECENT_DELIVERY_VALUE"]');
412        if (recentInput) {
413            recentInput.value = locationId;
414        }
415
416        if (prevValue === nextValue) {
417            return;
418        }
419
420        requestOrderRefreshAfterCityChange();
421    }
422
423    function selectShippingCityFromList($input, city) {
424        var $list = getShippingCitySuggestions($input);
425        var displayValue = city.label || city.name || '';
426        var component = window.BX && BX.Sale ? BX.Sale.OrderAjaxComponent : null;
427
428        $input.val(displayValue);
429        $input.attr('data-city-name', city.name || '');
430        $input.attr('data-location-id', city.id || '');
431        $input.attr('data-city-selected', '1');
432        hideShippingCitySuggestions($list, $input);
433        updateShippingCityTarget($input);
434
435        if (component && component.isAkvastomLayout && component.isAkvastomLayout()) {
436            component.akvastomCityState = {
437                locationId: String(city.id || ''),
438                cityName: city.name || '',
439                displayValue: displayValue,
440                selected: true
441            };
442            if (component.markAkvastomCityChange) {
443                component.markAkvastomCityChange();
444            }
445        }
446
447        setOrderLocationId(city.id);
448        updateAkvastomCityDependentUi();
449
450        if (component) {
451            if (component.syncAkvastomCityToOrderProps) {
452                component.syncAkvastomCityToOrderProps();
453            }
454            if (component.saveAkvastomCityState) {
455                component.saveAkvastomCityState();
456            }
457        }
458    }
459
460    function invalidateShippingCitySelection($input) {
461        if ($input.attr('data-city-selected') !== '1') {
462            return;
463        }
464
465        $input.removeAttr('data-city-selected');
466        $input.removeAttr('data-city-name');
467        clearShippingCityTarget();
468        updateAkvastomCityDependentUi();
469    }
470
471    function getShippingCitySuggestions($input) {
472        var $wrap = $input.closest('.js-shipping-city-autocomplete');
473
474        if (!$wrap.length) {
475            $input.wrap('<div class="input-type-1__autocomplete js-shipping-city-autocomplete"></div>');
476            $wrap = $input.parent();
477        }
478
479        var $list = $wrap.find('.js-shipping-city-suggestions');
480
481        if (!$list.length) {
482            $list = $('<div class="js-shipping-city-suggestions shipping-city-suggestions" role="listbox" hidden></div>');
483            $wrap.append($list);
484        }
485
486        return $list;
487    }
488
489    function getShippingCityWrap($input) {
490        return $input.closest('.js-shipping-city-autocomplete');
491    }
492
493    function hideShippingCitySuggestions($list, $input) {
494        $list.attr('hidden', true).empty();
495        $input.attr('aria-expanded', 'false');
496        getShippingCityWrap($input).removeClass('is-open');
497    }
498
499    function showShippingCitySuggestions($list, $input) {
500        $list.removeAttr('hidden');
501        $input.attr('aria-expanded', 'true');
502        getShippingCityWrap($input).addClass('is-open');
503    }
504
505    function setActiveShippingCitySuggestion($list, index) {
506        var $items = $list.find('.shipping-city-suggestions__item');
507
508        if (!$items.length) {
509            $list.data('activeIndex', -1);
510            return;
511        }
512
513        if (index < 0) {
514            index = $items.length - 1;
515        }
516
517        if (index >= $items.length) {
518            index = 0;
519        }
520
521        $list.data('activeIndex', index);
522        $items.removeClass('is-active').eq(index).addClass('is-active');
523    }
524
525    function renderShippingCitySuggestions($input, cities) {
526        var $list = getShippingCitySuggestions($input);
527
528        $list.empty();
529        $list.data('activeIndex', -1);
530
531        if (!cities.length) {
532            hideShippingCitySuggestions($list, $input);
533            return;
534        }
535
536        cities.forEach(function(city, index) {
537            var $item = $('<div>', {
538                class: 'shipping-city-suggestions__item',
539                role: 'option'
540            });
541
542            $('<span>', {
543                class: 'shipping-city-suggestions__title',
544                text: city.name || ''
545            }).appendTo($item);
546
547            if (city.region) {
548                $('<span>', {
549                    class: 'shipping-city-suggestions__region',
550                    text: city.region
551                }).appendTo($item);
552            }
553
554            $item.on('mouseenter', function() {
555                setActiveShippingCitySuggestion($list, index);
556            });
557
558            $item.on('mousedown', function(e) {
559                e.preventDefault();
560            });
561
562            $item.on('click', function() {
563                selectShippingCityFromList($input, city);
564                $input.trigger('focus');
565            });
566
567            $list.append($item);
568        });
569
570        showShippingCitySuggestions($list, $input);
571    }
572
573    function requestShippingCitySuggestions($input, term) {
574        var $list = getShippingCitySuggestions($input);
575
576        if (shippingCitySearchXhr) {
577            shippingCitySearchXhr.abort();
578            shippingCitySearchXhr = null;
579        }
580
581        if (term.length < 2) {
582            hideShippingCitySuggestions($list, $input);
583            return;
584        }
585
586        shippingCitySearchXhr = $.ajax({
587            url: '/local/ajax/shipping_cities.php',
588            method: 'GET',
589            dataType: 'json',
590            data: { q: term },
591            success: function(response) {
592                var cities = response && Array.isArray(response.cities) ? response.cities : [];
593                renderShippingCitySuggestions($input, cities);
594            },
595            error: function() {
596                hideShippingCitySuggestions($list, $input);
597            },
598            complete: function() {
599                shippingCitySearchXhr = null;
600            }
601        });
602    }
603
604    function initShippingCityAutocomplete($input) {
605        var $list = getShippingCitySuggestions($input);
606
607        $input.on('keydown.shippingCitySuggestions', function(e) {
608            if ($list.is('[hidden]')) {
609                return;
610            }
611
612            var $items = $list.find('.shipping-city-suggestions__item');
613            if (!$items.length) {
614                return;
615            }
616
617            var activeIndex = $list.data('activeIndex');
618            if (typeof activeIndex !== 'number') {
619                activeIndex = -1;
620            }
621
622            if (e.key === 'ArrowDown') {
623                e.preventDefault();
624                setActiveShippingCitySuggestion($list, activeIndex + 1);
625            } else if (e.key === 'ArrowUp') {
626                e.preventDefault();
627                setActiveShippingCitySuggestion($list, activeIndex - 1);
628            } else if (e.key === 'Enter' && activeIndex >= 0) {
629                e.preventDefault();
630                $items.eq(activeIndex).trigger('click');
631            } else if (e.key === 'Escape') {
632                hideShippingCitySuggestions($list, $input);
633            }
634        });
635
636        $input.on('input', function() {
637            var term = $.trim($input.val());
638
639            clearTimeout(shippingCitySearchTimer);
640            invalidateShippingCitySelection($input);
641
642            if (term.length < 2) {
643                hideShippingCitySuggestions($list, $input);
644                return;
645            }
646
647            shippingCitySearchTimer = setTimeout(function() {
648                requestShippingCitySuggestions($input, term);
649            }, 250);
650        });
651
652        $input.on('blur', function() {
653            setTimeout(function() {
654                hideShippingCitySuggestions($list, $input);
655            }, 150);
656        });
657    }
658
659    if ($('.js-shipping-city-target').length) {
660        clearShippingCityTarget();
661    }
662
663    $('.js-shipping-city').each(function() {
664        initShippingCityAutocomplete($(this));
665    });
666
667    window.initShippingCityAutocomplete = initShippingCityAutocomplete;
668    window.updateShippingCityTarget = updateShippingCityTarget;
669    window.syncShippingCityTargetSidebar = syncShippingCityTargetSidebar;
670    window.updateAkvastomCityDependentUi = updateAkvastomCityDependentUi;
671    window.setOrderLocationId = setOrderLocationId;
672    window.requestOrderRefreshAfterCityChange = requestOrderRefreshAfterCityChange;
673});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.