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">×</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.