PageSourceSearch

https://techmkt.pro/wp-content/plugins/techmkt-advanced-search/assets/techmkt-search.js?ver=2.2

js techmkt.pro collected 2026-10-07 18:12:16 UTC 27,164 bytes, 578 lines download raw bytes

1jQuery(document).ready(function($) {
2    const techSearch = {
3        init: function() {
4            this.cacheElements();
5            this.bindEvents();
6            this.initAjaxSearch();
7        },
8       
9        cacheElements: function() {
10            // Основные элементы формы фильтра
11            this.$form = $('.tech-advanced-product-search-form');
12            this.$catalog = $('#tech-acf-field-ap_branch');
13            this.$category = $('#tech-acf-field-make');
14            this.$model = $('#tech-acf-field-model');
15            this.$catalogField = $('.tech-div-ap-search-item[data-field_name="ap_branch"]');
16            this.$validationMessage = this.$catalogField.find('.tech-validation-message');
17            this.$preloader = $('.tech-search-preloader-overlay');
18            this.$container = $('.tech-css-generated-variation-div-1');
19           
20            // Элементы быстрого поиска
21            this.$ajaxSearchContainer = $('.techmkt-quick-search-container .tech-ajax-search-container');
22            this.$ajaxSearchInput = $('.techmkt-quick-search-container .tech-category-search-input');
23            this.$ajaxSearchResults = $('.techmkt-quick-search-container .tech-search-results');
24            this.$ajaxSearchSubmit = $('.techmkt-quick-search-container .tech-search-submit-btn');
25            
26            // ДОБАВЛЕНО: Кэшируем все поля для валидации
27            this.$categoryField = $('.tech-div-ap-search-item[data-field_name="make"]');
28            this.$modelField = $('.tech-div-ap-search-item[data-field_name="model"]');
29            this.$searchButtonField = $('.tech-div-uk-margin-ap-search-item-ap-search-button');
30        },
31       
32        bindEvents: function() {
33            this.$catalog.on('change', this.handleCatalogChange.bind(this));
34            this.$category.on('change', this.handleCategoryChange.bind(this));
35            this.$form.on('submit', this.handleSubmit.bind(this));
36            
37            // ДОБАВЛЕНО: Простые обработчики клика для всех полей
38            this.$ajaxSearchInput.on('click focus', this.simpleValidate.bind(this, 'quick_search'));
39            this.$category.on('click', this.simpleValidate.bind(this, 'category'));
40            this.$model.on('click', this.simpleValidate.bind(this, 'model'));
41        },
42        
43        // ДОБАВЛЕНО: Простая валидация при клике
44        simpleValidate: function(fieldType, e) {
45            const catalogId = this.$catalog.val();
46            
47            if (!catalogId) {
48                // Подсвечиваем поле каталога
49                this.$catalogField.addClass('tech-field-error');
50                
51                // Показываем сообщение под тем полем, на которое кликнули
52                this.showSimpleMessage(fieldType);
53                
54                // Для быстрого поиска блокируем ввод и клавиатуру
55                if (fieldType === 'quick_search') {
56                    e.preventDefault();
57                    this.$ajaxSearchInput.blur();
58                    // Временная блокировка для предотвращения клавиатуры
59                    this.$ajaxSearchInput.prop('readonly', true);
60                    setTimeout(() => {
61                        this.$ajaxSearchInput.prop('readonly', false);
62                    }, 500);
63                }
64                
65                return false;
66            }
67            
68            // Если каталог выбран, убираем все ошибки
69            this.clearMessages();
70            return true;
71        },
72        
73        // ДОБАВЛЕНО: Простой показ сообщения
74        showSimpleMessage: function(fieldType) {
75            // Сначала скрываем все сообщения
76            this.clearMessages();
77            
78            let targetField;
79            
80            switch(fieldType) {
81                case 'quick_search':
82                    targetField = this.$ajaxSearchContainer;
83                    break;
84                case 'category':
85                    targetField = this.$categoryField;
86                    break;
87                case 'model':
88                    targetField = this.$modelField;
89                    break;
90                case 'search_button':
91                    targetField = this.$searchButtonField;
92                    break;
93            }
94            
95            if (targetField) {
96                // Добавляем сообщение об ошибке
97                const errorMsg = $('<div class="tech-simple-validation-message" style="color: #EC6504; font-size: 14px; margin-top: 5px; font-family: Roboto;">Необходимо выбрать каталог</div>');
98                targetField.append(errorMsg);
99            }
100        },
101        
102        // ДОБАВЛЕНО: Очистка всех сообщений
103        clearMessages: function() {
104            this.$catalogField.removeClass('tech-field-error');
105            $('.tech-simple-validation-message').remove();
106        },
107       
108        initAjaxSearch: function() {
109            let searchTimeout;
110            let lastSearchTerm = '';
111           
112            // Добавляем оверлей и кнопку закрытия для мобильных
113            $('body').append('<div class="tech-search-overlay"></div>');
114            $('.techmkt-quick-search-container').append('<button class="tech-mobile-close-btn">×</button>');
115           
116            const self = this;
117            const overlay = $('.tech-search-overlay');
118            const mobileCloseBtn = $('.techmkt-quick-search-container .tech-mobile-close-btn');
119            const searchInput = this.$ajaxSearchInput;
120            const resultsContainer = this.$ajaxSearchResults;
121            const searchContainer = $('.techmkt-quick-search-container');
122           
123            let isMobileSearchActive = false;
124           
125            // Закрытие результатов при клике вне области (десктоп)
126            $(document).on('click', function(e) {
127                if (window.innerWidth > 767 &&
128                    !$(e.target).closest('.techmkt-quick-search-container').length &&
129                    !$(e.target).closest('.woosq-popup').length &&
130                    !$(e.target).closest('.tech-quick-view-btn').length &&
131                    resultsContainer.is(':visible')) {
132                    resultsContainer.hide();
133                }
134            });
135           
136            // Активация мобильного поиска с проверкой каталога
137            const activateMobileSearch = () => {
138                if (isMobileSearchActive) return;
139               
140                // ПРОВЕРКА КАТАЛОГА - если не выбран, показываем ошибку и НЕ активируем мобильный режим
141                const catalogId = self.$catalog.val();
142                if (!catalogId) {
143                    self.$catalogField.addClass('tech-field-error');
144                    self.showSimpleMessage('quick_search');
145                    return;
146                }
147               
148                self.clearMessages();
149               
150                isMobileSearchActive = true;
151                searchContainer.addClass('tech-mobile-search-active');
152                overlay.fadeIn(300);
153                mobileCloseBtn.show();
154               
155                setTimeout(() => {
156                    searchInput.focus();
157                }, 350);
158            };
159           
160            // Деактивация мобильного поиска
161            const deactivateMobileSearch = () => {
162                if (!isMobileSearchActive) return;
163               
164                isMobileSearchActive = false;
165                searchContainer.removeClass('tech-mobile-search-active');
166                overlay.fadeOut(300);
167                resultsContainer.hide();
168                mobileCloseBtn.hide();
169                searchInput.blur();
170            };
171           
172            // Закрытие при клике на крестик
173            mobileCloseBtn.on('click', function(e) {
174                e.stopPropagation();
175                deactivateMobileSearch();
176            });
177           
178            // Закрытие при клике на оверлей
179            overlay.on('click', function() {
180                deactivateMobileSearch();
181            });
182           
183            // Активация при фокусе на поле ввода (только мобильные) с проверкой каталога
184            searchInput.on('focus', function() {
185                if (window.innerWidth <= 767) {
186                    // Перед активацией проверяем каталог
187                    const catalogId = self.$catalog.val();
188                    if (!catalogId) {
189                        // Показываем валидацию без активации мобильного режима
190                        self.$catalogField.addClass('tech-field-error');
191                        self.showSimpleMessage('quick_search');
192                        // Блокируем клавиатуру
193                        searchInput.blur();
194                        searchInput.prop('readonly', true);
195                        setTimeout(() => {
196                            searchInput.prop('readonly', false);
197                        }, 500);
198                        return;
199                    }
200                    activateMobileSearch();
201                }
202            });
203           
204            // НОВАЯ ФУНКЦИЯ: Выносим логику поиска сюда
205            const performSearch = (force = false) => {
206                const searchTerm = searchInput.val().trim();
207                const catalogId = self.$catalog.val();
208               
209                if (!catalogId) {
210                    self.$catalogField.addClass('tech-field-error');
211                    self.showSimpleMessage('quick_search');
212                    resultsContainer.hide().empty();
213                    return;
214                }
215               
216                self.clearMessages();
217               
218                if (searchTerm.length < 2) {
219                    resultsContainer.hide().empty();
220                    lastSearchTerm = '';
221                    return;
222                }
223               
224                // Проверка на повтор: если не force и термин не изменился, пропускаем
225                if (!force && searchTerm === lastSearchTerm) {
226                    return;
227                }
228               
229                lastSearchTerm = searchTerm;
230               
231                clearTimeout(searchTimeout);
232                resultsContainer.html('<div class="tech-search-loading">🔍 Поиск...</div>').show();
233               
234                searchTimeout = setTimeout(() => {
235                    const categoryId = self.$category.val();
236                   
237                    $.ajax({
238                        url: techmkt_ajax.ajax_url,
239                        type: 'POST',
240                        data: {
241                            action: 'techmkt_ajax_search',
242                            search_term: searchTerm,
243                            catalog_id: catalogId,
244                            category_id: categoryId,
245                            nonce: techmkt_ajax.nonce
246                        },
247                        success: (response) => {
248                            if (response.success && response.data.length > 0) {
249                                let html = '';
250                                response.data.forEach(function(product) {
251                                    let metaHtml = '';
252                                    if (product.artikul) {
253                                        metaHtml += `<span class="tech-meta-item">Артикул: ${product.artikul}</span>`;
254                                    }
255                                    if (product.kod) {
256                                        metaHtml += `<span class="tech-meta-item">Код: ${product.kod}</span>`;
257                                    }
258                                    if (product.product_id_field) {
259                                        metaHtml += `<span class="tech-meta-item tech-hidden">ID: ${product.product_id_field}</span>`;
260                                    }
261                                   
262                                    html += `
263                                        <div class="tech-search-result-item" data-url="${product.url}">
264                                            <div class="tech-result-image">
265                                                ${product.image ? `<img src="${product.image}" alt="${product.title}" loading="lazy">` : '<div class="tech-no-image">📦</div>'}
266                                            </div>
267                                            <div class="tech-result-content">
268                                                <div class="tech-result-title">${product.title}</div>
269                                                ${metaHtml ? `<div class="tech-result-meta">${metaHtml}</div>` : ''}
270                                                <div class="tech-result-price">${product.price}</div>
271                                            </div>
272                                            <div class="tech-result-actions">
273                                                ${product.quick_view}
274                                            </div>
275                                        </div>
276                                    `;
277                                });
278                               
279                                if (window.innerWidth <= 767) {
280                                    html = `<div class="tech-results-count">Найдено: ${response.data.length}</div>` + html;
281                                } else {
282                                    html = `<div class="tech-results-count">Найдено: ${response.data.length} <span class="tech-close-results">&times;</span></div>` + html;
283                                }
284                               
285                                resultsContainer.html(html).show();
286                            } else {
287                                resultsContainer.html('<div class="tech-search-no-results">😔 Ничего не найдено</div>').show();
288                            }
289                        },
290                        error: (xhr, status, error) => {
291                            console.error('Search error:', error);
292                            resultsContainer.html('<div class="tech-search-error">⚠️ Ошибка поиска. Попробуйте еще раз.</div>').show();
293                        }
294                    });
295                }, 350);
296            };
297           
298            // Поиск при вводе текста (вызов без force)
299            searchInput.on('input', function() {
300                performSearch();
301            });
302           
303            // Обработка Enter (вызов с force)
304            searchInput.on('keydown', function(e) {
305                if (e.key === 'Enter') {
306                    e.preventDefault();
307                    if (searchInput.val().trim().length >= 2) {
308                        performSearch(true);
309                    }
310                }
311            });
312           
313            // Обработчик для кнопки поиска (вызов с force)
314            this.$ajaxSearchSubmit.on('click', function() {
315                if (searchInput.val().trim().length >= 2) {
316                    performSearch(true);
317                }
318            });
319           
320            // Закрытие результатов при клике на крестик в результатах (только десктоп)
321            $(document).on('click', '.tech-close-results', function() {
322                if (window.innerWidth > 767) {
323                    resultsContainer.hide();
324                }
325            });
326           
327            // Редирект при клике на результат
328            $(document).on('click', '.tech-search-result-item', function() {
329                window.location.href = $(this).data('url');
330            });
331           
332            // Предотвращаем переход при клике на кнопку быстрого просмотра
333            $(document).on('click', '.tech-quick-view-btn', function(e) {
334                e.stopPropagation();
335            });
336           
337            // Скрытие клавиатуры при скролле результатов (мобильные)
338            resultsContainer.on('scroll', function() {
339                if (window.innerWidth <= 767) {
340                    searchInput.blur();
341                }
342            });
343           
344            // Закрытие при нажатии ESC
345            $(document).on('keyup', function(e) {
346                if (e.keyCode === 27) {
347                    if (window.innerWidth <= 767 && isMobileSearchActive) {
348                        deactivateMobileSearch();
349                    } else {
350                        resultsContainer.hide();
351                        searchInput.blur();
352                    }
353                }
354            });
355           
356            // Сброс при изменении размера окна
357            $(window).on('resize orientationchange', function() {
358                if (window.innerWidth > 767 && isMobileSearchActive) {
359                    deactivateMobileSearch();
360                }
361            });
362        },
363       
364        showPreloader: function() {
365            this.$preloader.show();
366            this.$container.addClass('tech-search-loading');
367        },
368       
369        hidePreloader: function() {
370            this.$preloader.hide();
371            this.$container.removeClass('tech-search-loading');
372        },
373       
374        handleCatalogChange: function(e) {
375            const catalogId = $(e.target).val();
376           
377            // Сбрасываем зависимые поля
378            this.$category.prop('disabled', true).html('<option value="">Все категории</option>');
379            this.$model.prop('disabled', true).html('<option value="">Все модели</option>');
380           
381            if (catalogId) {
382                this.$category.prop('disabled', false);
383                this.showPreloader();
384               
385                // Убираем валидацию
386                this.clearMessages();
387               
388                // Запускаем обе загрузки параллельно
389                Promise.all([
390                    this.loadCategories(catalogId),
391                    this.loadAllProducts(catalogId)
392                ]).then(() => {
393                    this.hidePreloader();
394                }).catch(() => {
395                    this.hidePreloader();
396                });
397            } else {
398                // Если каталог не выбран, сбрасываем все
399                this.$category.prop('disabled', true).html('<option value="">Все категории</option>');
400                this.$model.prop('disabled', true).html('<option value="">Все модели</option>');
401            }
402        },
403       
404        handleCategoryChange: function(e) {
405            const categoryId = $(e.target).val();
406            const catalogId = this.$catalog.val();
407           
408            if (categoryId && catalogId) {
409                this.showPreloader();
410                this.loadProductsByCategory(catalogId, categoryId)
411                    .then(() => this.hidePreloader())
412                    .catch(() => this.hidePreloader());
413            } else if (catalogId) {
414                // Если категория не выбрана, показываем все товары каталога
415                this.showPreloader();
416                this.loadAllProducts(catalogId)
417                    .then(() => this.hidePreloader())
418                    .catch(() => this.hidePreloader());
419            }
420        },
421       
422        loadCategories: function(catalogId) {
423            return new Promise((resolve, reject) => {
424                $.ajax({
425                    url: techmkt_ajax.ajax_url,
426                    type: 'POST',
427                    data: {
428                        action: 'get_categories_by_catalog',
429                        catalog_id: catalogId,
430                        nonce: techmkt_ajax.nonce
431                    },
432                    success: (response) => {
433                        if (response.success) {
434                            let options = '<option value="">Все категории</option>';
435                            response.data.forEach(category => {
436                                options += `<option value="${category.id}">${category.name}</option>`;
437                            });
438                            this.$category.html(options);
439                            resolve();
440                        } else {
441                            reject();
442                        }
443                    },
444                    error: () => reject()
445                });
446            });
447        },
448       
449        loadAllProducts: function(catalogId) {
450            return new Promise((resolve, reject) => {
451                $.ajax({
452                    url: techmkt_ajax.ajax_url,
453                    type: 'POST',
454                    data: {
455                        action: 'get_all_products_by_catalog',
456                        catalog_id: catalogId,
457                        nonce: techmkt_ajax.nonce
458                    },
459                    success: (response) => {
460                        if (response.success) {
461                            this.updateProductsSelect(response.data);
462                            resolve();
463                        } else {
464                            reject();
465                        }
466                    },
467                    error: () => reject()
468                });
469            });
470        },
471       
472        loadProductsByCategory: function(catalogId, categoryId) {
473            return new Promise((resolve, reject) => {
474                $.ajax({
475                    url: techmkt_ajax.ajax_url,
476                    type: 'POST',
477                    data: {
478                        action: 'get_products_by_filters',
479                        catalog_id: catalogId,
480                        category_id: categoryId,
481                        nonce: techmkt_ajax.nonce
482                    },
483                    success: (response) => {
484                        if (response.success) {
485                            this.updateProductsSelect(response.data);
486                            resolve();
487                        } else {
488                            reject();
489                        }
490                    },
491                    error: () => reject()
492                });
493            });
494        },
495       
496        updateProductsSelect: function(products) {
497            let options = '<option value="">Все модели</option>';
498            products.forEach(product => {
499                const shortName = product.name.length > 50 ? product.name.substring(0, 50) + '...' : product.name;
500                options += `<option value="${product.id}" data-url="${product.url}" title="${product.name}">${shortName}</option>`;
501            });
502            this.$model.html(options).prop('disabled', false);
503        },
504       
505        handleSubmit: function(e) {
506            e.preventDefault();
507           
508            const catalogId = this.$catalog.val();
509            const categoryId = this.$category.val();
510            const modelId = this.$model.val();
511            const modelOption = this.$model.find('option:selected');
512           
513            // Валидация каталога
514            if (!catalogId) {
515                this.$catalogField.addClass('tech-field-error');
516                this.showSimpleMessage('search_button');
517                return false;
518            }
519           
520            // Определяем URL для редиректа
521            let redirectUrl = '';
522           
523            if (modelId && modelOption.data('url')) {
524                redirectUrl = modelOption.data('url');
525            } else if (categoryId) {
526                redirectUrl = this.getCategoryUrl(categoryId);
527            } else {
528                redirectUrl = this.getCatalogUrl(catalogId);
529            }
530           
531            if (redirectUrl) {
532                window.location.href = redirectUrl;
533            }
534           
535            return false;
536        },
537       
538        getCatalogUrl: function(catalogId) {
539            const catalogUrls = {
540                150: 'https://techmkt.pro/product-category/spectehnika-category/',
541                149: 'https://techmkt.pro/product-category/zapchasti-category/'
542            };
543            return catalogUrls[catalogId] || '';
544        },
545       
546        getCategoryUrl: function(categoryId) {
547            const categorySlugs = {
548                62: 'frontalnye-pogruzchiki',
549                63: 'ekskavatory-pogruzchiki',
550                64: 'karernye-samosvaly',
551                65: 'gusenichnye-ekskavatory',
552                66: 'kolesnye-ekskavatory',
553                67: 'teleskopicheskie-pogruzchiki',
554                136: 'filtri',
555                137: 'nozhi_koronki_zubi_krepeahi_k_nim',
556                138: 'masla_i_smazochnie_materiali',
557                139: 'sharniti-sochlenenia',
558                140: 'shini-i-kolesa',
559                141: 'dvigatel-i-komplektuiushie',
560                142: 'gidravlika-i-cilindri',
561                143: 'kuzov-i-stekla',
562                144: 'akkumuliatori-i-electrika',
563                145: 'zapchasti',
564                146: 'tormoznaia-sistema',
565                147: 'instrumenti-i-rashodniki'
566            };
567           
568            const slug = categorySlugs[categoryId];
569            if (slug) {
570                return `https://techmkt.pro/product-category/${slug}/`;
571            }
572           
573            return 'https://techmkt.pro/product-category/category/';
574        }
575    };
576   
577    techSearch.init();
578});

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.