custom/plugins/DreiwmBrandstetterPlugin/src/Resources/views/storefront/base.html.twig line 1

Open in your IDE?
  1. {% sw_extends "@Storefront/storefront/base.html.twig" %}
  2. {% block base_main %}
  3.     {{ parent() }}
  4.     {# Ein modales Fenster zum Zurücksetzen der Lieferoptionen #}
  5.     <div class="modal" id="resetDeliveryOptionsModal" tabindex="-1" role="dialog">
  6.         <div class="modal-dialog" role="document">
  7.             <div class="modal-content">
  8.                 <div class="modal-body">
  9.                     <div class="deliverySelectorModal">
  10.                         <img src="{{ asset('/assets/DALL·E 2023-11-21 13.37.49 - Ausrufebrot.svg', 'theme') }}"
  11.                              alt="Lieferart zurücksetzen Bild" id="reset-delivery-options-spinner">
  12.                         <div class="deliverySelectorModalContent">
  13.                             <div class="deliverySelectorModalHeadline">{{ "brandstetter.desiredDeliveryResetDescription"|trans|sw_sanitize }}</div>
  14.                             <button class="deliverySelectorButton" type="button"
  15.                                     data-dismiss="modal">{{ "brandstetter.desiredDeliveryResetCancel"|trans|sw_sanitize }}</button>
  16.                             <button class="deliverySelectorButton" type="submit"
  17.                                     id="deliverySelectorReset">{{ "brandstetter.desiredDeliveryReset"|trans|sw_sanitize }}</button>
  18.                         </div>
  19.                     </div>
  20.                 </div>
  21.             </div>
  22.         </div>
  23.     </div>
  24.     {# Hier wird der DeliverySelector angezeigt #}
  25.     <div class="deliverySelector" id="deliverySelector">
  26.         {% sw_include '@DreiwmBrandstetterPlugin/storefront/component/brandstetter/delivery-selector/loading-spinner.html.twig' %}
  27.         <div class="deliverySelectorContent" id="deliverySelectorContent">
  28.             {% if app.request.cookies.get('CustomerHasSelectedDelivery') == 'true' and app.request.cookies.get('CustomerHasSelectedDelivery')!= 'false' and app.request.cookies.get('customerSelectedDeliveryId') %}
  29.                 {% sw_include '@DreiwmBrandstetterPlugin/storefront/component/brandstetter/delivery-selector/user-has-selected-delivery.html.twig' %}
  30.             {% else %}
  31.                 {% sw_include '@DreiwmBrandstetterPlugin/storefront/component/brandstetter/delivery-selector/user-has-not-selected-delivery.html.twig' %}
  32.             {% endif %}
  33.         </div>
  34.     </div>
  35.     <script>
  36.         (function () {
  37.             'use strict';
  38.             // ===== Helpers =====
  39.             const WRAP_ID = 'delivery-selector-wrapper';
  40.             const SPIN_ID = 'delivery-selector-spinner';
  41.             function readCookies() {
  42.                 return document.cookie.split('; ').reduce((acc, c) => {
  43.                     const i = c.indexOf('=');
  44.                     if (i > -1) acc[decodeURIComponent(c.slice(0, i))] = decodeURIComponent(c.slice(i + 1));
  45.                     return acc;
  46.                 }, {});
  47.             }
  48.             function hasSelectedDeliveryCookie() {
  49.                 const c = readCookies();
  50.                 const v = (c['CustomerHasSelectedDelivery'] || '').toLowerCase();
  51.                 return v === 'true' || v === '1' || v === 'yes' || !!c['customerSelectedDeliveryId'];
  52.             }
  53.             // Großes "nicht gewählt"-Widget zuverlässig erkennen (beide Varianten + Fallback-Klasse)
  54.             function domShowsNotSelected() {
  55.                 const camel = document.getElementById('deliverySelectorContent');
  56.                 return !!(
  57.                     document.getElementById('delivery-selector-content') ||
  58.                     (camel && camel.querySelector && camel.querySelector('#delivery-selector-content')) ||
  59.                     document.querySelector('.delivery-selector-content')
  60.                 );
  61.             }
  62.             function isBackForward(evt) {
  63.                 const nav = (performance.getEntriesByType && performance.getEntriesByType('navigation')[0]) || null;
  64.                 return (evt && evt.persisted === true) || (nav && nav.type === 'back_forward');
  65.             }
  66.             function isPDS() {
  67.                 return document.body.classList.contains('is-ctl-product') || !!document.querySelector('.product-detail');
  68.             }
  69.             function isListing() {
  70.                 const b = document.body.classList;
  71.                 return b.contains('is-ctl-navigation') || b.contains('is-ctl-search') || !!document.querySelector('.cms-element-product-listing');
  72.             }
  73.             function restoreDeliverySelectorUI() {
  74.                 const wrap = document.getElementById(WRAP_ID);
  75.                 const spin = document.getElementById(SPIN_ID);
  76.                 if (wrap) wrap.style.visibility = 'visible';
  77.                 if (spin) spin.style.display = 'none';
  78.             }
  79.             // Cookies/URL-Helpers (auch global verfügbar)
  80.             function getCookie(name) {
  81.                 const m = document.cookie.match(new RegExp('(?:^|; )' + name.replace(/([.$?*|{}()[\]\\/+^])/g, '\\$1') + '=([^;]*)'));
  82.                 return m ? decodeURIComponent(m[1]) : undefined;
  83.             }
  84.             function setCookie(name, value) {
  85.                 const date = new Date();
  86.                 date.setTime(date.getTime() + (24 * 60 * 60 * 1000));
  87.                 document.cookie = name + '=' + (value || '') + '; expires=' + date.toUTCString() + '; path=/; SameSite=None; Secure';
  88.             }
  89.             function deleteCookie(name) {
  90.                 document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
  91.             }
  92.             function updateURLParameter(url, param, val) {
  93.                 const [base, query = ''] = url.split('?');
  94.                 const parts = query ? query.split('&').filter(p => p.split('=')[0] !== param) : [];
  95.                 parts.push(param + '=' + encodeURIComponent(val));
  96.                 return base + '?' + parts.join('&');
  97.             }
  98.             window.updateURLParameter = updateURLParameter;
  99.             window.setCookie = setCookie;
  100.             window.deleteCookie = deleteCookie;
  101.             // ===== Positions & Drag =====
  102.             function updatePositions() {
  103.                 const positions = JSON.parse(localStorage.getItem('positions') || '{}');
  104.                 document.querySelectorAll('.deliverySelector').forEach(el => {
  105.                     const pos = positions[el.id];
  106.                     if (pos) {
  107.                         let newLeft = (parseFloat(pos.left) * window.innerWidth) / 100;
  108.                         let newTop  = (parseFloat(pos.top)  * window.innerHeight) / 100;
  109.                         newLeft = Math.min(window.innerWidth  - el.clientWidth,  Math.max(0, newLeft));
  110.                         newTop  = Math.min(window.innerHeight - el.clientHeight, Math.max(0, newTop));
  111.                         el.style.left = newLeft + 'px';
  112.                         el.style.top  = newTop  + 'px';
  113.                     }
  114.                 });
  115.             }
  116.             window.addEventListener('resize', updatePositions);
  117.             document.addEventListener('DOMContentLoaded', function () {
  118.                 updatePositions();
  119.                 const positions = JSON.parse(localStorage.getItem('positions') || '{}');
  120.                 const els = document.querySelectorAll('.deliverySelector');
  121.                 els.forEach(el => {
  122.                     const pos = positions[el.id];
  123.                     if (pos) {
  124.                         el.style.left = (parseFloat(pos.left) * window.innerWidth / 100)  + 'px';
  125.                         el.style.top  = (parseFloat(pos.top)  * window.innerHeight / 100) + 'px';
  126.                     } else {
  127.                         const elementWidth = 350, elementHeight = 420;
  128.                         el.style.left = (window.innerWidth  - elementWidth)  + 'px';
  129.                         el.style.top  = (window.innerHeight - elementHeight) + 'px';
  130.                     }
  131.                 });
  132.                 els.forEach(el => {
  133.                     let isDragging = false, startX = 0, startY = 0, initialLeft = 0, initialTop = 0;
  134.                     el.addEventListener('mousedown', ev => {
  135.                         isDragging = true;
  136.                         startX = ev.clientX; startY = ev.clientY;
  137.                         initialLeft = parseFloat(el.style.left) || 0;
  138.                         initialTop  = parseFloat(el.style.top)  || 0;
  139.                     });
  140.                     document.addEventListener('mousemove', ev => {
  141.                         if (!isDragging) return;
  142.                         let newLeft = initialLeft + (ev.clientX - startX);
  143.                         let newTop  = initialTop  + (ev.clientY - startY);
  144.                         newLeft = Math.min(window.innerWidth  - el.clientWidth,  Math.max(0, newLeft));
  145.                         newTop  = Math.min(window.innerHeight - el.clientHeight, Math.max(0, newTop));
  146.                         el.style.left = newLeft + 'px';
  147.                         el.style.top  = newTop  + 'px';
  148.                     });
  149.                     document.addEventListener('mouseup', () => {
  150.                         if (!isDragging) return;
  151.                         isDragging = false;
  152.                         positions[el.id] = {
  153.                             left: (100 * (parseFloat(el.style.left) / window.innerWidth))  + '%',
  154.                             top:  (100 * (parseFloat(el.style.top)  / window.innerHeight)) + '%'
  155.                         };
  156.                         localStorage.setItem('positions', JSON.stringify(positions));
  157.                     });
  158.                 });
  159.                 // "Lieferart zurücksetzen"
  160.                 const resetBtn = document.getElementById('deliverySelectorReset');
  161.                 if (resetBtn) {
  162.                     resetBtn.addEventListener('click', function () {
  163.                         const spinner = document.getElementById('reset-delivery-options-spinner');
  164.                         if (spinner) spinner.style.animation = 'spin 1s linear infinite';
  165.                         const xhr = new XMLHttpRequest();
  166.                         xhr.open('POST', '/resetCustomerDeliveryChoice', true);
  167.                         xhr.setRequestHeader('Content-type', 'application/json; charset=UTF-8');
  168.                         xhr.onload = function () {
  169.                             if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
  170.                                 const content = document.getElementById('deliverySelectorContent');
  171.                                 if (content) content.innerHTML = xhr.responseText;
  172.                                 setCookie('CustomerHasSelectedDelivery', 'false');
  173.                                 setCookie('customerSelectedDeliveryId', '');
  174.                                 setCookie('customerSelectedDate', '');
  175.                             }
  176.                             location.reload();
  177.                         };
  178.                         xhr.send(JSON.stringify({ date: 'inputValue' }));
  179.                     });
  180.                 }
  181.             });
  182.             // ===== Auto-Add nach Overlay-Flow =====
  183.             window.addEventListener('load', function () {
  184.                 // Back-Reload-Flag für diese URL bei normalem Load zurücksetzen (neuer Zyklus)
  185.                 const backKey = 'backReloadedOnce:' + location.pathname + location.search;
  186.                 sessionStorage.removeItem(backKey);
  187.                 if (sessionStorage.getItem('detailAutoAdd') !== '1') return;
  188.                 sessionStorage.removeItem('detailAutoAdd');
  189.                 // (1) Shopware-Buy-Form (häufigster Fall)
  190.                 let form = document.querySelector('form.buy-widget[data-add-to-cart]');
  191.                 // (2) Fallback: generischer Add-to-Cart Endpoint
  192.                 if (!form) form = document.querySelector('form[action*="/checkout/line-item/add"]');
  193.                 if (form) {
  194.                     form.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
  195.                     return;
  196.                 }
  197.                 // (3) Fallback: Button klicken
  198.                 let btn = document.querySelector('form.buy-widget button.btn-buy, button.btn-buy, button[name="add-to-cart"]');
  199.                 if (btn) {
  200.                     btn.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));
  201.                     return;
  202.                 }
  203.                 console.warn('Auto-Add: Kein Buy-Form/-Button gefunden.');
  204.             });
  205.             // ===== Nur bei Zurück/Vorwärts: Reload, wenn DOM ≠ Cookies =====
  206.             function scheduleBackFix(trigger) {
  207.                 if (!(isPDS() || isListing())) return;
  208.                 const key = 'backReloadedOnce:' + location.pathname + location.search;
  209.                 const already = sessionStorage.getItem(key) === '1';
  210.                 function needReloadNow() {
  211.                     return hasSelectedDeliveryCookie() && domShowsNotSelected();
  212.                 }
  213.                 function doReload() {
  214.                     if (already) return;
  215.                     sessionStorage.setItem(key, '1'); // Loop verhindern
  216.                     location.reload();                // EIN Reload; Verlauf bleibt korrekt
  217.                 }
  218.                 // 1) Sofort prüfen
  219.                 if (needReloadNow()) { doReload(); return; }
  220.                 // 2) Kurze Nachchecks (DOM/BFCACHE Timing)
  221.                 const delays = [0, 120, 350, 900];
  222.                 let i = 0;
  223.                 (function again(){
  224.                     if (needReloadNow()) { doReload(); return; }
  225.                     if (i < delays.length) setTimeout(() => { i++; again(); }, delays[i]);
  226.                 })();
  227.                 // 3) DOM-Mutationen kurz beobachten
  228.                 const obs = new MutationObserver(() => {
  229.                     if (needReloadNow()) { obs.disconnect(); doReload(); }
  230.                 });
  231.                 obs.observe(document.documentElement, { childList: true, subtree: true });
  232.                 setTimeout(() => obs.disconnect(), 1500);
  233.             }
  234.             // Back/Forward & Normal-Show unterscheiden
  235.             window.addEventListener('pageshow', function (e) {
  236.                 if (isBackForward(e)) {
  237.                     // Nur bei Back/Forward: Auto-Flags aufräumen & ggf. Back-Fix starten
  238.                     sessionStorage.removeItem('autoAddProductName');
  239.                     sessionStorage.removeItem('autoClickOnReload');
  240.                     sessionStorage.removeItem('detailAutoAdd');
  241.                     scheduleBackFix('pageshow');
  242.                 } else {
  243.                     // Normaler Load: pfadbezogenes Back-Flag löschen (neuer Zyklus)
  244.                     const backKey = 'backReloadedOnce:' + location.pathname + location.search;
  245.                     sessionStorage.removeItem(backKey);
  246.                 }
  247.                 restoreDeliverySelectorUI();
  248.             });
  249.             window.addEventListener('popstate', () => scheduleBackFix('popstate'));
  250.             // Fallback: wenn Tab wieder sichtbar wird
  251.             document.addEventListener('visibilitychange', function () {
  252.                 if (document.visibilityState === 'visible') restoreDeliverySelectorUI();
  253.             });
  254.             // ===== Optional: Listing-Filter p=1 setzen =====
  255.             window.setfilter = function (name, value) {
  256.                 setCookie(name, value);
  257.                 const isListingPage = ({{ page.cmsPage.type|json_encode()|raw }}) === 'product_list';
  258.                 if (isListingPage) {
  259.                     location.href = updateURLParameter(window.location.href, 'p', 1);
  260.                 }
  261.             };
  262.         })();
  263.     </script>
  264. {% endblock %}
  265. {# Der Scroll-up-Button soll nur im Footer erscheinen #}
  266. {% block base_scroll_up %}
  267. {% endblock %}
  268. {% block base_pseudo_modal %}
  269.     {#    Muss in ein include sein und kein sw_include, da sonst Shopware die Original-Datei auch lädt und das
  270. Pseudo-Modal leine Blöcke zum Überschreiben hat für BFSG #}
  271.     {% include "@DreiwmBrandstetterPlugin/storefront/component/pseudo-modal.html.twig" %}
  272. {% endblock %}