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