diff --git a/.vscode/ftp-kr.sync.cache.json b/.vscode/ftp-kr.sync.cache.json index 955ea113..19a1798c 100644 --- a/.vscode/ftp-kr.sync.cache.json +++ b/.vscode/ftp-kr.sync.cache.json @@ -117,11 +117,17 @@ }, "google-merchant_id-1.xml": { "type": "-", - "size": 18781948, + "size": 18540350, "lmtime": 0, "modified": true }, ".htaccess": { + "type": "-", + "size": 87379, + "lmtime": 0, + "modified": true + }, + ".htaccess.2025-10-16-1760598489": { "type": "-", "size": 87360, "lmtime": 0, diff --git a/modules/onepagecheckoutps/views/js/front/onepagecheckoutps.js b/modules/onepagecheckoutps/views/js/front/onepagecheckoutps.js index d682d2ad..d9f4e45e 100644 --- a/modules/onepagecheckoutps/views/js/front/onepagecheckoutps.js +++ b/modules/onepagecheckoutps/views/js/front/onepagecheckoutps.js @@ -2864,7 +2864,6 @@ var Review = { ".bootstrap-touchspin-up, .bootstrap-touchspin-down, .remove-from-cart", function (e) { e.preventDefault() - e.stopPropagation() var url_call = "" var $input = $(e.currentTarget) diff --git a/modules/pdgoogleanalytycs4pro/views/js/scripts_17.js b/modules/pdgoogleanalytycs4pro/views/js/scripts_17.js index c5fd2104..a565d718 100644 --- a/modules/pdgoogleanalytycs4pro/views/js/scripts_17.js +++ b/modules/pdgoogleanalytycs4pro/views/js/scripts_17.js @@ -191,7 +191,7 @@ $(document).ready(function() { paymentRequestLock = true; setTimeout(() => paymentRequestLock = false, 1000); // odblokuj po sekundzie - let payment_module = $(this).data('module-name'); + let payment_module = $(this).val(); $.ajax({ type: "POST", url: pdgoogleanalytycs4pro_ajax_link, @@ -487,7 +487,7 @@ $(document).ready(function() { // qty up > stadard theme ps 17 $('body').on("click", "button.bootstrap-touchspin-up", function(e) { - let qty_input = $(this).parent().parent().find('input.js-cart-line-product-quantity'), + let qty_input = $(this).parent().parent().find('input.cart-line-product-quantity'), updat_url = qty_input.attr('data-update-url'), url_params = PdParseQuery(updat_url), iso_code = prestashop.currency.iso_code; @@ -536,9 +536,9 @@ $(document).ready(function() { }); // qty down > stadard theme ps 17 - $('body').on("click", "button.bootstrap-touchspin-down", function(e) { + $( 'body' ).on( "click", "button.bootstrap-touchspin-down", function(e) { - let qty_input = $(this).parent().parent().find('input.js-cart-line-product-quantity'), + let qty_input = $(this).parent().parent().find('input.cart-line-product-quantity'), updat_url = qty_input.attr('data-update-url'), url_params = PdParseQuery(updat_url), iso_code = prestashop.currency.iso_code; @@ -841,4 +841,362 @@ $(document).ready(function() { } return query; } -}); \ No newline at end of file +}); + +/* GA4: view_item_list + select_item (homepage + PDP) — finalna wersja */ +(function (window, document) { + 'use strict'; + + if (window.__ga4ItemListInit) return; + window.__ga4ItemListInit = true; + + // === Funkcje wspólne === + function isHomepage() { + var b = document.body; + return b && (b.id === 'index' || b.classList.contains('page-index') || b.classList.contains('index')); + } + function isProductPage() { + var b = document.body; + return b && (b.id === 'product' || b.classList.contains('page-product')); + } + function parsePrice(str) { + if (!str) return; + var s = String(str).replace(/\u00A0/g, ' ') + .replace(/zł|PLN/gi, '') + .trim() + .replace(/\s/g, '') + .replace(',', '.'); + var p = parseFloat(s); + return isNaN(p) ? undefined : p; + } + function getPathSegment(url, idx) { + try { + var u = new URL(url, window.location.origin); + var seg = u.pathname.split('/').filter(Boolean); + return seg[idx] || undefined; + } catch (e) { + return; + } + } + function gtagEvent(name, params) { + if (typeof window.gtag === 'function') { + window.gtag('event', name, params || {}); + } else { + window.dataLayer = window.dataLayer || []; + window.dataLayer.push({ + 'gtag_event_name': name, + 'gtag_event_params': params || {} + }); + } + } + function collectItems(section, cfg) { + var nodes = section.querySelectorAll(cfg.cardSelector); + var items = []; + nodes.forEach(function (card, i) { + var id = card.getAttribute('data-id-product'); + var varId = card.getAttribute('data-id-product-attribute'); + var nameEl = card.querySelector(cfg.nameSelector); + var name = nameEl ? nameEl.textContent.trim() : undefined; + var urlEl = card.querySelector(cfg.urlSelector); + var url = urlEl ? urlEl.getAttribute('href') : undefined; + var priceEl = card.querySelector(cfg.priceSelector); + var price = parsePrice(priceEl ? priceEl.textContent : ''); + var item_category = url ? decodeURIComponent(getPathSegment(url, 0) || '') : undefined; + + var item = { + item_id: id || undefined, + item_name: name || undefined, + index: i + 1, + item_list_id: cfg.list_id, + item_list_name: cfg.list_name, + price: price, + currency: 'PLN' + }; + if (item_category) item.item_category = item_category; + if (varId && varId !== '0') item.item_variant = varId; + items.push(item); + }); + return items; + } + function sendViewItemList(items, cfg) { + gtagEvent('view_item_list', { + item_list_id: cfg.list_id, + item_list_name: cfg.list_name, + items: items + }); + } + function wireSelectItem(section, cfg) { + section.addEventListener('click', function (e) { + var anchor = e.target.closest(cfg.clickAnchorSelector); + if (!anchor) return; + var card = anchor.closest(cfg.cardSelector); + if (!card) return; + var nodes = section.querySelectorAll(cfg.cardSelector); + var idx = Array.prototype.indexOf.call(nodes, card); + if (idx < 0) return; + var items = collectItems(section, cfg); + var item = items[idx]; + if (!item) return; + gtagEvent('select_item', { + item_list_id: cfg.list_id, + item_list_name: cfg.list_name, + items: [item] + }); + }); + } + + // === Inicjalizacja sekcji === + function initSection(cfg) { + if (cfg.when && !cfg.when()) return; + var section = document.querySelector(cfg.sectionSelector); + if (!section || section.__viewItemListSent) return; + + var send = function () { + if (section.__viewItemListSent) return; + var items = collectItems(section, cfg); + if (items.length) { + sendViewItemList(items, cfg); + section.__viewItemListSent = true; + } + }; + + // homepage — dopiero po widoczności; PDP — od razu + if (cfg.deferByScroll) { + if ('IntersectionObserver' in window) { + var io = new IntersectionObserver(function (entries) { + entries.forEach(function (entry) { + if (entry.isIntersecting && entry.intersectionRatio >= 0.5) { + send(); + io.disconnect(); + } + }); + }, { threshold: [0.5] }); + io.observe(section); + } else { + if (document.readyState === 'loading') + document.addEventListener('DOMContentLoaded', send); + else send(); + } + } else { + // natychmiast + send(); + } + + wireSelectItem(section, cfg); + } + + // === Konfiguracje sekcji === + var COMMON = { + cardSelector: '.product-miniature.js-product-miniature', + urlSelector: 'a.thumbnail.product-thumbnail', + priceSelector: '.product-price-and-shipping [itemprop="price"].price, .product-price-and-shipping .price', + clickAnchorSelector: '.product-miniature a' + }; + + // Homepage — "Super oferty" (tylko po widoczności) + var cfgFeatured = Object.assign({}, COMMON, { + when: isHomepage, + sectionSelector: 'section.featured-products', + list_name: 'Super oferty', + list_id: 'featured-products', + nameSelector: '[itemprop="name"]', + deferByScroll: true + }); + + // PDP — "Zobacz także" (natychmiast) + var cfgAccessories = Object.assign({}, COMMON, { + when: isProductPage, + sectionSelector: 'section.product-accessories', + list_name: 'Zobacz także', + list_id: 'product-accessories', + nameSelector: '[itemprop="name"]', + deferByScroll: false + }); + + // PDP — "Podobne produkty z tej samej kategorii" (natychmiast) + var cfgCategoryRelated = Object.assign({}, COMMON, { + when: isProductPage, + sectionSelector: 'section.category-products', + list_name: 'Podobne produkty z tej samej kategorii', + list_id: 'category-related', + nameSelector: '.product-title, [itemprop="name"]', + deferByScroll: false + }); + + // === Start === + function start() { + initSection(cfgFeatured); + initSection(cfgAccessories); + initSection(cfgCategoryRelated); + } + + if (document.readyState === 'loading') + document.addEventListener('DOMContentLoaded', start); + else + start(); + +})(window, document); + +/* GA4: view_promotion + select_promotion dla #bonslick (homepage) */ +(function (window, document) { + 'use strict'; + + if (window.__ga4PromoInit) return; + window.__ga4PromoInit = true; + + function isHomepage() { + var b = document.body; + return !!b && (b.id === 'index' || b.classList.contains('page-index') || b.classList.contains('index')); + } + if (!isHomepage()) return; + + // gtag fallback do dataLayer, gdyby gtag nie był gotowy + function gtagEvent(name, params) { + if (typeof window.gtag === 'function') { + window.gtag('event', name, params || {}); + } else { + window.dataLayer = window.dataLayer || []; + window.dataLayer.push({ + 'gtag_event_name': name, + 'gtag_event_params': params || {} + }); + } + } + + var ROOT_SEL = '#bonslick'; + var LINK_SEL = 'li.slick-slide:not(.slick-cloned) a.link-bonslick'; + var ANY_LINK = 'a.link-bonslick'; + var LOCATION = 'homepage_bonslick'; + var sentView = false; + + // Pomocnicze: wydłub nazwę kreatywu z albo z src + function getCreativeName(imgEl) { + if (!imgEl) return undefined; + var alt = imgEl.getAttribute('alt'); + if (alt && alt.trim()) return alt.trim(); + var src = imgEl.getAttribute('data-src') || imgEl.getAttribute('src') || ''; + if (!src) return undefined; + try { + var base = src.split('/').pop(); + return base ? base.split('?')[0] : undefined; + } catch (e) { return undefined; } + } + + // Zbierz unikalne slajdy (bez .slick-cloned) -> items[] do view_promotion + function collectPromoItems(container) { + var items = []; + var seenKey = Object.create(null); + + var links = container.querySelectorAll(LINK_SEL); + links.forEach(function (a, i) { + var href = a.getAttribute('href') || ''; + var title = a.getAttribute('title') || ''; + var img = a.querySelector('img'); + var creative = getCreativeName(img); + + // klucz unikalności (href + creative) + var key = (href || '') + '|' + (creative || ''); + if (seenKey[key]) return; + seenKey[key] = true; + + items.push({ + promotion_id: href || undefined, // ID jako docelowy URL + promotion_name: (title || creative || '').trim() || undefined, + creative_name: creative || undefined, + creative_slot: String(i + 1), // pozycja w sliderze (bez klonów) + location_id: LOCATION + }); + }); + + return items; + } + + // Przy kliknięciu w JEDEN slajd => select_promotion z 1 itemem + function buildClickedItem(anchor) { + var href = anchor.getAttribute('href') || ''; + var title = anchor.getAttribute('title') || ''; + var img = anchor.querySelector('img'); + var creative = getCreativeName(img); + + // Ustal slot z indeksu slajdu (bez klonów jeśli się da) + var li = anchor.closest('li.slick-slide'); + var slot = undefined; + if (li) { + var container = anchor.closest(ROOT_SEL) || document; + var list = Array.prototype.slice.call(container.querySelectorAll(LINK_SEL)); + var idx = list.indexOf(anchor); + if (idx >= 0) slot = String(idx + 1); + } + + return [{ + promotion_id: href || undefined, + promotion_name: (title || creative || '').trim() || undefined, + creative_name: creative || undefined, + creative_slot: slot, + location_id: LOCATION + }]; + } + + function fireViewPromotion(container) { + if (sentView) return; + var items = collectPromoItems(container); + if (!items.length) return; + gtagEvent('view_promotion', { items: items }); + sentView = true; + } + + function init() { + var root = document.querySelector(ROOT_SEL); + if (!root) return; + + // 1) view_promotion: gdy slider wejdzie >=50% w viewport (po wyświetleniu) + if ('IntersectionObserver' in window) { + var io = new IntersectionObserver(function (entries) { + entries.forEach(function (entry) { + if (entry.isIntersecting && entry.intersectionRatio >= 0.5) { + fireViewPromotion(root); + io.disconnect(); + } + }); + }, { threshold: [0.5] }); + io.observe(root); + } else { + // Fallback: wyślij po DOMContentLoaded (slider zwykle jest nad foldem) + fireViewPromotion(root); + } + + // 2) select_promotion: delegacja kliknięcia (obsłuży także klony) + root.addEventListener('click', function (e) { + var a = e.target.closest(ANY_LINK); + if (!a || !root.contains(a)) return; + var items = buildClickedItem(a); + if (!items || !items.length) return; + gtagEvent('select_promotion', { items: items }); + }); + + // 3) Gdy slick doda slajdy asynchronicznie — lekki watchdog z MutationObserver + if ('MutationObserver' in window) { + var mo = new MutationObserver(function () { + // jeśli jeszcze nie poszło, a pojawiły się slajdy — spróbuj wysłać + if (!sentView) { + var hasSlides = root.querySelector(LINK_SEL); + if (hasSlides && !('IntersectionObserver' in window)) { + fireViewPromotion(root); + } + } + }); + mo.observe(root, { childList: true, subtree: true }); + // rozłącz po wysłaniu + var stopWhenSent = setInterval(function(){ + if (sentView) { mo.disconnect(); clearInterval(stopWhenSent); } + }, 1500); + } + } + + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } + +})(window, document); \ No newline at end of file