1 2// // ******************************************************************** 3// // || æ©è½æ¦è¦ || åéè¿åãã¼ã¿åºå 4// // || || 5// // || 使è || Bui Minh Duc 6// // || ä½ææ¥ || 2024/03/28 7// // || æ´æ°å±¥æ´ || 8// // 2024/03/28 Bui Minh Duc 9// // ========================================================================= 10// // || æ»ãå¤ || ã¯ã¨ãªçµæ 11// // ******************************************************************** 12 13function getStockStatus(productStock, pmVariantPriceString) { 14 try { 15 if (productStock === 'outofstock') { 16 return 'å¨åº«ãªã'; 17 } 18 19 pmVariantPriceString = pmVariantPriceString.substring(1, pmVariantPriceString.length - 1); 20 var pairs = pmVariantPriceString.split("},"); 21 var allOutOfStock = true; 22 var partOutOfStock = false; 23 pairs.forEach(function(pair) { 24 if (pair.charAt(pair.length - 1) !== "}") { 25 pair += "}"; 26 } 27 var variantPriceObj; 28 try { 29 variantPriceObj = eval("(" + pair + ")"); 30 } catch (error) { 31 return; 32 } 33 34 if (variantPriceObj.stock_status !== "outofstock") { 35 allOutOfStock = false; 36 } 37 38 if (!variantPriceObj.variant.includes('ãã«ããã«') && variantPriceObj.stock_status === "outofstock") { 39 partOutOfStock = true; 40 } 41 }); 42 43 if (allOutOfStock) { 44 return 'å¨åº«ãªã'; 45 } 46 47 if (partOutOfStock) { 48 return 'ä¸é¨å¨åº«ãªã'; 49 } 50 } catch (error) { 51 console.error("Unexpected error:", error); 52 return []; 53 } 54} 55 56function isFullBottleAvailable(pmVariantPriceString) { 57 try { 58 pmVariantPriceString = pmVariantPriceString.substring(1, pmVariantPriceString.length - 1); 59 var pairs = pmVariantPriceString.split("},"); 60 var isFullBottleAvailable = false; 61 pairs.forEach(function(pair) { 62 if (pair.charAt(pair.length - 1) !== "}") { 63 pair += "}"; 64 } 65 var variantPriceObj; 66 try { 67 variantPriceObj = eval("(" + pair + ")"); 68 } catch (error) { 69 console.error("Error parsing variant price object:", error); 70 return; 71 } 72 if (variantPriceObj.variant.includes('ãã«ããã«') && variantPriceObj.stock_status === "instock") { 73 isFullBottleAvailable = true; 74 } 75 }); 76 77 return isFullBottleAvailable; 78 } catch (error) { 79 console.error("Unexpected error:", error); 80 return []; 81 } 82} 83 84 85function getPriceForVariant2(pmVariantPriceString) { 86 pmVariantPriceString = pmVariantPriceString.substring(1, pmVariantPriceString.length - 1); 87 var pairs = pmVariantPriceString.split("},"); 88 var prices = []; 89 90 pairs.forEach(function(pair) { 91 if (pair.charAt(pair.length - 1) !== "}") { 92 pair += "}"; 93 } 94 var variantPriceObj = eval("(" + pair + ")"); 95 96 prices.push(variantPriceObj); 97 }); 98 99 var selectedLabelsString = sessionStorage.getItem('selectedLabels'); 100 if (selectedLabelsString) { 101 var selectedLabels = JSON.parse(selectedLabelsString); 102 var fullBottleRegex = /ãã«ããã«.*/; 103 if (selectedLabels.length >= 1) { 104 var filteredPrices = prices.filter(function(variant) { 105 return selectedLabels.includes(variant.variant) 106 || (variant.stock_status === 'instock' && selectedLabels.includes('ãã«ããã«') && fullBottleRegex.test(variant.variant)); 107 }); 108 if (filteredPrices.length > 0) { 109 prices = filteredPrices; 110 } 111 } 112 } 113 114 // If the variants contains full bottle, only take the smallest price of full bottle 115 var cheapestFullBottle = prices 116 .filter(item => item.variant.startsWith("ãã«ããã«")) 117 .reduce((cheapest, current) => { 118 return current.price < cheapest.price ? current : cheapest; 119 }, { price: Infinity }); 120 var variantPrices = prices 121 .filter(item => !item.variant.startsWith("ãã«ããã«") || item.price === cheapestFullBottle.price); 122 123 var sortValue = sessionStorage.getItem('sort'); 124 if (sortValue?.startsWith('price') && sortValue.endsWith('desc')) { 125 variantPrices.sort(function(a, b) { 126 return b.price - a.price; 127 }); 128 } else { 129 variantPrices.sort(function(a, b) { 130 return a.price - b.price; 131 }); 132 } 133 134 if (variantPrices.length > 0) { 135 return variantPrices[0].price; 136 } else { 137 return 0; 138 } 139} 140 141function checkForSelectedWeights() { 142 var filterBlock = document.getElementById('filter-block-weight'); 143 var checkboxes = filterBlock.querySelectorAll('input[type="checkbox"]:checked'); 144 return checkboxes.length > 0;
145} 146 147function validateSearchPrice() { 148 var priceMinElement = document.getElementById('price-min'); 149 var priceMaxElement = document.getElementById('price-max'); 150 151 if (priceMinElement && priceMaxElement && parseInt(priceMinElement.value) > parseInt(priceMaxElement.value)) { 152 return false; 153 } 154 return true; 155} 156 157function validateBeforeSearch() { 158 // Validate weight 159 let hasWeight = checkForSelectedWeights(); 160 var filterWeight = document.getElementById('filter-block-weight'); 161 if (!hasWeight) { 162 filterWeight.classList.add('error'); 163 } else { 164 filterWeight.classList.remove('error'); 165 } 166 167 // Validate price 168 let validPrice = validateSearchPrice(); 169 var filterPrice = document.getElementById('filter-block-price'); 170 if (!validPrice) { 171 filterPrice.classList.add('error'); 172 } else { 173 filterPrice.classList.remove('error'); 174 } 175 176 return hasWeight && validPrice; 177} 178 179function hasFilterPrice() { 180 var hasFilterPrice = false; 181 var filterWeightBlock = document.getElementById('filter-block-weight'); 182 var checkboxes = filterWeightBlock.querySelectorAll('input[type="checkbox"]'); 183 var selectedWeights = filterWeightBlock.querySelectorAll('input[type="checkbox"]:checked'); 184 185 var minPrice = document.getElementById('price-min').value; 186 var maxPrice = document.getElementById('price-max').value; 187 188 if (checkboxes.length !== selectedWeights.length || minPrice || maxPrice) { 189 hasFilterPrice = true; 190 } 191 return hasFilterPrice; 192} 193 194function updateSelectedFilterPrice() { 195 var filterPriceLabel = document.getElementById('price'); 196 197 if (filterPriceLabel) { 198 if (hasFilterPrice()) { 199 filterPriceLabel.classList.add('active'); 200 } else { 201 filterPriceLabel.classList.remove('active'); 202 } 203 } 204} 205 206function toggleFilterFields(show) { 207 var filterBlocks = document.querySelectorAll('.accordion2.filter-block'); 208 document.querySelector('.more-filter').classList.toggle('hidden', !show); 209 filterBlocks.forEach(function(block) { 210 block.classList.toggle('hidden', !show); 211 }); 212 213 var resultSection = document.getElementById('result-list-filter'); 214 var filterStatus = document.getElementById('filter-status'); 215 var filterFields = document.getElementById('filter-fields'); 216 resultSection.style.display = show ? 'none' : 'block'; 217 filterFields.style.display = show ? 'none' : 'block'; 218 filterStatus.style.display = show ? 'none' : 'block'; 219 220 var filterFieldElements = document.querySelectorAll('.filter-field'); 221 filterFieldElements.forEach(function(filterField) { 222 filterField.classList.toggle('show-filter', show); 223 }); 224} 225 226function hideFilterFields() { 227 toggleFilterFields(false); 228} 229 230function showFilterFields() { 231 toggleFilterFields(true); 232} 233 234function removeBrandSEOInfo() { 235 let brandSEOTagEle = document.getElementById('brand-seo-tag'); 236 if (brandSEOTagEle) { 237 brandSEOTagEle.remove(); 238 } 239 240 let topBrandEle = document.querySelector('.section-collection-brand'); 241 if (topBrandEle) { 242 topBrandEle.remove(); 243 } 244 245 let brandReviewsEle = document.getElementById('section-brand-reviews'); 246 if (brandReviewsEle) { 247 brandReviewsEle.remove(); 248 } 249 250} 251 252async function handleFilter() { 253 let isValidSeach = validateBeforeSearch(); 254 255 if (isValidSeach) { 256 await fetchNewPageData(1); 257 } 258} 259 260document.getElementById('filter-button').addEventListener('click', async (e) => { 261 e.preventDefault(); 262 await handleFilter(); 263}); 264 265function getSelectedPriceFilters() { 266 const selectedLabelsArray = [ 267 { label: "ã¯ã³ã¿ãã (ãèã«1åã試ã)", value: "price2" }, 268 { label: "15åããã·ã¥ (0.75ml)", value: "price3" }, 269 { label: "50åããã·ã¥ (2.5ml)", value: "price5" }, 270 { label: "100åããã·ã¥ (5ml)", value: "price6" }, 271 { label: "ãã«ããã«", value: "price7" } 272 ]; 273 274 var selectedLabelsString = sessionStorage.getItem('selectedLabels'); 275 var selectedLabels = []; 276 277 if (selectedLabelsString) { 278 selectedLabels = JSON.parse(selectedLabelsString); 279 } 280 281 return selectedLabelsArray 282 .filter(item => selectedLabels.includes(item.label)) 283 .map(item => item.value); 284} 285 286function addPriceFilter(query){ 287 // Default: min price: 0, max price: 999999999 288 const minPrice = document.getElementById('price-min').value || 0; 289 const maxPrice = document.getElementById('price-max').value || 999999999; 290 291 const params = new URLSearchParams(query); 292 const selectedPriceFilters = getSelectedPriceFilters();
293 selectedPriceFilters.forEach(item => { 294 // Add filter price for each selected label 295 params.set(item, `${minPrice}-${maxPrice}`); 296 297 // Add filter field 298 const currentFilterFields = params.get('FilterFields') || ''; 299 params.set('FilterFields', `${currentFilterFields}:${item}`); 300 }); 301 302 return params.toString(); 303} 304 305function fetchNewPageData(pageNumber) { 306 var finalString = sessionStorage.getItem('finalString'); 307 var sortValue = sessionStorage.getItem('sort'); 308 var searchKeywords = sessionStorage.getItem('searchKeywords'); 309 310 const urlParams = new URLSearchParams(finalString); 311 if (searchKeywords) { 312 const searchKeywordsParams = new URLSearchParams(searchKeywords); 313 let keywords = searchKeywordsParams.get('Keywords'); 314 if (keywords) { 315 urlParams.set('s', keywords); 316 } 317 } 318 319 urlParams.delete('CountPerPage'); 320 urlParams.delete('FilterFields'); 321 urlParams.set('Page', pageNumber); 322 urlParams.set('Sort', (sortValue ? sortValue : 'total_sales desc')); 323 324 var selectedLabelsString = sessionStorage.getItem('selectedLabels'); 325 var selectedLabels = []; 326 327 if (urlParams.has('pa_brand_id')) { 328 let brandIdsString = urlParams.get('pa_brand_id'); 329 let brandIds = brandIdsString.split(','); 330 let brandSlugsString = ''; 331 brandIds.forEach(brandId => { 332 let brandAlphabetElement = document.getElementById(`pa_brand_id-${brandId}-alphabet`); 333 let brandSlug = brandAlphabetElement?.getAttribute('data-brand-slug'); 334 335 if (brandSlugsString.length > 0) { 336 brandSlugsString += ','; 337 } 338 brandSlugsString += brandSlug; 339 }); 340 urlParams.set('pa_brand', brandSlugsString); 341 urlParams.delete('pa_brand_id'); 342 } 343 344 if (selectedLabelsString) { 345 selectedLabels = JSON.parse(selectedLabelsString); 346 const labelsString = selectedLabels.join(','); 347 urlParams.set('selected_labels', labelsString); 348 } 349 350 if (hasFilterPrice()) { 351 const minPrice = document.getElementById('price-min').value || ''; 352 const maxPrice = document.getElementById('price-max').value || ''; 353 354 const selectedPriceFilters = getSelectedPriceFilters(); 355 selectedPriceFilters.forEach(item => { 356 urlParams.set(item, `${minPrice}-${maxPrice}`); 357 }); 358 } 359 360 // Remove null parameters 361 for (const [key, value] of urlParams.entries()) { 362 if (key === 'null') { 363 urlParams.delete(key); 364 } 365 } 366 367 window.location.href = window.location.pathname + '?' + urlParams.toString(); 368} 369 370async function handleChangePage(page) { 371 let response = await fetchNewPageData(page); 372 addHistoryState(response?.historyParams, response?.data); 373} 374 375function updateSelectedLabelsSessionStorage() { 376 var filterBlock = document.getElementById('filter-block-weight'); 377 var checkboxes = filterBlock.querySelectorAll('input[type="checkbox"]'); 378 var selectedLabels = []; 379 checkboxes.forEach(function(checkbox) { 380 if (checkbox.checked) { 381 var label = document.querySelector('label[for="' + checkbox.id + '"]'); 382 selectedLabels.push(label.textContent.trim()); 383 } 384 }); 385 sessionStorage.setItem('selectedLabels', JSON.stringify(selectedLabels)); 386} 387 388document.addEventListener('DOMContentLoaded', () => { 389 var filterBlock = document.getElementById('filter-block-weight'); 390 var checkboxes = filterBlock.querySelectorAll('input[type="checkbox"]'); 391 var sortItem = document.querySelectorAll('span[name="sort"]'); 392 var btnSort = document.getElementById('btn-sort'); 393 var sortPrice = document.querySelector('select[name="sort-price"]'); 394 var filterPrices = document.querySelectorAll('.filter-price'); 395 396 updateSelectedLabelsSessionStorage(); 397 398 // Add event listener for checkbox changes 399 checkboxes.forEach(function(checkbox) { 400 checkbox.addEventListener('change', function() { 401 updateSelectedLabelsSessionStorage(); 402 updateSelectedFilterPrice(); 403 getSearchResult(selectedValues); 404 }); 405 });
406 407 // Add event listener for sort item: 人æ°é , æ°çé , ã¬ãã¥ã¼ã®å¤ãé 408 sortItem.forEach(function(checkbox) { 409 checkbox.addEventListener('click', async function(e) { 410 let isValidSeach = validateBeforeSearch(); 411 if (isValidSeach && !this.classList.contains("active")) { 412 // Remove selected sort item 413 sortItem.forEach(element => { 414 element.classList.remove("active"); 415 }); 416 // Remove selected sort price 417 sortPrice.classList.remove("active"); 418 // Select ä¾¡æ ¼é option on sort price 419 sortPrice.selectedIndex = 0; 420 421 this.classList.add("active"); 422 document.querySelector('#btn-sort span').textContent = this.textContent; 423 424 var sortName = this.getAttribute('data-sort-name'); 425 var sortType = this.getAttribute('data-sort-type'); 426 sessionStorage.setItem('sort', `${sortName} ${sortType}`); 427 hideFilterFields(); 428 await fetchNewPageData(1); 429 } 430 }); 431 }); 432 433 // Add event listener for sort by price 434 sortPrice.addEventListener('change', async function() { 435 let isValidSeach = validateBeforeSearch(); 436 if (isValidSeach) { 437 // Remove selected sort item 438 sortItem.forEach(element => { 439 element.classList.remove("active"); 440 }); 441 442 sortPrice.classList.add("active"); 443 var selectedIndex = sortPrice.selectedIndex; 444 document.querySelector('#btn-sort span').textContent = sortPrice.options[selectedIndex].text; 445 446 var sortName = sortPrice.value; 447 if (sortName === 'highest_price') { 448 sessionStorage.setItem('sort', 'price desc'); 449 } else { 450 sessionStorage.setItem('sort', 'price asc'); 451 } 452 hideFilterFields(); 453 let response = await fetchNewPageData(1); 454 addHistoryState(response?.historyParams, response?.data); 455 } 456 }); 457 458 // Add event listener for toggle show sort item 459 btnSort.addEventListener('click', function(e) { 460 var sortBlock = document.getElementById('sort-block'); 461 if (sortBlock.classList.contains("show")) { 462 sortBlock.classList.remove("show"); 463 } else { 464 sortBlock.classList.add("show"); 465 } 466 ignoreScroll = true; 467 e.preventDefault(); 468 }); 469 470 filterPrices.forEach(function(filterPrice) { 471 filterPrice.addEventListener('input', function() { 472 updateSelectedFilterPrice(); 473 getSearchResult(selectedValues); 474 }); 475 }); 476 477 // Padding bottom to prevent content overlap by search button 478 var htmlToInsert = '<div class="padding-bottom-product-filter"></div>'; 479 document.body.insertAdjacentHTML('beforeend', htmlToInsert); 480 481 var filterAction = document.getElementById('filter-action'); 482 var paddingContainer = document.querySelector('.padding-bottom-product-filter'); 483 var filterActionObserver = new MutationObserver(function(mutationsList, observer) { 484 mutationsList.forEach(function(mutation) { 485 if (mutation.type === 'attributes' && mutation.attributeName === 'class') { 486 if (filterAction.classList.contains('filter-action-hidden')) { 487 paddingContainer.classList.add('no-padding'); 488 } else { 489 paddingContainer.classList.remove('no-padding'); 490 } 491 } 492 }); 493 }); 494 filterActionObserver.observe(document.querySelector('#filter-action'), { attributes: true }); 495}); 496 497function setSearchKeyWordsToSessionStorage (keyword) { 498 var searchKeywordsString = ''; 499 searchKeywordsString = 'Keywords=' + keyword + '&KeywordsSearchFields=item_name:item_e_name:pa_brand_name:pa_brand_name_kana:"post_excerpt"'; 500 501 sessionStorage.setItem('searchKeywords', searchKeywordsString); 502 503 return searchKeywordsString; 504} 505 506function updateSortBlock(sortName, sortType) { 507 var sortItem = document.querySelectorAll('span[name="sort"]'); 508 var sortPrice = document.querySelector('select[name="sort-price"]'); 509 // Remove selected sort item 510 sortItem.forEach(element => { 511 if (element.getAttribute('data-sort-name') === sortName && element.getAttribute('data-sort-type') === sortType) { 512 element.classList.add("active"); 513 document.querySelector('#btn-sort span').textContent = element.textContent; 514 } else { 515 element.classList.remove("active"); 516 } 517 });
518 if (sortName === 'price') { 519 if (sortType === 'desc') { 520 sortPrice.value = 'highest_price'; 521 } else { 522 sortPrice.value = 'lowest_price'; 523 } 524 sortPrice.classList.add("active"); 525 var selectedIndex = sortPrice.selectedIndex; 526 document.querySelector('#btn-sort span').textContent = sortPrice.options[selectedIndex].text; 527 } else { 528 sortPrice.classList.remove("active"); 529 } 530} 531 532var selectedValues = {}; 533var initPage = 1; 534var debounceTimerCheckbox; 535document.addEventListener('DOMContentLoaded', function() { 536 sessionStorage.removeItem('finalString'); 537 sessionStorage.removeItem('searchKeywords'); 538 sessionStorage.removeItem('sort'); 539 540 let hasFilter = loadFiltersFromUrl(); 541 var searchText = document.getElementById('search_text'); 542 543 var debounceTimer; 544 if (searchText) { 545 if (searchText && searchText.value) { 546 setSearchKeyWordsToSessionStorage(searchText.value); 547 } 548 549 searchText.addEventListener('input', function() { 550 var test = ''; 551 test = setSearchKeyWordsToSessionStorage(this.value); 552 sessionStorage.removeItem('sort'); 553 clearTimeout(debounceTimer); 554 debounceTimer = setTimeout(() => { 555 var finalString = sessionStorage.getItem('finalString'); 556 if (!finalString || finalString === '&FilterFields=%2b') { 557 sendAjaxRequest('', test); 558 } else { 559 sendAjaxRequest(finalString, test); 560 } 561 }, 1000); 562 }); 563 564 searchText.addEventListener("keydown", async function(event) { 565 if (event.key === "Enter") { 566 event.preventDefault(); 567 setSearchKeyWordsToSessionStorage(this.value); 568 sessionStorage.removeItem('sort'); 569 await handleFilter(); 570 } 571 }); 572 } 573 574 if (hasFilter) { 575 updateSelectedFilterField(selectedValues); 576 updateSelectedFilterPrice(); 577 showFooter(); 578 scrollToSearchResult(); 579 hideSearchButton(); 580 // Hide filter_form 581 document.querySelector('#filter_form').classList.add('scrolled-past-header', 'section-header-hidden', 'section-header-sticky'); 582 isLoading = false; 583 } else { 584 selectedValues = {}; 585 setDefaultFilter(); 586 showFilterFields(); 587 } 588 589 window.addEventListener('pageshow', (event) => { 590 if (event.persisted) { 591 selectedValues = {}; 592 let hasFilter = loadFiltersFromUrl(); 593 if (hasFilter) { 594 updateSelectedFilterField(selectedValues); 595 updateSelectedFilterPrice(); 596 showFooter(); 597 hideSearchButton(); 598 // Hide filter_form 599 document.querySelector('#filter_form').classList.add('scrolled-past-header', 'section-header-hidden', 'section-header-sticky'); 600 isLoading = false; 601 } else { 602 selectedValues = {}; 603 setDefaultFilter(); 604 showFilterFields(); 605 hideFooter(); 606 } 607 } 608 }); 609 610 addChangeEventListeners(); 611}); 612 613function scrollToSearchResult() { 614 var element = document.getElementById('result-list-filter'); 615 var headerHeight = document.querySelector('.navbar[role="navigation"]').offsetHeight; 616 var elementPosition = element.getBoundingClientRect().top + window.scrollY; 617 var offsetPosition = elementPosition - headerHeight; 618 window.scrollTo({ 619 top: offsetPosition, 620 behavior: 'smooth' 621 }); 622} 623 624function hideSearchButton() { 625 var navbarHeight = document.querySelector('.navbar').clientHeight 626 var resultListFilterHeight = document.querySelector('#result-list-filter').clientHeight; 627 var bottomPageWrapHeight = document.querySelector('.bottom-page-wrap').clientHeight; 628 var windowHeight = window.innerHeight; 629 if (navbarHeight + resultListFilterHeight + bottomPageWrapHeight > windowHeight) { 630 document.querySelector('#filter-action').classList.add('filter-action-hidden'); 631 } 632} 633 634function setDefaultFilter() { 635 let filterTextFields = document.querySelectorAll('#filter_form input[type=text]'); 636 filterTextFields.forEach(element => { 637 element.value = ''; 638 });
639 640 let filterCheckBoxs = document.querySelectorAll('input[type=checkbox][name=girlboy], input[type=checkbox][name=brand], input[type=checkbox][name=fragrancespice]'); 641 filterCheckBoxs.forEach(element => { 642 element.checked = false; 643 }); 644 645 let itemAlphabets = document.querySelectorAll('#modal-brand-list input[type=checkbox], #modal-fragrancespice-list input[type=checkbox]'); 646 itemAlphabets.forEach(element => { 647 element.checked = false; 648 }); 649 650 let selectWeightCheckBoxs = document.querySelectorAll('#filter-block-weight input[type=checkbox]'); 651 selectWeightCheckBoxs.forEach(element => { 652 element.checked = true; 653 }); 654 655 let selectedFilters = document.querySelectorAll('.filter-control:has(.remove-filter'); 656 selectedFilters.forEach(element => { 657 element.closest('.filter-block-grid').removeChild(element); 658 }); 659 660 sessionStorage.removeItem('searchKeywords'); 661 sessionStorage.removeItem('finalString'); 662 sessionStorage.removeItem('sort'); 663 updateSelectedLabelsSessionStorage(); 664 665 // Reset filter field 666 var filterFieldElements = document.querySelectorAll('.filter-field'); 667 filterFieldElements.forEach(function(filterField) { 668 filterField.classList.remove('active'); 669 }); 670 671 // Reset #filter_form scroll 672 var filterContainer = document.getElementById('filter_form'); 673 filterContainer.classList.remove('section-header-hidden', 'section-header-sticky', 'filter-action-hidden'); 674 675 // Collapse filter block 676 var filterBlocks = document.querySelectorAll('.accordion2.filter-block'); 677 filterBlocks.forEach(function(block) { 678 block.getElementsByClassName('toggle filter-block-toggle')[0].checked = false; 679 }); 680 681 // Only show 4 filter block 682 var filterContainer = document.querySelector('.filter-container'); 683 filterContainer.classList.remove('toggle-filter'); 684 685 // Show filter button 686 document.querySelector('#filter-action').classList.remove('filter-action-hidden'); 687} 688 689function addChangeEventListeners() { 690 document.querySelectorAll('input[type=checkbox][name=girlboy], input[type=checkbox][name=brand], input[type=checkbox][name=fragrancespice]') 691 .forEach(input => input.addEventListener('change', (event) => handleInputChange(event.target, selectedValues))); 692 693 // Click button confirm selected brand 694 var btnConfirmSelectedBrand = document.getElementById('confirm-selected-brand'); 695 btnConfirmSelectedBrand.addEventListener('click', function() { 696 handleConfirmSelectedOnModal('brand'); 697 }); 698 699 // Click button confirm selected fragrancespice 700 var btnConfirmSelectedFragrancespice = document.getElementById('confirm-selected-fragrancespice'); 701 btnConfirmSelectedFragrancespice.addEventListener('click', function() { 702 handleConfirmSelectedOnModal('fragrancespice'); 703 }); 704} 705 706function loadFiltersFromUrl() { 707 const acceptedParam = [ 708 'Keywords', 709 's', 710 'pa_brand', 711 'pa_brand_id', 712 'pa_girlboy', 713 'pa_smell-type', 714 'pa_smelltype', 715 'pa_馿', 716 'pa_fragrancespice', 717 'pa_image', 718 'pa_feeling', 719 'pa_scene', 720 'pa_seasons', 721 'selected_labels', 722 'price2', 723 'price3', 724 'price5', 725 'price6', 726 'price7', 727 'Sort', 728 'sort-by', 729 'sort-type', 730 'Page' 731 ]; 732 var hasSearchQuery = false; 733 734 const urlParams = new URLSearchParams(window.location.search); 735 for (let param of acceptedParam) { 736 if (urlParams.has(param)) { 737 hasSearchQuery = true; 738 let value = urlParams.get(param); 739 switch (param) { 740 case 'Keywords': 741 case 's': 742 document.getElementById('search_text').value = value; 743 setSearchKeyWordsToSessionStorage(value); 744 break; 745 case 'pa_brand': 746 let brandSlugs = value.split(',');
747 brandSlugs.forEach(slug => { 748 let brandAlphabetElement = document.querySelector(`.list-brand-alphabet[data-brand-slug="${slug}"]`); 749 if (brandAlphabetElement) { 750 let brandId = brandAlphabetElement.getAttribute('data-brand-id'); 751 selectedValues['pa_brand_id=' + brandId] = true; 752 setFinalStringToSessionStorage(selectedValues); 753 let brandNameEn = brandAlphabetElement.getAttribute('data-brand-name-en'); 754 let brandNameJp = brandAlphabetElement.getAttribute('data-brand-name-jp'); 755 updateFilterBlock('pa_brand_id=' + brandId, brandNameEn, brandNameJp, true); 756 updateTopFilterBlock('pa_brand_id=' + brandId, true); 757 updateItemListAlphabet('brand', selectedValues); 758 } 759 }); 760 break; 761 case 'pa_brand_id': 762 let brandIds = value.split(','); 763 brandIds.forEach(brandId => { 764 selectedValues['pa_brand_id=' + brandId] = true; 765 setFinalStringToSessionStorage(selectedValues); 766 let brandAlphabetElement = document.getElementById(`pa_brand_id-${brandId}-alphabet`); 767 let brandNameEn = brandAlphabetElement?.getAttribute('data-brand-name-en'); 768 let brandNameJp = brandAlphabetElement?.getAttribute('data-brand-name-jp'); 769 updateFilterBlock('pa_brand_id=' + brandId, brandNameEn, brandNameJp, true); 770 updateTopFilterBlock('pa_brand_id=' + brandId, true); 771 updateItemListAlphabet('brand', selectedValues); 772 }); 773 break; 774 case 'pa_girlboy': 775 let girlboyIds = value.split(','); 776 girlboyIds.forEach(girlboyId => { 777 selectedValues['pa_girlboy=' + girlboyId] = true; 778 setFinalStringToSessionStorage(selectedValues); 779 updateTopFilterBlock('pa_girlboy=' + girlboyId, true); 780 }); 781 break; 782 case 'pa_smell-type': 783 let smelltype = document.querySelector('#search_smell_type')?.value; 784 selectedValues['pa_smelltype=' + smelltype] = true; 785 setFinalStringToSessionStorage(selectedValues); 786 updateTopFilterBlock('pa_smelltype=' + smelltype, true); 787 break; 788 case 'pa_smelltype': 789 let smelltypes = value.split(','); 790 smelltypes.forEach(smelltype => { 791 selectedValues['pa_smelltype=' + smelltype] = true; 792 setFinalStringToSessionStorage(selectedValues); 793 updateTopFilterBlock('pa_smelltype=' + smelltype, true); 794 }); 795 break; 796 case 'pa_馿': 797 let fragrancespice = document.querySelector('#search_fragrance')?.value; 798 selectedValues['pa_fragrancespice=' + fragrancespice] = true; 799 setFinalStringToSessionStorage(selectedValues); 800 let fragrancespiceAlphabetElement = document.getElementById(`pa_fragrancespice-${fragrancespice}-alphabet`); 801 let fragrancespiceName = fragrancespiceAlphabetElement?.getAttribute('data-fragrancespice-name'); 802 updateFilterBlock('pa_fragrancespice=' + fragrancespice, fragrancespiceName, '', true); 803 updateTopFilterBlock('pa_fragrancespice=' + fragrancespice, true); 804 updateItemListAlphabet('fragrancespice', selectedValues); 805 break; 806 case 'pa_fragrancespice': 807 let fragrancespices = value.split(',');
808 fragrancespices.forEach(fragrancespice => { 809 selectedValues['pa_fragrancespice=' + fragrancespice] = true; 810 setFinalStringToSessionStorage(selectedValues); 811 let fragrancespiceAlphabetElement = document.getElementById(`pa_fragrancespice-${fragrancespice}-alphabet`); 812 let fragrancespiceName = fragrancespiceAlphabetElement?.getAttribute('data-fragrancespice-name'); 813 updateFilterBlock('pa_fragrancespice=' + fragrancespice, fragrancespiceName, '', true); 814 updateTopFilterBlock('pa_fragrancespice=' + fragrancespice, true); 815 updateItemListAlphabet('fragrancespice', selectedValues); 816 }); 817 break; 818 case 'pa_image': 819 let images = value.split(','); 820 images.forEach(image => { 821 selectedValues['pa_image=' + image] = true; 822 setFinalStringToSessionStorage(selectedValues); 823 updateTopFilterBlock('pa_image=' + image, true); 824 }); 825 break; 826 case 'pa_feeling': 827 let feelings = value.split(','); 828 feelings.forEach(feeling => { 829 selectedValues['pa_feeling=' + feeling] = true; 830 setFinalStringToSessionStorage(selectedValues); 831 updateTopFilterBlock('pa_feeling=' + feeling, true); 832 }); 833 break; 834 case 'pa_scene': 835 let scenes = value.split(','); 836 scenes.forEach(scene => { 837 selectedValues['pa_scene=' + scene] = true; 838 setFinalStringToSessionStorage(selectedValues); 839 updateTopFilterBlock('pa_scene=' + scene, true); 840 }); 841 break; 842 case 'pa_seasons': 843 let seasons = value.split(','); 844 seasons.forEach(season => { 845 selectedValues['pa_seasons=' + season] = true; 846 setFinalStringToSessionStorage(selectedValues); 847 updateTopFilterBlock('pa_seasons=' + season, true); 848 }); 849 break; 850 case 'selected_labels': 851 let selectedLabels = value.split(','); 852 let selectWeightElements = document.querySelectorAll('#filter-block-weight input[type="checkbox"]'); 853 selectWeightElements.forEach(element => { 854 element.checked = selectedLabels.includes(element.value); 855 }); 856 updateSelectedLabelsSessionStorage(); 857 break; 858 case 'price2': 859 case 'price3': 860 case 'price5': 861 case 'price6': 862 case 'price7': 863 let prices = value.split('-'); 864 document.getElementById('price-min').value = prices[0]; 865 document.getElementById('price-max').value = prices[1]; 866 break; 867 case 'Sort': 868 let sort = value.split(' '); 869 sessionStorage.setItem('sort', value); 870 updateSortBlock(sort[0], sort[1]); 871 break; 872 case 'sort-by': 873 let sortName = urlParams.get('sort-by'); 874 let sortType = urlParams.get('sort-type') ?? 'desc'; 875 let sortValue = sortName + ' ' + sortType; 876 sessionStorage.setItem('sort', sortValue); 877 updateSortBlock(sortName, sortType); 878 break; 879 case 'Page': 880 initPage = parseInt(value); 881 break; 882 default: 883 break; 884 } 885 } 886 } 887 888 return hasSearchQuery; 889} 890 891function sendAjaxRequest(filterValue,keywordValue) { 892 var param1 = ''; 893 if (filterValue && keywordValue) { 894 param1 = filterValue + '&' + keywordValue; 895 } else if (filterValue || keywordValue) { 896 param1 = filterValue || keywordValue; 897 } 898 var bodyData = { 899 param1: param1, 900 }; 901 902 if (hasFilterPrice()) { 903 bodyData.param1 = addPriceFilter(bodyData.param1); 904 } 905 906 var requestOptions = { 907 method: 'POST', 908 headers: { 909 'Content-Type': 'application/json' 910 }, 911 body: JSON.stringify(bodyData) 912 }; 913 fetch('/wp-json/custom/v1/fetch-products/', requestOptions) 914 .then(response => response.json()) 915 .then(data => { 916 totalCount = data.code && data.code === 'no_data' ? 0 : data.HitCount; 917 document.querySelector('.filter-action-button span').textContent = 'ï¼' + totalCount.toLocaleStr
917ing() + 'ä»¶ï¼'; 918 }) 919 .catch(error => console.error('Fetch error: ' + error)); 920} 921 922/** 923 * 924 * @param {filterType} string - The type of action to perform. Must be either 'brand' or 'fragrancespice'. 925 * @param {selectedValues} object - selected values 926 */ 927function updateItemListAlphabet(filterType, selectedValues) { 928 var selectedItemIds = []; 929 for (var key in selectedValues) { 930 if ((filterType === 'brand' && key.indexOf(`pa_brand_id`) === 0) || (filterType === 'fragrancespice' && key.indexOf(`pa_fragrancespice`) === 0)) { 931 var id = key.split("=")[1]; 932 selectedItemIds.push(id); 933 } 934 } 935 936 // Check to selected item on modal, otherwise uncheck 937 var itemListElement = document.querySelectorAll(`.list-${filterType}-alphabet`); 938 itemListElement.forEach(element => { 939 element.checked = selectedItemIds.includes(element.getAttribute(`data-${filterType}-id`)); 940 }); 941} 942 943function setFinalStringToSessionStorage(selectedValues) { 944 var result = []; 945 for (var key in selectedValues) { 946 if (key === 'pa_girlboy' || key === 'pa_brand') { 947 result.push(selectedValues[key]); 948 } else { 949 result.push(key); 950 } 951 } 952 953 const processed = result.reduce((acc, curr) => { 954 const [key, value] = curr.split('='); 955 if (!acc[key]) { 956 acc[key] = []; 957 } 958 acc[key].push(value); 959 return acc; 960 }, {}); 961 962 const result2 = Object.entries(processed).map(([key, values]) => { 963 return `${key}=${values.sort((a, b) => a - b).join(',')}`; 964 }); 965 966 const keysArray = Object.keys(processed); 967 const filterFields = keysArray.join('+'); 968 const finalString = `${result2.join('&')}&FilterFields=%2b${encodeURIComponent(filterFields)}`; 969 970 sessionStorage.setItem('finalString', finalString); 971 return finalString; 972} 973 974function getSearchResult(selectedValues) { 975 let finalString = setFinalStringToSessionStorage(selectedValues); 976 977 const searchKeywords = sessionStorage.getItem('searchKeywords'); 978 979 clearTimeout(debounceTimerCheckbox); 980 debounceTimerCheckbox = setTimeout(function() { 981 if(searchKeywords && searchKeywords.length > 0) { 982 if (finalString !== '&FilterFields=%2b') { 983 sendAjaxRequest(finalString, searchKeywords); 984 } 985 else { 986 sendAjaxRequest('', searchKeywords); 987 } 988 989 } else { 990 if (finalString !== '&FilterFields=%2b') { 991 sendAjaxRequest(finalString,''); 992 } 993 else{ 994 sendAjaxRequest('',''); 995 } 996 } 997 }, 1000); 998} 999 1000function updateSelectedFilterField(selectedValues) { 1001 const filterFieldsMap = { 1002 "pa_brand_id": "#brand", 1003 "pa_girlboy": "#gender", 1004 "pa_smelltype": "#smelltype", 1005 "pa_fragrancespice": "#fragrancespice", 1006 "pa_image": "#image", 1007 "pa_feeling": "#feeling", 1008 "pa_scene": "#scene", 1009 "pa_seasons": "#seasons" 1010 }; 1011 for (const [selectedKey, filterFieldSelector] of Object.entries(filterFieldsMap)) { 1012 const filterField = document.querySelector(filterFieldSelector); 1013 if (Object.keys(selectedValues).some(key => key.startsWith(selectedKey))) { 1014 if (filterField && !filterField.classList.contains('active')) { 1015 filterField.classList.add('active'); 1016 } 1017 } else if (filterField && filterField.classList.contains('active')) { 1018 filterField.classList.remove('active'); 1019 } 1020 } 1021} 1022 1023function handleInputChange(element, selectedValues) { 1024 var filterType = element.getAttribute('name'); 1025 var paramName = 'pa_' + filterType; 1026 var selectedValue = element.value; 1027 1028 1029 if (element.getAttribute('type') === 'radio' && element.checked) { 1030 if (selectedValues[paramName]) { 1031 delete selectedValues[paramName]; 1032 } 1033 selectedValues[paramName] = selectedValue; 1034 } else if (element.getAttribute('type') === 'checkbox') { 1035 1036 var brandNameElement = element.parentNode.querySelector('label .name'); 1037 var smallTextElement = element.parentNode.querySelector('label .small'); 1038 1039 if (brandNameElement) { 1040 var brandName = brandNameElement.textContent; 1041 var smallText = smallTextElement?.textContent ?? ''; 1042 1043 if (element.checked) { 1044 updateFilterBlock(selectedValue, brandName, smallText, true); 1045 selectedValues[selectedValue] = true; 1046 1047 } else { 1048 updateFilterBlock(selectedValue, brandName, smallText, false); 1049 delete selectedValues[selectedValue]; 1050 1051 } 1052 } else { 1053 if (element.checked) { 1054 selectedValues[selectedValue] = true; 1055 1056 } else { 1057 delete selectedValues[selectedValue]; 1058 1059 } 1060 } 1061 1062 } 1063 1064 if (filterType === 'brand' || filterType === 'fragrancespice') { 1065 updateItemListAlphabet(filterType, selectedValues); 1066 } 1067 updateSelectedFilterField(selectedValues); 1068 1069 getSearchResult(selectedValues); 1070} 1071 1072function updateSelectedValues(selectedValue, checked) { 1073 if (checked) { 1074 selectedValues[selectedValue] = checked; 1075 } else { 1076 delete selectedValues[selectedValue]; 1077 } 1078} 1079 1080function handleSelectBrand(type, selectedValue, brandName, smallText, checked) { 1081 updateSelectedValues(selectedValue, checked); 1082 if (type == 'search-result'){ 1083 updateFilterBlock(selectedValue, brandName, smallText, checked); 1084 } 1085 updateTopFilterBlock(selectedValue, checked); 1086 if (selectedValue.startsWith('pa_brand_id')) { 1087 updateItemListAlphabet('brand', selectedValues); 1088 } else if (selectedValue.startsWith('pa_fragrancespice')) { 1089 updateItemListAlphabet('fragrancespice', selectedValues); 1090 } 1091 getSearchResult(selectedValues); 1092 updateSelectedFilterField(selectedValues); 1093} 1094 1095function updateTopFilterBlock(selectedValue, checked) { 1096 var checkbox = document.getElementById(selectedValue); 1097 if (checkbox) { 1098 checkbox.checked = checked; 1099 } 1100} 1101 1102/** 1103 * 1104 * @param {filterType} string - The type of action to perform. Must be either 'brand' or 'fragrancespice'. 1105 */ 1106function handleConfirmSelectedOnModal(filterType) { 1107 var selectedItemOnModal = document.querySelectorAll(`#modal-${filterType}-list .list-${filterType}-alphabet:checked`); 1108 1109 // Update selected item 1110 let selectedBrandValues = []; 1111 selectedItemOnModal.forEach(element => { 1112 let selectedValue = element.value; 1113 selectedValues[selectedValue] = true; 1114 selectedBrandValues.push(selectedValue); 1115 if (filterType === 'brand') { 1116 updateFilterBlock(selectedValue, element.getAttribute('data-brand-name-en'), element.getAttribute('data-brand-name-jp'), true); 1117 } else { 1118 updateFilterBlock(selectedValue, element.getAttribute('data-fragrancespice-name'), null, true); 1119 } 1120 updateTopFilterBlock(selectedValue, true); 1121 });
1122 1123 // Remove unselected item 1124 for (var selectedValue in selectedValues) { 1125 if (selectedValue.startsWith(`pa_${filterType}_id`) && !selectedBrandValues.includes(selectedValue)) { 1126 delete selectedValues[selectedValue]; 1127 updateFilterBlock(selectedValue, null, null, false, true); 1128 updateTopFilterBlock(selectedValue, false); 1129 } 1130 } 1131 updateSelectedFilterField(selectedValues); 1132 1133 getSearchResult(selectedValues); 1134} 1135 1136function removeFilter(selectedValue, brandName, smallText = null) { 1137 updateSelectedValues(selectedValue, false); 1138 updateFilterBlock(selectedValue, brandName, smallText, false); 1139 updateTopFilterBlock(selectedValue, false); 1140 if (selectedValue.startsWith('pa_brand_id')) { 1141 updateItemListAlphabet('brand', selectedValues); 1142 } else if (selectedValue.startsWith('pa_fragrancespice')) { 1143 updateItemListAlphabet('fragrancespice', selectedValues); 1144 } 1145 getSearchResult(selectedValues); 1146 updateSelectedFilterField(selectedValues); 1147} 1148 1149function encodeHtml(str) { 1150 return str.replace(/&/g, '&') 1151 .replace(/</g, '<') 1152 .replace(/>/g, '>') 1153 .replace(/"/g, '"') 1154 .replace(/'/g, '''); 1155} 1156 1157/** 1158 * @param type - type of filter block 1159 * + search-result (render filter block on search result area) 1160 * + selected (render filter block on selected brand area) 1161*/ 1162function createFilterBlockHtml(type, id, brandName, smallText, checked) { 1163 return ` 1164 <label for="${id}" class="filter-control grid-item" id="${encodeHtml(id)}-block"> 1165 <input type="checkbox" ${checked ? 'checked' : ''} name="brand" id="${encodeHtml(id)}-${encodeHtml(type)}" value="${encodeHtml(id)}" data-value="${encodeHtml(id)}" onchange="handleSelectBrand("${encodeHtml(type)}", "${encodeHtml(id)}", "${encodeHtml(brandName)}", "${smallText ? encodeHtml(smallText) : smallText}", this.checked)"> 1166 <span class="check-mark" style="position: relative; z-index: 0;"> 1167 <svg class="uncheck" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" fill="none"> 1168 <path d="M2.3 17.5C1.8 17.5 1.375 17.325 1.025 16.975C0.675 16.625 0.5 16.2 0.5 15.7V2.3C0.5 1.8 0.675 1.375 1.025 1.025C1.375 0.675 1.8 0.5 2.3 0.5H15.7C16.2
11680.5 16.625 0.675 16.975 1.025C17.325 1.375 17.5 1.8 17.5 2.3V15.7C17.5 16.2 17.325 16.625 16.975 16.975C16.625 17.325 16.2 17.5 15.7 17.5H2.3ZM2.3 16H15.7C15.7667 16 15.8333 15.9667 15.9 15.9C15.9667 15.8333 16 15.7667 16 15.7V2.3C16 2.23333 15.9667 2.16667 15.9 2.1C15.8333 2.03333 15.7667 2 15.7 2H2.3C2.23333 2 2.16667 2.03333 2.1 2.1C2.03333 2.16667 2 2.23333 2 2.3V15.7C2 15.7667 2.03333 15.8333 2.1 15.9C2.16667 15.9667 2.23333 16 2.3 16Z" fill="#B2C2C1"/> 1169 </svg> 1170 <svg class="checked" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" fill="none"> 1171 <path d="M7.6 12.85L14.325 6.125L13.275 5.075L7.6 10.75L4.75 7.9L3.7 8.95L7.6 12.85ZM2.3 17.5C1.8 17.5 1.375 17.325 1.025 16.975C0.675 16.625 0.5 16.2 0.5 15.7V2.3C0.5 1.8 0.675 1.375 1.025 1.025C1.375 0.675 1.8 0.5 2.3 0.5H15.7C16.2 0.5 16.625 0.675 16.975 1.025C17.325 1.375 17.5 1.8 17.5 2.3V15.7C17.5 16.2 17.325 16.625 16.975 16.975C16.625 17.325 16.2 17.5 15.7 17.5H2.3Z" fill="#21D4C8"/> 1172 </svg> 1173 </span> 1174 ${type == 'search-result' ? '<span class="filter-bg"></span>' : ''} 1175 <span class="text-content" style="position: relative; z-index: 0;"><span class="name">${brandName}</span>${smallText ? `<br><span class="small m-top">${smallText}</span>` : ''}</span> 1176 ${type == 'selected' ? '<span class="remove-filter" onclick="removeFilter("' + encodeHtml(id) + '", "' + encodeHtml(brandName) + '"' + (smallText ? (', "' + encodeHtml(smallText) + '"') : '') + ')">Ã</span>' : ''} 1177 </label>`; 1178} 1179 1180function updateFilterBlock(id, brandName, smallText, checked) { 1181 var existingBlock = document.getElementById(`${id}-block`); 1182 var filterBlockGrid; 1183 var gridClass; 1184 1185 switch (true) { 1186 case id.includes('pa_brand'): 1187 gridClass = '.filter-block-grid.brand-unique-class'; 1188 break; 1189 case id.includes('pa_fragrancespice'): 1190 gridClass = '.filter-block-grid.brand-unique-class-2'; 1191 break; 1192 // Thêm các case khác nếu cần 1193 default: 1194 return; // Trưá»ng hợp mặc Äá»nh, thoát khá»i hà m nếu không có grid phù hợp 1195 } 1196 filterBlockGrid = document.querySelector(gridClass); 1197 1198 if (!filterBlockGrid) return; // Kiá»m tra nếu không tìm thấy grid tương ứng, thoát khá»i hà m 1199 1200 if (filterBlockGrid.contains(existingBlock)) { 1201 if (!checked) { 1202 filterBlockGrid.removeChild(existingBlock); 1203 } else { 1204 var checkboxRefId = CSS.escape(`${id}-selected`); 1205 existingBlock.querySelector(`#${checkboxRefId}`).checked = true; 1206 } 1207 } else { 1208 if (checked) { 1209 filterBlockGrid.insertAdjacentHTML('beforeend', createFilterBlockHtml('selected', id, brandName, smallText, true)); 1210 } 1211 } 1212} 1213 1214function toggleFooter(isShow) { 1215 document.querySelector('.bottom-page-wrap').style.display = isShow ? 'block' : ''; 1216 ignoreScroll = true; 1217} 1218 1219function showFooter(){ 1220 toggleFooter(true); 1221} 1222 1223function hideFooter(){ 1224 toggleFooter(false); 1225} 1226 1227var filterFields = document.querySelectorAll('.filter-field'); 1228 1229// Duyá»t qua từng phần tá» span 1230filterFields.forEach(function(field) { 1231 // Lắng nghe sá»± kiá»n click cho má»i phần tá» 1232 field.addEventListener('click', function() { 1233 // Lấy id cá»§a phần tá» span ÄÆ°á»£c click 1234 var id = this.getAttribute('id'); 1235 1236 // Tạo id cá»§a khá»i accordion2 filter-block tương ứng 1237 var blockId = id + '-filter-block'; 1238 1239 // Lấy phần tá» khá»i tương ứng 1240 var block = document.getElementById(blockId); 1241 1242 // Kiá»m tra nếu khá»i Äã ÄÆ°á»£c hiá»n thá», thì ẩn nó Äi và ngược lại 1243 if (block.classList.contains('hidden')) { 1244 block.classList.remove('hidden'); 1245 1246 // Expand filter block 1247 block.getElementsByClassName('toggle filter-block-toggle')[0].checked = true; 1248 1249 // Show more than 4 filter block 1250 block.closest('.filter-container').classList.add('toggle-filter'); 1251 1252 // Scroll to expanded filter block 1253 var filterContainer = document.getElementById('filter_form'); 1254 if (!filterContainer.classList.contains('section-header-sticky')) { 1255 var targetElement = document.querySelector(`#${id}-filter-block`); 1256 var headerHeight = document.querySelector('.navbar.navbar-fixed-top').offsetHeight; 1257 1258 var elementPosition = targetElement.offsetTop + window.scrollY; 1259 var offsetPosition = elementPosition - headerHeight; 1260 1261 window.scrollTo({ 1262 top: offsetPosition 1263 }); 1264 } else { 1265 goToView(`#${id}-filter-block`); 1266 } 1267 } else { 1268 block.classList.add('hidden'); 1269 } 1270 1271 // Highlight selected filter field 1272 if (this.classList.contains('show-filter')) { 1273 this.classList.remove('show-filter'); 1274 } else { 1275 this.classList.add('show-filter'); 1276 document.querySelector('#filter-action').classList.remove('filter-action-hidden'); 1277 } 1278 1279 ignoreScroll = true; 1280 });
vendor: 3 bytes, line 1281
1281});
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.