const translationsStrings = { phoneCode: { cs: "+420 ", sk: "+421 ", pl: "+48 ", }, contactHours: { cs: "Po–Pá 8:00–16:00", sk: "Po–Pá 8:00–16:00", pl: "Pn–Pt 8:00–16:00", }, showAllCategories: { cs: "Zobrazit další kategorie", sk: "Zobraziť ďalšie kategórie", pl: "Pokaż więcej kategorii", }, showNext: { cs: "Zobrazit další", sk: "Zobraziť ďalšie", pl: "Pokaż więcej", }, moreButtonMoreThanFour: { cs: "dalších ", sk: "ďalších ", pl: "kolejnych ", }, moreButtonLessThanFour: { cs: "další ", sk: "ďalšie ", pl: "kolejne ", }, moreButtonOne: { cs: "další ", sk: "ďalšia ", pl: "kolejna ", }, more: { cs: "Více", sk: "Viac", pl: "Więcej", }, moreThan: { cs: "více než ", sk: "viac ako ", pl: "więcej niż ", }, cartTotalLabel: { cs: "Cena celkem", sk: "Cena spolu", pl: "Cena łącznie", }, customFilterButton: { cs: "Filtrování výsledků", sk: "Filtrovanie výsledkov", pl: "Filtrowanie wyników", }, selectedFilters: { cs: "Vybrané filtry", sk: "Vybrané filtre", pl: "Wybrane filtry", }, product: { cs: "Produkt", sk: "Produkt", pl: "Produkt", }, verifiedReviews: { cs: "Ověřená hodnocení", sk: "Overené hodnotenia", pl: "Zweryfikowane opinie", }, shopRatingUrl: { cs: "/hodnoceni-obchodu", sk: "/hodnotenie-obchodu", pl: "/opinie-o-sklepie", }, noSaleCoupon: { cs: "U tohoto produktu není možné uplatnit slevový kód.", sk: "U tohto produktu nie je možné uplatniť zľavový kód.", pl: "U tego produktu nie można zastosować kodu rabatowego.", }, noLoyaltySale: { cs: "U tohoto produktu není možné uplatnit věrnostní slevu.", sk: "U tohto produktu nie je možné uplatniť vernostnú zľavu.", pl: "U tego produktu nie można zastosować zniżki lojalnościowej.", }, denDetiKupon: { cs: "Na tento produkt lze uplatnit kód PRODETI10 pro 10% slevu.", sk: "Na tento produkt je možné uplatniť kód PREDETI10 pre 10% zľavu.", pl: "Na ten produkt można użyć kod rabatowy DLADZIECI10 ze zniżką 10%.", }, descriptionTitle: { cs: "Popis", sk: "Popis", pl: "Opis", }, directionsTitle: { cs: "Dávkování", sk: "Dávkovanie", pl: "Dawkowanie", }, ingredientsTitle: { cs: "Složení", sk: "Zloženie", pl: "Skład", }, certificatesTitle: { cs: "Certifikáty", sk: "Certifikáty", pl: "Certyfikaty", }, reviewsTitle: { cs: "Hodnocení", sk: "Hodnotenie", pl: "Opinie", }, weSupportTitle: { cs: "Pomáháme", sk: "Pomáhame", pl: "Pomagamy", }, relatedProductsTitle: { cs: "Související produkty", sk: "Súvisiace produkty", pl: "Produkty powiązane", }, showRelatedProducts: { cs: "Zobrazit související produkty", sk: "Zobraziť súvisiace produkty", pl: "Pokaż produkty powiązane", }, relatedFilesTitle: { cs: "Dokumenty", sk: "Dokumenty", pl: "Dokumenty", }, show: { cs: "Zobrazit", sk: "Zobraziť", pl: "Pokaż", }, showCertificate: { cs: "Zobrazit certifikát", sk: "Zobraziť certifikát", pl: "Pokaż certyfikat", }, outOf: { cs: "z", sk: "z", pl: "z", }, natiosDescription: { cs: "Natios je česká značka, která se zaměřuje na výrobu kvalitních doplňků stravy s čistým složením bez zbytečných příměsí, konzervantů a éček.", sk: "Natios je česká značka, ktorá sa zameriava na výrobu kvalitných doplnkov stravy s čistým zložením bez zbytočných prísad, konzervantov a éčok.", pl: "Natios to czeska marka, która koncentruje się na produkcji wysokiej jakości suplementów diety o czystym składzie – bez zbędnych domieszek, konserwantów i sztucznych dodatków (E).", }, natiosSupportTextTop: { cs: "Nákupem přispějete 1 Kč dětské hematoonkologii.", sk: "Nákupom prispievate 1 Kč detskej hematoonkológii.", pl: "Kupując, wspierasz dziecięcą hematoonkologię kwotą 1 CZK.", }, natiosSupportHeaderBottom: { cs: "

Pomáháme

 dětské hematoonkologii", sk: "

Pomáhame

 detskej hematoonkológii", pl: "

Pomagamy

 pediatrycznej hematoonkologii", }, natiosSupportTextBottom: { cs: "Natios z každého prodaného produktu daruje 1 Kč dětské hematoonkologii ve Fakultní nemocnici v Ostravě. Léčba každého onkologického pacienta v České republice se odhaduje na přibližně 8 000 Kč měsíčně. Věříme tedy, že tímto krokem společně dokážeme pomoci několika rodinám.", sk: "Natios z každého predaného produktu daruje 1 Kč detskej hematoonkológii vo Fakultnej nemocnici v Ostrave. Liečba každého onkologického pacienta v České republice sa odhaduje na približne 8 000 Kč mesačne. Veríme teda, že týmto krokom spoločne dokážeme pomôcť niekoľkým rodinám.", pl: "Natios z każdego sprzedanego produktu przekazuje 1 CZK na rzecz pediatrycznej hematoonkologii w Szpitalu Uniwersyteckim w Ostrawie. Leczenie jednego pacjenta onkologicznego w Czechach szacuje się na około 8 000 CZK miesięcznie. Wierzymy, że tym krokiem wspólnie możemy pomóc wielu rodzinom.", }, natiosSupportTotalAmount: { cs: "Společně jsme již dokázali přispět přes 915 000 Kč. Děkujeme!", sk: "Spoločne sme už dokázali prispieť cez 915 000 Kč. Ďakujeme!", pl: "Wspólnie udało nam się już przekazać ponad 915 000 CZK. Dziękujemy!", }, natiosSupportBlogUrl: { cs: "/blog/natios-pomaha-hematoonkologii-v-ostrave/", sk: "/blog/natios-pomaha-hematoonkologii-v-ostrave/", pl: "/", }, moreAboutSupport: { cs: "Více o pomoci", sk: "Viac o pomoci", pl: "Więcej o pomocy", }, insertFirstReview: { cs: "Vložit první hodnocení", sk: "Vložiť prvé hodnotenie", pl: "Wstaw pierwszą opinię", }, watchDog: { cs: "Hlídat dostupnost", sk: "Strážiť dostupnosť", pl: "Obserwuj dostępność", }, readMore: { cs: "Číst dále", sk: "Čítať ďalej", pl: "Czytaj dalej", }, productVariants: { cs: "Varianty produktu", sk: "Varianty produktu", pl: "Warianty produktu", }, showMoreVariants: { cs: "Zobrazit více variant", sk: "Zobraziť viac variantov", pl: "Pokaż więcej wariantów", }, withVAT: { cs: "s DPH", sk: "s DPH", pl: "z VAT", }, toCart: { cs: "Do košíku", sk: "Do košíka", pl: "Do koszyka", }, alertMe: { cs: "Upozornit", sk: "Upozorniť", pl: "Powiadom", }, gitFiltersUrl: { cs: "https://raw.githubusercontent.com/NatimaFilip/natima_eshop_files/refs/heads/main/filters_cz.json", sk: "https://raw.githubusercontent.com/NatimaFilip/natima_eshop_files/refs/heads/main/filters_sk.json", pl: "https://raw.githubusercontent.com/NatimaFilip/natima_eshop_files/refs/heads/main/filters_pl.json", }, gitHeurekaReviewsUrl: { cs: "https://raw.githubusercontent.com/NatimaFilip/natima_eshop_files/refs/heads/main/heureka_reviews_cz.json", sk: "https://raw.githubusercontent.com/NatimaFilip/natima_eshop_files/refs/heads/main/heureka_reviews_sk.json", pl: "https://raw.githubusercontent.com/NatimaFilip/natima_eshop_files/refs/heads/main/data/ceneo_reviews_pl.json" /*ceneo*/, }, laboratoryAnalysisText: { cs: "Laboratorně testováno", sk: "Laboratórne testované", pl: "Testowano laboratoryjnie", }, clientUrl: { cs: "https://www.natima.cz/klient", sk: "https://www.natima.sk/klient", pl: "https://www.natima.pl/centrum-klientow", }, vhodnePro: { cs: "Vhodné pro:", sk: "Vhodné pre:", pl: "Odpowiednie dla:", }, kosikUrl: { cs: "https://www.natima.cz/kosik", sk: "https://www.natima.sk/kosik", pl: "https://www.natima.pl/koszyk", }, nahoru: { cs: "Nahoru", sk: "Hore", pl: "Do góry", }, currencySymbol: { cs: "Kč", sk: "€", pl: "zł", }, measuringUnitSingulars: { cs: { kapslí: "kapsle", tablet: "tableta", tobolek: "tobolka", tabletek: "tabletka", dávek: "dávka", dávky: "dávka", produkty: "produkt", produktů: "produkt", }, sk: { kapsúl: "kapsula", kapsula: "kapsula", tabliet: "tableta", tablietek: "tabletka", dávok: "dávka", dávky: "dávka", produktov: "produkt", produkty: "produkt", }, pl: { kapsułek: "kapsułka", kapsułki: "kapsułka", tabletek: "tableta", saszetek: "saszetka", pastylek: "pastylka", gumisiów: "gumiś", dawek: "dawka", produktów: "produkt", produkty: "produkt", }, }, showAll: { cs: "Zobrazit vše", sk: "Zobraziť všetko", pl: "Zobacz wszystko", }, skladem: { cs: "Skladem", sk: "Skladom", pl: "Na stanie", }, nedostupne: { cs: "Momentálně nedostupné", sk: "Momentálne nedostupné", pl: "Chwilowo niedostępne", }, doKosiku: { cs: "Do košíku", sk: "Do košíka", pl: "Do koszyka", }, // --- Raventic search widgets (results + dropdown). SK/PL machine-translated; review. --- raventicNoResults: { cs: "Nic jsme nenašli, zkuste to znovu", sk: "Nič sme nenašli, skúste to znova", pl: "Nic nie znaleźliśmy, spróbuj ponownie", }, raventicResultsTitle: { cs: "Hledáme", sk: "Hľadáme", pl: "Szukamy", }, raventicNoQueryTitle: { cs: "Produkty", sk: "Produkty", pl: "Produkty", }, raventicCategoriesTitle: { cs: "Kategorie", sk: "Kategórie", pl: "Kategorie", }, raventicManufacturersTitle: { cs: "Výrobce", sk: "Výrobca", pl: "Producent", }, raventicPriceTitle: { cs: "Cena", sk: "Cena", pl: "Cena", }, raventicFiltersTitle: { cs: "Filtry", sk: "Filtre", pl: "Filtry", }, raventicFilterButton: { cs: "Zobrazit filtry", sk: "Zobraziť filtre", pl: "Pokaż filtry", }, raventicClearAllFilters: { cs: "Zrušit všechny filtry", sk: "Zrušiť všetky filtre", pl: "Usuń wszystkie filtry", }, raventicParamDescription: { cs: "Popis", sk: "Popis", pl: "Opis", }, raventicParamRating: { cs: "Hodnocení", sk: "Hodnotenie", pl: "Ocena", }, raventicParamReviewCount: { cs: "Počet recenzí", sk: "Počet recenzií", pl: "Liczba recenzji", }, raventicParamAltImage: { cs: "Alternativní obrázek", sk: "Alternatívny obrázok", pl: "Alternatywny obrazek", }, raventicParamStock: { cs: "Skladem", sk: "Skladom", pl: "Na stanie", }, raventicBrandsTitle: { cs: "Značky", sk: "Značky", pl: "Marki", }, raventicArticlesTitle: { cs: "Články", sk: "Články", pl: "Artykuły", }, raventicAddToCart: { cs: "DO KOŠÍKU", sk: "DO KOŠÍKA", pl: "DO KOSZYKA", }, raventicWelcome: { cs: "Najděte přesně to, co hledáte!", sk: "Nájdite presne to, čo hľadáte!", pl: "Znajdź dokładnie to, czego szukasz!", }, raventicRecommendedProducts: { cs: "Top produkty", sk: "Top produkty", pl: "Top produkty", }, raventicFoundProducts: { cs: "Top produkt", sk: "Top produkt", pl: "Top produkt", }, raventicSearchingFor: { cs: "Hledáme frázi", sk: "Hľadáme frázu", pl: "Szukamy frazy", }, raventicWouldYouSearchFor: { cs: "chcete raději hledat", sk: "chcete radšej hľadať", pl: "czy chcesz raczej wyszukać", }, raventicShowAll: { cs: "ZOBRAZIT VŠECHNY PRODUKTY", sk: "ZOBRAZIŤ VŠETKY PRODUKTY", pl: "POKAŻ WSZYSTKIE PRODUKTY", }, raventicCloseLabel: { cs: "Zavřít vyhledávání", sk: "Zavrieť vyhľadávanie", pl: "Zamknij wyszukiwanie", }, raventicClearLabel: { cs: "Vymazat hledání", sk: "Vymazať hľadanie", pl: "Wyczyść wyszukiwanie", }, }; /*--------------------------------------- Přepsání funkcí*/ function moveFilters() {} /*-------------------------------------- Custom events*/ // Debounce function to limit the rate at which a function can fire let resizeTimer; let lastWindowWidth = window.innerWidth; window.addEventListener("resize", function () { if (window.innerWidth !== lastWindowWidth) { document.dispatchEvent(new CustomEvent("resizeX")); clearTimeout(resizeTimer); resizeTimer = setTimeout(function () { lastWindowWidth = window.innerWidth; // Dispatch a custom event when X axis resize is complete console.log("CUSTOM EVENT DISPATCHED: debouncedResize"); document.dispatchEvent(new CustomEvent("debouncedResize")); }, 250); } }); /*-------------------------------------- Media sizes*/ const mediaSizes = { desktop: 1280, tablet: 768, }; let isMobile = false; let isTablet = false; let isDesktop = false; let body = document.querySelector("body"); function checkMediaSizes() { if (window.innerWidth < mediaSizes.tablet) { isMobile = true; isTablet = false; isDesktop = false; } if (window.innerWidth >= mediaSizes.tablet && window.innerWidth < mediaSizes.desktop) { isMobile = false; isTablet = true; isDesktop = false; } if (window.innerWidth >= mediaSizes.desktop) { isMobile = false; isTablet = false; isDesktop = true; } } checkMediaSizes(); document.addEventListener("resizeX", function () { checkMediaSizes(); }); /*-------------------------------------- Custom functions*/ //click and touchstart listener for elements that should work on both desktop and mobile /* function addSmartTouchClickListener(element, handler) { let touched = false; ["touchstart", "click"].forEach((event) => { element.addEventListener(event, function (e) { if (event === "touchstart") { touched = true; handler(e); } else if (event === "click") { if (touched) { touched = false; return; // Skip this click, already handled by touchstart } handler(e); } }); }); // element.addEventListener("pointerdown", function (e) { //handler(e); // e.preventDefault(); //}); } */ function scrollToElement(element) { const headerHeight = document.querySelector("#header").offsetHeight; window.scrollTo({ top: element.getBoundingClientRect().top + window.pageYOffset - headerHeight, behavior: "smooth", }); } function addSmartTouchClickListener(element, handler) { let touched = false; let touchTimer = null; /* element.addEventListener("touchstart" , function () { touched = true; // Reset touch if touchend doesn't happen soon touchTimer = setTimeout(() => { touched = false; }, 100); console.log("touchstart on element:", element); }); element.addEventListener("touchend", function (e) { if (touched) { handler(e); touched = false; clearTimeout(touchTimer); } console.log("touchend on element:", element); }); */ element.addEventListener("click", function (e) { if (touched) { // Click after touch, skip touched = false; return; } handler(e); }); } /*-------------------------------------- HEADER*/ let header = document.getElementById("header"); let headerTop = header.querySelector(".header-top"); let topNavigationContacts = document.querySelector(".top-navigation-contacts"); addContactToHeaderTop(); addAccountToHeaderTop(); stickyHeaderToggle(); function addContactToHeaderTop() { headerTop.appendChild(topNavigationContacts); headerTop.classList.add("header-loaded"); let projectPhone = headerTop.querySelector(".project-phone"); const contactHoursSpan = document.createElement("span"); contactHoursSpan.className = "contact-hours"; projectPhone.innerHTML = projectPhone.innerHTML.replace(translationsStrings.phoneCode[activeLang], ""); contactHoursSpan.innerHTML = translationsStrings.contactHours[activeLang]; projectPhone.appendChild(contactHoursSpan); } function addAccountToHeaderTop() { const accountButton = document.createElement("a"); accountButton.className = "login-button-custom"; accountButton.setAttribute("data-target", "login"); accountButton.setAttribute("href", translationsStrings.clientUrl[activeLang]); headerTop.appendChild(accountButton); let originalAccountButton = document.querySelector(".top-navigation-tools .top-nav-button-login"); if (originalAccountButton) { addSmartTouchClickListener(accountButton, function (event) { event.preventDefault(); originalAccountButton.click(); }); } } function stickyHeaderToggle() { const header = document.getElementById("header"); if (!header) return; if (body.classList.contains("ordering-process")) return; let lastScrollPosition = 0; let lastScrollUp = 0; let lastScrollDown = 0; let scrolledUp = false; const headerHeight = header.offsetHeight; const headerTopPosition = header.getBoundingClientRect().top + window.pageYOffset; const scrollThreshold = 150; let scrollDifference = 0; const handleScroll = () => { const currentScrollPosition = Math.round(window.pageYOffset || document.documentElement.scrollTop); // Scrolling up if (currentScrollPosition < lastScrollPosition) { lastScrollUp = currentScrollPosition; if (scrollDifference > scrollThreshold) { deactivateStickyHeader(); scrolledUp = true; } if (currentScrollPosition <= headerTopPosition) { // If scrolled to the top removeStickyHeader(); scrolledUp = false; } } // Scrolling down else { lastScrollDown = currentScrollPosition; scrollDifference = lastScrollDown - lastScrollUp; if (currentScrollPosition > headerHeight && scrollDifference > scrollThreshold) { if (scrolledUp) { activateStickyHeader(); } else { document.body.classList.add("scrolled-down"); } } } lastScrollPosition = Math.max(currentScrollPosition, 0); // Prevent negative scroll }; const activateStickyHeader = () => { document.body.classList.add("scrolled-down"); document.body.classList.add("sticky-header-off"); document.body.classList.remove("sticky-header-on"); }; const deactivateStickyHeader = () => { document.body.classList.add("sticky-header-on"); document.body.classList.remove("sticky-header-off"); document.body.classList.remove("scrolled-down"); }; const removeStickyHeader = () => { document.body.classList.remove("sticky-header-on"); document.body.classList.remove("sticky-header-off"); }; window.addEventListener("scroll", handleScroll); } /*-------------------------------------- MENU OVERFLOW DETECTION*/ let mainCategoryMenu = header.querySelector(".menu-level-1"); let mainCategoryMenuItems = mainCategoryMenu.querySelectorAll(":scope > li"); const originalMainCategoryMenuHelper = header.querySelector(".menu-helper"); const textOfOriginalMainCategoryMenuHelper = originalMainCategoryMenuHelper.innerHTML; header.querySelector(".menu-helper").remove(); let mainCategoryMenuHelper = document.createElement("div"); mainCategoryMenuHelper.className = "menu-helper-custom"; mainCategoryMenuHelper.innerHTML = textOfOriginalMainCategoryMenuHelper; const mainCategoryMenuHelperSubmenuDiv = document.createElement("div"); mainCategoryMenuHelperSubmenuDiv.className = "menu-helper-submenu"; mainCategoryMenuHelper.appendChild(mainCategoryMenuHelperSubmenuDiv); let mainCategoryMenuHelperSubmenu = mainCategoryMenuHelper.querySelector(".menu-helper-submenu"); let menuLevelsTwo; let menuLevelsThree; mainCategoryMenu.appendChild(mainCategoryMenuHelper); let mobileMenuIsTriggered = false; function inicializeMenu() { if (isMobile) { if (mobileMenuIsTriggered) { return; } mobileMenuIsTriggered = true; mainCategoryMenuItems.forEach((item) => { mainCategoryMenuHelperSubmenu.appendChild(item); }); mainCategoryMenu.append(mainCategoryMenuHelperSubmenu); mainCategoryMenuHelper.classList.remove("active"); mainCategoryMenuHelperSubmenuDiv.classList.remove("active"); menuLevelsTwo = mainCategoryMenu.querySelectorAll(".menu-level-2"); menuLevelsTwo.forEach((menuLevelTwo) => { addSmartTouchClickListener(menuLevelTwo, function (event) { if (isMobile) { menuLevelTwo.classList.add("active"); menuLevelTwo.parentElement.classList.add("active"); mainCategoryMenuHelperSubmenu.classList.add("level-two-active"); //mainCategoryMenuHelperSubmenuDiv scroll to top mainCategoryMenuHelperSubmenuDiv.scrollTop = 0; } }); }); menuLevelsThree = mainCategoryMenu.querySelectorAll(".menu-level-3"); menuLevelsThree.forEach((menuLevelThree) => { addSmartTouchClickListener(menuLevelThree, function (event) { if (!isMobile) { return; } menuLevelThree.classList.add("active"); menuLevelThree.parentElement.parentElement.classList.add("active"); mainCategoryMenuHelperSubmenu.classList.add("level-three-active"); mainCategoryMenuHelperSubmenuDiv.scrollTop = 0; }); }); let liHasThirdLevel = mainCategoryMenu.querySelectorAll(".has-third-level"); liHasThirdLevel.forEach((item) => { let aElement = item.querySelector(":scope > div > a"); addSmartTouchClickListener(aElement, function (event) { if (!isMobile) { return; } if (item.classList.contains("active")) { event.preventDefault(); mainCategoryMenuHelperSubmenu.classList.remove("level-three-active"); item.querySelector(".menu-level-3").classList.remove("active"); item.classList.remove("active"); mainCategoryMenuHelperSubmenuDiv.scrollTop = 0; } }); }); let liHasSecondLevel = mainCategoryMenu.querySelectorAll("li.ext"); liHasSecondLevel.forEach((item) => { let aElement = item.querySelector(":scope > a"); addSmartTouchClickListener(aElement, function (event) { if (!isMobile) { return; } if (item.classList.contains("active")) { event.preventDefault(); mainCategoryMenuHelperSubmenu.classList.remove("level-two-active"); item.querySelector(".menu-level-2").classList.remove("active"); item.classList.remove("active"); mainCategoryMenuHelperSubmenuDiv.scrollTop = 0; } }); }); /* if (isTestEshop) { */ copyFooterContactsToHeader(); copyFooterLinksToHeader(); function copyFooterContactsToHeader() { let footerContactBlock = document.querySelector(".top-navigation-contacts"); if (footerContactBlock) { const footerContactBlockClone = footerContactBlock.cloneNode(true); footerContactBlockClone.classList.add("top-navigation-contacts-clone"); mainCategoryMenuHelperSubmenu.appendChild(footerContactBlockClone); } } function copyFooterLinksToHeader() { let customerLinks = document.querySelector(".customer-links"); let aboutUsLinks = document.querySelector(".about-us-links"); if (customerLinks) { const customerLinksClone = customerLinks.cloneNode(true); customerLinksClone.classList.add("customer-links-clone"); mainCategoryMenuHelperSubmenu.appendChild(customerLinksClone); } if (aboutUsLinks) { const aboutUsLinksClone = aboutUsLinks.cloneNode(true); aboutUsLinksClone.classList.add("about-us-links-clone"); mainCategoryMenuHelperSubmenu.appendChild(aboutUsLinksClone); } } /* } */ return; } if (!isMobile && mobileMenuIsTriggered) { mainCategoryMenuHelper.append(mainCategoryMenuHelperSubmenu); mainCategoryMenu.querySelectorAll(".active").forEach((activeItems) => { activeItems.classList.remove("active"); }); mainCategoryMenuHelperSubmenu.classList.remove("level-two-active"); mainCategoryMenuHelperSubmenu.classList.remove("level-three-active"); document.body.classList.remove("scroll-lock"); document.body.classList.remove("content-hidden"); mobileMenuIsTriggered = false; } let mainCategoryMenuItemsInSubmenu = mainCategoryMenuHelperSubmenu.querySelectorAll(":scope > li"); if (mainCategoryMenuItemsInSubmenu.length > 0) { mainCategoryMenuItemsInSubmenu.forEach((item) => { mainCategoryMenu.appendChild(item); }); mainCategoryMenu.appendChild(mainCategoryMenuHelper); } let mainCategoryMenuItemsWidth = []; let cumulativeMainCategoryMenuItemWidth = 0; let mainCategoryMenuHelperWidth = mainCategoryMenuHelper.offsetWidth; mainCategoryMenuItems.forEach((item) => { let itemWidth = item.offsetWidth; cumulativeMainCategoryMenuItemWidth += itemWidth; mainCategoryMenuItemsWidth.push(cumulativeMainCategoryMenuItemWidth); }); let mainCategoryMenuWidth = mainCategoryMenu.offsetWidth; /* console.log("menuWidth", mainCategoryMenuWidth); console.log("cumulativeMainCategoryMenuItemWidth", cumulativeMainCategoryMenuItemWidth); console.log("menuItemsWidth", mainCategoryMenuItemsWidth); console.log("menuHelperWidth", mainCategoryMenuHelperWidth); */ if (mainCategoryMenuWidth < cumulativeMainCategoryMenuItemWidth) { mainCategoryMenuHelper.classList.remove("menu-helper-hidden"); let indexOfOverflowItem = mainCategoryMenuItemsWidth.findIndex( (itemWidth) => itemWidth > mainCategoryMenuWidth - mainCategoryMenuHelperWidth, ); /* console.log("indexOfOverflowItem", indexOfOverflowItem); console.log("mainCategoryMenuItemsWidth Idex", mainCategoryMenuItemsWidth[indexOfOverflowItem]); */ // from this index onwards, hide the items with style.display = "none" for (let i = indexOfOverflowItem; i < mainCategoryMenuItems.length; i++) { mainCategoryMenuHelperSubmenu.appendChild(mainCategoryMenuItems[i]); } } else { mainCategoryMenuHelper.classList.add("menu-helper-hidden"); } } inicializeMenu(); document.addEventListener("resizeX", function () { inicializeMenu(); }); /*-------------------------------------- HEADER SUBMENU LISTENER (hlavně pro mobil)*/ let addedListenerToClickOutsideOfMenu = false; addSmartTouchClickListener(mainCategoryMenuHelper, function (event) { mainCategoryMenuHelper.classList.toggle("active"); mainCategoryMenuHelperSubmenuDiv.classList.toggle("active"); if (isMobile) { document.body.classList.toggle("scroll-lock"); document.body.classList.toggle("content-hidden"); mainCategoryMenu.querySelectorAll(".menu-helper-submenu .active").forEach((activeItems) => { activeItems.classList.remove("active"); }); mainCategoryMenuHelperSubmenu.classList.remove("level-two-active"); mainCategoryMenuHelperSubmenu.classList.remove("level-three-active"); } if (!addedListenerToClickOutsideOfMenu) { addedListenerToClickOutsideOfMenu = true; addSmartTouchClickListener(document, function (event) { if (!mainCategoryMenuHelperSubmenuDiv.contains(event.target) && !mainCategoryMenuHelper.contains(event.target)) { mainCategoryMenuHelper.classList.remove("active"); mainCategoryMenuHelperSubmenuDiv.classList.remove("active"); if (isMobile) { document.body.classList.remove("scroll-lock"); document.body.classList.remove("content-hidden"); } } }); } }); /*-------------------------------------- MENU MAXIMUM POLOŽEK*/ function removeCommasFromMenu() { mainCategoryMenuItems.forEach((item) => { let menuLinkHref = item.querySelector(":scope > a")?.getAttribute("href") || null; let menuLevelTwo = item.querySelector(".menu-level-2"); let menuLevelTwoLi = item.querySelectorAll(".menu-level-2 > li"); if (menuLevelTwoLi.length > 0) { if (menuLevelTwoLi.length > 12) { for (let i = 11; i < menuLevelTwoLi.length; i++) { menuLevelTwoLi[i].style.display = "none"; } const numberOfHiddenItems = menuLevelTwoLi.length - 12 + 1; const showAllCategoriesButton = document.createElement("a"); showAllCategoriesButton.setAttribute("href", menuLinkHref); showAllCategoriesButton.className = "show-all-categories"; showAllCategoriesButton.innerHTML = "" + translationsStrings.showAllCategories[activeLang] + " (" + numberOfHiddenItems + ")"; menuLevelTwo.appendChild(showAllCategoriesButton); } menuLevelTwoLi.forEach((li, index) => { let menuLevelThreeLinkHref = li.querySelector(":scope > a")?.getAttribute("href") || null; let menuLevelThree = li.querySelector(".menu-level-3"); let menuLevelThreeLi = li.querySelectorAll(".menu-level-3 > li"); //Odstranení čárky z menu level 3 if (menuLevelThreeLi.length > 0) { if (menuLevelThreeLi.length > 4) { for (let i = 3; i < menuLevelThreeLi.length; i++) { menuLevelThreeLi[i].style.display = "none"; } const numberOfHiddenItems = menuLevelThreeLi.length - 4 + 1; const showAllSubcategoriesButton = document.createElement("a"); showAllSubcategoriesButton.setAttribute("href", menuLevelThreeLinkHref); showAllSubcategoriesButton.className = "show-all-subcategories"; if (numberOfHiddenItems > 4) { showAllSubcategoriesButton.innerHTML = "+ " + translationsStrings.moreButtonMoreThanFour[activeLang] + " " + numberOfHiddenItems; } else if (numberOfHiddenItems == 1) { showAllSubcategoriesButton.innerHTML = "+ " + translationsStrings.moreButtonOne[activeLang] + " " + numberOfHiddenItems; } else { showAllSubcategoriesButton.innerHTML = "+ " + translationsStrings.moreButtonLessThanFour[activeLang] + " " + numberOfHiddenItems; } menuLevelThree.appendChild(showAllSubcategoriesButton); } menuLevelThreeLi.forEach((li) => { let liHTML = li.innerHTML; liHTML = liHTML.replace(/<\/a>,\s*<\/li>$/, ""); liHTML = liHTML.replace(/<\/a>,\s*$/, ""); li.innerHTML = liHTML; }); } }); } }); /* menuLevelThreeAElements.forEach((item) => { // Get the text content of the item let itemHTML = item.innerHTML; // Replace any comma followed by whitespace at the end of links itemHTML = itemHTML.replace(/<\/a>,\s*<\/li>$/, ""); itemHTML = itemHTML.replace(/<\/a>,\s*$/, ""); // Update the item's HTML item.innerHTML = itemHTML; }); */ } removeCommasFromMenu(); /*----------------------------------------HEADER Calculate to free shipping*/ function calculateFreeShipping() { if ( !window.dataLayer[0].shoptet.cartInfo || typeof window.dataLayer[0].shoptet.cartInfo.freeShipping === "undefined" ) { console.warn("Cart info or freeShipping is not available in the data layer."); return; } let freeShippingBoolean = window.dataLayer[0].shoptet.cartInfo.freeShipping; if (freeShippingBoolean == true) { document.body.classList.add("has-free-shipping"); } if (freeShippingBoolean == false) { document.body.classList.remove("has-free-shipping"); let cartWidget = document.querySelector("#cart-widget"); if (!cartWidget) { return; } let percentageProgressToFreeShipping = 0; let leftToFreeShipping = window.dataLayer[0].shoptet.cartInfo.leftToFreeShipping.priceLeft || 0; let cartTotal = window.dataLayer[0].shoptet.cartInfo.getNoBillingShippingPrice.withVat || 0; leftToFreeShipping = Math.round(leftToFreeShipping); cartTotal = Math.round(cartTotal); percentageProgressToFreeShipping = 100 - Math.round((leftToFreeShipping / (cartTotal + leftToFreeShipping)) * 100); cartWidget.style.setProperty("--free-shipping-progress", percentageProgressToFreeShipping + "%"); if (leftToFreeShipping <= 0) { document.body.classList.add("has-free-shipping"); } } } document.addEventListener("DOMContentLoaded", function () { calculateFreeShipping(); }); document.addEventListener("ShoptetDOMCartContentLoaded", function () { calculateFreeShipping(); document.body.classList.add("cart-widget-has-loaded"); }); /*------------------------------------------------- KOSIK WIDGET - cena celkem do widgetu*/ document.addEventListener("ShoptetDOMCartContentLoaded", function () { insertTotalPriceToCartWidget(); }); let priceAddedToCartWidget = false; function insertTotalPriceToCartWidget() { if (!header.querySelector(".cart-price")) { return; } let totalPrice = header.querySelector(".cart-price").textContent.trim(); if (!totalPrice) { return; } let cartWidgetButton = document.querySelector("#cart-widget .cart-widget-button"); if (!cartWidgetButton) { return; } if (priceAddedToCartWidget) { const existingTotalPriceElement = cartWidgetButton.querySelector(".cart-total-price-wrapper"); if (existingTotalPriceElement) { const totalPriceStrong = existingTotalPriceElement.querySelector(".cart-total-price"); if (totalPriceStrong) { totalPriceStrong.innerHTML = totalPrice; } } return; } const totalPriceInCartWidgetElement = document.createElement("div"); totalPriceInCartWidgetElement.className = "cart-total-price-wrapper"; const totalPriceStrong = document.createElement("strong"); totalPriceStrong.className = "cart-total-price"; totalPriceStrong.innerHTML = totalPrice; const totalPriceLabel = document.createElement("span"); totalPriceLabel.innerHTML = translationsStrings.cartTotalLabel[activeLang]; totalPriceInCartWidgetElement.appendChild(totalPriceLabel); totalPriceInCartWidgetElement.appendChild(totalPriceStrong); cartWidgetButton.appendChild(totalPriceInCartWidgetElement); priceAddedToCartWidget = true; } /*-------------------------------------- KOSIK WIDGET - na mobilu rovnou do kosiku*/ addCartWidgetToCartMobileListener(); function addCartWidgetToCartMobileListener() { let cartButton = header.querySelector(".navigation-buttons"); if (!cartButton) { console.warn("Cart button not found."); return; } let cartHrefA = cartButton.querySelector("a"); if (!cartHrefA) { console.warn("Cart button href not found."); return; } let cartHref = cartHrefA.getAttribute("href"); if (!cartHref) { console.warn("Cart button href is empty."); return; } addSmartTouchClickListener(cartButton, function (event) { if (!isDesktop) { console.log("Cart button clicked on mobile, redirecting to cart page."); event.preventDefault(); window.location.href = cartHref; } else { console.log("Cart button clicked on desktop, no action needed."); } }); } let categoryTop; let filterInOriginalPosition; let filtersElement; let filterSections; let categoryContentWrapper; let selectedFiltersInSidebar; let customOpenFilterButtonListenerAdded; let asideElement; let customOpenFilterButton; /*------------------------------------------------- CATEGORY Filtry*/ if (body.classList.contains("type-category")) { /*------------------------------FILTRY*/ let categoryTop = document.querySelector(".category-top"); filterInOriginalPosition = true; filtersElement = document.querySelector("#filters"); asideElement = document.querySelector("aside"); /* let filtersWrapperElement = document.querySelector(".filters-wrapper"); */ filterSections = document.querySelectorAll("#filters .filter-section"); categoryContentWrapper = document.querySelector(".category-content-wrapper"); selectedFiltersInSidebar = true; customOpenFilterButtonListenerAdded = false; customOpenFilterButton = document.createElement("a"); customOpenFilterButton.className = "custom-open-filter-button"; customOpenFilterButton.innerHTML = translationsStrings.customFilterButton[activeLang]; moveAsideToCategoryContent(); customOpenFilterButtonListener(); customMoveFilter(); editClearFiltersButton(); moveSelectedFilters(); editManufacturerFilter(); cleanEmptyFilters(); editProductSorting(); document.addEventListener("DOMContentLoaded", function () { addPriceFilterClearButton(); cleanEmptyActiveFiltersSection(); }); document.addEventListener("resizeX", function () { customMoveFilter(); moveSelectedFilters(); }); document.addEventListener("ShoptetDOMPageContentLoaded", function (event) { // potřebuje znovu definovat, protože se to z nějakého důvodu přepíše categoryTop = document.querySelector(".category-top"); filterInOriginalPosition = true; filtersElement = document.querySelector("#filters"); /* filtersWrapperElement = document.querySelector(".filters-wrapper"); */ filterSections = document.querySelectorAll("#filters .filter-section"); categoryContentWrapper = document.querySelector(".category-content-wrapper"); selectedFiltersInSidebar = true; customOpenFilterButtonListener(); customMoveFilter(); editClearFiltersButton(); addPriceFilterClearButton(); cleanEmptyActiveFiltersSection(); moveSelectedFilters(); editManufacturerFilter(); cleanEmptyFilters(); editProductSorting(); if (customOpenFilterButton.classList.contains("active")) { filtersElement.classList.add("active"); } else { filtersElement.classList.remove("active"); } }); function moveAsideToCategoryContent() { if (asideElement) { categoryContentWrapper.prepend(asideElement); } } function customMoveFilter() { if (!isDesktop) { if (filterInOriginalPosition) { filterInOriginalPosition = false; customOpenFilterButton.insertAdjacentElement("afterend", filtersElement); } } if (isDesktop) { if (!filterInOriginalPosition) { filterInOriginalPosition = true; categoryContentWrapper.appendChild(filtersElement); } } } function customOpenFilterButtonListener() { /* categoryTop.insertAdjacentElement("afterend", customOpenFilterButton); */ try { categoryTop.appendChild(customOpenFilterButton); if (customOpenFilterButtonListenerAdded) { return; } customOpenFilterButtonListenerAdded = true; addSmartTouchClickListener(customOpenFilterButton, function () { filtersElement.classList.toggle("active"); customOpenFilterButton.classList.toggle("active"); }); } catch (error) { console.error("Error in customOpenFilterButtonListener:", error); } } function editClearFiltersButton() { try { let clearFilterButton = filtersElement.querySelector("#clear-filters"); if (!clearFilterButton) { body.classList.remove("has-filters-active"); return; } body.classList.add("has-filters-active"); const selectedFiltersDiv = document.createElement("div"); selectedFiltersDiv.className = "selected-filters"; const selectedFiltersSpan = document.createElement("span"); selectedFiltersSpan.className = "selected-filters-text"; selectedFiltersSpan.innerHTML = translationsStrings.selectedFilters[activeLang]; filtersElement.prepend(selectedFiltersDiv); selectedFiltersDiv.appendChild(selectedFiltersSpan); //for each fieldset get active labels, create copies of them and append tgem to selectedFiltersDiv filterSections.forEach((section) => { let fieldsetHeader = section.querySelector("h4 > span"); let activeLabels = section.querySelectorAll("fieldset > div > label.active"); if (activeLabels.length === 0) { return; } const activeFilterSection = document.createElement("div"); activeFilterSection.className = "active-filter-section"; if (fieldsetHeader) { activeFilterSection.innerHTML = `${fieldsetHeader.textContent}`; } else { activeFilterSection.innerHTML = `${translationsStrings.product[activeLang]}`; } selectedFiltersDiv.appendChild(activeFilterSection); activeLabels.forEach((label) => { // Extract only the text node, excluding the .filter-count let labelText = Array.from(label.childNodes) .filter((node) => node.nodeType === Node.TEXT_NODE) // Get only text nodes .map((node) => node.textContent.trim()) // Trim the text content .join(""); // Combine the text if there are multiple text nodes const activeNewLabel = document.createElement("span"); activeNewLabel.className = "active-filter-label"; activeNewLabel.textContent = labelText; //on click also click the original label activeFilterSection.appendChild(activeNewLabel); addSmartTouchClickListener(activeNewLabel, function () { label.click(); }); }); }); selectedFiltersDiv.appendChild(clearFilterButton); } catch (error) { console.error("Error in editClearFiltersButton:", error); } } function addPriceFilterClearButton() { try { /* setTimeout(() => { */ let sliderWrapper = filtersElement.querySelector(".slider-wrapper"); let priceSlider = document.querySelector(".ui-slider-range"); if (sliderWrapper && priceSlider && priceSlider.style.width !== "100%") { let minFilterValue = sliderWrapper.querySelector(".slider-header .from").textContent.trim(); let maxFilterValue = sliderWrapper.querySelector(".slider-header .to").textContent.trim(); minFilterValue = minFilterValue.replace(/ +/g, " "); maxFilterValue = maxFilterValue.replace(/ +/g, " "); const sliderHeader = sliderWrapper.querySelector("h4 > span"); const activeFilterSection = document.createElement("div"); activeFilterSectionElement = document.querySelector(".active-filter-section"); activeFilterSection.className = "active-filter-section"; activeFilterSection.innerHTML = `${sliderHeader.textContent}`; selectedFiltersDiv = document.querySelector(".selected-filters"); selectedFiltersDiv.appendChild(activeFilterSection); if (!selectedFiltersDiv) { return; } selectedFilterText = selectedFiltersDiv.querySelector(".selected-filters-text"); if (!selectedFilterText) { return; } const activeNewLabel = document.createElement("span"); activeNewLabel.className = "active-filter-label"; activeNewLabel.setAttribute("data-filter-type", "price"); activeNewLabel.textContent = `${minFilterValue} - ${maxFilterValue}`; activeFilterSection.appendChild(activeNewLabel); selectedFiltersDiv.insertBefore(activeFilterSection, selectedFilterText.nextSibling); /* addSmartTouchClickListener(activeNewLabel, function () { label.click(); }); */ } /* }, 500); */ } catch (error) { console.error("Error in addPriceFilterClearButton:", error); } } function cleanEmptyActiveFiltersSection() { if ( document.querySelector(".selected-filters") && document.querySelectorAll(".active-filter-section").length === 0 ) { document.querySelector(".selected-filters").remove(); } } function moveSelectedFilters() { try { let selectedFiltersDiv = document.querySelector(".selected-filters"); if (!selectedFiltersDiv) { return; } if (isDesktop) { if (selectedFiltersInSidebar) { selectedFiltersInSidebar = false; categoryContentWrapper.prepend(selectedFiltersDiv); } } else { if (!selectedFiltersInSidebar) { selectedFiltersInSidebar = true; filtersElement.prepend(selectedFiltersDiv); } } } catch (error) { console.error("Error in moveSelectedFilters:", error); } } function editManufacturerFilter() { try { let manufacturerFilter = document.querySelector("#manufacturer-filter"); if (!manufacturerFilter) { return; } let manufacturerFilterFieldset = manufacturerFilter.querySelector("fieldset"); //remove disabled manufacturers let disabledManufacturers = manufacturerFilterFieldset.querySelectorAll(":scope >div > label.disabled"); disabledManufacturers.forEach((label) => { label.parentElement.remove(); }); //move natios to the top let natiosManufacturer = manufacturerFilterFieldset.querySelector( ":scope > div > label[for='manufacturerId[]natios']", ); if (natiosManufacturer) { manufacturerFilterFieldset.prepend(natiosManufacturer.parentElement); } let manufacturers = manufacturerFilterFieldset.querySelectorAll(":scope > div"); let manufacturersNumber = manufacturers.length; let manufacturersNumberMinusVisible = manufacturersNumber - 5; // If there are more than 5 active manufacturers, hide the rest if (manufacturersNumber <= 5) { return; } const showAllManufacturersButton = document.createElement("a"); showAllManufacturersButton.className = "show-all-manufacturers"; if (manufacturersNumberMinusVisible > 4) { showAllManufacturersButton.innerHTML = "+ " + translationsStrings.moreButtonMoreThanFour[activeLang] + " " + manufacturersNumberMinusVisible; } else if (manufacturersNumberMinusVisible == 1) { showAllManufacturersButton.innerHTML = "+ " + translationsStrings.moreButtonOne[activeLang] + " " + manufacturersNumberMinusVisible; } else { showAllManufacturersButton.innerHTML = "+ " + translationsStrings.moreButtonLessThanFour[activeLang] + " " + manufacturersNumberMinusVisible; } manufacturerFilter.appendChild(showAllManufacturersButton); addSmartTouchClickListener(showAllManufacturersButton, function () { manufacturerFilter.classList.add("active"); }); } catch (error) { console.error("Error in editManufacturerFilter:", error); } } function cleanEmptyFilters() { try { filterSections.forEach((section) => { let filterItems = section.querySelectorAll("fieldset > div > label:not(.disabled)"); if (filterItems.length === 0) { section.remove(); } let disabletFilterItems = section.querySelectorAll("fieldset > div > label.disabled"); let sectionAppendingPlace = section.querySelector("fieldset"); disabletFilterItems.forEach((disabledItem) => { sectionAppendingPlace.appendChild(disabledItem.parentElement); }); }); } catch (error) { console.error("Error in cleanEmptyFilters:", error); } } } function productListMoveAppendixToDescription() { /* if (!isTestEshop) { return; } */ // Get all product elements const products = document.querySelectorAll(".products-block .product"); if (!products || products.length === 0) { return; } products.forEach((product) => { const appendix = product.querySelector(".product-appendix"); const desc = product.querySelector(".p-desc"); if (appendix && desc) { // Move the appendix content to the beginning of the description if (!appendix.textContent.trim().endsWith(";")) { appendix.insertAdjacentText("beforeend", ";"); } desc.prepend(appendix); } }); } function fixKosikInVyhledavani() { let navigationButtons = header.querySelector(".navigation-buttons"); if (!navigationButtons) { return; } if (navigationButtons.textContent.trim().length === 0) { console.log("Navigation buttons are empty, fixing cart icon in search."); const cartLink = document.createElement("a"); cartLink.href = translationsStrings.kosikUrl[activeLang]; cartLink.className = "btn btn-icon toggle-window cart-count full hovered"; cartLink.dataset.target = "cart"; cartLink.dataset.hover = "true"; cartLink.dataset.redirect = "true"; cartLink.dataset.testid = "headerCart"; cartLink.rel = "nofollow"; cartLink.setAttribute("aria-haspopup", "dialog"); cartLink.setAttribute("aria-expanded", "false"); cartLink.setAttribute("aria-controls", "cart-widget"); navigationButtons.appendChild(cartLink); navigationButtons.style.setProperty("display", "flex", "important"); } } /*------------------------------------------------- CATEGORY Obecné*/ let perexTrimmedIsVisible; if (body.classList.contains("type-category")) { /*------------------------------PEREX*/ perexTrimmedIsVisible = false; if (isMobile) { trimPerex(); } function trimPerex() { const maxLength = 130; const perexElement = document.querySelector(".category-perex"); if (!perexElement) return; const paragraphElement = perexElement.querySelector(":scope > p"); if (!paragraphElement) return; let originalText = paragraphElement.textContent; originalText = originalText.replace(/\s+/g, " ").trim(); if (originalText.length <= maxLength) { // If the text is already short enough, do nothing return; } perexElement.classList.add("category-perex-has-shortened"); // Find the last full word within the maxLength let truncatedText = originalText.slice(0, maxLength); const lastSpaceIndex = truncatedText.lastIndexOf(" "); if (lastSpaceIndex !== -1) { truncatedText = truncatedText.slice(0, lastSpaceIndex); } const categoryPerexShortened = document.createElement("p"); categoryPerexShortened.innerHTML = truncatedText; categoryPerexShortened.className = "category-perex-shortened"; perexElement.appendChild(categoryPerexShortened); const readMoreButton = document.createElement("span"); readMoreButton.className = "read-more-perex"; readMoreButton.innerHTML = translationsStrings.more[activeLang]; categoryPerexShortened.appendChild(readMoreButton); addSmartTouchClickListener(readMoreButton, function () { perexElement.classList.add("active"); perexTrimmedIsVisible = true; }); //make it so it trims after 3 lines and saves the rest of the text in a data attribute } /*------------------------------ZOBRAZENÝ POČET POLOŽEK*/ showAmountOfProducts(); function showAmountOfProducts() { let allProducts = document.querySelectorAll(".product"); const amountOfProducts = allProducts.length; let categoryHeaderInsideDiv = document.querySelector("#category-header .listItemsTotal"); if (!amountOfProducts) return; if (!categoryHeaderInsideDiv) return; if (document.querySelector(".amount-of-products")) { document.querySelector(".amount-of-products").remove(); } const amountOfProductsSpan = document.createElement("span"); amountOfProductsSpan.className = "amount-of-products"; amountOfProductsSpan.textContent = amountOfProducts.toString() + " " + translationsStrings.outOf[activeLang]; categoryHeaderInsideDiv.prepend(amountOfProductsSpan); } /*------------------------------DOM PAGE CONTET LOADED FUNKCE*/ document.addEventListener("ShoptetDOMContentLoaded", function (event) { if (isMobile) { if (!perexTrimmedIsVisible) { trimPerex(); } } allProducts = document.querySelectorAll(".product"); showAmountOfProducts(); }); } function editProductSorting() { let categoryHeader = document.querySelector("#category-header"); if (!categoryHeader) return; let sortingForm = categoryHeader.querySelector(".listSorting"); if (!sortingForm) return; let activeOSortingInput = categoryHeader.querySelector(".listSorting__control--current"); if (!activeOSortingInput) return; const toggleOpenSortingForm = document.createElement("span"); toggleOpenSortingForm.className = "toggle-open-sorting-form"; activeOSortingInput.parentElement.append(toggleOpenSortingForm); // Find all inputs within the category header /* let sortingInputs = sortingForm.querySelectorAll(".listSorting__controls li"); */ /* sortingInputs.forEach((input) => { let label = categoryHeader.querySelector(`label[for='${input.id}']`); if (input.checked && label) { label.classList.add("active"); // Add 'active' class to the label of the checked input if (!isDesktop) { sortingForm.querySelector("fieldset").prepend(label); // Move the label to the end of the fieldset } } else if (label) { label.classList.remove("active"); // Remove 'active' class from other labels } }); */ // Add event listener to the toggle button addSmartTouchClickListener(toggleOpenSortingForm, function () { sortingForm.classList.toggle("active"); toggleOpenSortingForm.classList.toggle("active"); }); } /*------------------------------------------------- Brand*/ if (body.classList.contains("type-manufacturer-detail")) { /*------------------------------------------------- PRODUCT Stránka produktu*/ editProductSorting(); document.addEventListener("ShoptetDOMPageContentLoaded", function (event) { editProductSorting(); }); } /*---------------------------------------------------------Uprava zobrazení produktu v product listu*/ let measureFiltersData = []; measureUnitFromFiltersProducts(); document.addEventListener("ShoptetDOMContentLoaded", function (event) { actionPriceToFinalPriceAndReviewsNumber(); measureUnitFromFiltersProducts(); productListMoveAppendixToDescription(); /* measureUnitFromAppendixProducts(); */ }); document.addEventListener("luigiSearchDone", function (event) { actionPriceToFinalPriceAndReviewsNumber(); measureUnitFromFiltersProducts(); productListMoveAppendixToDescription(); fixKosikInVyhledavani(); /* measureUnitFromAppendixProducts(); */ }); document.addEventListener("RAVENTIC SEARCH RESULTS TRANSFORMED", function (event) { actionPriceToFinalPriceAndReviewsNumber(); measureUnitFromFiltersProducts(); productListMoveAppendixToDescription(); /* measureUnitFromAppendixProducts(); */ }); /*---------ACTION PRICE AND REVIEWS NUMBER*/ actionPriceToFinalPriceAndReviewsNumber(); productListMoveAppendixToDescription(); function actionPriceToFinalPriceAndReviewsNumber() { let allProductsInProductsBlock = document.querySelectorAll(".products-block .product"); if (!allProductsInProductsBlock || allProductsInProductsBlock.length === 0) { return; // No products found } allProductsInProductsBlock.forEach((product) => { if (product.classList.contains("product-edited-price-reviews")) { return; // Skip if already processed } product.classList.add("product-edited-price-reviews"); let priceStandard = product.querySelector(".flag-discount .price-standard"); let priceFinal = product.querySelector(".price-final"); if (priceStandard && priceFinal) { priceFinal.appendChild(priceStandard); } let starWrapper = product.querySelector(".stars-wrapper"); if (starWrapper) { let reviewsNumber = starWrapper.getAttribute("data-micro-rating-count"); if (reviewsNumber) { const reviewsNumberSpan = document.createElement("span"); reviewsNumberSpan.className = "reviews-number"; reviewsNumberSpan.innerHTML = reviewsNumber + "x"; starWrapper.appendChild(reviewsNumberSpan); } } }); } /*NEW MEASURE UNIT - JSON GITHUB*/ async function downloadAndSaveMeasureUnitFilter() { const url = translationsStrings.gitFiltersUrl[activeLang]; const storageKey = "measureFilters"; const expiryKey = "measureFilters_expiry_01"; // Check if data is already in localStorage and not expired const now = Date.now(); const expiry = localStorage.getItem(expiryKey); const cached = localStorage.getItem(storageKey); if (expiry && cached && now < parseInt(expiry)) { // Data is still valid console.log("Measure filters loaded from localStorage."); measureFiltersData = JSON.parse(cached); return; } // Fetch and save try { const response = await fetch(url); if (!response.ok) throw new Error("Network response was not ok"); const data = await response.json(); localStorage.setItem(storageKey, JSON.stringify(data)); localStorage.setItem(expiryKey, (now + 24 * 60 * 60 * 1000).toString()); console.log("Measure filters saved to localStorage."); measureFiltersData = data; } catch (error) { console.warn("Failed to fetch Measure filters:", error); } } async function measureUnitFromFiltersProducts() { let allProductsInProductsBlock = document.querySelectorAll(".products-block .product"); if (!allProductsInProductsBlock || allProductsInProductsBlock.length === 0) { return; // No products found } await downloadAndSaveMeasureUnitFilter(); let productFilterData = measureFiltersData; if (!productFilterData || productFilterData.length === 0) { return; // No filter data available } allProductsInProductsBlock.forEach((product) => { if (product.classList.contains("product-edited-measure")) { return; // Skip if already processed } product.classList.add("product-edited-measure"); let productCodeForFilter = product.querySelector("span[data-micro='sku']")?.textContent.trim(); if (!productCodeForFilter) { console.warn("Product code not found for a product."); return; } let amountText = productFilterData.find((item) => item.code === productCodeForFilter)?.value; if (!amountText) { console.warn("No measure unit found for product code:", productCodeForFilter); return; } // Convert comma to dot, then extract the number and unit let normalizedAmountText = amountText.replace(",", ".").trim(); // Extract the numeric part (including decimal) let productMeasureAmount = normalizedAmountText.match(/[\d.]+/) ? normalizedAmountText.match(/[\d.]+/)[0] : ""; // Extract the unit part (letters and spaces after the number) let productMeasureUnit = normalizedAmountText.replace(/[\d.\s]+/, "").trim(); /* let productMeasureAmount = amountText.replace(/[^\d]/g, ""); //keep only digits from the measure unit let productMeasureUnit = amountText.replace(/[\d\s]/g, ""); //keep only letters from the measure unit */ let ratingsWrapper = product.querySelector(".ratings-wrapper"); const measureUnitSpan = document.createElement("span"); if (ratingsWrapper) { // Create a new span element to display the amount measureUnitSpan.className = "product-measure-unit"; measureUnitSpan.textContent = amountText; // Append the amount span to the ratings wrapper ratingsWrapper.appendChild(measureUnitSpan); } const pricePerUnitDiv = document.createElement("div"); pricePerUnitDiv.className = "product-price-per-unit"; let prices = product.querySelector(".prices"); let priceFinal = product.querySelector(".price-final strong"); let priceFinalValue; if (priceFinal) { // Extract the text content, trim it, and remove everything but numbers priceFinalValue = priceFinal.textContent.trim().replace(/[^\d.,]/g, ""); // Keep only digits, commas, and dots priceFinalValue = parseFloat(priceFinalValue.replace(",", ".")).toFixed(2); } let singleMeasuringUnit = {}; let ignoredMeasuringUnits = []; if (csLang) { singleMeasuringUnit = { kapslí: "kapsle", tablet: "tableta", tobolek: "tobolka", tabletek: "tabletka", dávek: "dávka", dávky: "dávka", produkty: "produkt", produktů: "produkt", }; ignoredMeasuringUnits = ["ks"]; } if (skLang) { singleMeasuringUnit = { kapsúl: "kapsula", kapsula: "kapsula", tabliet: "tableta", tablietek: "tabletka", dávok: "dávka", dávky: "dávka", produktov: "produkt", produkty: "produkt", }; ignoredMeasuringUnits = ["ks"]; } if (plLang) { singleMeasuringUnit = { kapsułek: "kapsułka", kapsułki: "kapsułka", tabletek: "tableta", saszetek: "saszetka", pastylek: "pastylka", gumisiów: "gumiś", dawek: "dawka", produktów: "produkt", produkty: "produkt", }; ignoredMeasuringUnits = ["szt"]; } if (ignoredMeasuringUnits.includes(productMeasureUnit)) { measureUnitSpan.style.display = "none"; return; // Skip processing for ignored units } let pricePerUnit_Unit; let foundUnitMatch = false; // Iterate over the keys in the object for (let key in singleMeasuringUnit) { if (productMeasureUnit.includes(key)) { foundUnitMatch = true; pricePerUnit_Unit = singleMeasuringUnit[key]; break; // Exit the loop once a match is found } } if (!foundUnitMatch) { // If no match is found, use the original measure unit pricePerUnit_Unit = productMeasureUnit; } const pricePerUnit_Value = priceFinalValue / productMeasureAmount; const pricePerUnit_ValueSpan = document.createElement("span"); pricePerUnit_ValueSpan.className = "product-price-per-unit-value"; if (csLang) { pricePerUnit_ValueSpan.textContent = pricePerUnit_Value.toFixed(2).replace(".", ",") + " Kč / 1 " + pricePerUnit_Unit; } if (skLang) { pricePerUnit_ValueSpan.textContent = pricePerUnit_Value.toFixed(2).replace(".", ",") + " € / 1 " + pricePerUnit_Unit; } if (plLang) { pricePerUnit_ValueSpan.textContent = pricePerUnit_Value.toFixed(2).replace(".", ",") + " zł / 1 " + pricePerUnit_Unit; } if (prices && pricePerUnitDiv) { prices.appendChild(pricePerUnitDiv); pricePerUnitDiv.appendChild(pricePerUnit_ValueSpan); } }); } /*--------------------MEASURE UNIT FROM APENDIX INTO CAPSULE*/ /* measureUnitFromAppendixProducts(); function measureUnitFromAppendixProducts() { let allProductsInProductsBlock = document.querySelectorAll(".products-block .product"); if (!allProductsInProductsBlock || allProductsInProductsBlock.length === 0) { return; // No products found } allProductsInProductsBlock.forEach((product) => { if (product.classList.contains("product-edited-measure")) { return; // Skip if already processed } product.classList.add("product-edited-measure"); let productAppendix = product.querySelector(".product-appendix"); if (!productAppendix) return; let productMeasureUnitComplet; let productMeasureAmount; let appendixText = productAppendix.textContent; // Use a regular expression to extract the desired value let match = appendixText.match(/^([^;]*);/); if (match) { productMeasureUnitComplet = match[1].trim(); // Save the extracted value productMeasureAmount = productMeasureUnitComplet.replace(/[^\d]/g, ""); //keep only digits from the measure unit productMeasureUnit = productMeasureUnitComplet.replace(/[\d\s]/g, ""); //keep only letters from the measure unit let ratingsWrapper = product.querySelector(".ratings-wrapper"); if (ratingsWrapper) { // Create a new span element to display the amount let measureUnitSpan = document.createElement("span"); measureUnitSpan.className = "product-measure-unit"; measureUnitSpan.textContent = productMeasureUnitComplet; // Append the amount span to the ratings wrapper ratingsWrapper.appendChild(measureUnitSpan); } const pricePerUnitDiv = document.createElement("div"); pricePerUnitDiv.className = "product-price-per-unit"; let prices = product.querySelector(".prices"); let priceFinal = product.querySelector(".price-final strong"); let priceFinalValue; if (priceFinal) { // Extract the text content, trim it, and remove everything but numbers priceFinalValue = priceFinal.textContent.trim().replace(/[^\d.,]/g, ""); // Keep only digits, commas, and dots priceFinalValue = parseFloat(priceFinalValue.replace(",", ".")).toFixed(2); } let singleMeasuringUnit = { kapslí: "kapsle", tablet: "tableta", tobolek: "tobolka", tabletek: "tabletka", }; let pricePerUnit_Unit; let foundUnitMatch = false; // Iterate over the keys in the object for (let key in singleMeasuringUnit) { if (productMeasureUnit.includes(key)) { foundUnitMatch = true; pricePerUnit_Unit = singleMeasuringUnit[key]; break; // Exit the loop once a match is found } } if (!foundUnitMatch) { // If no match is found, use the original measure unit pricePerUnit_Unit = productMeasureUnit; } const pricePerUnit_Value = priceFinalValue / productMeasureAmount; const pricePerUnit_ValueSpan = document.createElement("span"); pricePerUnit_ValueSpan.className = "product-price-per-unit-value"; pricePerUnit_ValueSpan.textContent = pricePerUnit_Value.toFixed(2).replace(".", ",") + " Kč / 1 " + pricePerUnit_Unit; if (prices && pricePerUnitDiv) { prices.appendChild(pricePerUnitDiv); pricePerUnitDiv.appendChild(pricePerUnit_ValueSpan); } // Remove "Množství ...;" from the text appendixText = appendixText.replace(/Množství:\s*[^;]+;/, "").trim(); productAppendix.textContent = appendixText; // Update the element's text content } }); } */ /*------------------------------------------------- FOOTER*/ let footer = document.querySelector("#footer"); if (footer) { //Edit sledovat na instagramu tlačítko ve widgetu editFollowOnInstagramWidgetButton(); function editFollowOnInstagramWidgetButton() { let instagramWidgetFollowBtn = footer.querySelector(".instagram-follow-btn a"); if (!instagramWidgetFollowBtn) return; const instagramProfileName = footer .querySelector("a.footer-social-link.instagram") .getAttribute("href") .replace("https://www.instagram.com/", "") .replace("/", ""); if (!instagramProfileName) return; const instagramProfileNameElement = document.createElement("span"); instagramProfileNameElement.className = "instagram-profile-name"; instagramProfileNameElement.textContent = instagramProfileName; const instagramImagePlaceholder = document.createElement("span"); instagramImagePlaceholder.className = "instagram-image-placeholder"; instagramWidgetFollowBtn.prepend(instagramProfileNameElement); instagramWidgetFollowBtn.prepend(instagramImagePlaceholder); } } /*------------------------------------------------- DOWNLOAD HEUREKA REVIES*/ let heurekaReviewsData; let numberOfTotalViableReviews = 0; let heurekaScrolled = false; document.addEventListener("DOMContentLoaded", async function () { if (!footer) { return; } document.addEventListener("downloadAndSaveHeurekaReviews", () => { insertHeurekaReviews(); let heurekaWrapper = document.querySelector(".heureka-reviews-wrapper"); let heurekaParent = document.querySelector("#heureka-reviews-insert"); let heurekaReviews = document.querySelectorAll(".heureka-review"); inicializeSliderElement(heurekaWrapper, heurekaParent, heurekaReviews, "heureka-slider", null); }); downloadAndSaveHeurekaReviews(); }); async function insertHeurekaReviews() { if (!footer) { return; } let heurekaInsertElement = footer.querySelector("#heureka-reviews-insert"); if (!heurekaInsertElement) { console.warn("Heureka reviews insert element not found."); return; } if (!heurekaReviewsData || heurekaReviewsData.length === 0) { console.warn("No Heureka reviews data available."); return; } heurekaReviewsData.forEach((review) => { const reviewElement = document.createElement("div"); reviewElement.className = "heureka-review"; let contentLength = 0; //review stars const reviewRatingWrapper = document.createElement("div"); reviewRatingWrapper.className = "heureka-review-rating-wrapper"; if (!review.total_rating || !review.total_rating._text) { return; } for (let i = 0; i < review.total_rating._text; i++) { const starIcon = document.createElement("i"); starIcon.className = "heureka-icon-star"; reviewRatingWrapper.appendChild(starIcon); } reviewElement.appendChild(reviewRatingWrapper); //review summary if (review.summary && review.summary._cdata) { if (review.summary._cdata.length < 100) { const reviewText = document.createElement("p"); reviewText.className = "heureka-review-summary"; reviewText.textContent = review.summary._cdata; reviewElement.appendChild(reviewText); contentLength += review.summary._cdata.length; } } if (csLang || skLang) { //review pros if (review.pros && review.pros._cdata) { let reviesEditedProData = []; const reviewPros = document.createElement("div"); reviewPros.className = "heureka-review-pros"; let prosString = review.pros._cdata; // Extract the string from _cdata let prosStringEdited = prosString.match(/[A-Z][^A-Z]*/g); // Split by sequences starting with a capital letter if (prosStringEdited && prosStringEdited.length > 0) { reviesEditedProData = prosStringEdited; } else { reviesEditedProData[0] = prosString; } //return if there are more than 3 pros (praveděpodobně chyba) if (reviesEditedProData.length > 3) { return; } reviesEditedProData.forEach((pro) => { const proElement = document.createElement("span"); proElement.className = "heureka-review-pro"; proElement.textContent = pro.trim(); reviewPros.appendChild(proElement); }); reviewElement.appendChild(reviewPros); contentLength += review.pros._cdata.length * 1.5; } // Review cons if (review.cons && review.cons._cdata) { let reviewsEditedConsData = []; const reviewCons = document.createElement("div"); reviewCons.className = "heureka-review-cons"; let consString = review.cons._cdata; // Extract the string from _cdata let consStringEdited = consString.match(/[A-Z][^A-Z]*/g); // Split by sequences starting with a capital letter if (consStringEdited && consStringEdited.length > 0) { reviewsEditedConsData = consStringEdited; } else { reviewsEditedConsData[0] = consString; } // Return if there are more than 3 cons (likely an error) if (reviewsEditedConsData.length > 3) { return; } reviewsEditedConsData.forEach((con) => { const conElement = document.createElement("span"); conElement.className = "heureka-review-con"; conElement.textContent = con.trim(); reviewCons.appendChild(conElement); }); reviewElement.appendChild(reviewCons); contentLength += review.cons._cdata.length * 1.5; } //return if content is less than 40 and more than 150 if (contentLength < 50 || contentLength > 100) { return; } } numberOfTotalViableReviews = numberOfTotalViableReviews + 1; /* // review date const reviewDate = document.createElement("span"); reviewDate.className = "heureka-review-date"; const reviewTimestamp = parseInt(review.unix_timestamp._text, 10) * 1000; // Convert to milliseconds const reviewDateObject = new Date(reviewTimestamp); // Format the date as DD-MM-YYYY const formattedDate = `${reviewDateObject.getDate().toString().padStart(2, "0")}.${(reviewDateObject.getMonth() + 1) .toString() .padStart(2, "0")}.${reviewDateObject.getFullYear()}`; reviewDate.textContent = formattedDate; reviewElement.appendChild(reviewDate); */ //add to heurekaInsertElement heurekaInsertElement.appendChild(reviewElement); }); } async function downloadAndSaveHeurekaReviews() { const url = translationsStrings.gitHeurekaReviewsUrl[activeLang]; const storageKey = "heurekaReviews"; const expiryKey = "heurekaReviews_expiry"; // Check if data is already in localStorage and not expired const now = Date.now(); const expiry = localStorage.getItem(expiryKey); const cached = localStorage.getItem(storageKey); if (expiry && cached && now < parseInt(expiry)) { // Data is still valid heurekaReviewsData = JSON.parse(cached).reviews.review; console.log("Heureka reviews loaded from localStorage."); console.log("CUSTOM EVENT DISPATCHED: downloadAndSaveHeurekaReviews"); document.dispatchEvent(new CustomEvent("downloadAndSaveHeurekaReviews")); return; } // Fetch and save try { const response = await fetch(url); if (!response.ok) throw new Error("Network response was not ok"); const data = await response.json(); localStorage.setItem(storageKey, JSON.stringify(data)); localStorage.setItem(expiryKey, (now + 24 * 60 * 60 * 1000).toString()); heurekaReviewsData = data.reviews.review; console.log("Heureka reviews saved to localStorage."); console.log("CUSTOM EVENT DISPATCHED: downloadAndSaveHeurekaReviews"); document.dispatchEvent(new CustomEvent("downloadAndSaveHeurekaReviews")); } catch (error) { console.error("Failed to fetch Heureka reviews:", error); } } /*------------------------------------------------- FOOTER Jazyky*/ footerLanguagesToggle(); function footerLanguagesToggle() { if (!footer) { return; } let footerLanguagesWrapper = footer.querySelector(".footer-languages-wrapper"); if (!footerLanguagesWrapper) { return; } let footerLanguagesToggleButton = footerLanguagesWrapper.querySelector(".footer-languages-current"); if (!footerLanguagesToggleButton) { return; } addSmartTouchClickListener(footerLanguagesToggleButton, function () { footerLanguagesWrapper.classList.toggle("active"); }); } /*------------------------------------------------- FOOTER Platby*/ footerPaymentsMove(); function footerPaymentsMove() { if (!footer) { return; } let footerPaymentsWrapper = footer.querySelector(".footer-online-payments"); if (!footerPaymentsWrapper) { return; } let footerBottom = footer.querySelector(".footer-bottom"); if (!footerBottom) { return; } footerBottom.appendChild(footerPaymentsWrapper); } /*------------------------------------------------- Produkty change add to cart button to + - 1170*/ function changeAddToCartButtonToIncreaseDecrease() { // Check if cartItems exist in the dataLayer let cartItems = window.dataLayer[0]?.shoptet?.cartInfo?.cartItems || []; if (!cartItems || cartItems.length === 0) { console.warn("No cart items found in the dataLayer."); return; } // Extract all the codes and quantities into an array of objects let cartItemCodesAndQuantities = cartItems.map((item) => ({ code: item.code, quantity: item.quantity, priceId: item.priceId, // Include priceId if needed itemId: item.itemId, // Include itemId if needed })); let allProducts = document.querySelectorAll(".product"); if (!allProducts || allProducts.length === 0) { console.warn("No products found on the page."); return; } allProducts.forEach((product) => { const productCode = product.querySelector(".p-code > span").textContent.trim(); if (!productCode) { console.warn("Product code not found for a product."); return; } if (!cartItemCodesAndQuantities.some((item) => item.code === productCode)) { return; // Skip products not in the cart } productAddButton = product.querySelector(".p-tools .add-to-cart-button"); if (!productAddButton) { console.warn(`Add to cart button not found for product with code ${productCode}.`); return; // Skip if no add to cart button } let selectedProductFromCart = cartItemCodesAndQuantities.find((item) => item.code === productCode); if (product.classList.contains("product-in-cart")) { if (selectedProductFromCart.quantity === 0) { shoptet.cartShared.removeFromCart({ itemId: selectedProductFromCart.itemId }); product.classList.remove("product-in-cart"); product.querySelector(".increase-decrease-wrapper").remove(); return; // Skip if quantity is 0 } product.querySelector(".quantity-input").value = selectedProductFromCart.quantity || "1"; // Default to 1 if not found return; // Skip if already processed } product.classList.add("product-in-cart"); const increaseDecreaseWrapper = document.createElement("div"); increaseDecreaseWrapper.className = "increase-decrease-wrapper"; const increaseButton = document.createElement("div"); increaseButton.className = "increase-button"; increaseButton.innerHTML = "+"; const decreaseButton = document.createElement("div"); decreaseButton.className = "decrease-button"; decreaseButton.innerHTML = "-"; const quantityInput = document.createElement("input"); quantityInput.className = "quantity-input"; quantityInput.type = "number"; quantityInput.value = selectedProductFromCart.quantity || "1"; // Default to 1 if not found quantityInput.min = "1"; // Minimum value quantityInput.max = "999"; // Maximum value quantityInput.setAttribute("data-product-code", productCode); // Store the product code increaseDecreaseWrapper.appendChild(decreaseButton); increaseDecreaseWrapper.appendChild(quantityInput); increaseDecreaseWrapper.appendChild(increaseButton); product.querySelector(".p-tools>*").appendChild(increaseDecreaseWrapper); if (/* document.body.classList.contains("is-test-eshop") && */ document.body.classList.contains("id--11")) { product.querySelector(".p-tools").appendChild(increaseDecreaseWrapper); } increaseButton.addEventListener("click", function () { quantityInput.value = parseInt(quantityInput.value) + 1; quantityInput.dispatchEvent(new Event("change")); // Manually trigger the change event }); decreaseButton.addEventListener("click", function () { if (parseInt(quantityInput.value) <= 1) { quantityInput.value = 0; quantityInput.dispatchEvent(new Event("change")); // Manually trigger the change event return; } quantityInput.value = parseInt(quantityInput.value) - 1; quantityInput.dispatchEvent(new Event("change")); // Manually trigger the change event }); function debounce(func, delay) { let timeout; return function (...args) { clearTimeout(timeout); timeout = setTimeout(() => func.apply(this, args), delay); }; } quantityInput.addEventListener( "change", debounce(function () { const quantityInputValue = parseInt(quantityInput.value); if (parseInt(quantityInputValue) < 1) { shoptet.cartShared.removeFromCart({ itemId: selectedProductFromCart.itemId }); product.classList.remove("product-in-cart"); product.querySelector(".increase-decrease-wrapper").remove(); } else { shoptet.cartShared.updateQuantityInCart({ itemId: selectedProductFromCart.itemId, priceId: selectedProductFromCart.priceId, amount: quantityInputValue, }); } }, 1000), // Debounce delay of 200ms ); }); } document.addEventListener("ShoptetCartUpdated", function () { changeAddToCartButtonToIncreaseDecrease(); /* ShoptetCartUpdated ShoptetDOMCartContentLoaded */ }); document.addEventListener("ShoptetDOMPageContentLoaded", function () { changeAddToCartButtonToIncreaseDecrease(); }); document.addEventListener("DOMContentLoaded", function () { changeAddToCartButtonToIncreaseDecrease(); }); document.addEventListener("luigiSearchDone", function () { changeAddToCartButtonToIncreaseDecrease(); }); document.addEventListener("RAVENTIC SEARCH RESULTS TRANSFORMED", function () { changeAddToCartButtonToIncreaseDecrease(); }); /*------------------------------------------------- Shorten breadcrumbs*/ shortenBreadcrumbs(); /* function shortenBreadcrumbs() { if (isDesktop) { return; // Skip if on desktop } let breadcrumbs = document.querySelectorAll(".breadcrumbs > span"); if (!breadcrumbs || breadcrumbs.length === 0) { return; } breadcrumbs.forEach((breadcrumb) => { if (breadcrumb.getAttribute("id") === "navigation-first") { return; // Skip the home breadcrumb } let breadcrumbTextElement = breadcrumb.querySelector("span[itemprop='name']"); console.log("breadcrumbTextElement:", breadcrumbTextElement); let breadcrumbText = breadcrumbTextElement.textContent.trim(); if (breadcrumbText.length > 20) { breadcrumb.textContent = breadcrumbText.slice(0, 20) + "..."; } }); } */ function shortenBreadcrumbs() { let breadcrumbs = document.querySelector(".breadcrumbs"); if (!breadcrumbs) { return; } const breadcrumbsSpans = Array.from(breadcrumbs.querySelectorAll("span[itemprop='itemListElement']")); if (breadcrumbsSpans.length <= 2) { breadcrumbs.classList.add("only-home"); } else { breadcrumbs.classList.add("shortened"); } } /*------------------------------------------------- Detail produktu*/ let isNatiosProduct; let isAvailableProduct; let infoWrapper; let productName; let productCode; let productCodeValue; let productBrand; let starsWrapper; let tabContent; let extendedDescription; let detailParameters; let shortDescription; let longDescription; let dostupnost; let shippingOptions; let addToCartBtn; let priceWrapper; let finalProductPrice; let continueReadingShortDescription; let souvisejiciProdukty; let souvisejiciProduktyTitle; let benefitBanner; let productsAlternative; let watchdog; let relatedFiles; let ratingTab; let productVotesWraps; let loadNextRatings; if (body.classList.contains("type-product")) { isNatiosProduct = false; isAvailableProduct = false; infoWrapper = document.querySelector(".product-top .p-info-wrapper"); productName = document.querySelector(".p-detail-inner-header h1"); productCode = document.querySelector(".p-detail-inner-header .p-code"); productCodeValue = ""; productBrand = document.querySelector(".product-top a[data-testid='productCardBrandName']"); starsWrapper = document.querySelector(".product-top .stars-wrapper"); tabContent = document.querySelector("#tab-content"); extendedDescription = document.querySelector("#description .extended-description"); detailParameters = document.querySelector(".description-inner .detail-parameters"); shortDescription = document.querySelector(".p-short-description"); longDescription = document.querySelector("#description"); dostupnost = document.querySelector(".product-top .availability-value"); shippingOptions = document.querySelector(".product-top .shipping-options")?.closest("table") || null; addToCartBtn = document.querySelector(".product-top .add-to-cart"); priceWrapper = document.querySelector(".product-top .p-final-price-wrapper"); finalProductPrice = document.querySelector(".product-top .price-final"); continueReadingShortDescription = document.querySelector(".product-top p[data-testid='productCardDescr']"); souvisejiciProdukty = document.querySelector(".products-block.products-related"); souvisejiciProduktyTitle = document.querySelector(".products-related-header"); benefitBanner = document.querySelector(".benefitBanner"); productsAlternative = document.querySelector("#productsAlternative"); watchdog = document.querySelector(".product-top .watchdog"); relatedFiles = document.querySelector("#relatedFiles"); ratingTab = document.querySelector("#ratingTab"); productVotesWraps = document.querySelectorAll("#ratingsList .vote-wrap"); loadNextRatings = document.querySelector("#ratingTab .load-next-wrap") || document.querySelector("#ratingTab .listingControls"); moveElementsInProduct(); /* measureUnitFromAppendixDetail(); */ function moveElementsInProduct() { if (!infoWrapper) { console.warn("Info wrapper not found."); return; // Exit if any of the elements are not found } if (!isMobile) { if (productName) { infoWrapper.prepend(productName); } } const rightContentWrapper = document.createElement("div"); rightContentWrapper.className = "right-content-wrapper"; const shortBenefitsWrapper = document.createElement("div"); shortBenefitsWrapper.className = "short-benefits-wrapper"; const vhodneProWrapper = document.createElement("div"); vhodneProWrapper.className = "vhodne-pro-wrapper"; const manufacturerAndCodeWrapper = document.createElement("div"); manufacturerAndCodeWrapper.className = "manufacturer-and-code-wrapper"; rightContentWrapper.appendChild(shortBenefitsWrapper); rightContentWrapper.appendChild(vhodneProWrapper); rightContentWrapper.appendChild(manufacturerAndCodeWrapper); infoWrapper.appendChild(rightContentWrapper); if (shortDescription) { let shortDescriptionFirstUl = shortDescription.querySelector("ul"); if (shortDescriptionFirstUl) { shortBenefitsWrapper.appendChild(shortDescriptionFirstUl); shortBenefitsWrapper.classList.add("active"); } } if (productBrand || document.querySelector(".product-widgets[product-template='natios']")) { if (productBrand) { manufacturerAndCodeWrapper.appendChild(productBrand); manufacturerAndCodeWrapper.classList.add("active"); } if ( document.querySelector(".product-widgets[product-template='natios']") || (productBrand && productBrand.textContent && productBrand.textContent.toLowerCase().includes("natios")) ) { if (productBrand && productBrand.textContent && productBrand.textContent.toLowerCase().includes("natios")) { isNatiosProduct = true; } body.classList.add("product-is-natios"); if (isNatiosProduct) { productBrand.setAttribute("href", "/natios"); } if (csLang || skLang) { if (isNatiosProduct) { productBrand.classList.add("natios"); const natiosBrandBlock = document.createElement("div"); natiosBrandBlock.className = "natios-brand-description-block-wrapper"; const natiosLargeBrandBlock = document.createElement("div"); natiosLargeBrandBlock.className = "natios-support-wrapper"; if (plLang) { return; } natiosBrandBlock.innerHTML = '

' + translationsStrings.natiosDescription[activeLang] + '' + translationsStrings.more[activeLang] + '

Charity

' + translationsStrings.natiosSupportTextTop[activeLang] + '' + translationsStrings.more[activeLang] + "

"; if (benefitBanner) { benefitBanner.classList.add("natios-block-added"); } natiosLargeBrandBlock.innerHTML = '
Natios Charity
' + translationsStrings.natiosSupportHeaderBottom[activeLang] + "

" + translationsStrings.natiosSupportTextBottom[activeLang] + "

" + translationsStrings.natiosSupportTotalAmount[activeLang] + '

' + translationsStrings.moreAboutSupport[activeLang] + "

"; if (tabContent) { tabContent.appendChild(natiosLargeBrandBlock); } document.querySelector(".product-top").insertAdjacentElement("afterend", natiosBrandBlock); document.querySelector(".scroll-to-FNO").addEventListener("click", function () { scrollToElement(natiosLargeBrandBlock); }); } } } } if (productCode) { manufacturerAndCodeWrapper.appendChild(productCode); manufacturerAndCodeWrapper.classList.add("active"); productCodeValue = productCode.querySelector("span:not(.p-code-label)").textContent.trim(); } if (starsWrapper) { if (!isMobile) { infoWrapper.appendChild(starsWrapper); } else { if (productName) { productName.parentElement.appendChild(starsWrapper); } } let starsElement = starsWrapper.querySelector(".star"); if (starsElement) { let starsScore = starsElement.getAttribute("title") || starsElement.getAttribute("data-original-title"); if (starsScore) { starsScore = starsScore.split(":")[1].split("/")[0].trim(); starsScore = parseFloat(starsScore).toFixed(2).replace(".", ","); if (starsScore != null && starsScore != "NaN") { const starsScoreElement = document.createElement("div"); starsScoreElement.className = "stars-score"; starsScoreElement.innerHTML = `${starsScore} / 5`; starsWrapper.appendChild(starsScoreElement); } else { starsWrapper.classList.add("no-score"); if (ratingTab) { ratingTab.classList.add("no-score"); } let starsLabel = starsWrapper.querySelector(".stars-label"); if (starsLabel) { starsLabel.textContent = translationsStrings.insertFirstReview[activeLang]; } } } } if (ratingTab) { starsWrapper.addEventListener("click", function (event) { event.preventDefault(); scrollToElement(ratingTab); }); } } if (detailParameters) { let parametersInProductTop = document.createElement("div"); parametersInProductTop.className = "product-parameters-product-top"; parametersInProductTop.innerHTML = detailParameters.outerHTML; infoWrapper.appendChild(parametersInProductTop); parametersInProductTopTrs = parametersInProductTop.querySelectorAll("tr"); //for each tr in parametersInProductTopTrs get text content of th and if its "Vhodné pro", append it to vhodne pro wrapper parametersInProductTopTrs.forEach((tr) => { let th = tr.querySelector("th"); if (th && th.textContent.trim() === translationsStrings.vhodnePro[activeLang]) { let td = tr.querySelector("td"); if (td) { const vhodneProElement = document.createElement("div"); vhodneProElement.className = "vhodne-pro-element"; const thSpan = document.createElement("span"); thSpan.textContent = thSpan.textContent.replace(":", ""); thSpan.textContent = th.textContent.trim(); thSpan.className = "vhodne-pro-title"; vhodneProElement.appendChild(thSpan); const entries = td.textContent .split(",") .map((e) => e.trim()) .filter((e) => e.length > 0); entries.forEach((entry) => { const entrySpan = document.createElement("span"); entrySpan.textContent = entry; vhodneProElement.appendChild(entrySpan); }); vhodneProWrapper.appendChild(vhodneProElement); vhodneProWrapper.classList.add("active"); tr.remove(); // Remove the tr element } } }); } const dostupnostADoruceniDoWrapper = document.createElement("div"); dostupnostADoruceniDoWrapper.className = "dostupnost-doruceni-wrapper"; if (dostupnost) { dostupnostADoruceniDoWrapper.appendChild(dostupnost); dostupnostADoruceniDoWrapper.classList.add("active"); let availabilityAmount = dostupnost.querySelector(".availability-amount"); //jestlize je skladem if (availabilityAmount) { isAvailableProduct = true; body.classList.add("product-is-available"); availabilityAmount.textContent = availabilityAmount.textContent.replace(/[()]/g, ""); availabilityAmount.textContent = availabilityAmount.textContent.replace( ">", translationsStrings.moreThan[activeLang], ); if (souvisejiciProdukty) { document.querySelector(".p-detail").appendChild(souvisejiciProdukty); if (souvisejiciProduktyTitle) { souvisejiciProdukty.insertAdjacentElement("beforebegin", souvisejiciProduktyTitle); } } } //když není skladem if (!availabilityAmount) { body.classList.add("product-not-available"); dostupnostADoruceniDoWrapper.classList.add("not-available"); if (souvisejiciProdukty) { document.querySelector(".p-detail-inner").insertAdjacentElement("afterend", souvisejiciProdukty); if (souvisejiciProduktyTitle) { souvisejiciProdukty.insertAdjacentElement("beforebegin", souvisejiciProduktyTitle); } } } } if (shippingOptions) { dostupnostADoruceniDoWrapper.appendChild(shippingOptions); dostupnostADoruceniDoWrapper.classList.add("active"); } infoWrapper.appendChild(dostupnostADoruceniDoWrapper); if (addToCartBtn) { priceWrapper.appendChild(addToCartBtn); } else { //tady bude co se stane když není k prodeji const notifyMeButtonWrapper = document.createElement("div"); notifyMeButtonWrapper.classList.add("sold-out-add-to-cart"); notifyMeButtonWrapper.classList.add("add-to-cart"); if (watchdog) { const notifyMeButton = document.createElement("div"); notifyMeButton.classList.add("notify-me-button"); notifyMeButton.classList.add("custom-add-to-cart-button"); notifyMeButton.textContent = translationsStrings.watchDog[activeLang]; notifyMeButtonWrapper.appendChild(notifyMeButton); notifyMeButton.addEventListener("click", function () { watchdog.click(); }); } else { const emptyDiv = document.createElement("div"); emptyDiv.className = "empty-div"; notifyMeButtonWrapper.appendChild(emptyDiv); } if (souvisejiciProdukty) { const showSimiliarProductsButton = document.createElement("div"); showSimiliarProductsButton.className = "show-similiar-products-button"; showSimiliarProductsButton.textContent = translationsStrings.showRelatedProducts[activeLang]; notifyMeButtonWrapper.prepend(showSimiliarProductsButton); showSimiliarProductsButton.addEventListener("click", function () { scrollToElement(souvisejiciProdukty); }); } else { const emptyDiv = document.createElement("div"); emptyDiv.className = "empty-div"; notifyMeButtonWrapper.prepend(emptyDiv); } priceWrapper.appendChild(notifyMeButtonWrapper); } if (finalProductPrice) { const withVATElement = document.createElement("span"); withVATElement.className = "with-vat"; withVATElement.textContent = translationsStrings.withVAT[activeLang]; finalProductPrice.appendChild(withVATElement); } if (continueReadingShortDescription) { let continueReadingShortDescriptionA = continueReadingShortDescription.querySelector("a"); if (continueReadingShortDescriptionA) { continueReadingShortDescriptionA.textContent = translationsStrings.readMore[activeLang]; } } if (productsAlternative) { let natiosBlockSelector = document.querySelector(".natios-brand-description-block-wrapper"); if (natiosBlockSelector) { natiosBlockSelector.insertAdjacentElement("beforebegin", productsAlternative); } else { benefitBanner.insertAdjacentElement("beforebegin", productsAlternative); } const productsAlternativeTitle = document.createElement("p"); productsAlternativeTitle.className = "products-alternative-title"; productsAlternativeTitle.textContent = translationsStrings.productVariants[activeLang]; productsAlternative.prepend(productsAlternativeTitle); let productsAlternativeItems = productsAlternative.querySelectorAll(".product"); if (productsAlternativeItems && productsAlternativeItems.length > 0) { productsAlternativeItems.forEach((item) => { if (!item.querySelector(".availability-amount")) { item.remove(); // Remove items without availability amount } }); } productsAlternativeItems = productsAlternative.querySelectorAll(".product"); if (!productsAlternativeItems || productsAlternativeItems.length == 0) { productsAlternative.remove(); productsAlternativeTitle.remove(); } if (productsAlternativeItems && productsAlternativeItems.length > 4) { productsAlternative.classList.add("multiple-rows-of-alternatives"); const showMoreAlternativesButton = document.createElement("div"); showMoreAlternativesButton.className = "show-more-alternatives-button"; showMoreAlternativesButton.textContent = translationsStrings.showMoreVariants[activeLang]; productsAlternative.appendChild(showMoreAlternativesButton); showMoreAlternativesButton.addEventListener("click", function () { productsAlternative.classList.add("active-all"); }); } } if (ratingTab) { const ratingTabTitleElement = document.createElement("h3"); ratingTabTitleElement.textContent = translationsStrings.reviewsTitle[activeLang]; let rateAverageWrap = ratingTab.querySelector(".rate-average-wrap"); if (rateAverageWrap) { rateAverageWrap.prepend(ratingTabTitleElement); } } if (relatedFiles) { const natiosAnalysis = document.querySelector(".product-widgets .natios-analysis .natios-analysis-content-left"); if (natiosAnalysis) { let allHrefsInRelatedFiles = relatedFiles.querySelectorAll("a:not(.btn)"); if (allHrefsInRelatedFiles && allHrefsInRelatedFiles.length > 0) { allHrefsInRelatedFiles.forEach((a) => { // Remove any text in parentheses with "kB" or "MB" etc. a.textContent = a.textContent.replace(/\(\s*[\d.,]+\s*[kMGT]?B\s*\)/gi, "").trim(); }); } natiosAnalysis.appendChild(relatedFiles); const showTestsButton = natiosAnalysis.querySelector(".show-tests-button"); if (showTestsButton) { showTestsButton.remove(); } } else { const basicDescription = document.querySelector("#description .basic-description"); if (basicDescription) { basicDescription.insertAdjacentElement("afterend", relatedFiles); } } } /* if (relatedFiles) { const basicDescription = document.querySelector("#description .basic-description"); if (basicDescription) { basicDescription.insertAdjacentElement("afterend", relatedFiles); } } */ if (extendedDescription) { if (tabContent) { tabContent.appendChild(extendedDescription); } } let imageElement = document.querySelector(".p-image-wrapper .p-image"); let flagsWrapper = document.querySelector(".product-top .flags.flags-default"); if (imageElement && flagsWrapper) { imageElement.appendChild(flagsWrapper); } //merne jednotky v detailu produktu try { /* measureUnitFromAppendixDetail */ measureUnitFromFiltersDetail(); } catch (error) { console.error("Error in measureUnitFromFiltersDetail:", error); } if (!loadNextRatings && productVotesWraps && productVotesWraps.length > 0) { let isAnyWrapHidden = false; //if any wrap has display none (not inline) productVotesWraps.forEach((wrap) => { if (getComputedStyle(wrap).display === "none") { isAnyWrapHidden = true; } }); if (isAnyWrapHidden) { const customListingControls = document.createElement("div"); customListingControls.className = "listingControls"; customListingControls.setAttribute("aria-labelledby", "listingControlsHeadingRatings"); const customLoadMore = document.createElement("div"); customLoadMore.className = "loadMore"; customLoadMore.setAttribute("data-context", "ratings"); const customLoadMoreButton = document.createElement("button"); customLoadMoreButton.classList.add( "loadMore__button", "loadMore__button--ratings", "btn", "btn-secondary", "js-loadMore__button--ratings", ); customLoadMoreButton.type = "button"; customLoadMoreButton.setAttribute("aria-controls", "ratingsList"); customLoadMoreButton.textContent = translationsStrings.showNext[activeLang]; customLoadMore.appendChild(customLoadMoreButton); customListingControls.appendChild(customLoadMore); productVotesWraps[0].parentElement.parentElement.appendChild(customListingControls); customLoadMoreButton.addEventListener("click", function (e) { if (ratingTab) { ratingTab.classList.add("all-visible"); customListingControls.style.display = "none"; } }); } } if (loadNextRatings) { loadNextRatings.addEventListener("click", function (e) { if (ratingTab) { ratingTab.classList.add("all-visible"); } }); } /* showNext: { cs: "Zobrazit další", sk: "Zobraziť ďalšie", pl: "Pokaż więcej", }, */ // Add sticky sell section - uplne poslední if (longDescription) { const stickySell = document.createElement("div"); stickySell.className = "sticky-sell"; const stickySellText = document.createElement("span"); stickySellText.className = "sticky-sell-text"; stickySellText.innerHTML = productName ? productName.innerHTML : ""; stickySell.appendChild(stickySellText); const stickySellRatingsWrapper = document.createElement("div"); stickySellRatingsWrapper.className = "sticky-sell-ratings-wrapper"; if (starsWrapper) { stickySellRatingsWrapper.innerHTML = starsWrapper.outerHTML; } stickySellRatingsWrapper.addEventListener("click", function (event) { event.preventDefault(); let ratingTab = document.querySelector("#ratingTab"); if (ratingTab) { scrollToElement(ratingTab); } }); stickySell.appendChild(stickySellRatingsWrapper); const stickySellAvailability = document.createElement("div"); stickySellAvailability.className = "sticky-sell-availability"; const editedDostupnost = document.querySelector(".product-top .dostupnost-doruceni-wrapper"); if (editedDostupnost) { stickySellAvailability.innerHTML = editedDostupnost.outerHTML; } stickySell.appendChild(stickySellAvailability); const stickyPriceAndButton = document.createElement("div"); stickyPriceAndButton.className = "sticky-price-and-button"; const editedPriceWrapper = document.querySelector(".product-top .p-final-price-wrapper"); if (editedPriceWrapper) { stickyPriceAndButton.innerHTML = editedPriceWrapper.outerHTML; } stickySell.appendChild(stickyPriceAndButton); longDescription.appendChild(stickySell); let stickySellButton = document.querySelector(".sticky-sell .p-final-price-wrapper .add-to-cart-button"); let productTopSellButton = document.querySelector(".product-top .p-final-price-wrapper .add-to-cart-button"); if (stickySellButton) { stickySellButton.addEventListener("click", function (event) { event.preventDefault(); productTopSellButton.click(); }); } let stickySellInput = document.querySelector(".sticky-sell input.amount"); let productTopInput = document.querySelector(".product-top input.amount"); let productStickySimiliar = document.querySelector(".sticky-sell .show-similiar-products-button"); if (stickySellInput && productTopInput) { let isProgrammaticChange = false; stickySellInput.addEventListener("change", function () { if (isProgrammaticChange) { isProgrammaticChange = false; // Reset the flag return; } isProgrammaticChange = true; // Set the flag before triggering the other input productTopInput.value = stickySellInput.value; productTopInput.dispatchEvent(new Event("change")); // Trigger the change event if needed }); productTopInput.addEventListener("change", function () { if (isProgrammaticChange) { isProgrammaticChange = false; // Reset the flag return; } isProgrammaticChange = true; // Set the flag before triggering the other input stickySellInput.value = productTopInput.value; stickySellInput.dispatchEvent(new Event("change")); // Trigger the change event if needed }); } if (productStickySimiliar && souvisejiciProdukty) { productStickySimiliar.addEventListener("click", function () { scrollToElement(souvisejiciProdukty); }); } } } function measureUnitFromFiltersDetail() { let product = document.querySelector(".product-top"); if (product.classList.contains("product-edited-measure")) { return; // Skip if already processed } downloadAndSaveMeasureUnitFilter(); product.classList.add("product-edited-measure"); let productFilterData = measureFiltersData; if (!productFilterData || productFilterData.length === 0) { return; // No filter data available } if (!productCodeValue) { console.warn("Product code not found for a product."); return; } let amountText = productFilterData.find((item) => item.code === productCodeValue)?.value; if (!amountText) { console.warn("No measure unit found for product code:", productCodeValue); return; } let normalizedAmountText = amountText.replace(",", ".").trim(); // Extract the numeric part (including decimal) let productMeasureAmount = normalizedAmountText.match(/[\d.]+/) ? normalizedAmountText.match(/[\d.]+/)[0] : ""; // Extract the unit part (letters and spaces after the number) let productMeasureUnit = normalizedAmountText.replace(/[\d.\s]+/, "").trim(); /* let productMeasureAmount = amountText.replace(/[^\d]/g, ""); //keep only digits from the measure unit let productMeasureUnit = amountText.replace(/[\d\s]/g, ""); //keep only letters from the measure unit */ let priceFinalWrapper = product.querySelector(".p-final-price-wrapper"); const pricePerUnitDiv = document.createElement("div"); pricePerUnitDiv.className = "product-price-per-unit-detail"; let priceFinal = product.querySelector(".price-final"); let priceFinalValue; if (priceFinal) { // Extract the text content, trim it, and remove everything but numbers priceFinalValue = priceFinal.textContent.trim().replace(/[^\d.,]/g, ""); // Keep only digits, commas, and dots priceFinalValue = parseFloat(priceFinalValue.replace(",", ".")).toFixed(2); } let singleMeasuringUnit = {}; if (csLang) { singleMeasuringUnit = { kapslí: "kapsle", tablet: "tableta", tobolek: "tobolka", tabletek: "tabletka", dávek: "dávka", dávky: "dávka", produkty: "produkt", produktů: "produkt", }; } if (skLang) { singleMeasuringUnit = { kapsúl: "kapsula", kapsula: "kapsula", tabliet: "tableta", tablietek: "tabletka", dávok: "dávka", dávky: "dávka", produktov: "produkt", produkty: "produkt", }; } if (plLang) { singleMeasuringUnit = { kapsułek: "kapsułka", kapsułki: "kapsułka", tabletek: "tableta", saszetek: "saszetka", pastylek: "pastylka", gumisiów: "gumiś", dawek: "dawka", produktów: "produkt", produkty: "produkt", }; } let pricePerUnit_Unit; let foundUnitMatch = false; // Iterate over the keys in the object for (let key in singleMeasuringUnit) { if (productMeasureUnit.includes(key)) { foundUnitMatch = true; pricePerUnit_Unit = singleMeasuringUnit[key]; break; // Exit the loop once a match is found } } if (!foundUnitMatch) { // If no match is found, use the original measure unit pricePerUnit_Unit = productMeasureUnit; } const pricePerUnit_Value = priceFinalValue / productMeasureAmount; const pricePerUnit_ValueSpan = document.createElement("span"); pricePerUnit_ValueSpan.className = "product-price-per-unit-value-detail"; if (csLang) { pricePerUnit_ValueSpan.textContent = pricePerUnit_Value.toFixed(2).replace(".", ",") + " Kč / 1 " + pricePerUnit_Unit; } if (skLang) { pricePerUnit_ValueSpan.textContent = pricePerUnit_Value.toFixed(2).replace(".", ",") + " € / 1 " + pricePerUnit_Unit; } if (plLang) { pricePerUnit_ValueSpan.textContent = pricePerUnit_Value.toFixed(2).replace(".", ",") + " zł / 1 " + pricePerUnit_Unit; } priceFinalWrapper.appendChild(pricePerUnitDiv); pricePerUnitDiv.appendChild(pricePerUnit_ValueSpan); } /* function measureUnitFromAppendixDetail() { let product = document.querySelector(".product-top"); if (product.classList.contains("product-edited-measure")) { return; // Skip if already processed } product.classList.add("product-edited-measure"); let productAppendix = document.querySelector(".product-appendix"); if (!productAppendix) return; let productMeasureUnitComplet; let productMeasureAmount; let appendixText = productAppendix.textContent; // Use a regular expression to extract the desired value let match = appendixText.match(/^([^;]*);/); if (match) { productMeasureUnitComplet = match[1].trim(); // Save the extracted value productMeasureAmount = productMeasureUnitComplet.replace(/[^\d]/g, ""); //keep only digits from the measure unit productMeasureUnit = productMeasureUnitComplet.replace(/[\d\s]/g, ""); //keep only letters from the measure unit let priceFinalWrapper = product.querySelector(".p-final-price-wrapper"); const pricePerUnitDiv = document.createElement("div"); pricePerUnitDiv.className = "product-price-per-unit-detail"; let prices = product.querySelector(".prices"); let priceFinal = product.querySelector(".price-final"); let priceFinalValue; if (priceFinal) { // Extract the text content, trim it, and remove everything but numbers priceFinalValue = priceFinal.textContent.trim().replace(/[^\d.,]/g, ""); // Keep only digits, commas, and dots priceFinalValue = parseFloat(priceFinalValue.replace(",", ".")).toFixed(2); } let singleMeasuringUnit = { kapslí: "kapsle", tablet: "tableta", tobolek: "tobolka", tabletek: "tabletka", }; let pricePerUnit_Unit; let foundUnitMatch = false; // Iterate over the keys in the object for (let key in singleMeasuringUnit) { if (productMeasureUnit.includes(key)) { foundUnitMatch = true; pricePerUnit_Unit = singleMeasuringUnit[key]; break; // Exit the loop once a match is found } } if (!foundUnitMatch) { // If no match is found, use the original measure unit pricePerUnit_Unit = productMeasureUnit; } const pricePerUnit_Value = priceFinalValue / productMeasureAmount; const pricePerUnit_ValueSpan = document.createElement("span"); pricePerUnit_ValueSpan.className = "product-price-per-unit-value-detail"; pricePerUnit_ValueSpan.textContent = pricePerUnit_Value.toFixed(2).replace(".", ",") + " Kč / 1 " + pricePerUnit_Unit; priceFinalWrapper.appendChild(pricePerUnitDiv); pricePerUnitDiv.appendChild(pricePerUnit_ValueSpan); // Remove "Množství ...;" from the text appendixText = appendixText.replace(/Množství:\s*[^;]+;/, "").trim(); productAppendix.textContent = appendixText; // Update the element's text content } } */ document.addEventListener("DOMContentLoaded", function () { productThumbnailInNavigation(); productNavigationCustom(); makeCarouselFromImages(); }); function productThumbnailInNavigation() { let navigaceProduktu = document.querySelector(".shp-tabs-row"); let productMainImage = document.querySelector(".p-image-wrapper .p-main-image"); let productName = document.querySelector("h1"); let productPrice = document.querySelector(".product-top .price-final"); if (!navigaceProduktu || !productMainImage || !productName || !productPrice) { console.warn("Product main image, name, or price not found."); return; // Exit if any of the elements are not found } const productThumbnailButton = document.createElement("div"); if (isAvailableProduct) { productThumbnailButton.className = "product-thumbnail-add-to-cart-button"; productThumbnailButton.textContent = translationsStrings.toCart[activeLang]; } if (!isAvailableProduct) { productThumbnailButton.className = "product-thumbnail-notice-me-button"; productThumbnailButton.textContent = translationsStrings.alertMe[activeLang]; } const productThumbnail = document.createElement("div"); productThumbnail.className = "product-thumbnail"; productThumbnail.innerHTML = `
${productMainImage.innerHTML}
${productName.innerHTML}
${productPrice.innerHTML}
${productThumbnailButton.outerHTML}
`; navigaceProduktu.prepend(productThumbnail); if (isAvailableProduct) { document.querySelector(".product-thumbnail-add-to-cart-button").addEventListener("click", function () { shoptet.cartShared.addToCart({ productCode: productCodeValue }); }); } if (!isAvailableProduct) { if (watchdog) { document.querySelector(".product-thumbnail-notice-me-button").addEventListener("click", function () { watchdog.click(); }); } } } function productNavigationCustom() { let detailTabs = document.querySelector("#p-detail-tabs"); if (!detailTabs) { return; // Exit if detail tabs are not found } let shpTabs = document.querySelectorAll(".shp-tab"); if (shpTabs && shpTabs.length > 0) { shpTabs.forEach((tab) => { tab.remove(); }); } // Example usage: /* let description = document.querySelector("#description"); if (description) { const descriptionTab = document.createElement("li"); descriptionTab.className = "shp-tab"; let descriptionTabTitle = "Description"; if (csLang) { descriptionTabTitle = "Popis"; } if (skLang) { descriptionTabTitle = "Popis"; } if (plLang) { descriptionTabTitle = "Opis"; } descriptionTab.innerHTML = `${descriptionTabTitle}`; detailTabs.appendChild(descriptionTab); descriptionTab.addEventListener("click", function () { const activeShopTab = document.querySelector(".shp-tab.active"); if (activeShopTab && activeShopTab !== descriptionTab) { activeShopTab.classList.remove("active"); } scrollToElement(description); }); const observer = new IntersectionObserver( (entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { const activeShopTab = document.querySelector(".shp-tab.active"); if (activeShopTab) { activeShopTab.classList.remove("active"); } descriptionTab.classList.add("active"); } }); }, { root: null, threshold: 0.01 } // Trigger when 50% of the description is visible ); observer.observe(description); } */ let filesButtonDesc = document.querySelector("#show-tests-button"); if (relatedFiles) { const filesTabTitleElement = document.createElement("h3"); filesTabTitleElement.textContent = translationsStrings.relatedFilesTitle[activeLang]; relatedFiles.prepend(filesTabTitleElement); let productFiles = relatedFiles.querySelectorAll("li"); if (productFiles && productFiles.length > 0) { productFiles.forEach((file) => { const fileHref = file.querySelector("a").href; const fileType = fileHref.split(".").pop().toUpperCase(); const showFileBtn = document.createElement("a"); showFileBtn.href = fileHref; showFileBtn.classList.add("btn", "show-file"); showFileBtn.setAttribute("target", "_blank"); if (document.querySelector(".natios-analysis")) { showFileBtn.textContent = translationsStrings.showCertificate[activeLang]; } else { showFileBtn.textContent = translationsStrings.show[activeLang]; } const fileTypeSpan = document.createElement("span"); fileTypeSpan.className = "file-type"; fileTypeSpan.textContent = "(" + fileType + ")"; showFileBtn.appendChild(fileTypeSpan); file.appendChild(showFileBtn); }); } if (filesButtonDesc) { filesButtonDesc.addEventListener("click", function (event) { event.preventDefault(); scrollToElement(relatedFiles); }); } } if (detailTabs) { createTabForSection("#description", translationsStrings.descriptionTitle[activeLang], true, detailTabs); createTabForSection( ".product-widget[widget-type='directions']", translationsStrings.directionsTitle[activeLang], false, detailTabs, ); createTabForSection( ".product-widget[widget-type='ingredients']", translationsStrings.ingredientsTitle[activeLang], false, detailTabs, ); createTabForSection("table.ingredients", translationsStrings.ingredientsTitle[activeLang], true, detailTabs); createTabForSection(".natios-analysis", translationsStrings.certificatesTitle[activeLang], true, detailTabs); createTabForSection("#ratingTab", translationsStrings.reviewsTitle[activeLang], false, detailTabs); createTabForSection(".natios-support-wrapper", translationsStrings.weSupportTitle[activeLang], false, detailTabs); createTabForSection(".products-related", translationsStrings.relatedProductsTitle[activeLang], false, detailTabs); } function createTabForSection(sectionId, tabTitle, isHardcoded, detailTabs) { const section = document.querySelector(sectionId); if (!section) { console.warn(`Section with ID ${sectionId} not found.`); return; } const tab = document.createElement("li"); tab.className = "shp-tab"; let tabTitleText = tabTitle; if (!isHardcoded) { tabTitleText = section.querySelector("h2") ? section.querySelector("h2").textContent.trim() : section.querySelector("h3") ? section.querySelector("h3").textContent.trim() : section.querySelector("h4") ? section.querySelector("h4").textContent.trim() : tabTitle; } tab.innerHTML = `${tabTitleText}`; if (sectionId === "#ratingTab") { try { let numberOfReviews = section.querySelector(".stars-label").textContent.trim().match(/^\d+/)?.[0]; tab.innerHTML = `${tabTitleText}${numberOfReviews}`; } catch (error) { console.warn("Error parsing number of reviews:", error); } } detailTabs.appendChild(tab); tab.addEventListener("click", function () { const activeShopTab = document.querySelector(".shp-tab.active"); if (activeShopTab && activeShopTab !== tab) { activeShopTab.classList.remove("active"); } scrollToElement(section); }); const observer = new IntersectionObserver( (entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { const activeShopTab = document.querySelector(".shp-tab.active"); if (activeShopTab) { activeShopTab.classList.remove("active"); } tab.classList.add("active"); } }); }, { root: null, threshold: 0.01 }, // Trigger when 1% of the section is visible ); observer.observe(section); } } function makeCarouselFromImages() { /* if (!body.classList.contains("is-test-eshop")) { return; } */ let productTopImage = document.querySelector(".product-top .p-image-wrapper .p-main-image"); if (!productTopImage) { return; } //wrap productTopImage in image-carousel-wrapper const imageCarouselWrapper = document.createElement("div"); imageCarouselWrapper.classList.add("image-carousel-wrapper"); productTopImage.parentNode.insertBefore(imageCarouselWrapper, productTopImage); imageCarouselWrapper.appendChild(productTopImage); let allImagesInThumbnails = document.querySelectorAll(".p-thumbnails-inner .p-thumbnail"); if (!allImagesInThumbnails || allImagesInThumbnails.length === 0 || allImagesInThumbnails.length === 1) { return; } let imageIndex = 0; allImagesInThumbnails.forEach((thumbnail, index) => { if (index !== 0) { const thumbnailClone = thumbnail.cloneNode(true); const thumbnailHref = thumbnailClone.getAttribute("href"); const thumbnailImage = thumbnailClone.querySelector("img"); if (thumbnailImage) { thumbnailImage.setAttribute("src", thumbnailHref); thumbnailImage.setAttribute("data-src", thumbnailHref); thumbnailImage.setAttribute("width", 1024); thumbnailImage.setAttribute("height", 768); } thumbnailClone.classList.add("p-main-image"); thumbnailClone.classList.add("no-first-image"); thumbnailClone.classList.remove("p-thumbnail"); imageCarouselWrapper.appendChild(thumbnailClone); } thumbnail.removeAttribute("href"); thumbnail.addEventListener("click", function (event) { event.preventDefault(); imageIndex = index; transformTopImage(); let activeThumbnail = document.querySelector(".p-thumbnails-inner .p-thumbnail.active"); if (activeThumbnail) { activeThumbnail.classList.remove("active"); } thumbnail.classList.add("active"); }); }); let imagesWrapper = document.querySelector(".p-image-wrapper .p-image"); let allImagesInCarousel = imageCarouselWrapper.querySelectorAll(".p-main-image"); inicializeSliderElementSnap( imagesWrapper, imageCarouselWrapper, allImagesInCarousel, "main-images-slider", "img", true, ); changeActiveThumbnail(); let thumbnailDebounce; imageCarouselWrapper.addEventListener("scroll", function () { const imageWidth = allImagesInCarousel[0].clientWidth; imageIndex = Math.round(imageCarouselWrapper.scrollLeft / imageWidth); clearTimeout(thumbnailDebounce); thumbnailDebounce = setTimeout(changeActiveThumbnail, 80); }); function transformTopImage() { if (!allImagesInCarousel) return; const imageWidth = allImagesInCarousel[0].clientWidth; imageCarouselWrapper.scrollTo({ left: imageIndex * imageWidth, behavior: "smooth", }); } function changeActiveThumbnail() { allImagesInThumbnails.forEach((thumbnail, thumbnailIndex) => { if (thumbnailIndex === imageIndex) { thumbnail.classList.add("active"); } else { thumbnail.classList.remove("active"); } }); } } addLaboratoryAnalysisToTop(); function addLaboratoryAnalysisToTop() { let natiosAnalysis = document.querySelector(".natios-analysis"); if (natiosAnalysis) { let shortBenefitsWrapper = document.querySelector(".product-top .short-benefits-wrapper ul"); if (shortBenefitsWrapper) { let laboratoryAnalysisElement = document.createElement("li"); laboratoryAnalysisElement.classList.add("laboratory-analysis-element"); laboratoryAnalysisElement.setAttribute("tabindex", "0"); laboratoryAnalysisElement.textContent = translationsStrings.laboratoryAnalysisText[activeLang]; shortBenefitsWrapper.appendChild(laboratoryAnalysisElement); laboratoryAnalysisElement.addEventListener("click", function () { scrollToElement(natiosAnalysis); }); } } } analysisTableExplanation(); function analysisTableExplanation() { const analysisContentRight = document.querySelector(".natios-analysis-content-right"); if (!analysisContentRight) return; analysisContentRight.classList.add("test-element"); let currentUl = null; let currentActiveFourthTd = null; // 1) Global clearer: runs BEFORE bubbling handlers (capture phase) document.addEventListener( "click", (e) => { if (currentUl) { const clickedInsideUl = currentUl.contains(e.target); const td = e.target.closest("td"); const insideanalysisContentRight = analysisContentRight.contains(e.target); const isFourthTd = !!td && td.cellIndex === 3; const isFifthTd = !!td && td.cellIndex === 4; // keep open if clicking the floating UL itself if (clickedInsideUl) return; // let the container handler manage clicks on a 4th td if (insideanalysisContentRight && isFourthTd) return; // ignore clicks on a 5th td inside the container if (insideanalysisContentRight && isFifthTd) return; // Otherwise remove currentUl and clear active state currentUl.remove(); currentUl = null; if (currentActiveFourthTd) { currentActiveFourthTd.classList.remove("active"); currentActiveFourthTd = null; } } }, true, ); // 2) Inside-container logic: activate the 5th td's UL when 4th td is clicked analysisContentRight.addEventListener("click", (e) => { const td = e.target.closest("td"); if (!td || !analysisContentRight.contains(td)) return; const isFourthTd = td.cellIndex === 3; // zero-based if (isFourthTd) { // Toggle behavior: if clicking the same active 4th td, close it if (currentActiveFourthTd === td) { if (currentUl) { currentUl.remove(); currentUl = null; } td.classList.remove("active"); currentActiveFourthTd = null; return; } // Clear any existing open UL and active 4th td if (currentUl) { currentUl.remove(); currentUl = null; } if (currentActiveFourthTd) { currentActiveFourthTd.classList.remove("active"); currentActiveFourthTd = null; } const fifthTd = td.parentElement.querySelector("td:nth-child(5)"); if (!fifthTd) return; const ul = fifthTd.querySelector("ul"); if (!ul) return; // clone and append the ul to body currentUl = ul.cloneNode(true); currentUl.style.position = "absolute"; currentUl.classList.add("active-table-explanation"); // position it relative to the 4th td clicked const rect = td.getBoundingClientRect(); currentUl.style.top = rect.bottom + window.scrollY - rect.height - 5 + "px"; currentUl.style.right = window.innerWidth - rect.right - window.scrollX + "px"; document.body.appendChild(currentUl); // mark the 4th td as active td.classList.add("active"); currentActiveFourthTd = td; } }); } if ($(".nelze-uplatnit-slevovy-kod").length > 0) { $(".nelze-uplatnit-slevovy-kod").html("

" + translationsStrings.noSaleCoupon[activeLang] + "

"); } if ($(".nelze-uplatnit-vernostni-slevu").length > 0) { $(".nelze-uplatnit-vernostni-slevu").html("

" + translationsStrings.noLoyaltySale[activeLang] + "

"); } function addDenDetiTextToShortDescription() { if (!shortDescription) return; const denDetiFlag = document.querySelector(".product-top .flag-dendeti10"); if (!denDetiFlag) return; const denDetiDiv = document.createElement("div"); denDetiDiv.className = "den-deti-text"; const denDetiText = document.createElement("p"); denDetiText.innerHTML = translationsStrings.denDetiKupon[activeLang]; denDetiDiv.appendChild(denDetiText); shortDescription.appendChild(denDetiDiv); } addDenDetiTextToShortDescription(); document.addEventListener("DOMContentLoaded", function () { let thumbnailsWrapper = document.querySelector(".p-thumbnails-inner"); let thumbnailsParent = document.querySelector(".p-thumbnails-inner > div"); let thumbnails = document.querySelectorAll(".p-thumbnail"); if (thumbnails && thumbnailsParent && thumbnailsWrapper) { inicializeSliderElement(thumbnailsWrapper, thumbnailsParent, thumbnails, "thumbnails-slider", null); } inicializeReviewFromEmail(); }); function inicializeReviewFromEmail() { if (window.location.hash !== "#ratingTab") return; const params = new URLSearchParams(window.location.search); const name = params.get("name"); const trigger = document.querySelector("#ratingTab .rate-form-trigger"); if (trigger) trigger.click(); if (name) { const nameInput = document.querySelector('#ratingTab input[name="fullName"]'); if (nameInput) nameInput.value = name; } } /*Možnosti doručení popup*/ editDeliveryPricesPopup(); function editDeliveryPricesPopup() { let lastShippingCheck = Date.now(); const observerShippingOptions = new MutationObserver((mutationsList, observer) => { for (const mutation of mutationsList) { if (mutation.type === "childList") { const shippingOptionsPopup = document.querySelector(".shipping-options-popup"); const now = Date.now(); if (shippingOptionsPopup) { if (now - lastShippingCheck < 1000) { return; // Skip if the last check was less than 1 second ago } lastShippingCheck = now; /* observer.disconnect(); */ changePricesInShippingTooltip(); } } } }); observerShippingOptions.observe(document.body, { childList: true, subtree: true }); function changePricesInShippingTooltip() { let shippingOptionsPopup = document.querySelector(".shipping-options-popup"); if (!shippingOptionsPopup) return; let priceRange = shippingOptionsPopup.querySelector(".price-range"); if (!priceRange) return; let shippingPrices = {}; if (csLang) { shippingPrices = { "Zásilkovna (Odběrné místo)": "49 Kč", "Balíkovna - ČP (Výdejní místa)": "49 Kč", "DPD (Pick Up) - Výdejní místa": "49 Kč", "DPD (Doručení na adresu)": "79 Kč", "Balíkovna na adresu - ČP": "85 Kč", "Zásilkovna (Doručení na adresu)": "89 Kč", }; } if (skLang) { shippingPrices = { "Zásilkovna Z-point (odberné miesto)": "€3,20", "Slovenská pošta – Balík na poštu": "€2,80", "Slovenská pošta – Balík do BalíkoBOXU": "€2,80", "Slovenská pošta – Kuriér na adresu": "€3,30", "DPD (doručenie na adresu)": "€4,20", "Zásielkovňa (doručenie na adresu)": "€4,50", }; } if (plLang) { shippingPrices = { "UPS - Kurier na adres następnego dnia roboczego": "18 zł", "Inpost - Kurier na adres": "15 zł", "Inpost - Paczkomaty 24/7": "13 zł", }; } document.querySelectorAll(".shipping-billing-name").forEach((nameEl) => { const name = nameEl.textContent.trim().replace(/\s+/g, " "); const price = shippingPrices[name]; if (price) { const priceEl = nameEl.closest(".shipping-row")?.querySelector(".payment-shipping-price"); if (priceEl) { priceEl.textContent = price; priceEl.classList.remove("for-free"); } } }); } } } /*------------------------------------------------- Index*/ let addedWhiteBanners; let allProductsBlocks = document.querySelectorAll(".products-block"); let hodnoceniObchoduAdded = false; if (body.classList.contains("in-index")) { let carousel = document.querySelector("#carousel"); let carouselInner = document.querySelector(".carousel-inner"); let carouselItems = document.querySelectorAll("#carousel .item"); inicializeSliderElement(carousel, carouselInner, carouselItems, "carousel-slider", "a"); addedWhiteBanners = false; if (!addedWhiteBanners) { if (indexesOfWhiteBanners) { carouselItems.forEach((item, index) => { if (indexesOfWhiteBanners.includes(index)) { item.classList.add("white"); } }); } addedWhiteBanners = true; } document.addEventListener("DOMContentLoaded", function () { customLazyVideos(); }); function customLazyVideos() { let lazyVideos = document.querySelectorAll("a.carousel-video-lazy"); if (!lazyVideos || lazyVideos.length === 0) { return; } lazyVideos.forEach(function (videoLink) { let video = videoLink.querySelector("video"); if (video && !video.classList.contains("loaded")) { let sources = video.querySelectorAll("source"); sources.forEach(function (source) { let dataSrc = source.getAttribute("data-src"); if (dataSrc) { source.setAttribute("src", dataSrc); } }); // Listen for the video to be fully loaded video.addEventListener("loadeddata", function onLoaded() { videoLink.classList.add("loaded"); video.classList.add("loaded"); video.removeEventListener("loadeddata", onLoaded); }); video.load(); } }); } allProductsBlocks = document.querySelectorAll(".products-block"); if (allProductsBlocks && allProductsBlocks.length > 0) { allProductsBlocks.forEach((block) => { let productsBlockItems = block.querySelectorAll(".product"); inicializeSliderElement(null, block, productsBlockItems, "products-slider", "img"); }); } footerNatiosBanner(); function footerNatiosBanner() { let footerBanner = document.querySelector(".footer-banner"); if (!footerBanner) { console.warn("Footer banner not found."); return; } // Move the footer banner after the second products block allProductsBlocks = document.querySelectorAll(".products-block"); if (allProductsBlocks && allProductsBlocks.length >= 2) { allProductsBlocks[1].parentElement.insertAdjacentElement("afterend", footerBanner.parentElement); } else { console.warn("Not enough products blocks to move the footer banner."); } } hodnoceniObchoduAdded = false; welcomeWrapper(); function welcomeWrapper() { let welcomeSection = document.querySelector(".welcome-wrapper .welcome"); let welcomeWrapper = document.querySelector(".welcome-wrapper"); if (welcomeSection) { let h1Element = welcomeSection.querySelector("h1"); let welcomeTexts = welcomeSection.querySelector(".homepage-welcome-texts"); if (h1Element && welcomeTexts) { welcomeTexts.prepend(h1Element); } let homepageBlogWrapper = document.querySelector(".homepage-blog-wrapper"); if (homepageBlogWrapper && welcomeWrapper) { homepageBlogWrapper.parentNode.insertBefore(welcomeWrapper, homepageBlogWrapper); hodnoceniObchodu(); } else { console.warn("Homepage blog not found in the wrapper."); } } } document.addEventListener("votesWrapLoaded", () => { let votesWrap = document.querySelector(".votes-wrap"); let votesItems = document.querySelectorAll(".votes-wrap .vote-wrap"); inicializeSliderElement(null, votesWrap, votesItems, "votes-slider", null); }); hodnoceniObchodu(); async function hodnoceniObchodu() { if (plLang) { return; // Skip for Polish language } if (hodnoceniObchoduAdded) { return; } hodnoceniObchoduAdded = true; const hodnoceniObchoduSection = document.createElement("div"); hodnoceniObchoduSection.className = "hodnoceni-obchodu-section"; const hodnoceniTitle = document.createElement("h2"); hodnoceniTitle.className = "hodnoceni-obchodu-title"; hodnoceniTitle.textContent = translationsStrings.verifiedReviews[activeLang]; let welcomeWrapper = document.querySelector(".welcome-wrapper"); if (welcomeWrapper) { welcomeWrapper.parentNode.insertBefore(hodnoceniObchoduSection, welcomeWrapper); } hodnoceniObchoduSection.appendChild(hodnoceniTitle); let fetchAddress = translationsStrings.shopRatingUrl[activeLang]; if (isTestEshop) { fetchAddress = "/hodnoceni-obchodu.html"; } //get .content-inner from the adress and append it to the hodnoceniObchoduSection try { const response = await fetch(fetchAddress); if (!response.ok) { throw new Error("Failed to fetch data from the server."); } const html = await response.text(); const parser = new DOMParser(); const doc = parser.parseFromString(html, "text/html"); const votesWrap = doc.querySelector(".votes-wrap"); let numberOfReviews = doc.querySelector("#ratingWrapper .stars-label"); //change span number of reviews to a let numberOfReviewsLink = document.createElement("a"); if (numberOfReviews) { numberOfReviewsLink.href = fetchAddress; numberOfReviewsLink.classList.add("stars-label-link"); numberOfReviewsLink.appendChild(numberOfReviews); } if (votesWrap) { hodnoceniObchoduSection.appendChild(numberOfReviewsLink); hodnoceniObchoduSection.appendChild(votesWrap); console.log("CUSTOM EVENT DISPATCHED: votesWrapLoaded"); document.dispatchEvent(new CustomEvent("votesWrapLoaded")); } else { console.warn("No .content-inner found in the fetched content."); } } catch (error) { console.error("Error fetching or processing hodnoceni obchodu:", error); } } homepageGroupTitlesFunc(); function homepageGroupTitlesFunc() { let homepageGroupTitles = document.querySelectorAll(".homepage-group-title"); if (!homepageGroupTitles || homepageGroupTitles.length === 0) { return; } let zobrazitVseTexty = []; let nejprodavanejsiUrl = ""; let novinkyUrl = ""; let akceUrl = ""; let blogUrl = ""; if (document.body.classList.contains("cs")) { zobrazitVseTexty = [ "Zobrazit všechny nejprodávanější", "Zobrazit všechny novinky", "Zobrazit všechny akce", "Zobrazit všechny články", ]; nejprodavanejsiUrl = "/nejprodavanejsi/"; novinkyUrl = "/novinky/"; akceUrl = "/-akce-mesice/"; /* akceUrl = "/black-friday/"; */ blogUrl = "/blog/"; } if (document.body.classList.contains("sk")) { zobrazitVseTexty = [ "Zobraziť všetky najpredávanejšie", "Zobraziť všetky novinky", "Zobraziť všetky akcie", "Zobraziť všetky články", ]; nejprodavanejsiUrl = "/najpredavanejsie/"; novinkyUrl = "/novinky/"; akceUrl = "/--akcie-mesiaca/"; /* akceUrl = "/black-friday/"; */ blogUrl = "/blog/"; } if (document.body.classList.contains("pl")) { zobrazitVseTexty = [ "Zobacz wszystkie najczęściej kupowane", "Zobacz wszystkie nowości", "Zobacz wszystkie promocje", "Zobacz wszystkie artykuły", ]; nejprodavanejsiUrl = "/najczesciej-kupowane/"; novinkyUrl = "/nowosci/"; akceUrl = "/promocja-miesiaca/"; /* akceUrl = "/black-friday/"; */ blogUrl = "/blog/"; } const titleUrlMap = [nejprodavanejsiUrl, novinkyUrl, akceUrl, blogUrl]; homepageGroupTitles.forEach((titleElement, index) => { const titleHref = document.createElement("a"); titleHref.href = titleUrlMap[index] || "#"; titleHref.classList.add("homepage-group-title-link"); titleHref.textContent = titleElement.textContent; titleElement.innerHTML = titleHref.outerHTML; const titleHrefShowAll = document.createElement("a"); titleHrefShowAll.href = titleUrlMap[index] || "#"; titleHrefShowAll.classList.add("homepage-group-title-show-all"); titleHrefShowAll.classList.add("desktop"); titleHrefShowAll.textContent = zobrazitVseTexty[index] || "Show All"; titleElement.appendChild(titleHrefShowAll); let titleHrefShowAllBottom = titleHrefShowAll.cloneNode(true); titleHrefShowAllBottom.classList.remove("desktop"); titleHrefShowAllBottom.classList.add("mobile"); if (index !== 3) { // Find the next sibling .products-block-wrapper let sibling = titleElement.nextElementSibling; while (sibling && !sibling.classList.contains("products-slider")) { sibling = sibling.nextElementSibling; } if (sibling) { sibling.appendChild(titleHrefShowAllBottom); } } else { const homepageBlogWrapper = document.querySelector(".homepage-blog-wrapper"); if (homepageBlogWrapper) { homepageBlogWrapper.appendChild(titleHrefShowAllBottom); } } }); } } /*-------------------------------------------------- LUPA NA MOBILU VYHLEDEAVANI*/ let searchElement = document.querySelector("#header .search"); const searchInput = document.querySelector("#header .search .search-input"); if (searchInput) { searchElement.addEventListener("click", (e) => { if (e.target !== searchInput) { searchInput.classList.toggle("active"); if (searchInput.classList.contains("active")) { body.classList.add("custom-search-active"); searchInput.focus(); setTimeout(() => { function outsideClickHandler(f) { const luigiAc = document.querySelector(".luigi-ac"); const luigiAcClose = document.querySelector(".luigi-ac-close"); const luigiShowAll = document.querySelector(".luigi-ac-button-block--show-all .luigi-ac-button"); if (f.target == luigiAcClose || f.target == luigiShowAll) { searchInput.classList.remove("active"); document.removeEventListener("click", outsideClickHandler); body.classList.remove("custom-search-active"); } if (f.target !== searchInput && (!luigiAc || !luigiAc.contains(f.target))) { searchInput.classList.remove("active"); document.removeEventListener("click", outsideClickHandler); body.classList.remove("custom-search-active"); } } document.addEventListener("click", outsideClickHandler); document.addEventListener("luigiSearchDone", function () { searchInput.classList.remove("active"); body.classList.remove("custom-search-active"); document.removeEventListener("click", outsideClickHandler); }); }, 200); } } }); } let luigiHero = document.querySelector(".luigi-ac-hero"); if (searchElement && searchInput) { searchElement.addEventListener("click", function () { if (luigiHero) { luigiHero.classList.toggle("active"); } }); } /* document.addEventListener("luigiSearchDone", function () { addSwapImageLuigi(); function addSwapImageLuigi() { let lbResults = document.querySelector("#lb-results"); console.log(lbResults); if (!lbResults) { return; } let luigiProducts = lbResults.querySelectorAll(".product"); if (!luigiProducts || luigiProducts.length < 1) { return; } luigiProducts.forEach((product) => { let swapImage = product.querySelector(".swap-image"); if (!swapImage) { return; } let mainImage = swapImage.src; let nextImage = swapImage.getAttribute("data-next"); if (mainImage && nextImage) { product.addEventListener("mouseenter", function () { swapImage.src = nextImage; }); product.addEventListener("mouseleave", function () { swapImage.src = mainImage; }); } }); } }); */ /*custom scroll to anchor*/ document.addEventListener("DOMContentLoaded", function () { // Check if there's an anchor in the URL if (window.location.hash) { const anchor = window.location.hash.replace(/^[#\/]+|\/+$/g, ""); const target = document.getElementById(anchor); if (target) { // Scroll to the element with a small offset (e.g., 80px) const offset = 80; const elementPosition = target.getBoundingClientRect().top + window.pageYOffset; window.scrollTo({ top: elementPosition - offset, behavior: "smooth", }); } } }); /*-----------------------------------------------------BLOG*/ if (document.body.classList.contains("in-blog") && document.body.classList.contains("type-post")) { document.addEventListener("DOMContentLoaded", function () { oldBlog(); function oldBlog() { let timeElement = $(".news-item-detail time[datetime]"); let dateStr = timeElement.attr("datetime"); let [day, month, year] = dateStr.split(".").map(Number); let date = new Date(year, month - 1, day); let comparisonDate = new Date(2024, 6, 31); if (date < comparisonDate) { $("body").addClass("old-blog"); } else { articleNav(); blogAutor(); fetchAndAppendRelatedBlogs(); fetchAndAppendBlogProducts3(); fetchAndAppendBlogProducts2(); fetchAndAppendBlogProducts1(); fetchAndAppendBlogProducts(); fetchAndAppendBlogCategory(); } } function blogAutor() { $("#content p").each(function () { if (/##AUTOR##KATEŘINAT/i.test($(this).text())) { if (document.body.classList.contains("cs")) { $(this).replaceWith( '
Kateřina

Autor

Kateřina

Zajímám se o zdravý životní styl, sport, kosmetiku a zdravou stravu. Mým cílem je inspirovat ostatní, aby pečovali o své tělo i mysl a stali se tou nejlepší verzí sebe samých. Pravidelně se věnuji různým sportovním aktivitám a hledám nové cesty, jak optimalizovat svou fyzickou kondici i duševní pohodu.

Zdravá strava je pro mě klíčovým prvkem, který podporuje mé zdraví a energii. Kromě sportu a výživy mě baví objevovat nové kosmetické trendy a produkty, které podporují přirozenou krásu a zdraví. Ve volném čase si ráda přečtu dobrou knihu, která mi poskytne nejen odpočinek, ale i nové poznatky. Na blogu se s vámi podělím o své zkušenosti, tipy a rady, jak žít zdravěji a spokojeněji.

', ); } if (document.body.classList.contains("sk")) { $(this).replaceWith( '
Kateřina

Autor

Kateřina

Zaujímam sa o zdravý životný štýl, šport, kozmetiku a zdravú stravu. Môj cieľ je inšpirovať ostatných, aby sa starali o svoje telo aj myseľ a stali sa tou najlepšou verziou seba samých. Pravidelne sa venujem rôznym športovým aktivitám a hľadám nové cesty, ako optimalizovať svoju fyzickú kondíciu aj duševnú pohodu.

Zdravá strava je pre mňa kľúčovým prvkom, ktorý podporuje moje zdravie a energiu. Okrem športu a výživy ma baví objavovať nové kozmetické trendy a produkty, ktoré podporujú prirodzenú krásu a zdravie. Vo voľnom čase si rada prečítam dobrú knihu, ktorá mi poskytne nielen oddych, ale aj nové poznatky. Na blogu sa s vami podelím o svoje skúsenosti, tipy a rady, ako žiť zdravšie a spokojnejšie.

', ); } if (document.body.classList.contains("pl")) { $(this).replaceWith( '
Kasia

Autor

Kasia

Interesuję się zdrowym stylem życia, sportem, metodami pielęgnacji skóry i zdrowym odżywianiem. Moim celem jest inspirowanie innych do dbania o ciało i umysł oraz stawania się najlepszą wersją siebie. Regularnie uprawiam różne sporty i poszukuję nowe sposoby na poprawę kondycji fizycznej i zdrowia psychicznego.

Zdrowa dieta jest dla mnie kluczowym elementem wspierającym moje zdrowie i energię. Oprócz sportu i zdrowego odżywiania lubię odkrywać nowe trendy w branży kosmetycznej oraz produkty, które promują naturalne piękno i zdrowie. W wolnym czasie lubię przeczytać dobrą książkę, która nie tylko pozwala mi się zrelaksować, ale także dowiedzieć się czegoś nowego. Na blogu będę dzielić się z Tobą moimi doświadczeniami, wskazówkami i poradami dotyczącymi tego, jak żyć zdrowszym i szczęśliwszym życiem.

', ); } } if (/##AUTOR##BARBORAP/i.test($(this).text())) { if (document.body.classList.contains("cs")) { $(this).replaceWith( `
Barbora P.

Autor

Barbora P.

Zajímám se o cestu ke zdraví a pohodě především přirozenou cestou. Objevuji síly bylinek, principy tradiční čínské medicíny a hledání rovnováhy mezi tělem a myslí. Jako studentka upřednostňuji efektivní řešení, která nebolí mě ani peněženku. Velkou částí mého života je moje border kolie, se kterou se věnujeme psím sportům a podnikáme dobrodružné výlety do hor.

Pohyb v přírodě je pro mě zdrojem energie i klidu. V kuchyni mě baví testovat různé stravovací styly a nové recepty, u kterých nepohrdnu kvalitní muzikou nebo zajímavým podcastem. Mou vášní je psaní a skrze něj chci sdílet své tipy, zkušenosti i drobné triky, které mohou ostatním pomoct ke spokojenějšímu životu.

`, ); } if (document.body.classList.contains("sk")) { $(this).replaceWith( `
Barbora P.

Autor

Barbora P.

Zaujímam sa o cestu k zdraviu a pohode predovšetkým prirodzenou cestou. Objavujem silu byliniek, princípy tradičnej čínskej medicíny a hľadanie rovnováhy medzi telom a mysľou. Ako študentka uprednostňujem efektívne riešenia, ktoré nebolia mňa ani peňaženku. Veľkou súčasťou môjho života je moja border kólia, s ktorou sa venujeme psím športom a podnikáme dobrodružné výlety do hôr.

Pohyb v prírode je pre mňa zdrojom energie aj pokoja. V kuchyni ma baví testovať rôzne stravovacie štýly a nové recepty, pri ktorých nepohrdnem kvalitnou muzikou alebo zaujímavým podcastom. Mojou vášňou je písanie a prostredníctvom neho chcem zdieľať svoje tipy, skúsenosti aj drobné triky, ktoré môžu ostatným pomôcť k spokojnejšiemu životu.

`, ); } if (document.body.classList.contains("pl")) { $(this).replaceWith( `
Barbora P.

Autor

Barbara P.

Interesuję się drogą do zdrowia i dobrego samopoczucia przede wszystkim w naturalny sposób. Odkrywam moc ziół, zasady tradycyjnej medycyny chińskiej oraz poszukiwanie równowagi między ciałem a umysłem. Jako studentka stawiam na skuteczne rozwiązania, które nie obciążają ani mnie, ani mojego portfela. Dużą częścią mojego życia jest moja border collie, z którą uprawiamy psie sporty i wyruszamy na pełne przygód wycieczki w góry.

Ruch na łonie natury jest dla mnie źródłem energii i spokoju. W kuchni uwielbiam eksperymentować z różnymi sposobami odżywiania i nowymi przepisami, a w tle najczęściej towarzyszy mi dobra muzyka lub ciekawy podcast. Moją pasją jest pisanie i właśnie poprzez nie chcę dzielić się swoimi wskazówkami, doświadczeniami oraz drobnymi trikami, które mogą pomóc innym żyć szczęśliwiej.

`, ); } } if (/##AUTOR##TEREZABERGLOWCOVA/i.test($(this).text())) { if (document.body.classList.contains("cs")) { $(this).replaceWith( `
Tereza Berglowcová

Autor

Tereza Berglowcová

Zajímám se o přírodní podporu zdraví prostřednictvím bylinek, výživy, pohybu a doplňků stravy. Blízký je mi aktivní životní styl, sport a přirozená péče o zdraví, stejně jako chvíle klidu a odpočinku s dobrou knihou.

Jako maminka malé dcery hledám šetrné a přirozené cesty, jak podpořit imunitu a celkovou vitalitu celé rodiny. Nejbližší jsou mi přírodní produkty a šetrná řešení, která respektují potřeby organismu.

Ráda se dělím o poznatky a zkušenosti, které mi dávají smysl a mohou být přínosné i pro ostatní.

`, ); } if (document.body.classList.contains("sk")) { $(this).replaceWith( `
Tereza Berglowcová

Autor

Tereza Berglowcová

Zaujímam sa o prírodnú podporu zdravia prostredníctvom byliniek, výživy, pohybu a výživových doplnkov. Blízky je mi aktívny životný štýl, šport a prirodzená starostlivosť o zdravie, rovnako ako chvíle pokoja a oddychu s dobrou knihou.

Ako mamička malej dcéry hľadám šetrné a prirodzené cesty, ako podporiť imunitu a celkovú vitalitu celej rodiny. Najbližšie sú mi prírodné produkty a šetrné riešenia, ktoré rešpektujú potreby organizmu.

Rada sa delím o poznatky a skúsenosti, ktoré mi dávajú zmysel a môžu byť prínosné aj pre ostatných.

`, ); } if (document.body.classList.contains("pl")) { $(this).replaceWith( `
Tereza Berglowcová

Autor

Tereza Berglowcová

Interesuję się naturalnym wspieraniem zdrowia poprzez zioła, odżywianie, ruch i suplementy diety. Bliski jest mi aktywny styl życia, sport i naturalna troska o zdrowie, a także chwile spokoju i odpoczynku z dobrą książką.

Jako mama małej córki szukam łagodnych i naturalnych sposobów na wspieranie odporności oraz ogólnej witalności całej rodziny. Najbliższe są mi produkty naturalne i delikatne rozwiązania, które szanują potrzeby organizmu.

Chętnie dzielę się wiedzą i doświadczeniami, które mają dla mnie sens i mogą być wartościowe także dla innych.

`, ); } } }); } function generateId(text) { return text .normalize("NFD") .replace(/[\u0300-\u036f]/g, "") .replace(/\s+/g, "-") .toLowerCase(); } function articleNav() { const content = document.querySelector("#content"); const headings = Array.from(content.querySelectorAll("h2, h3, h4, h5")); const nav = document.createElement("div"); nav.classList.add("article-nav"); const navList = document.createElement("ul"); let currentUl = navList; let lastLevel = 2; // Remove the last h3 from the list const lastH3Index = headings.map((h) => h.tagName).lastIndexOf("H3"); if (lastH3Index !== -1) { headings.splice(lastH3Index, 1); } headings.forEach((heading) => { const level = parseInt(heading.tagName.substring(1)); const id = generateId(heading.textContent); heading.id = id; const li = document.createElement("li"); const a = document.createElement("a"); a.href = `#${id}`; a.textContent = heading.textContent; li.appendChild(a); if (level > lastLevel) { const newUl = document.createElement("ul"); currentUl.lastElementChild.appendChild(newUl); currentUl = newUl; } else if (level < lastLevel) { currentUl = navList; for (let i = 2; i < level; i++) { currentUl = currentUl.lastElementChild.querySelector("ul"); } } currentUl.appendChild(li); lastLevel = level; }); const articleContent = document.createElement("div"); articleContent.classList.add("article-content"); articleContent.appendChild(navList); const whatFind = document.createElement("div"); whatFind.id = "open-article-nav"; const span1whatFind = document.createElement("span"); const span2whatFind = document.createElement("span"); const spanShow = document.createElement("span"); const spanHide = document.createElement("span"); if (document.body.classList.contains("cs")) { span1whatFind.textContent = "Co v článku najdete?"; spanShow.textContent = "Zobrazit seznam"; spanHide.textContent = "Skrýt seznam"; } if (document.body.classList.contains("sk")) { span1whatFind.textContent = "Čo v článku nájdete?"; spanShow.textContent = "Zobraziť zoznam"; spanHide.textContent = "Skryť zoznam"; } if (document.body.classList.contains("pl")) { span1whatFind.textContent = "Co znajdziesz w artykule?"; spanShow.textContent = "Pokaż listę"; spanHide.textContent = "Ukryj listę"; } whatFind.appendChild(span1whatFind); spanShow.classList.add("show-article"); span2whatFind.appendChild(spanShow); spanHide.classList.add("hide-article"); span2whatFind.appendChild(spanHide); whatFind.appendChild(span2whatFind); nav.appendChild(whatFind); nav.appendChild(articleContent); whatFind.addEventListener("click", function () { nav.classList.toggle("open"); }); // Insert after the first img in #content const firstImg = content.querySelector("img"); if (firstImg) { const parent = firstImg.parentElement; parent.insertAdjacentElement("afterend", nav); } else { content.insertBefore(nav, content.firstChild); } document.querySelectorAll(".article-nav a").forEach((anchor) => { anchor.addEventListener("click", function (e) { e.preventDefault(); const targetId = this.getAttribute("href").substring(1); const targetElement = document.getElementById(targetId); let offsetPosition = 0; if (!isMobile) { offsetPosition = targetElement.getBoundingClientRect().top + window.scrollY - 150; } else { offsetPosition = targetElement.getBoundingClientRect().top + window.scrollY - 80; } window.scrollTo({ top: offsetPosition, behavior: "smooth", }); }); }); } async function fetchAndAppendRelatedBlogs() { let blogURLs = []; let maxNumberOfBlogs = 5; $("#content p").each(function () { let text = $(this).text(); if (/##BLOG##/i.test(text)) { let urlMatch = text.match(/https?:\/\/[^\s]+/); if (urlMatch && blogURLs.length < maxNumberOfBlogs) { blogURLs.push(urlMatch[0]); } $(this).remove(); $("#content .next-prev").remove(); } }); if (blogURLs.length > 0) { let relatedBlogsDiv = $("
", { class: "blog-fetched-related" }); let blogURL = ""; let showBlogText = ""; let showBlogHeadingText = ""; if (document.body.classList.contains("cs")) { blogURL = "/blog/"; showBlogText = "Zobrazit všechny články"; showBlogHeadingText = "Mohlo by vás také zajímat"; } if (document.body.classList.contains("sk")) { blogURL = "/blog/"; showBlogText = "Zobraziť všetky články"; showBlogHeadingText = "Mohlo by vás tiež zaujímať"; } if (document.body.classList.contains("pl")) { blogURL = "/blog/"; showBlogText = "Zobacz wszystkie artykuły"; showBlogHeadingText = "Może Cię również zainteresować"; } let showBlogButton = $("
", { class: "show-all-blog-btn" }).append( $("", { href: blogURL, target: "_blank" }).text(showBlogText), ); let showBlogHeading = $("

", { class: "show-blog-heading" }).text(showBlogHeadingText); for (let url of blogURLs) { try { const response = await fetch(url); const text = await response.text(); const parser = new DOMParser(); const doc = parser.parseFromString(text, "text/html"); const metaImage = doc.querySelector('meta[property="og:image"]').getAttribute("content"); const metaSection = doc.querySelector('meta[property="article:section"]').getAttribute("content"); let metaDescription = doc.querySelector('meta[itemprop="description"]').getAttribute("content"); if (metaImage && metaSection && metaDescription) { // Create an anchor element let anchorElement = $("", { href: url, target: "_blank" }); // Create an img element let blogImage = $("", { src: metaImage, alt: "Blog Image", }); // Create a paragraph element for the meta section content let blogName = $("

").text(metaSection); // Create a paragraph element for the meta description content metaDescription = metaDescription.replace(/ /g, " "); let blogDescdription = $("

").text(metaDescription); // Append the img, section paragraph, and description paragraph elements to the anchor element anchorElement.append(blogImage); anchorElement.append(blogName); anchorElement.append(blogDescdription); // Append the anchor element to the relatedBlogsDiv relatedBlogsDiv.append(anchorElement); } } catch (error) { console.error("Error fetching related blog data:", error); } } // Append the relatedBlogsDiv to the body $(".content-wrapper-in").append(showBlogHeading); $(".content-wrapper-in").append(relatedBlogsDiv); $(".content-wrapper-in").append(showBlogButton); $(".content-wrapper-in").append($(".comments")); $(".content-wrapper-in").append($(".share")); } } async function fetchAndAppendBlogProducts() { let productURLs = []; let firstProductParagraph = null; let maxNumberOfProducts = 4; $("#content p").each(function () { let text = $(this).text(); if (/##PRODUKT##/i.test(text)) { if (!firstProductParagraph) { firstProductParagraph = $(this); } let urlMatch = text.match(/https?:\/\/[^\s]+/); if (urlMatch && productURLs.length < maxNumberOfProducts) { productURLs.push(urlMatch[0]); } } }); if (productURLs.length > 0 && firstProductParagraph) { let blogProductsDiv = $("

", { class: "blog-fetched-products" }); for (let url of productURLs) { try { const response = await fetch(url); const text = await response.text(); const parser = new DOMParser(); const doc = parser.parseFromString(text, "text/html"); const metaImage = doc.querySelector('meta[property="og:image"]'); const metaName = doc.querySelector('meta[itemprop="name"]'); if (metaImage && metaName) { // Create an anchor element let anchorElement = $("", { href: url, target: "_blank" }); // Create an img element let blogImage = $("", { src: metaImage.getAttribute("content"), alt: "Product Image", }); // Create a paragraph element for the meta name content let productName = $("

").text(metaName.getAttribute("content")); // Append the img element and the paragraph element to the anchor element anchorElement.append(blogImage); anchorElement.append(productName); // Append the anchor element to the blogProductsDiv blogProductsDiv.append(anchorElement); } } catch (error) { console.error("Error fetching product data:", error); } } // Insert the blogProductsDiv before the first found paragraph firstProductParagraph.before(blogProductsDiv); // Remove the paragraphs containing ##PRODUKT## $("p").each(function () { let text = $(this).text(); if (/##PRODUKT##/i.test(text)) { $(this).remove(); } }); } } async function fetchAndAppendBlogProducts1() { let productURLs = []; let firstProductParagraph = null; let maxNumberOfProducts = 4; $("#content p").each(function () { let text = $(this).text(); if (/##PRODUKT##1/i.test(text)) { if (!firstProductParagraph) { firstProductParagraph = $(this); } let urlMatch = text.match(/https?:\/\/[^\s]+/); if (urlMatch && productURLs.length < maxNumberOfProducts) { productURLs.push(urlMatch[0]); } } }); if (productURLs.length > 0 && firstProductParagraph) { let blogProductsDiv = $("

", { class: "blog-fetched-products" }); for (let url of productURLs) { try { const response = await fetch(url); const text = await response.text(); const parser = new DOMParser(); const doc = parser.parseFromString(text, "text/html"); const metaImage = doc.querySelector('meta[property="og:image"]'); const metaName = doc.querySelector('meta[itemprop="name"]'); if (metaImage && metaName) { // Create an anchor element let anchorElement = $("", { href: url, target: "_blank" }); // Create a paragraph element for the meta name content let productName = $("

").text(metaName.getAttribute("content")); // Create an img element let blogImage = $("", { src: metaImage.getAttribute("content"), alt: productName.text(), loading: "lazy", }); // Append the img element and the paragraph element to the anchor element anchorElement.append(blogImage); anchorElement.append(productName); /* const showBtn = document.createElement("div"); showBtn.classList.add("show-product-btn"); showBtn.textContent = "Zobrazit produkt"; anchorElement.append(showBtn); */ // Append the anchor element to the blogProductsDiv blogProductsDiv.append(anchorElement); } } catch (error) { console.error("Error fetching product data:", error); } } // Insert the blogProductsDiv before the first found paragraph firstProductParagraph.before(blogProductsDiv); // Remove the paragraphs containing ##PRODUKT## $("p").each(function () { let text = $(this).text(); if (/##PRODUKT##1/i.test(text)) { $(this).remove(); } }); } } async function fetchAndAppendBlogProducts2() { let productURLs = []; let firstProductParagraph = null; let maxNumberOfProducts = 4; $("#content p").each(function () { let text = $(this).text(); if (/##PRODUKT##2/i.test(text)) { if (!firstProductParagraph) { firstProductParagraph = $(this); } let urlMatch = text.match(/https?:\/\/[^\s]+/); if (urlMatch && productURLs.length < maxNumberOfProducts) { productURLs.push(urlMatch[0]); } } }); if (productURLs.length > 0 && firstProductParagraph) { let blogProductsDiv = $("

", { class: "blog-fetched-products" }); for (let url of productURLs) { try { const response = await fetch(url); const text = await response.text(); const parser = new DOMParser(); const doc = parser.parseFromString(text, "text/html"); const metaImage = doc.querySelector('meta[property="og:image"]'); const metaName = doc.querySelector('meta[itemprop="name"]'); if (metaImage && metaName) { // Create an anchor element let anchorElement = $("", { href: url, target: "_blank" }); // Create a paragraph element for the meta name content let productName = $("

").text(metaName.getAttribute("content")); // Create an img element let blogImage = $("", { src: metaImage.getAttribute("content"), alt: productName.text(), loading: "lazy", }); // Append the img element and the paragraph element to the anchor element anchorElement.append(blogImage); anchorElement.append(productName); /* const showBtn = document.createElement("div"); showBtn.classList.add("show-product-btn"); showBtn.textContent = "Zobrazit produkt"; anchorElement.append(showBtn); */ // Append the anchor element to the blogProductsDiv blogProductsDiv.append(anchorElement); } } catch (error) { console.error("Error fetching product data:", error); } } // Insert the blogProductsDiv before the first found paragraph firstProductParagraph.before(blogProductsDiv); // Remove the paragraphs containing ##PRODUKT## $("p").each(function () { let text = $(this).text(); if (/##PRODUKT##2/i.test(text)) { $(this).remove(); } }); } } async function fetchAndAppendBlogProducts3() { let productURLs = []; let firstProductParagraph = null; let maxNumberOfProducts = 4; $("#content p").each(function () { let text = $(this).text(); if (/##PRODUKT##3/i.test(text)) { if (!firstProductParagraph) { firstProductParagraph = $(this); } let urlMatch = text.match(/https?:\/\/[^\s]+/); if (urlMatch && productURLs.length < maxNumberOfProducts) { productURLs.push(urlMatch[0]); } } }); if (productURLs.length > 0 && firstProductParagraph) { let blogProductsDiv = $("

", { class: "blog-fetched-products" }); for (let url of productURLs) { try { const response = await fetch(url); const text = await response.text(); const parser = new DOMParser(); const doc = parser.parseFromString(text, "text/html"); const metaImage = doc.querySelector('meta[property="og:image"]'); const metaName = doc.querySelector('meta[itemprop="name"]'); if (metaImage && metaName) { // Create an anchor element let anchorElement = $("", { href: url, target: "_blank" }); // Create a paragraph element for the meta name content let productName = $("

").text(metaName.getAttribute("content")); // Create an img element let blogImage = $("", { src: metaImage.getAttribute("content"), alt: productName.text(), loading: "lazy", }); // Append the img element and the paragraph element to the anchor element anchorElement.append(blogImage); anchorElement.append(productName); /* const showBtn = document.createElement("div"); showBtn.classList.add("show-product-btn"); showBtn.textContent = "Zobrazit produkt"; anchorElement.append(showBtn); */ // Append the anchor element to the blogProductsDiv blogProductsDiv.append(anchorElement); } } catch (error) { console.error("Error fetching product data:", error); } } // Insert the blogProductsDiv before the first found paragraph firstProductParagraph.before(blogProductsDiv); // Remove the paragraphs containing ##PRODUKT## $("p").each(function () { let text = $(this).text(); if (/##PRODUKT##3/i.test(text)) { $(this).remove(); } }); } } fetchAndAppendBlogCategory(); async function fetchAndAppendBlogCategory() { let productRequests = []; let maxNumberOfProducts = 4; $("#content p").each(function () { let text = $(this).text(); if (/##KATEGORIE##/i.test(text)) { let match = text.match(/##KATEGORIE##(\d+)\s+(https?:\/\/[^\s]+)/); if (match) { let numberOfProducts = Math.min(parseInt(match[1], 10), maxNumberOfProducts); let url = match[2]; productRequests.push({ numberOfProducts, url, paragraph: $(this) }); } } }); if (productRequests.length > 0) { for (let request of productRequests) { let blogProductsDiv = $("

", { class: "blog-fetched-category" }); try { const response = await fetch(request.url); const text = await response.text(); const parser = new DOMParser(); const doc = parser.parseFromString(text, "text/html"); const products = doc.querySelectorAll("#products > .product"); for (let i = 0; i < request.numberOfProducts && i < products.length; i++) { let product = products[i].cloneNode(true); // Replace src with data-src for all img elements $(product) .find("img") .each(function () { let dataSrc = $(this).attr("data-src"); if (dataSrc) { $(this).attr("src", dataSrc); } }); $(product).find("a.image").append($(product).find(".p-in")); blogProductsDiv.append(product); } let showCategoryText = ""; if (document.body.classList.contains("cs")) { showCategoryText = "Zobrazit vše"; } if (document.body.classList.contains("sk")) { showCategoryText = "Zobraziť všetko"; } if (document.body.classList.contains("pl")) { showCategoryText = "Zobacz wszystko"; } // Create the show-all-blog-btn div with an anchor inside let showBlogButtonDiv = $("
", { class: "show-all-blog-btn" }).append( $("", { href: request.url, target: "_blank" }).text(showCategoryText), ); // Insert the blogProductsDiv before the paragraph containing ##KATEGORIE## request.paragraph.before(blogProductsDiv); // Insert the show-all-blog-btn div before the paragraph containing ##KATEGORIE## request.paragraph.before(showBlogButtonDiv); // Remove the paragraph containing ##KATEGORIE## request.paragraph.remove(); } catch (error) { console.error("Error fetching blog products:", error); } } } } }); } function inicializeSliderElement(sliderWrapper, sliderParent, sliderItem, customClass, itemForHeightForControls) { if (!sliderParent || !sliderItem || sliderItem.length === 0) { console.warn("inicializeSliderElement has been tried to be initialized with invalid parameters."); return; } if (!sliderWrapper) { const sliderWrapperElement = document.createElement("div"); sliderWrapperElement.classList.add("slider-custom-wrapper"); sliderParent.parentNode.insertBefore(sliderWrapperElement, sliderParent); sliderWrapperElement.appendChild(sliderParent); sliderWrapper = sliderWrapperElement; } sliderWrapper.classList.add(customClass, "slider-custom-wrapper"); createControls(); enableDragging(); function createControls() { let initialControls = sliderWrapper.querySelectorAll(".carousel-control"); if (initialControls && initialControls.length > 0) { initialControls.forEach((control) => control.remove()); } const leftControl = document.createElement("div"); leftControl.classList.add("carousel-control", "left", "hidden-control"); leftControl.setAttribute("role", "button"); leftControl.setAttribute("data-slide", "prev"); const rightControl = document.createElement("div"); rightControl.classList.add("carousel-control", "right"); rightControl.setAttribute("role", "button"); rightControl.setAttribute("data-slide", "next"); sliderWrapper.appendChild(leftControl); sliderWrapper.appendChild(rightControl); leftControl.addEventListener("click", () => slide("left")); rightControl.addEventListener("click", () => slide("right")); setTopPositionOfControls(); document.addEventListener("DOMContentLoaded", setTopPositionOfControls); window.addEventListener("resize", setTopPositionOfControls); function setTopPositionOfControls() { let heightItem; if (itemForHeightForControls) { heightItem = sliderItem[0].querySelector(itemForHeightForControls); } else { heightItem = sliderItem[0]; } if (heightItem) { const style = window.getComputedStyle(heightItem); const marginTop = parseFloat(style.marginTop) || 0; const marginBottom = parseFloat(style.marginBottom) || 0; const heightOfItem = heightItem.offsetHeight || 0; const totalHeight = heightOfItem + marginTop + marginBottom; leftControl.style.top = totalHeight / 2 + "px"; rightControl.style.top = totalHeight / 2 + "px"; if (totalHeight === 0) { leftControl.style.top = "50%"; rightControl.style.top = "50%"; } } else { leftControl.style.top = "50%"; rightControl.style.top = "50%"; } } //if sliderParent is not scrollable hide controls if (sliderParent.scrollWidth <= sliderParent.clientWidth) { leftControl.classList.add("hidden-control"); rightControl.classList.add("hidden-control"); } } function slide(direction) { if (sliderParent.classList.contains("sliding")) return; sliderParent.classList.add("sliding"); const numberOfItems = parseInt(getComputedStyle(sliderWrapper).getPropertyValue("--number-of-items")) || 1; const gapValue = parseInt(getComputedStyle(sliderParent).getPropertyValue("--gap")) || 0; const largeItemMultiplier = parseFloat(getComputedStyle(sliderWrapper).getPropertyValue("--width-multiplier-of-1st-item")) - 1 || 0; const nextItemPreview = parseInt(getComputedStyle(sliderWrapper).getPropertyValue("--next-item-preview")) || 0; let scrollAmount; /* if (sliderItem.length > 2) { scrollAmount = sliderItem[2]?.offsetWidth * numberOfItems + gapValue * (numberOfItems - largeItemMultiplier - 1) + nextItemPreview || 200; } else { scrollAmount = sliderItem[0]?.offsetWidth * numberOfItems + gapValue * (numberOfItems - largeItemMultiplier - 1) + nextItemPreview || 200; } */ scrollAmount = sliderParent.offsetWidth - (nextItemPreview - gapValue); const to = direction === "left" ? sliderParent.scrollLeft - scrollAmount : sliderParent.scrollLeft + scrollAmount; sliderParent.scrollTo({ left: to, behavior: "smooth" }); setTimeout(() => { sliderParent.classList.remove("sliding"); }, 300); } function enableDragging() { let isDragging = false; let startX = 0; let startScrollLeft = 0; let moved = false; let activePointerId = null; let moveThreshold = 5; // px // Start drag const onPointerDown = (e) => { // Only primary button if mouse if (e.pointerType === "mouse" && e.button !== 0) return; isDragging = true; moved = false; activePointerId = e.pointerId; startX = e.clientX; startScrollLeft = sliderParent.scrollLeft; sliderParent.classList.add("grabbing"); // Attach move/up/cancel to window for robust dragging window.addEventListener("pointermove", onPointerMove); window.addEventListener("pointerup", endDrag); window.addEventListener("pointercancel", endDrag); window.addEventListener("pointerleave", endDrag); }; // Drag move const onPointerMove = (e) => { if (!isDragging || e.pointerId !== activePointerId) return; const dx = e.clientX - startX; if (Math.abs(dx) > moveThreshold) moved = true; sliderParent.scrollLeft = startScrollLeft - dx; e.preventDefault(); }; // End/cancel drag const endDrag = (e) => { if (e && activePointerId !== null && e.pointerId !== activePointerId) return; isDragging = false; activePointerId = null; sliderParent.classList.remove("grabbing"); window.removeEventListener("pointermove", onPointerMove); window.removeEventListener("pointerup", endDrag); window.removeEventListener("pointercancel", endDrag); window.removeEventListener("pointerleave", endDrag); }; // Suppress clicks if a drag happened (avoids accidental link/card clicks) const onClick = (e) => { if (moved) { e.preventDefault(); e.stopPropagation(); moved = false; // reset } }; // Attach pointerdown to sliderWrapper so dragging works from wrapper or any child sliderWrapper.addEventListener("pointerdown", onPointerDown); sliderParent.addEventListener("click", onClick); function removeHiddenControl(element) { element.classList.remove("hidden-control"); } function addHiddenControl(element) { element.classList.add("hidden-control"); } let leftControl = sliderWrapper.querySelector(".carousel-control.left"); let rightControl = sliderWrapper.querySelector(".carousel-control.right"); if (leftControl && rightControl) { sliderParent.addEventListener("scroll", () => { if (sliderParent.scrollLeft <= 0) { addHiddenControl(leftControl); } else { removeHiddenControl(leftControl); } if (sliderParent.scrollLeft >= sliderParent.scrollWidth - sliderParent.clientWidth - 1) { addHiddenControl(rightControl); } else { removeHiddenControl(rightControl); } }); } } } function inicializeSliderElementSnap( sliderWrapper, sliderParent, sliderItem, customClass, itemForHeightForControls, scrollSnap, ) { if (!sliderParent || !sliderItem || sliderItem.length === 0) { console.warn("inicializeSliderElement has been tried to be initialized with invalid parameters."); return; } if (!sliderWrapper) { const sliderWrapperElement = document.createElement("div"); sliderWrapperElement.classList.add("slider-custom-wrapper"); sliderParent.parentNode.insertBefore(sliderWrapperElement, sliderParent); sliderWrapperElement.appendChild(sliderParent); sliderWrapper = sliderWrapperElement; } sliderWrapper.classList.add(customClass, "slider-custom-wrapper"); if (scrollSnap) { sliderParent.style.scrollSnapType = "x mandatory"; sliderItem.forEach((item) => { item.style.scrollSnapAlign = "start"; }); } createControls(); enableDragging(); function createControls() { let initialControls = sliderWrapper.querySelectorAll(".carousel-control"); if (initialControls && initialControls.length > 0) { initialControls.forEach((control) => control.remove()); } const leftControl = document.createElement("div"); leftControl.classList.add("carousel-control", "left", "hidden-control"); leftControl.setAttribute("role", "button"); leftControl.setAttribute("data-slide", "prev"); const rightControl = document.createElement("div"); rightControl.classList.add("carousel-control", "right"); rightControl.setAttribute("role", "button"); rightControl.setAttribute("data-slide", "next"); sliderWrapper.appendChild(leftControl); sliderWrapper.appendChild(rightControl); leftControl.addEventListener("click", () => slide("left")); rightControl.addEventListener("click", () => slide("right")); setTopPositionOfControls(); document.addEventListener("DOMContentLoaded", setTopPositionOfControls); window.addEventListener("resize", setTopPositionOfControls); function setTopPositionOfControls() { let heightItem; if (itemForHeightForControls) { heightItem = sliderItem[0].querySelector(itemForHeightForControls); } else { heightItem = sliderItem[0]; } if (heightItem) { const style = window.getComputedStyle(heightItem); const marginTop = parseFloat(style.marginTop) || 0; const marginBottom = parseFloat(style.marginBottom) || 0; const heightOfItem = heightItem.offsetHeight || 0; const totalHeight = heightOfItem + marginTop + marginBottom; leftControl.style.top = totalHeight / 2 + "px"; rightControl.style.top = totalHeight / 2 + "px"; if (totalHeight === 0) { leftControl.style.top = "50%"; rightControl.style.top = "50%"; } } else { leftControl.style.top = "50%"; rightControl.style.top = "50%"; } } console.log(sliderParent.scrollWidth, sliderParent.clientWidth); console.log("----------------------------------------------------------"); //if sliderParent is not scrollable hide controls if (sliderParent.scrollWidth <= sliderParent.clientWidth) { leftControl.classList.add("hidden-control"); rightControl.classList.add("hidden-control"); } } function slide(direction) { if (sliderParent.classList.contains("sliding")) return; sliderParent.classList.add("sliding"); const numberOfItems = parseInt(getComputedStyle(sliderWrapper).getPropertyValue("--number-of-items")) || 1; const gapValue = parseInt(getComputedStyle(sliderParent).getPropertyValue("--gap")) || 0; const largeItemMultiplier = parseFloat(getComputedStyle(sliderWrapper).getPropertyValue("--width-multiplier-of-1st-item")) - 1 || 0; const nextItemPreview = parseInt(getComputedStyle(sliderWrapper).getPropertyValue("--next-item-preview")) || 0; let scrollAmount; /* if (sliderItem.length > 2) { scrollAmount = sliderItem[2]?.offsetWidth * numberOfItems + gapValue * (numberOfItems - largeItemMultiplier - 1) + nextItemPreview || 200; } else { scrollAmount = sliderItem[0]?.offsetWidth * numberOfItems + gapValue * (numberOfItems - largeItemMultiplier - 1) + nextItemPreview || 200; } */ scrollAmount = sliderParent.offsetWidth - (nextItemPreview - gapValue); const to = direction === "left" ? sliderParent.scrollLeft - scrollAmount : sliderParent.scrollLeft + scrollAmount; sliderParent.scrollTo({ left: to, behavior: "smooth" }); setTimeout(() => { sliderParent.classList.remove("sliding"); }, 300); } function enableDragging() { let isDragging = false; let startX = 0; let startScrollLeft = 0; let moved = false; let activePointerId = null; let moveThreshold = 5; // px let scrollThreshold = 70; // px for snap // Start drag const onPointerDown = (e) => { // Only primary button if mouse if (e.pointerType === "mouse" && e.button !== 0) return; isDragging = true; moved = false; activePointerId = e.pointerId; startX = e.clientX; startScrollLeft = sliderParent.scrollLeft; sliderParent.classList.add("grabbing"); // Attach move/up/cancel to window for robust dragging window.addEventListener("pointermove", onPointerMove); window.addEventListener("pointerup", endDrag); window.addEventListener("pointercancel", endDrag); window.addEventListener("pointerleave", endDrag); }; // Drag move const onPointerMove = (e) => { if (!isDragging || e.pointerId !== activePointerId) return; const dx = e.clientX - startX; if (Math.abs(dx) > scrollThreshold) { moved = true; let plusOrMinus = dx > 0 ? -1 : 1; let itemWidth; if (itemForHeightForControls) { itemWidth = sliderItem[0].querySelector(itemForHeightForControls).offsetWidth; } else { itemWidth = sliderItem[0].offsetWidth; } sliderParent.scrollTo({ left: startScrollLeft + itemWidth * plusOrMinus, behavior: "smooth" }); } /* sliderParent.scrollLeft = startScrollLeft - dx; */ //toto je jiné e.preventDefault(); }; // End/cancel drag const endDrag = (e) => { if (e && activePointerId !== null && e.pointerId !== activePointerId) return; isDragging = false; activePointerId = null; sliderParent.classList.remove("grabbing"); window.removeEventListener("pointermove", onPointerMove); window.removeEventListener("pointerup", endDrag); window.removeEventListener("pointercancel", endDrag); window.removeEventListener("pointerleave", endDrag); }; // Suppress clicks if a drag happened (avoids accidental link/card clicks) const onClick = (e) => { if (moved) { e.preventDefault(); e.stopPropagation(); moved = false; // reset } }; // Attach pointerdown to sliderWrapper so dragging works from wrapper or any child sliderWrapper.addEventListener("pointerdown", onPointerDown); sliderParent.addEventListener("click", onClick); function removeHiddenControl(element) { element.classList.remove("hidden-control"); } function addHiddenControl(element) { element.classList.add("hidden-control"); } let leftControl = sliderWrapper.querySelector(".carousel-control.left"); let rightControl = sliderWrapper.querySelector(".carousel-control.right"); if (leftControl && rightControl) { sliderParent.addEventListener("scroll", () => { if (sliderParent.scrollLeft <= 0) { addHiddenControl(leftControl); } else { removeHiddenControl(leftControl); } if (sliderParent.scrollLeft >= sliderParent.scrollWidth - sliderParent.clientWidth - 1) { addHiddenControl(rightControl); } else { removeHiddenControl(rightControl); } }); } } } if (plLang || skLang) { if ( document.body.classList.contains("type-category") || document.body.classList.contains("type-manufacturer-detail") || document.body.classList.contains("type-page") ) { let h1 = $("h1").first(); let title = document.title; // If the first h1 isn't equal to the page title, if (h1.text() !== title) { // Change h1 to page title but remove " - Natima" or " | Natima" if it's in there title = title.replace(/ - Natima| - natima| \| Natima| \| natima/g, ""); h1.text(title); } } } document.addEventListener("dkLabFavouriteProductsLoaded", function () { let headerFavoritesIcon = document.querySelector("#dkLabFavHeaderWrapper"); let topNavTools = document.querySelector(".top-navigation-tools"); let headerTopElement = document.querySelector("#header .header-top"); if (headerFavoritesIcon && topNavTools && headerTopElement) { if (!isMobile) { topNavTools.prepend(headerFavoritesIcon); } else { headerTopElement.appendChild(headerFavoritesIcon); } } document.addEventListener("debouncedResize", function () { if (headerFavoritesIcon && topNavTools && headerTopElement) { if (!isMobile) { topNavTools.prepend(headerFavoritesIcon); } else { headerTopElement.appendChild(headerFavoritesIcon); } } }); if (document.body.classList.contains("type-product")) { let favoriteDiv = document.querySelector("#dkLabFavouriteDiv"); let pImage = document.querySelector(".p-image"); if (favoriteDiv && pImage) { pImage.appendChild(favoriteDiv); } } }); document.addEventListener("DOMContentLoaded", function () { // Fix for Solgar product pages if (document.body.classList.contains("type-product")) { fixSolgar(); } goToTopBtn(); }); function fixSolgar() { const any = document.querySelectorAll(".rc-parameter__header-right"); if (any.length === 0) return; const nodes = document.querySelectorAll( "#pobo-all-content .widget-projector .rc-parameter-small-left__box .rc-parameter__header-right", ); if (nodes.length === 0) return; nodes.forEach((el) => { el.parentElement.parentElement.classList.add("fixBullets"); let text = el.innerHTML; const characters = Array.from(text); let whichHashtag = 0; for (let i = 0; i < characters.length; i++) { if (characters[i] === "#") { characters[i] = whichHashtag % 2 === 0 ? "" : ""; whichHashtag++; } else if (characters[i] === "$") { characters[i] = "
"; } } const newHtml = characters.join(""); const p = document.createElement("p"); p.className = "rc-parameter__header-right"; const span = document.createElement("span"); span.innerHTML = newHtml; p.appendChild(span); el.replaceWith(p); }); } function goToTopBtn() { const goToTopBtnElement = document.querySelector(".goToTop__button"); if (!goToTopBtnElement) return; goToTopBtnElement.addEventListener("click", (event) => { event.preventDefault(); window.scrollTo({ top: 0, behavior: "smooth", }); }); } function deliveryAndPaymentPage() { let deliveriesAndPaymentsBlock = document.querySelector(".page-deliveries-and-payments"); if (!deliveriesAndPaymentsBlock) return; let itemsToToggle = deliveriesAndPaymentsBlock.querySelectorAll(".item"); if (!itemsToToggle || itemsToToggle.length === 0) return; itemsToToggle.forEach((item) => { expandedToggle(item); }); } document.addEventListener("DOMContentLoaded", function () { deliveryAndPaymentPage(); }); function expandedToggle(item) { item.addEventListener("click", function () { item.classList.toggle("expanded"); }); } /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ window.NAT = window.NAT || {}; window.NAT.lang = window.NAT.lang || document.documentElement.lang || "cs"; window.NAT.translations = function (key) { const entry = translationsStrings[key]; if (!entry) { console.warn(`[NAT.translations] missing translation key: "${key}"`); return key; } return entry[window.NAT.lang] ?? entry.cs ?? key; }; window.NAT.raventic = window.NAT.raventic || { cs: { apiKey: "euc28f5007d854bb5b8b89120288e45", bestsellersApiKey: "euc28f5007d854bb5b8b89120288e45", locale: "cs-CZ", currency: "CZK", priceDecimals: 0, /* apiKey: "euca0e3736860cd1072be643e4e32e5", bestsellersApiKey: "euca0e3736860cd1072be643e4e32e5", locale: "sk-SK", currency: "EUR", priceDecimals: 2, */ /* apiKey: "euc8c5f31012cea7c050d4b3c2d0467", bestsellersApiKey: "euc8c5f31012cea7c050d4b3c2d0467", locale: "pl-PL", currency: "PLN", priceDecimals: 2, */ // Dropdown: where Enter / the "show all" button submits the query. submitUrl: "https://www.natima.cz/vyhledavani/", // Results: substring the page URL must contain for the results widget to run. resultsUrlMatch: "www.natima.cz/vyhledavani", /* submitUrl: "https://696098.myshoptet.com/vyhledavani/", resultsUrlMatch: "696098.myshoptet.com/vyhledavani", */ }, sk: { apiKey: "euca0e3736860cd1072be643e4e32e5", bestsellersApiKey: "euca0e3736860cd1072be643e4e32e5", locale: "sk-SK", currency: "EUR", priceDecimals: 2, submitUrl: "https://www.natima.sk/vyhladavanie/", resultsUrlMatch: "www.natima.sk/vyhladavanie", }, pl: { apiKey: "euc8c5f31012cea7c050d4b3c2d0467", bestsellersApiKey: "euc8c5f31012cea7c050d4b3c2d0467", locale: "pl-PL", currency: "PLN", priceDecimals: 2, submitUrl: "https://www.natima.pl/wyszukiwanie/", resultsUrlMatch: "www.natima.pl/wyszukiwanie", }, }; window.NAT.utils = window.NAT.utils || {}; window.NAT.utils.goTopBtn = function () { const goTopBtn = document.querySelector(".goToTop__button"); if (!goTopBtn) return; goTopBtn.addEventListener("click", (e) => { e.preventDefault(); window.scrollTo({ top: 0, behavior: "smooth", }); }); }; window.NAT = window.NAT || {}; const mediaSizesNew = { desktop: 1280, smallTabletMax: 1023, tablet: 768, }; window.NAT.media = { // Raw breakpoints, in case a caller wants the numbers. sizes: mediaSizesNew, get isMobile() { return window.innerWidth < mediaSizesNew.tablet; }, get isTablet() { return window.innerWidth >= mediaSizesNew.tablet && window.innerWidth < mediaSizesNew.desktop; }, get isDesktop() { return window.innerWidth >= mediaSizesNew.desktop; }, get isSmallTablet() { return window.innerWidth <= mediaSizesNew.smallTabletMax; }, }; /* document.addEventListener("DOMContentLoaded", () => { window.NAT.utils.goTopBtn(); }); document.addEventListener("ShoptetDOMContentLoaded", () => { window.NAT.utils.goTopBtn(); }); */ //RAVENTIC SETUP DROPDOWN // 2_components/search_raventic_dropdown_setup_new.js // Vendor Raventic search-DROPDOWN integration (test eshop only), v4 SDK: defines // window.RaventicSearchDropdownConfig and runs Raventic's loader snippet, which // injects the v4 dropdown SDK. The minified loader IIFE is vendor code, left untouched. raventicSetupDropdown(); function raventicSetupDropdown() { /* if (!document.body.classList.contains("is-test-eshop")) return; */ window.RaventicSearchDropdownConfig = { elementSelectors: ["#formSearchForm input[type='search']"], config: { locale: window.NAT.raventic[window.NAT.lang].locale, apiKey: window.NAT.raventic[window.NAT.lang].apiKey, bestsellersApiKey: window.NAT.raventic[window.NAT.lang].bestsellersApiKey, currency: window.NAT.raventic[window.NAT.lang].currency, priceDecimals: window.NAT.raventic[window.NAT.lang].priceDecimals, welcomeMessage: window.NAT.translations("raventicWelcome"), recommendedProductsTitle: window.NAT.translations("raventicRecommendedProducts"), foundProductsTitle: window.NAT.translations("raventicFoundProducts"), foundProductsTitleShort: window.NAT.translations("raventicFoundProducts"), noResultsFoundMessage: window.NAT.translations("raventicNoResults"), searchingForMessage: window.NAT.translations("raventicSearchingFor"), wouldYouLikeToSearchForMessage: window.NAT.translations("raventicWouldYouSearchFor"), analyticsEventsTarget: "dataLayer", zIndex: 9999, queryParameterName: "string", buttonTypeParameterName: "button-type", buttonLabelParameterName: "button-text", buttonStyleParameterName: "button-style", defaultButtonLabel: window.NAT.translations("raventicAddToCart"), cartConfig: { type: "NoActionCart", }, submitUrl: window.NAT.raventic[window.NAT.lang].submitUrl, disableDefaultStyles: true, doNotCropImages: true, customStyles: ``, customPageStyles: ``, priceParameterName: "_price", salePriceParameterName: "_sale-price", individualParameters: [ { parameterName: "SHORT_DESCRIPTION", title: window.NAT.translations("raventicParamDescription"), }, /* { parameterName: "RATING_AVG", title: "Hodnocení", }, { parameterName: "RATING_TOTAL", title: "Počet recenzí", }, */ /* { parameterName: "IMGURL_ALTERNATIVE", title: "Alternativní obrázek", }, */ /* { parameterName: "STOCK_AMOUNT", title: "Skladem", }, */ ], showAllMessage: window.NAT.translations("raventicShowAll"), content: [ { type: "categories_feed", title: window.NAT.translations("raventicCategoriesTitle"), }, { type: "brands", title: window.NAT.translations("raventicBrandsTitle"), }, { type: "articles", title: window.NAT.translations("raventicArticlesTitle"), }, ], }, onOpen: handleOpen, onProductClick: handleProductClickDropdown, resultHandler: handleResultDropdown, onClose: handleClose, runABTest: false, }; // Vendor Raventic v4 loader — reads window.RaventicSearchDropdownConfig, wires the // click-capture machinery, and injects .../semsearch/v4/dropdown.min.js. Left // exactly as provided by Raventic. !(function () { const e = window.RaventicSearchDropdownConfig; if (!e) return void console.error( "RaventicSearchDropdownConfig is not defined. Please set window.RaventicSearchDropdownConfig before loading this script.", ); const { elementSelectors: t, config: n, onOpen: o, onProductClick: r, errorHandler: a, resultHandler: c, eventPusher: i, onClose: s, onContentClick: d, runABTest: l, } = e; if (l) { const e = "search_dropdown", t = "RaventicSearchIntegrationTest"; void 0 === window.dataLayer && (window.dataLayer = []); const n = "_rvn_ab", o = "0", r = "1"; let a = null; try { a = window.localStorage.getItem(n); } catch { a = document.cookie .split("; ") .find((e) => e.startsWith(n + "=")) ?.split("=")[1]; } variant = a === o || a === r ? a : Math.random() < 0.5 ? o : r; try { window.localStorage.setItem(n, variant); } catch {} if ( ((document.cookie = `${n}=${variant}; domain=${location.hostname}; path=/; max-age=${365 * 86400}; sameSite=Lax`), t && window.dataLayer.push({ event: t, raventic: { search: {}, raventic_variant: variant, raventic_widget: e } }), variant === o) ) return; } const u = { mousedown: !0, mouseup: !1, click: !1, touchstart: !0, touchend: !1 }, f = { click: !0 }, v = (e) => { (e.preventDefault(), e.stopImmediatePropagation(), e.stopPropagation()); }, w = new Set(), m = new Map(), p = (e, t) => { const n = t instanceof HTMLInputElement ? t : null, o = (t) => { (v(t), w.add(e)); }; m.set(e, () => { for (const [e, r] of Object.entries(n ? u : f)) t.removeEventListener(e, r ? o : v, !0); }); for (const [e, r] of Object.entries(n ? u : f)) t.addEventListener(e, r ? o : v, !0); }; let h = !1; const g = Array.isArray(t) ? t : [t]; for (const e of g) { const t = document.querySelector(e); t ? p(e, t) : document.addEventListener("DOMContentLoaded", () => { if (h) return; const t = document.querySelector(e); t && p(e, t); }); } window.raventicDropDownReady = function (e) { if (h) return; for (const [, e] of m) e(); h = !0; const t = e(g, n, o, r, a, c, i, s, d); for (let e = 0; e < t.length; e++) { const n = t[e]; w.has(g[e]) && n.open(); } }; const S = document.createElement("script"); ((S.defer = !0), (S.src = "https://sdk.rvndn.com/semsearch/v4/dropdown.min.js"), document.head.appendChild(S)); })(); } function handleOpen(instanceId) { document.body.classList.add("raventic-search-dropdown-open"); document.body.classList.add("custom-search-active"); addDropdownControls(); } // The SDK renders no close/clear controls on our custom-styled panel, so add our own // .close-raventic and .clear-raventic buttons into the dropdown body. Runs on the next // frame because the body may not be in the DOM yet at on-open time; idempotent so // re-opens don't stack buttons. function addDropdownControls() { requestAnimationFrame(() => { const dropdownBody = document.querySelector(".raventic-search-dropdown-body"); if (!dropdownBody) return; if (!dropdownBody.querySelector(".close-raventic")) { const closeButton = document.createElement("div"); closeButton.className = "close-raventic"; closeButton.setAttribute("role", "button"); closeButton.setAttribute("tabindex", "0"); closeButton.setAttribute("aria-label", window.NAT.translations("raventicCloseLabel")); closeButton.addEventListener("click", closeRaventicDropdown); dropdownBody.appendChild(closeButton); } const searchFormFieldset = document.querySelector("#formSearchForm fieldset"); if (!searchFormFieldset.querySelector(".clear-raventic")) { const clearButton = document.createElement("div"); clearButton.className = "clear-raventic"; clearButton.setAttribute("role", "button"); clearButton.setAttribute("tabindex", "0"); clearButton.setAttribute("aria-label", window.NAT.translations("raventicClearLabel")); clearButton.addEventListener("click", clearRaventicSearch); searchFormFieldset.appendChild(clearButton); } }); } // The native search "×" can't clear the field (the vendor loader preventDefault()s // pointer events on the input), so clear it ourselves and fire an input event so the // widget re-queries. Selector comes from the config to stay in sync with the widget. function clearRaventicSearch() { const selectors = window.RaventicSearchDropdownConfig?.elementSelectors; const selector = Array.isArray(selectors) ? selectors[0] : selectors; const input = selector ? document.querySelector(selector) : null; if (!input) return; // The widget is React-based: assigning input.value directly bypasses React's internal // value tracker, so its onChange never fires and the results don't reset. Clear via the // native value setter, then dispatch the events so React (and any plain listeners) pick // up the empty query and re-render. change/keyup cover non-React or keystroke-debounced // listeners too. const nativeValueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set; if (nativeValueSetter) { nativeValueSetter.call(input, ""); } else { input.value = ""; } input.dispatchEvent(new Event("input", { bubbles: true })); input.dispatchEvent(new Event("change", { bubbles: true })); input.dispatchEvent(new KeyboardEvent("keyup", { bubbles: true })); body.classList.add("custom-search-active"); input.classList.add("active"); setTimeout(() => { input.click(); input.focus(); body.classList.add("custom-search-active"); input.classList.add("active"); }, 10); } // We can't reach the widget instance's close() (it lives in the vendor loader closure), // so close the way a user would: a pointer event outside the panel (this widget is // mousedown/touch driven) plus Escape as a fallback. Closing an already-closed widget // is a no-op, so firing both is safe. function closeRaventicDropdown() { if (window.NAT.media.isMobile) { const mobileSearchButton = document.querySelector("#header .search-form"); if (mobileSearchButton) { mobileSearchButton.click(); } } else { document.body.click(); } } function handleProductClickDropdown(product, instanceId, action, source) { if (action === "add-to-cart") { shoptet.cartShared.addToCart({ productCode: product.id }); } } function handleResultDropdown(result, error, reference, instanceId) { if (result && !error) { document.dispatchEvent(new CustomEvent("RAVENTIC SEARCH RESULTS DROPDOWN LOADED")); console.log( "%c CUSTOM EVENT DISPATCHED: RAVENTIC SEARCH RESULTS DROPDOWN LOADED", "background: lime; color: black; padding: 5px 10px; font-weight: bold;", ); } } function handleClose(instanceId) { document.body.classList.remove("raventic-search-dropdown-open"); document.body.classList.remove("custom-search-active"); } /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ //RAVENTIC SETUP RESULTS // 2_components/search_raventic_results_setup_new.js // Vendor Raventic search-RESULTS integration (test eshop only), v4 SDK: defines // window.RaventicSearchResultsConfig and runs Raventic's loader snippet, which // injects the v4 results SDK. The minified loader IIFE is vendor code, left untouched. raventicSetupResults(); function raventicSetupResults() { /* if (!document.body.classList.contains("is-test-eshop")) return; */ if (!location.href.includes(window.NAT.raventic[window.NAT.lang].resultsUrlMatch)) return; window.RaventicSearchResultsConfig = { elementSelector: "#content", config: { locale: window.NAT.raventic[window.NAT.lang].locale, apiKey: window.NAT.raventic[window.NAT.lang].apiKey, currency: window.NAT.raventic[window.NAT.lang].currency, priceDecimals: window.NAT.raventic[window.NAT.lang].priceDecimals, noResultsFoundMessage: window.NAT.translations("raventicNoResults"), queryParameterName: "string", pageSize: 20, title: window.NAT.translations("raventicResultsTitle"), noQueryTitle: window.NAT.translations("raventicNoQueryTitle"), categoriesTitle: window.NAT.translations("raventicCategoriesTitle"), manufacturersTitle: window.NAT.translations("raventicManufacturersTitle"), /* showManufacturers: true, */ showManufacturers: false, analyticsEventsTarget: "dataLayer", priceTitle: window.NAT.translations("raventicPriceTitle"), disableDefaultStyles: true, doNotCropImages: true /*true*/, filtersTitle: window.NAT.translations("raventicFiltersTitle"), filterButtonTitle: window.NAT.translations("raventicFilterButton"), clearAllFiltersTitle: window.NAT.translations("raventicClearAllFilters"), buttonTypeParameterName: "button-type", buttonLabelParameterName: "button-text", buttonStyleParameterName: "button-style", priceParameterName: "_price", salePriceParameterName: "_sale-price", individualParameters: [ { parameterName: "SHORT_DESCRIPTION", title: window.NAT.translations("raventicParamDescription"), }, { parameterName: "RATING_AVG", title: window.NAT.translations("raventicParamRating"), }, { parameterName: "RATING_TOTAL", title: window.NAT.translations("raventicParamReviewCount"), }, { parameterName: "IMGURL_ALTERNATIVE", title: window.NAT.translations("raventicParamAltImage"), }, { parameterName: "STOCK_AMOUNT", title: window.NAT.translations("raventicParamStock"), }, ], promoContent: [ { title: window.NAT.translations("raventicCategoriesTitle"), // titulek bloku identifier: "categories_feed", maxCount: 8, }, { title: window.NAT.translations("raventicArticlesTitle"), // titulek tabu pro výsledky článků identifier: "articles", maxCount: 3, // maximální počet výsledků na stránku }, ], /* additionalContent: [ { title: "Články", // titulek tabu pro výsledky článků identifier: "articles", maxCount: 10, // maximální počet výsledků na stránku }, ], */ customStyles: ``, customPageStyles: ``, desktopMode: "left", defaultButtonLabel: window.NAT.translations("raventicAddToCart"), cartConfig: { type: "NoActionCart", }, }, onProductClick: handleProductClick, resultHandler: handleResult, runABTest: false, }; // Vendor Raventic v4 loader — reads window.RaventicSearchResultsConfig and injects // .../semsearch/v4/results.min.js. Left exactly as provided by Raventic. !(function () { const e = window.RaventicSearchResultsConfig; if (!e) return void console.error( "RaventicSearchResultsConfig is not defined. Please set window.RaventicSearchResultsConfig before loading this script.", ); const { elementSelector: t, config: n, onOpen: a, onProductClick: i, errorHandler: r, resultHandler: o, eventPusher: c, runABTest: s, } = e; if (s) { const e = "search_dropdown", t = "RaventicSearchIntegrationTest"; void 0 === window.dataLayer && (window.dataLayer = []); const n = "_rvn_ab", a = "0", i = "1"; let r = null; try { r = window.localStorage.getItem(n); } catch { r = document.cookie .split("; ") .find((e) => e.startsWith(n + "=")) ?.split("=")[1]; } variant = r === a || r === i ? r : Math.random() < 0.5 ? a : i; try { window.localStorage.setItem(n, variant); } catch {} if ( ((document.cookie = `${n}=${variant}; domain=${location.hostname}; path=/; max-age=${365 * 86400}; sameSite=Lax`), t && window.dataLayer.push({ event: t, raventic: { search: {}, raventic_variant: variant, raventic_widget: e } }), variant === a) ) return; } let d = !1; window.raventicResultsReady = function (e) { d || ((d = !0), e(t, n, a, i, r, o, c)); }; const l = document.createElement("script"); ((l.src = "https://sdk.rvndn.com/semsearch/v4/results.min.js"), document.head.appendChild(l)); })(); } function handleProductClick(product, instanceId, action) { if (action === "add-to-cart") { shoptet.cartShared.addToCart({ productCode: product.id }); } } function handleResult(result, error, reference, instanceId) { if (error) { console.error("Raventic API error:", error); return; } window.raventicResult = result; document.dispatchEvent(new CustomEvent("RAVENTIC SEARCH RESULTS LOADED")); console.log( "%c CUSTOM EVENT DISPATCHED: RAVENTIC SEARCH RESULTS LOADED", "background: lime; color: black; padding: 5px 10px; font-weight: bold;", ); } /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------------*/ //RAVENTIC PAGE RESULTS // 3_pages/search_raventic_results.js // Raventic search results page (test eshop only): transforms Raventic's product // list into Shoptet-style product cards (rating, stock, price, add-to-cart), // re-transforming via a MutationObserver, and adds a go-to-top button, filter // heading, per-identifier classes on the promo-content blocks, and header-menu // icons on the promo category links. searchRaventicResults(); function searchRaventicResults() { /* if (!document.body.classList.contains("is-test-eshop")) return; */ document.addEventListener( "RAVENTIC SEARCH RESULTS LOADED", () => { editRaventicSearchResults(); }, { once: true }, ); document.addEventListener("RAVENTIC SEARCH RESULTS TRANSFORMED", () => { document.body.classList.add("raventic-search-results-transformed"); addGoToTopButton(); addFilterHeading(); addPromoContentClasses(); removeUnwantedFilters(); }); function editRaventicSearchResults() { const RV_LIST_SELECTOR = ".raventic-search-results-products-list"; const TRANSFORMED_FLAG = "shoptetTransformed"; function escapeHtml(s) { return String(s).replace( /[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'", })[c], ); } function getParamValue(product, name) { const el = product.querySelector(`[data-raventic-parameter="${name}"] [data-raventic-parameter-value]`); return el ? el.getAttribute("data-raventic-parameter-value") : null; } function getParamText(product, name) { const wrap = product.querySelector(`[data-raventic-parameter="${name}"]`); if (!wrap) return null; const inner = wrap.querySelector("span[title] span[title]") || wrap.querySelector("span[title]"); return inner ? inner.textContent.trim() : null; } function buildStars(avg) { const v = parseFloat(avg); if (isNaN(v)) return ""; const rounded = Math.round(v * 2) / 2; let html = ''; for (let i = 1; i <= 5; i++) { if (rounded >= i) html += ''; else if (rounded >= i - 0.5) html += ''; else html += ''; } return html + ""; } function relativizeHref(href) { if (!href) return "#"; return href.replace(/^https?:\/\/[^/]+/, "") || "#"; } function findProductByHref(href) { const products = window.raventicResult?.products; if (!Array.isArray(products)) return null; const target = relativizeHref(href).replace(/\/$/, ""); return ( products.find((p) => { if (!p?.url) return false; const candidate = relativizeHref(p.url).replace(/\/$/, ""); return candidate === target; }) || null ); } function buildProductCard(rvProduct) { const href = relativizeHref(rvProduct.getAttribute("href")); const apiProduct = findProductByHref(href); const productId = apiProduct?.id || ""; const name = (rvProduct.querySelector(".raventic-product-name")?.textContent || "").trim(); const imgEl = rvProduct.querySelector(".raventic-product-image img"); const imgSrc = imgEl?.getAttribute("src") || ""; const imgAlt = imgEl?.getAttribute("alt") || name; const altImg = (getParamValue(rvProduct, "imgurl_alternative") || "").replace("/orig/", "/detail/"); const ratingAvg = getParamValue(rvProduct, "rating_avg"); const ratingTotal = getParamValue(rvProduct, "rating_total"); const stockAmount = getParamValue(rvProduct, "stock_amount"); const description = getParamText(rvProduct, "short_description"); const price = (rvProduct.querySelector(".raventic-product-price-value")?.textContent || "").trim(); const priceBefore = (rvProduct.querySelector(".raventic-product-price-before")?.textContent || "").trim(); const cartBtn = rvProduct.querySelector(".raventic-product-button-cart"); const priceNum = parseFloat(price.replace(/[^\d.,]/g, "").replace(",", ".")); const priceBeforeNum = parseFloat(priceBefore.replace(/[^\d.,]/g, "").replace(",", ".")); const hasDiscount = priceBefore && !isNaN(priceNum) && !isNaN(priceBeforeNum) && priceBeforeNum > priceNum; const discountPercent = hasDiscount ? Math.round((1 - priceNum / priceBeforeNum) * 100) : 0; const parts = []; parts.push('
'); parts.push(``); if (hasDiscount) { parts.push( `
–${discountPercent} %
`, ); } if (imgSrc) { /* const next = altImg ? ` data-next="${escapeHtml(altImg)}"` : ""; */ parts.push( /* `${escapeHtml(imgAlt)}`, */ `${escapeHtml(imgAlt)}`, ); } parts.push("
"); parts.push('
'); if (name) { parts.push( `${escapeHtml(name)}`, ); } const hasRating = ratingAvg != null; const hasStock = stockAmount != null; const stockNum = hasStock ? parseInt(stockAmount, 10) : NaN; const isUnavailable = hasStock && (isNaN(stockNum) || stockNum <= 0); if (hasRating || hasStock) { parts.push('
'); if (hasRating) { const cnt = ratingTotal != null ? ` data-micro-rating-count="${escapeHtml(ratingTotal)}"` : ""; parts.push( `
${buildStars(ratingAvg)}
`, ); } if (hasStock) { if (isUnavailable) { parts.push( `
${window.NAT.translations("nedostupne")}
`, ); } else { const stockText = stockNum >= 10 ? "(>10 ks)" : `(${stockNum} ks)`; parts.push( `
${window.NAT.translations("skladem")} ${stockText}
`, ); } } parts.push("
"); } parts.push("
"); parts.push('
'); if (price) { const standard = hasDiscount ? `${escapeHtml(priceBefore)}` : ""; parts.push( `
${escapeHtml(price)}${standard}
`, ); } if (cartBtn) { parts.push( `
`, ); } if (description) { parts.push(`

${escapeHtml(description)}

`); } parts.push("
"); parts.push("
"); if (productId) { parts.push(`Kód: ${escapeHtml(productId)}`); } parts.push("
"); const wrapper = document.createElement("div"); wrapper.className = isUnavailable ? "product unavailable" : "product"; wrapper.innerHTML = parts.join(""); if (cartBtn) { const newBtn = wrapper.querySelector(".add-to-cart-button"); newBtn?.addEventListener("click", (e) => { e.preventDefault(); cartBtn.click(); }); } return wrapper; } function findExistingTransformed(list) { const sibling = list.nextElementSibling; if (sibling?.id === "products" && sibling.classList.contains("products-block")) return sibling; return null; } function transformResults() { const list = document.querySelector(RV_LIST_SELECTOR); if (!list) return; const items = list.querySelectorAll(".raventic-product"); if (!items.length) return; if (list.dataset[TRANSFORMED_FLAG] === "true" && findExistingTransformed(list)) return; findExistingTransformed(list)?.remove(); const container = document.createElement("div"); container.id = "products"; container.className = "products products-page products-block"; container.setAttribute("data-testid", "productCards"); items.forEach((rv) => container.appendChild(buildProductCard(rv))); list.style.display = "none"; list.dataset[TRANSFORMED_FLAG] = "true"; list.parentNode.insertBefore(container, list.nextSibling); console.log( "%c CUSTOM EVENT DISPATCHED: RAVENTIC SEARCH RESULTS TRANSFORMED ", "background: lime; color: black; padding: 5px 10px; font-weight: bold;", ); document.dispatchEvent(new CustomEvent("RAVENTIC SEARCH RESULTS TRANSFORMED")); } document.addEventListener("RAVENTIC SEARCH RESULTS LOADED", () => { observer.disconnect(); const list = document.querySelector(RV_LIST_SELECTOR); if (list) { findExistingTransformed(list)?.remove(); delete list.dataset[TRANSFORMED_FLAG]; } observer.observe(document.body, { childList: true, subtree: true }); }); transformResults(); const observer = new MutationObserver(() => { const list = document.querySelector(RV_LIST_SELECTOR); if (!list) return; if (list.dataset[TRANSFORMED_FLAG] === "true") return; if (list.querySelector(".raventic-product")) transformResults(); }); observer.observe(document.body, { childList: true, subtree: true }); } function addGoToTopButton() { const previousBtn = document.querySelector(".goToTop"); if (previousBtn) { return; } const paginator = document.querySelector(".raventic-search-results-paginator"); if (!paginator) return; const raventicHeading = document.querySelector(".raventic-search-results-container"); if (!raventicHeading) { return; } raventicHeading.id = "productsListHeading"; const goToTop = document.createElement("div"); goToTop.className = "goToTop"; goToTop.innerHTML = '' + window.NAT.translations("nahoru") + ""; paginator.prepend(goToTop); window.NAT.utils.goTopBtn(); } // The v4 SDK renders every enum filter group with the same generic class, so the // only reliable way to target a specific group is by its

title text. Kategorie // also has a dedicated class, but matching by title keeps all removals consistent. function removeUnwantedFilters() { const unwantedTitles = [ "Kategorie", "Množství", "Denní dávka", "Kategórie", "Vstřebatelnost", "Objem", "Množstvo", "Denná dávka", "Vstrebateľnosť", "Ilość", "Dzienna dawka", "Pojemność", ]; const filters = document.querySelectorAll(".raventic-search-results-filters-filter"); filters.forEach((filter) => { const title = filter.querySelector("h3 span")?.textContent.trim(); if (title && unwantedTitles.includes(title)) filter.remove(); }); } function addFilterHeading() { const raventicSelectedFiltersWrapper = document.querySelector(".raventic-search-results-filter-selection"); if (!raventicSelectedFiltersWrapper) return; const existingHeading = raventicSelectedFiltersWrapper.querySelector(".selected-filters-heading"); if (existingHeading) return; const selectedFiltersHeading = document.createElement("div"); selectedFiltersHeading.className = "selected-filters-heading"; selectedFiltersHeading.textContent = window.NAT.translations("selectedFilters"); raventicSelectedFiltersWrapper.prepend(selectedFiltersHeading); } // The v4 SDK renders every promo block with the same generic class, so add a // per-identifier modifier (e.g. raventic-search-results-promo-content-type--categories) // to allow styling each block separately. The title->identifier map is read from the // widget config (window.RaventicSearchResultsConfig) so there's a single source of truth. function addPromoContentClasses() { const promoContent = window.RaventicSearchResultsConfig?.config?.promoContent; if (!Array.isArray(promoContent)) return; const titleToIdentifier = new Map(promoContent.map((item) => [item.title, item.identifier])); const blocks = document.querySelectorAll(".raventic-search-results-promo-content-type"); blocks.forEach((block) => { const titleEl = block.querySelector(".raventic-search-results-promo-content-type-title"); const identifier = titleEl ? titleToIdentifier.get(titleEl.textContent.trim()) : null; if (!identifier) return; block.classList.add(`raventic-search-results-promo-content-type--${identifier}`); }); shortenBlogAdditionalContentInRaventicResults(); } } //empty search document.addEventListener("RAVENTIC SEARCH RESULTS LOADED", function () { emptySearchQuery(); }); function emptySearchQuery() { const headerSearch = document.querySelector("#header .search"); if (!headerSearch) return; const queryInput = headerSearch.querySelector("input[type='search']"); if (queryInput) { queryInput.value = ""; } } function shortenBlogAdditionalContentInRaventicResults() { const MAX_LENGTH = 35; console.log("Shortening blog additional content in Raventic results..."); const spans = document.querySelectorAll(".raventic-search-results-promo-content-type--articles span"); console.log(`Found ${spans.length} spans to shorten.`); spans.forEach((span) => { const original = span.textContent.trim(); // Already shortened on a previous run — leave it (and its title) untouched. if (original.endsWith("...")) return; span.title = original; if (original.length <= MAX_LENGTH) return; // Keep whole words up to and including the one that crosses MAX_LENGTH, // so the text never ends mid-word. const words = original.split(/\s+/); let shortened = ""; for (const word of words) { shortened += (shortened ? " " : "") + word; if (shortened.length >= MAX_LENGTH) break; } span.textContent = shortened + "..."; }); } // document.addEventListener("DOMContentLoaded", function () { /* if (document.body.classList.contains("is-test-eshop")) { */ addSearchButtonForMobile(); clickOutsideSearchDropdown(); /* } */ }); function addSearchButtonForMobile() { const headerSearch = document.querySelector("#header .search"); if (!headerSearch) return; const headerTop = document.querySelector("#header .header-top"); if (!headerTop) return; const headerSearchFormRaventic = document.querySelector("#header .search-form"); if (!headerSearchFormRaventic) return; const queryInput = headerSearch.querySelector("input[type='search']"); if (!queryInput) return; headerSearchFormRaventic.addEventListener("click", function () { console.log("-------- CLICK"); headerSearch.classList.toggle("custom-search-active"); if (body.classList.contains("raventic-search-dropdown-open")) { body.classList.add("custom-search-active"); } if (queryInput) { // timeout 10ms to wait for the animation to finish setTimeout(() => { if ( document.body.classList.contains("raventic-search-dropdown-open") || document.body.classList.contains("custom-search-active") ) { queryInput.click(); console.log("-------- Raventic Search Dropdown Opened (from mobile search button) ------"); } queryInput.focus(); }, 10); } /* if (body.classList.contains("custom-search-active")) { setTimeout(() => { queryInput.click(); console.log("-------- Raventic Search Dropdown Opened (from mobile search button) 2------"); }, 10); } */ const searchHeight = headerSearch.offsetHeight; document.body.style.setProperty("--mobile-search-height", searchHeight + "px"); document.body.classList.remove("has-opened-hamburger-menu"); }); } //when i click elsewhere than: #header.search and its children and .raventic-search-dropdown-body and its children then from body remove custom-search-active function clickOutsideSearchDropdown() { document.addEventListener("click", function (event) { if (!document.body.classList.contains("custom-search-active")) { return; } const headerSearch = document.querySelector("#header .search"); const dropdownBody = document.querySelector(".raventic-search-dropdown-body"); if (headerSearch && dropdownBody && !headerSearch.contains(event.target) && !dropdownBody.contains(event.target)) { document.body.classList.remove("custom-search-active"); console.log("-------- Raventic Search Dropdown Closed (clicked outside) ------"); } }); } document.addEventListener("RAVENTIC SEARCH RESULTS TRANSFORMED", function (event) { addFilterButtonToggleRaventic(); function addFilterButtonToggleRaventic() { const alreadyExistsRaventicFilterButton = document.querySelector(".custom-open-filter-button"); if (alreadyExistsRaventicFilterButton) return; const customOpenFilterButtonRaventic = document.createElement("a"); customOpenFilterButtonRaventic.className = "custom-open-filter-button"; customOpenFilterButtonRaventic.innerHTML = translationsStrings.customFilterButton[activeLang]; try { const raventicResultsTop = document.querySelector(".raventic-search-results-container"); raventicResultsTop.appendChild(customOpenFilterButtonRaventic); customOpenFilterButtonRaventic.addEventListener("click", function () { const raventicFilters = document.querySelector(".raventic-search-results-filters"); if (raventicFilters) { raventicFilters.classList.toggle("active"); } customOpenFilterButtonRaventic.classList.toggle("active"); }); } catch (error) { console.error("Error in customOpenFilterButtonListener:", error); } } });