Files
Commerce/script.js

449 lines
17 KiB
JavaScript

// Initialize dataLayer for Google Tag Manager
window.dataLayer = window.dataLayer || [];
// Push virtual page view event on page load
window.dataLayer.push({
'event': 'virtualPageview',
'pagePath': window.location.pathname + window.location.search,
'pageTitle': document.title
});
// --- Product Carousel Logic ---
document.addEventListener('DOMContentLoaded', function initProductCarousel() {
const carouselMain = document.querySelector('.carousel-main');
if (!carouselMain) return;
const mainImg = carouselMain.querySelector('img');
const thumbs = Array.from(document.querySelectorAll('.carousel-thumbnails .product-img-small'));
const leftArrow = document.querySelector('.carousel-arrow.left');
const rightArrow = document.querySelector('.carousel-arrow.right');
if (!mainImg || thumbs.length === 0) return;
let current = thumbs.findIndex(t => t.classList.contains('selected'));
if (current === -1) current = 0;
let isAnimating = false;
function updateCarousel(idx, smooth = true) {
if (isAnimating || thumbs.length === 0) return;
// Infinite loop logic
if (idx < 0) idx = thumbs.length - 1;
if (idx >= thumbs.length) idx = 0;
// Animate transition
if (smooth) {
isAnimating = true;
mainImg.style.opacity = '0.5';
}
// Update selected thumbnail
thumbs.forEach(t => t.classList.remove('selected'));
thumbs[idx].classList.add('selected');
// Update main image
const newSrc = thumbs[idx].querySelector('img').src;
if (smooth) {
setTimeout(() => {
mainImg.src = newSrc;
mainImg.style.opacity = '1';
isAnimating = false;
}, 150);
} else {
mainImg.src = newSrc;
}
current = idx;
// Scroll thumbnail into view (centered)
const thumbContainer = document.querySelector('.carousel-thumbnails');
if (thumbContainer) {
const thumbElement = thumbs[idx];
const containerRect = thumbContainer.getBoundingClientRect();
const thumbRect = thumbElement.getBoundingClientRect();
const scrollLeft = thumbElement.offsetLeft - (containerRect.width / 2) + (thumbRect.width / 2);
thumbContainer.scrollTo({ left: scrollLeft, behavior: 'smooth' });
}
}
// Arrow click handlers
if (leftArrow) {
leftArrow.addEventListener('click', (e) => {
e.preventDefault();
updateCarousel(current - 1);
});
}
if (rightArrow) {
rightArrow.addEventListener('click', (e) => {
e.preventDefault();
updateCarousel(current + 1);
});
}
// Thumbnail click handlers
thumbs.forEach((thumb, idx) => {
thumb.addEventListener('click', () => updateCarousel(idx));
});
// Swipe support for touch devices
let touchStartX = null;
carouselMain.addEventListener('touchstart', (e) => {
touchStartX = e.touches[0].clientX;
}, { passive: true });
carouselMain.addEventListener('touchend', (e) => {
if (touchStartX === null) return;
const endX = e.changedTouches[0].clientX;
const diffX = endX - touchStartX;
// Require minimum swipe distance
if (Math.abs(diffX) > 50) {
if (diffX > 0) {
updateCarousel(current - 1); // Swipe right = previous
} else {
updateCarousel(current + 1); // Swipe left = next
}
}
touchStartX = null;
}, { passive: true });
// Keyboard navigation
document.addEventListener('keydown', (e) => {
// Only if carousel is visible in viewport
const rect = carouselMain.getBoundingClientRect();
const inViewport = rect.top < window.innerHeight && rect.bottom > 0;
if (!inViewport) return;
if (e.key === 'ArrowLeft') {
e.preventDefault();
updateCarousel(current - 1);
} else if (e.key === 'ArrowRight') {
e.preventDefault();
updateCarousel(current + 1);
}
});
// Initialize first thumbnail as selected
updateCarousel(current, false);
});
// --- Sticky Add to Basket Button ---
(function handleStickyButton() {
const btn = document.querySelector('.add-to-basket-sticky');
if (!btn) return;
// Store original position after page load
let originalBottom = null;
let isInitialized = false;
function initPosition() {
const rect = btn.getBoundingClientRect();
originalBottom = window.scrollY + rect.bottom;
isInitialized = true;
checkSticky();
}
function checkSticky() {
if (!isInitialized) return;
// On tablet/mobile (992px and below), always keep sticky
if (window.innerWidth <= 992) {
btn.classList.add('is-sticky');
return;
}
// On desktop: sticky while user hasn't scrolled past the button's original position
const viewportBottom = window.scrollY + window.innerHeight;
if (viewportBottom < originalBottom) {
// User hasn't scrolled enough to see the button naturally
btn.classList.add('is-sticky');
} else {
// User has scrolled past where the button would naturally be
btn.classList.remove('is-sticky');
}
}
function handleResize() {
// Recalculate position on resize
btn.classList.remove('is-sticky');
setTimeout(() => {
initPosition();
}, 100);
}
// Initialize after DOM is ready and images are loaded
if (document.readyState === 'complete') {
initPosition();
} else {
window.addEventListener('load', initPosition);
}
window.addEventListener('scroll', checkSticky, { passive: true });
window.addEventListener('resize', handleResize, { passive: true });
})();
if (document.querySelector('.product #product-form')) {
let updatePrice = () => {
let price = parseFloat(document.querySelector('.product .price').dataset.price);
let rrp = document.querySelector('.product .rrp') ?? 0;
if (rrp !=0)
{
rrp = parseFloat(document.querySelector('.product .rrp').dataset.rrp) ?? 0;
}
document.querySelectorAll('.product #product-form .option').forEach(e => {
if (e.value) {
let optionPrice = e.classList.contains('text') || e.classList.contains('datetime') ? e.dataset.price : 0.00;
optionPrice = e.classList.contains('select') ? e.options[e.selectedIndex].dataset.price : optionPrice;
optionPrice = (e.classList.contains('radio') || e.classList.contains('checkbox')) && e.checked ? e.dataset.price : optionPrice;
price = (e.classList.contains('select') ? e.options[e.selectedIndex].dataset.modifier : e.dataset.modifier) == 1 ? price+parseFloat(optionPrice) : price-parseFloat(optionPrice);
let optionRRP = e.classList.contains('text') || e.classList.contains('datetime') ? e.dataset.rrp : 0.00;
optionRRP = e.classList.contains('select') ? e.options[e.selectedIndex].dataset.rrp : optionRRP;
optionRRP = (e.classList.contains('radio') || e.classList.contains('checkbox')) && e.checked ? e.dataset.rrp : optionRRP;
rrp = (e.classList.contains('select') ? e.options[e.selectedIndex].dataset.modifier : e.dataset.modifier) == 1 ? rrp+parseFloat(optionRRP) : rrp-parseFloat(optionRRP);
}
});
document.querySelector('.product .price').innerHTML = currency_code + (price > 0.00 ? price.toFixed(2) : 0.00);
if (rrp !=0)
{
document.querySelector('.product .rrp').innerHTML = currency_code + (rrp > 0.00 ? rrp.toFixed(2) : 0.00);
}
};
document.querySelectorAll('.product #product-form .option').forEach(ele => ele.onchange = () => updatePrice());
updatePrice();
// Add to cart event
document.querySelector('.product #product-form').addEventListener('submit', function(e) {
e.preventDefault(); // Prevent immediate submission
let productId = document.querySelector('input[name="product[product]"]').value;
let quantity = parseInt(document.querySelector('input[name="product[quantity]"]').value);
let productName = document.querySelector('.product .name').textContent;
let price = parseFloat(document.querySelector('.product .price').dataset.price);
window.dataLayer.push({
'event': 'addToCart',
'ecommerce': {
'add': {
'products': [{
'id': productId,
'name': productName,
'price': price,
'quantity': quantity
}]
}
},
'content_type': 'product',
'content_ids': [productId],
'content_name': productName,
'value': price * quantity,
'currency': 'EUR'
});
// Submit form after a short delay
setTimeout(() => {
e.target.submit();
}, 100);
});
}
if (document.querySelector('.products-form')) {
let products_form_submit = () => {
document.querySelector('.products-form')
if (rewrite_url) {
window.location.href = encodeURI(base_url + 'products/' + document.querySelector('.category select').value + '/' + document.querySelector('.sortby select').value);
} else {
window.location.href = encodeURI(base_url + 'index.php?page=products&category=' + document.querySelector('.category select').value + '&sort=' + document.querySelector('.sortby select').value);
}
};
document.querySelector('.sortby select').onchange = () => products_form_submit();
document.querySelector('.category select').onchange = () => products_form_submit();
}
if (document.querySelector('.cart .ajax-update')) {
document.querySelectorAll('.cart .ajax-update').forEach(ele => {
ele.onchange = () => {
let formEle = document.querySelector('.cart form');
let formData = new FormData(formEle);
formData.append('update', 'Update');
console.log(formData);
fetch(formEle.action, {
method: 'POST',
body: formData
}).then(response => response.text()).then(html => {
let doc = (new DOMParser()).parseFromString(html, 'text/html');
document.querySelector('.total').innerHTML = doc.querySelector('.total').innerHTML;
document.querySelectorAll('.product-total').forEach((e,i) => {
e.innerHTML = doc.querySelectorAll('.product-total')[i].innerHTML;
});
// Push cart update event
window.dataLayer.push({
'event': 'updateCart'
});
});
};
});
}
const checkoutHandler = () => {
if (document.querySelector('.checkout .ajax-update')) {
document.querySelectorAll('.checkout .ajax-update').forEach(ele => {
ele.onchange = () => {
let formEle = document.querySelector('.checkout form');
let formData = new FormData(formEle);
formData.append('update', 'Update');
fetch(formEle.action, {
method: 'POST',
body: formData
}).then(response => response.text()).then(html => {
let doc = (new DOMParser()).parseFromString(html, 'text/html');
document.querySelector('.summary').innerHTML = doc.querySelector('.summary').innerHTML;
document.querySelector('.total').innerHTML = doc.querySelector('.total').innerHTML;
document.querySelector('.discount-code .result').innerHTML = doc.querySelector('.discount-code .result').innerHTML;
document.querySelector('.shipping-methods-container').innerHTML = doc.querySelector('.shipping-methods-container').innerHTML;
// Push checkout update event
window.dataLayer.push({
'event': 'checkoutUpdate'
});
checkoutHandler();
});
};
if (ele.name == 'discount_code') {
ele.onkeydown = event => {
if (event.key == 'Enter') {
event.preventDefault();
ele.onchange();
}
};
}
});
}
};
checkoutHandler();
function openMenu(div){
let nav_display = document.querySelector(div).style.display;
document.querySelector(div).style.display = nav_display == 'block' ? 'none' : 'block';
}
function update(id_large, IMG_large, option_id, price){
let url_id_a = id_large + 'A';
let url_id_b = id_large + 'B';
let url_id_c = id_large + 'C';
//change picture
document.getElementById(id_large).src = IMG_large;
document.getElementById(url_id_a).href = option_id;
document.getElementById(url_id_b).href = option_id;
document.getElementById(url_id_c).innerHTML = price;
}
function updateOption(id_large, IMG_large){
//change picture
document.getElementById(id_large).src = IMG_large;
// Update the first thumbnail to match the new main image
let firstThumbnail = document.querySelector('.product-img-small img');
if (firstThumbnail) {
firstThumbnail.src = IMG_large;
firstThumbnail.parentElement.classList.add('selected');
}
}
// Function to change the title and flag when a language is selected
function changeLanguage(language, langCode, flagUrl) {
const title = document.getElementById("title");
title.src = flagUrl;
title.alt = language+" Flag";
}
// Enhanced slider functionality for multiple carousels
function initializeCarousels() {
// Handle product sliders (highlightedProducts2)
const productSliders = document.querySelectorAll('.product-slider');
productSliders.forEach((slider) => {
const carouselId = slider.getAttribute('data-carousel');
const prevBtn = slider.querySelector('.prev-btn');
const nextBtn = slider.querySelector('.next-btn');
const productContainer = slider.querySelector('.product-container-slider');
const products = slider.querySelectorAll('.product-card-slider');
if (!products.length) return;
let currentIndex = 0;
const productsPerView = window.innerWidth < 480 ? 1 :
window.innerWidth < 768 ? 2 :
window.innerWidth < 992 ? 3 : 4;
function updateSliderPosition() {
const productWidth = products[0].offsetWidth;
productContainer.style.transform = `translateX(-${currentIndex * productWidth}px)`;
}
prevBtn.addEventListener('click', () => {
if (currentIndex > 0) {
currentIndex--;
updateSliderPosition();
}
});
nextBtn.addEventListener('click', () => {
if (currentIndex < products.length - productsPerView) {
currentIndex++;
updateSliderPosition();
}
});
// Update slider on window resize
window.addEventListener('resize', () => {
// Reset position when screen size changes
currentIndex = 0;
updateSliderPosition();
});
});
// Handle sample sliders (getSamples)
const sampleButtons = document.querySelectorAll('.scrollButton');
sampleButtons.forEach((button) => {
const samplesId = button.getAttribute('data-samples');
if (!samplesId) return;
const samplesContainer = document.getElementById('add_samples_container_' + samplesId);
if (!samplesContainer) return;
const isLeftButton = button.id.includes('slideLeft');
button.addEventListener('click', () => {
const scrollAmount = 200; // Adjust as needed
const currentScroll = samplesContainer.scrollLeft;
if (isLeftButton) {
samplesContainer.scrollTo({
left: currentScroll - scrollAmount,
behavior: 'smooth'
});
} else {
samplesContainer.scrollTo({
left: currentScroll + scrollAmount,
behavior: 'smooth'
});
}
});
});
}
// Only initialize carousels once DOM is loaded
// (No duplicate or stray HTML allowed)