1document.addEventListener("DOMContentLoaded", function () { 2 3 const form = document.querySelector(".js-adv-filter__form"); 4 if(form){ 5 const container = document.querySelector("#adv-filter-gallery"); 6 const phoneNum = container ? container.getAttribute('data-phone') : ''; 7 const spinner = document.getElementById("loading-spinner"); 8 const sortRadios = form.querySelectorAll('input[name="sort"]'); 9 const countFilter = document.querySelector(".js-adv-filter__results-count"); 10 const filterPanel = document.querySelector("#filter-panel"); 11 12 let currentPage = 1; 13 let loading = false; 14 let allLoaded = false; 15 let abortController = null; 16 let currentRequestId = 0; 17 18 const priceMinInput = form.querySelector('input[name="price-min-value"]'); 19 const priceMaxInput = form.querySelector('input[name="price-max-value"]'); 20 const yearMinInput = form.querySelector('input[name="year-min-value"]'); 21 const yearMaxInput = form.querySelector('input[name="year-max-value"]'); 22 23 const manualInputFlags = { 24 priceMin: false, 25 priceMax: false, 26 yearMin: false, 27 yearMax: false, 28 }; 29 30 const urlParams = new URLSearchParams(window.location.search); 31 const paramMap = { 32 'price-min-value': { input: priceMinInput, flag: 'priceMin' }, 33 'price-max-value': { input: priceMaxInput, flag: 'priceMax' }, 34 'year-min-value': { input: yearMinInput, flag: 'yearMin' }, 35 'year-max-value': { input: yearMaxInput, flag: 'yearMax' }, 36 }; 37 for (const [param, cfg] of Object.entries(paramMap)) { 38 const val = urlParams.get(param); 39 if (val && cfg.input) { 40 cfg.input.value = val; 41 manualInputFlags[cfg.flag] = true; 42 } 43 } 44 45 const inputs = [ 46 { el: priceMinInput, key: 'priceMin' }, 47 { el: priceMaxInput, key: 'priceMax' }, 48 { el: yearMinInput, key: 'yearMin' }, 49 { el: yearMaxInput, key: 'yearMax' }, 50 ]; 51 52 for (const { el, key } of inputs) { 53 el.addEventListener('input', () => { 54 manualInputFlags[key] = true; 55 }); 56 } 57 58 var applyBtn = document.querySelector('[data-filter-apply]'); 59 var resetBtnEl = document.querySelector('[data-filter-reset]'); 60 function setBtnLoading(btn, on) { 61 if (!btn) return; 62 if (on) btn.classList.add('btn--loading'); 63 else btn.classList.remove('btn--loading'); 64 } 65 66 function animateCount(el, target) { 67 target = parseInt(target) || 0; 68 var start = parseInt(el.textContent) || 0; 69 if (start === target) { el.textContent = target; return; } 70 var dur = 400, t0 = null; 71 function step(ts) { 72 if (!t0) t0 = ts; 73 var p = Math.min((ts - t0) / dur, 1); 74 var ease = 1 - Math.pow(1 - p, 3); 75 el.textContent = Math.round(start + (target - start) * ease); 76 if (p < 1) requestAnimationFrame(step); 77 } 78 requestAnimationFrame(step); 79 } 80 81 const skelHtml = '<article class="vcard-skel"><div class="vcard-skel__media"></div><div class="vcard-skel__body"><div class="vcard-skel__line"></div><div class="vcard-skel__line vcard-skel__line--short"></div><div class="vcard-skel__specs"><div class="vcard-skel__spec"></div><div class="vcard-skel__spec"></div><div class="vcard-skel__spec"></div><div class="vcard-skel__spec"></div></div><div class="vcard-skel__line vcard-skel__line--xs"></div><div class="vcard-skel__btn"></div></div></article>'; 82 function showSkeletons(){ container.innerHTML = skelHtml.repeat(6); } 83 function clearSkeletons(){ var skels = container.querySelectorAll('.vcard-skel'); skels.forEach(function(s){ s.remove(); }); } 84 const showSpinner = () => { if(!container.children.length) showSkeletons(); }; 85 const hideSpinner = () => { clearSkeletons(); }; 86 87 function buildFilterUrl() { 88 const slugFields = { drive: {}, transmission: {}, make: {}, state: {} }; 89 90 document.querySelectorAll('input[name="make[]"]').forEach(input => { 91 slugFields.make[input.value] = input.dataset.slug; 92 }); 93 document.querySelectorAll('input[name="drive[]"]').forEach(input => { 94 slugFields.drive[input.value] = input.dataset.slug; 95 }); 96 document.querySelectorAll('input[name="transmission[]"]').forEach(input => { 97 slugFields.transmission[input.value] = input.dataset.slug; 98 }); 99 document.querySelectorAll('input[name="state[]"]').forEach(input => { 100 slugFields.state[input.value] = input.dataset.slug; 101 }); 102 103 const params = new URLSearchParams(); 104 const slugs = []; 105 const formData = new FormData(form); 106 const selectedSort = form.querySelector('input[name="sort"]:checked'); 107 if (selectedSort?.value) params.set("sort", selectedSort.value); 108 109 if (manualInputFlags.priceMin && priceMinInput?.value) { 110 params.set("price-min-value", priceMinInput.value); 111 } 112 if (manualInputFlags.priceMax && priceMaxInput?.value) { 113 params.set("price-max-value", priceMaxInput.value); 114 } 115 if (manualInputFlags.yearMin && yearMinInput?.value) { 116 params.set("year-min-value", yearMinInput.value); 117 } 118 if (manualInputFlags.yearMax && yearMaxInput?.value) { 119 params.set("year-max-value", yearMaxInput.value); 120 } 121 122 const selectedValues = { make: [], drive: [], transmission: [], state: [] }; 123 124 for (const [key, value] of formData.entries()) { 125 if (!value) continue; 126 127 if ( 128 (key === 'price-min-value' && manualInputFlags.priceMin) || 129 (key === 'price-max-value' && manualInputFlags.priceMax) || 130 (key === 'year-min-value' && manualInputFlags.yearMin) || 131 (key === 'year-max-value' && manualInputFlags.yearMax) 132 ) { 133 continue; 134 } 135 136 if (key.endsWith('[]')) { 137 const field = key.replace('[]', ''); 138 if (selectedValues.hasOwnProperty(field)) { 139 selectedValues[field].push(value); 140 } else { 141 params.append(key, value); 142 } 143 } else { 144 params.append(key, value); 145 } 146 } 147 148 for (const field of ["make", "transmission", "drive", "state"]) { 149 if (selectedValues[field].length === 1) { 150 slugs.push(slugFields[field][selectedValues[field][0]]); 151 } else if (selectedValues[field].length > 1) {
152 selectedValues[field].forEach(value => params.append(`${field}[]`, value)); 153 } 154 } 155 156 let url = "/stock/"; 157 if (slugs.length) url += slugs.join("/") + "/"; 158 const queryString = params.toString(); 159 if (queryString) url += "?" + queryString; 160 161 return url; 162 } 163 164 function updateUrl() { 165 const newUrl = buildFilterUrl(); 166 window.history.pushState(null, "", newUrl); 167 } 168 169 let apiData = null; 170 171 async function loadProducts(page = 1) { 172 if (loading || allLoaded) return; 173 174 if (abortController) abortController.abort(); 175 abortController = new AbortController(); 176 177 currentRequestId++; 178 const requestId = currentRequestId; 179 180 loading = true; 181 showSpinner(); 182 183 try { 184 const url = `/site-api/get-autos/?${getParams(page, apiData)}`; 185 const response = await fetch(url, { signal: abortController.signal }); 186 187 if (!response.ok) throw new Error('Network response was not ok'); 188 const res = await response.json(); 189 if (requestId !== currentRequestId) return; 190 191 if (!res.success) throw new Error('API response was not successful'); 192 193 if (res.ranges) { 194 apiData = res.ranges; 195 196 if (priceMinInput && !manualInputFlags.priceMin) priceMinInput.value = apiData.minPrice || ''; 197 if (priceMaxInput && !manualInputFlags.priceMax) priceMaxInput.value = apiData.maxPrice || ''; 198 if (yearMinInput && !manualInputFlags.yearMin) yearMinInput.value = apiData.minYear || ''; 199 if (yearMaxInput && !manualInputFlags.yearMax) yearMaxInput.value = apiData.maxYear || ''; 200 201 priceMinInput?.dispatchEvent(new Event('input')); 202 priceMaxInput?.dispatchEvent(new Event('input')); 203 yearMinInput?.dispatchEvent(new Event('input')); 204 yearMaxInput?.dispatchEvent(new Event('input')); 205 206 updateUrl(); 207 } 208 209 if (page === 1) { 210 211 var oldCards = container.querySelectorAll('.vcard'); 212 oldCards.forEach(function(c){ c.style.opacity='0'; c.style.transform='translateY(10px)'; }); 213 await new Promise(function(r){ setTimeout(r, oldCards.length ? 250 : 0); }); 214 container.innerHTML = ""; 215 allLoaded = false; 216 } 217 218 if (res.products.length === 0) { 219 allLoaded = true; 220 if (page === 1) { 221 animateCount(countFilter, 0); 222 container.innerHTML = "<p>ÐÐµÑ ÑоваÑов по вÑбÑаннÑм ÑилÑÑÑам.</p>"; 223 } 224 return; 225 } 226 227 const fragment = document.createDocumentFragment(); 228 res.products.forEach(product => { 229 const el = document.createElement('article'); 230 el.className = "vcard vcard--entering"; 231 const totalDiscount = (product.CreditDiscount || 0) + (product.InsuranceDiscount || 0) + (product.TradeinDiscount || 0); 232 const rawPrice = Number(String(product.Price).replace(/\s/g, '')); 233 const priceFmt = rawPrice.toLocaleString('ru'); 234 const finalPrice = totalDiscount ? (rawPrice - totalDiscount).toLocaleString('ru') : priceFmt; 235 const mileageNum = Number(product.Mileage) || 0; 236 const powerMatch = (product.Modification || '').match(/\((\d+)\s*л\.?\s*Ñ\.?\)/); 237 const powerText = powerMatch ? powerMatch[1] + ' л.Ñ.' : ''; 238 var _volN = (product.EngineValue && Number(product.EngineValue) > 0) ? product.EngineValue : ''; 239 if (!_volN) { 240 var _ms = String(product.Modification || ''); 241 242 var _vm = _ms.match(/^\s*(\d(?:[.,]\d)?)\b/) || _ms.match(/\b(\d[.,]\d)\b/); 243 if (_vm) _volN = _vm[1].replace(',', '.'); 244 } 245 const volText = _volN ? (_volN + ' л') : (product.Engine || ''); 246 const engineText = volText + (powerText ? ' (' + powerText + ')' : ''); 247 248 const CREDIT_DOWN = 0.5, CREDIT_TERM = 96, CREDIT_RATE = 0.03; 249 const _cr = CREDIT_RATE / 12, _fin = rawPrice * (1 - CREDIT_DOWN); 250 const monthly = _cr > 0 ? Math.round(_fin * _cr / (1 - Math.pow(1 + _cr, -CREDIT_TERM))) : Math.round(_fin / CREDIT_TERM); 251 const trim = [product.Complectation, product.Modification].filter(
251Boolean).join(' '); 252 const trimLine = trim + (product.Year ? ((trim ? ', ' : '') + product.Year + ' год') : ''); 253 const company = product.Company || 'AAA MOTORS, РоÑÑов-на-ÐонÑ'; 254 255 const specRows = [ 256 ['ÐÑобег', mileageNum > 0 ? mileageNum.toLocaleString('ru') + ' км' : ''], 257 ['ÐвигаÑелÑ', engineText], 258 ['ÐоÑобка', product.Transmission || ''], 259 ['ÐÑивод', product.Drive || ''] 260 ]; 261 const specsHtml = specRows 262 .filter(function(r){ return r[1]; }) 263 .map(function(r){ return '<li><span>' + r[0] + '</span><b>' + r[1] + '</b></li>'; }) 264 .join(''); 265 el.innerHTML = ` 266 <div class="vcard__media"> 267 ${product.image} 268 ${totalDiscount ? '<span class="vcard__save">ÐÑгода ' + totalDiscount.toLocaleString('ru') + ' â½</span>' : ''} 269 <span class="vcard__state">${product.State}</span> 270 </div> 271 <div class="vcard__body"> 272 <span class="vcard__accent" aria-hidden="true"></span> 273 <h3 class="vcard__name">${product.Make} ${product.Model}</h3> 274 <p class="vcard__trim">${trimLine}</p> 275 <ul class="vspecs vspecs--list">${specsHtml}</ul> 276 <div class="vcard__pricebox"> 277 <div class="vcard__price">${finalPrice} â½</div> 278 ${totalDiscount ? '<div class="vcard__old">' + priceFmt + ' â½</div>' : ''} 279 </div> 280 <div class="vcard__foot"> 281 <a class="btn btn--primary width-100%" href="${product.URL}"><span>ÐодÑобнее</span></a> 282 <button type="button" class="vcard__call" aria-controls="form-callback-opener" aria-label="ÐаказаÑÑ Ð·Ð²Ð¾Ð½Ð¾Ðº"><svg width="20" height="20"><use href="#i-phone"></use></svg></button> 283 </div> 284 <a class="vcard__link" href="${product.URL}" aria-label="${product.Model}"></a> 285 </div> 286 `; 287 fragment.appendChild(el); 288 }); 289 290 container.appendChild(fragment); 291 292 var newCards = container.querySelectorAll('.vcard--entering'); 293 newCards.forEach(function(c, i){ 294 setTimeout(function(){ c.classList.remove('vcard--entering'); }, i * 40); 295 }); 296 297 animateCount(countFilter, res.total); 298 } catch (err) { 299 if (err.name !== 'AbortError') { 300 console.error("Fetch error:", err); 301 if (page === 1) { 302 container.innerHTML = "<p>ÐÑибка загÑÑзки ÑоваÑов.</p>"; 303 } 304 allLoaded = true; 305 } 306 } finally { 307 hideSpinner(); 308 loading = false; 309 abortController = null; 310 } 311 } 312 313 function getParams(page = 1, apiData = null) { 314 const params = new URLSearchParams(); 315 316 if (priceMinInput) { 317 if (manualInputFlags.priceMin) { 318 params.set('price-min-value', priceMinInput.value); 319 } else if (apiData?.minPrice != null) { 320 params.set('price-min-value', apiData.minPrice); 321 } 322 } 323 324 if (priceMaxInput) { 325 if (manualInputFlags.priceMax) { 326 params.set('price-max-value', priceMaxInput.value); 327 } else if (apiData?.maxPrice != null) { 328 params.set('price-max-value', apiData.maxPrice); 329 } 330 } 331 332 if (yearMinInput) { 333 if (manualInputFlags.yearMin) { 334 params.set('year-min-value', yearMinInput.value); 335 } else if (apiData?.minYear != null) { 336 params.set('year-min-value', apiData.minYear); 337 } 338 } 339 340 if (yearMaxInput) { 341 if (manualInputFlags.yearMax) { 342 params.set('year-max-value', yearMaxInput.value); 343 } else if (apiData?.maxYear != null) { 344 params.set('year-max-value', apiData.maxYear); 345 } 346 } 347 348 const formData = new FormData(form); 349 for (const [key, value] of formData.entries()) { 350 if (!value) continue; 351 if (key.endsWith('[]')) { 352 params.append(key, value); 353 } else { 354 params.set(key, value); 355 } 356 } 357 358 params.set('page', page); 359 return params.toString(); 360 } 361 362 async function fetchAndApplyRanges() { 363 const baseFormData = new FormData(form); 364 baseFormData.delete('price-min-value'); 365 baseFormData.delete('price-max-value'); 366 baseFormData.delete('year-min-value'); 367 baseFormData.delete('year-max-value'); 368 369 const baseParams = new URLSearchParams(baseFormData); 370 baseParams.set('page', 1); 371
372 try { 373 const resRanges = await fetch(`/site-api/get-autos/?${baseParams.toString()}`); 374 const rangesData = await resRanges.json(); 375 if (rangesData.success && rangesData.ranges) { 376 apiData = rangesData.ranges; 377 378 if (priceMinInput && !manualInputFlags.priceMin) priceMinInput.value = apiData.minPrice || ''; 379 if (priceMaxInput && !manualInputFlags.priceMax) priceMaxInput.value = apiData.maxPrice || ''; 380 if (yearMinInput && !manualInputFlags.yearMin) yearMinInput.value = apiData.minYear || ''; 381 if (yearMaxInput && !manualInputFlags.yearMax) yearMaxInput.value = apiData.maxYear || ''; 382 383 priceMinInput.dispatchEvent(new Event('input')); 384 priceMaxInput.dispatchEvent(new Event('input')); 385 yearMinInput.dispatchEvent(new Event('input')); 386 yearMaxInput.dispatchEvent(new Event('input')); 387 } 388 } catch (err) { 389 console.error("ÐÑибка пÑи полÑÑении диапазонов:", err); 390 } 391 } 392 393 form.addEventListener("submit", async (e) => { 394 e.preventDefault(); 395 currentPage = 1; 396 allLoaded = false; 397 apiData = null; 398 399 setBtnLoading(applyBtn, true); 400 filterPanel.classList.remove("sidebar--is-visible"); 401 402 await fetchAndApplyRanges(); 403 await loadProducts(currentPage); 404 setBtnLoading(applyBtn, false); 405 406 const filters = {}; 407 408 ["make", "transmission", "drive", "state"].forEach((key) => { 409 const checked = document.querySelectorAll(`input[name="${key}[]"]:checked`); 410 if (checked.length === 1) { 411 const input = checked[0]; 412 filters[key] = { 413 slug: input.dataset.slug, 414 title: input.dataset.title, 415 }; 416 } else { 417 filters[key] = null; 418 } 419 }); 420 }); 421 422 form.querySelectorAll('input[type="checkbox"]').forEach(checkbox => { 423 checkbox.addEventListener('change', async () => { 424 currentPage = 1; 425 allLoaded = false; 426 apiData = null; 427 428 manualInputFlags.priceMin = false; 429 manualInputFlags.priceMax = false; 430 manualInputFlags.yearMin = false; 431 manualInputFlags.yearMax = false; 432 433 }); 434 }); 435 436 let scrollTicking = false; 437 window.addEventListener("scroll", () => { 438 if (scrollTicking) return; 439 scrollTicking = true; 440 requestAnimationFrame(() => { 441 const { scrollTop, scrollHeight, clientHeight } = document.documentElement; 442 const preloadMargin = Math.max(clientHeight * 4, scrollHeight * 0.5); 443 if (scrollTop + clientHeight >= scrollHeight - preloadMargin && !loading && !allLoaded) { 444 currentPage++; 445 loadProducts(currentPage); 446 } 447 scrollTicking = false; 448 }); 449 }, { passive: true }); 450 451 window.addEventListener("popstate", () => { 452 currentPage = 1; 453 allLoaded = false; 454 loadProducts(currentPage); 455 }); 456 457 var STOCK_SNAP_KEY = "sigmaStockSnap"; 458 function stockUrlKey(){ return location.pathname + location.search; } 459 function saveStockSnap(){
460 try { 461 sessionStorage.setItem(STOCK_SNAP_KEY, JSON.stringify({ 462 url: stockUrlKey(), 463 html: container.innerHTML, 464 docH: document.documentElement.scrollHeight, 465 scrollY: window.scrollY || document.documentElement.scrollTop || 0, 466 pages: currentPage, 467 allLoaded: allLoaded, 468 count: countFilter ? countFilter.textContent : "", 469 sliders: { 470 priceMin: priceMinInput ? priceMinInput.value : null, 471 priceMax: priceMaxInput ? priceMaxInput.value : null, 472 yearMin: yearMinInput ? yearMinInput.value : null, 473 yearMax: yearMaxInput ? yearMaxInput.value : null 474 }, 475 flags: { 476 priceMin: manualInputFlags.priceMin, priceMax: manualInputFlags.priceMax, 477 yearMin: manualInputFlags.yearMin, yearMax: manualInputFlags.yearMax 478 }, 479 ts: Date.now() 480 })); 481 } catch(e){ try { sessionStorage.removeItem(STOCK_SNAP_KEY); } catch(_){} } 482 } 483 function readStockSnap(){
484 try { 485 var raw = sessionStorage.getItem(STOCK_SNAP_KEY); 486 if(!raw) return null; 487 var sn = JSON.parse(raw); 488 if(!sn || sn.url !== stockUrlKey() || !sn.html) return null; 489 if(Date.now() - (sn.ts || 0) > 1800000) return null; 490 return sn; 491 } catch(e){ return null; } 492 } 493 494 if (container) { 495 container.addEventListener("click", function(e){ 496 var a = e.target.closest(".vcard a[href]"); 497 if(a){ var h = a.getAttribute("href"); if(h && h.charAt(0) === "/") saveStockSnap(); } 498 }); 499 } 500 window.addEventListener("pagehide", function(){ saveStockSnap(); }); 501 502 if ("scrollRestoration" in history) history.scrollRestoration = "manual"; 503 504 var _snap = readStockSnap(); 505 if (_snap) { 506 try { sessionStorage.removeItem(STOCK_SNAP_KEY); } catch(e){} 507 container.innerHTML = _snap.html; 508 509 if (_snap.docH) document.body.style.minHeight = _snap.docH + "px"; 510 currentPage = _snap.pages || 1; 511 allLoaded = !!_snap.allLoaded; 512 if (countFilter && _snap.count) countFilter.textContent = _snap.count; 513 if (_snap.sliders) { 514 if (priceMinInput && _snap.sliders.priceMin != null) priceMinInput.value = _snap.sliders.priceMin; 515 if (priceMaxInput && _snap.sliders.priceMax != null) priceMaxInput.value = _snap.sliders.priceMax; 516 if (yearMinInput && _snap.sliders.yearMin != null) yearMinInput.value = _snap.sliders.yearMin; 517 if (yearMaxInput && _snap.sliders.yearMax != null) yearMaxInput.value = _snap.sliders.yearMax; 518 [priceMinInput, priceMaxInput, yearMinInput, yearMaxInput].forEach(function(el){ if(el) el.dispatchEvent(new Event("input")); }); 519 } 520 if (_snap.flags) { 521 manualInputFlags.priceMin = _snap.flags.priceMin; manualInputFlags.priceMax = _snap.flags.priceMax; 522 manualInputFlags.yearMin = _snap.flags.yearMin; manualInputFlags.yearMax = _snap.flags.yearMax; 523 } 524 525 var _ty = _snap.scrollY || 0, _deadline = Date.now() + 1500; 526 function _jump(y){ 527 try { window.scrollTo({ top: y, left: 0, behavior: "instant" }); } catch(e){ window.scrollTo(0, y); } 528 document.documentElement.scrollTop = y; 529 } 530 (function stick(){ 531 _jump(_ty); 532 if (Math.abs((window.scrollY || 0) - _ty) > 2 && Date.now() < _deadline) { 533 requestAnimationFrame(stick); 534 } else { 535 setTimeout(function(){ document.body.style.minHeight = ""; }, 300); 536 } 537 })(); 538 } else { 539 loadProducts(currentPage); 540 } 541 542 var resetBtn = document.querySelector('[data-filter-reset]'); 543 if (resetBtn) { 544 resetBtn.addEventListener('click', async function() { 545 setBtnLoading(resetBtnEl, true); 546 547 form.querySelectorAll('input[type="checkbox"]:checked').forEach(function(cb){ cb.checked = false; cb.dispatchEvent(new Event('change', {bubbles:true})); }); 548 form.querySelectorAll('input[type="radio"]:checked').forEach(function(rb){ rb.checked = false; rb.dispatchEvent(new Event('change', {bubbles:true})); }); 549 550 form.querySelectorAll('.js-accordion__item, .js-adv-filter__item').forEach(function(item){ 551 var sel = item.querySelector('.js-adv-filter__selection'); 552 if(sel){ var def = item.getAttribute('data-default-text'); if(def) sel.textContent = def; } 553 }); 554 555 manualInputFlags.priceMin = false; 556 manualInputFlags.priceMax = false; 557 manualInputFlags.yearMin = false; 558 manualInputFlags.yearMax = false; 559 560 if (priceMinInput) priceMinInput.value = priceMinInput.min; 561 if (priceMaxInput) priceMaxInput.value = priceMaxInput.max; 562 if (yearMinInput) yearMinInput.value = yearMinInput.min; 563 if (yearMaxInput) yearMaxInput.value = yearMaxInput.max; 564 565 [priceMinInput, priceMaxInput, yearMinInput, yearMaxInput].forEach(function(el){ if(el) el.dispatchEvent(new Event('input')); }); 566 apiData = null; 567 currentPage = 1; 568 allLoaded = false; 569 570 if (filterPanel) filterPanel.classList.remove('sidebar--is-visible'); 571 window.history.pushState(null, '', '/stock/'); 572 573 await fetchAndApplyRanges(); 574 await loadProducts(currentPage); 575 setBtnLoading(resetBtnEl, false); 576 }); 577 } 578 579 const filters = {}; 580 581 ["make", "transmission", "drive", "state"].forEach((key) => { 582 const checked = document.querySelectorAll(`input[name="${key}[]"]:checked`); 583 if (checked.length === 1) { 584 const input = checked[0]; 585 filters[key] = { 586 slug: input.dataset.slug, 587 title: input.dataset.title, 588 }; 589 } else { 590 filters[key] = null; 591 } 592 }); 593 594 const accordionItems = document.querySelectorAll('.js-accordion__item'); 595
596 accordionItems.forEach(item => { 597 598 const checkboxes = item.querySelectorAll('input[type="checkbox"]'); 599 600 const hasChecked = Array.from(checkboxes).some(checkbox => checkbox.checked); 601 602 const rangeInputs = item.querySelectorAll('input[type="range"]'); 603 const hasUrlRange = Array.from(rangeInputs).some(function(input) { 604 return urlParams.has(input.name); 605 }); 606 607 if (hasChecked || hasUrlRange) { 608 item.classList.add('accordion__item--is-open'); 609 610 const button = item.querySelector('.js-accordion__trigger'); 611 const panel = item.querySelector('.js-accordion__panel'); 612 if (button) button.setAttribute('aria-expanded', 'true'); 613 if (panel) panel.removeAttribute('hidden'); 614 } 615 }); 616 } 617 618 function checkCheckboxesAndShowDiv() { 619 620 const checkboxes = document.querySelectorAll('input.makeall'); 621 let selectedCheckbox = 0; 622 checkboxes.forEach((cb, index) => { 623 if(cb.checked){ 624 selectedCheckbox++; 625 document.getElementById('make-div-' + cb.dataset.minititle + '').style.display = 'block'; 626 }else{ 627 document.getElementById('make-div-' + cb.dataset.minititle + '').style.display = 'none'; 628 const allCheckboxesModels = document.querySelectorAll('.for-make-div-' + cb.dataset.minititle + ''); 629 allCheckboxesModels.forEach((cbmodel, index) => { 630 cbmodel.checked = false; 631 }); 632 } 633 }); 634 if(selectedCheckbox === 0){ 635 document.getElementById('hidden-filter-badge').style.display = 'block'; 636 }else{ 637 document.getElementById('hidden-filter-badge').style.display = 'none'; 638 } 639 } 640 641 document.querySelectorAll('input.makeall').forEach(cb => { 642 cb.addEventListener('change', checkCheckboxesAndShowDiv); 643 }); 644 645 (function(){ 646 var back = document.querySelector('.car__back'); 647 if(!back) return; 648 try { 649 var raw = sessionStorage.getItem("sigmaStockSnap"); 650 if(!raw) return; 651 var sn = JSON.parse(raw); 652 if(!sn || !sn.url) return; 653 if(Date.now() - (sn.ts || 0) > 1800000) return; 654 back.setAttribute('href', sn.url); 655 } catch(e){} 656 })(); 657});
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.