theme/templates/layouts/base.html.twig line 17

Open in your IDE?
  1. <!DOCTYPE html>
  2. <html lang="{% if languagecode is defined %}{{ languagecode.locale|default((app.request.getLocale()|default)) }}{% else %}{{ app.request.getLocale()|default }}{% endif %}">
  3. <head>
  4.     {% block head -%}
  5.         {%- include 'partials\\head.html.twig' -%}
  6.     {%- endblock %}
  7. </head>
  8. <body{% block body_class %}{%- endblock %}>
  9. {{ get_config('scripts_body',app.request.getLocale())|default|raw }}
  10. {{ scriptsbody|default|raw }}
  11. {% if is_authenticated_in_studio() %}
  12.     {% include 'admin\\adminbar.html.twig' %}
  13. {% endif %}
  14. {% block body %}
  15.     <div class="wrap">
  16.         {% block header %}
  17.             {% include 'partials\\variants\\' ~ get_config('header_style','') ~ '.html.twig' %}
  18.         {% endblock %}
  19.         {% if preview|default %}
  20.             <div class="mt-3 mx-4 alert alert-danger">
  21.                 {{ 'is_preview'|trans({},'pages') }}
  22.             </div>
  23.         {% endif %}
  24.         {% block breadcrumb %}
  25.             {% include 'partials\\breadcrumb.html.twig' %}
  26.         {% endblock %}
  27.         <main>
  28.             {% block content %}
  29.                 {{ blockscontent|default|raw }}
  30.             {% endblock %}
  31.         </main>
  32.         {% block footer %}
  33.             {% block pub_standard %}
  34.                 {% if hide_pub is not defined or hide_pub == false %}
  35.                     {% if is_ad_zone_active('standard') %}
  36.                         {% include 'partials/ads-banners/standard.html.twig' %}
  37.                     {% endif %}
  38.                 {% endif %}
  39.             {% endblock %}
  40.             {% block pubs %}
  41.                 {% if is_ad_zone_active('layer') %}
  42.                     {% include 'partials/ads-banners/layer.html.twig' %}
  43.                 {% endif %}
  44.                 {% if is_ad_zone_active('xtrad') %}
  45.                     {% include 'partials/ads-banners/xtrad.html.twig' %}
  46.                 {% endif %}
  47.                 {% if is_mobile() and is_ad_zone_active('splash') %}
  48.                     {% include 'partials/ads-banners/splash.html.twig' %}
  49.                 {% endif %}
  50.             {% endblock %}
  51.             {% include 'partials\\variants\\' ~ get_config('footer_style','') ~ '.html.twig' %}
  52.             {% if get_config('mobilebottombar',locale)|default %}
  53.                 {% include 'partials\\elements\\mobile-bar.twig' %}
  54.             {% endif %}
  55.         {% endblock %}
  56.     </div>
  57. {% endblock %}
  58. {% block cookies %}
  59.     {% if get_config('cookies_pages', '')|default
  60.         and (
  61.         (get_env('COOKIE_DATABASE_ENABLED') and studio.getCookie() is null)
  62.         or
  63.         (not get_env('COOKIE_DATABASE_ENABLED') and app.request.cookies.get(get_env('COOKIE_STD_NAME'),'') == '')
  64.         ) %}
  65.         {% set cookiepage=get_page_info(app.request.locale,get_config('cookies_pages','')) %}
  66.         <div id="cookies-modal" data-url="{{ cookiepage.url|default }}"
  67.              data-accept="{{ path('std_cookies_accept') }}"></div>
  68.     {% endif %}
  69. {% endblock %}
  70. {% block modalFlashes %}
  71.     {% set flashessuccess=app.flashes('success') %}
  72.     {% set flasheserror=app.flashes('error') %}
  73.     <div class="modal fade" id="modalMessages" tabindex="-1">
  74.         <div class="modal-dialog modal-dialog modal-dialog-centered" role="document">
  75.             <div class="modal-content">
  76.                 <div class="modal-body">
  77.                     <button type="button" class="close-modal ml-auto" data-dismiss="modal" aria-label="Close">
  78.                         <span aria-hidden="true">×</span>
  79.                     </button>
  80.                     <div class="js-modal-messages-content">
  81.                         {% for message in flashessuccess %}
  82.                             {{ message|html_entity_decode|raw }}
  83.                         {% endfor %}
  84.                         {% for message in flasheserror %}
  85.                             {{ message|html_entity_decode|raw }}
  86.                         {% endfor %}
  87.                     </div>
  88.                 </div>
  89.             </div>
  90.         </div>
  91.     </div>
  92. {% endblock %}
  93. {% block scripts %}
  94.     {# ============================
  95.        Publicidade – Provider Loader
  96.        ============================ #}
  97.     {% set adsProvider = get_config('ads_provider', '')|default('none') %}
  98.     {% set adsScripts = get_config('ads_scripts', '')|default('') %}
  99.     {% if adsProvider == 'studio' %} 
  100.         <script src="/build/assets/js/ads-banners.js"></script>
  101.     {%elseif adsScripts is defined and adsScripts != '' and adsProvider!='none' %}
  102.         {{ adsScripts|raw }}
  103.     {% endif %} 
  104.     {% include 'partials\\scripts.html.twig' %}
  105.     {% set webpackEntries=app.request.attributes.get('webpackEntries')|default([]) %}
  106.     {% if get_config('notificationsbar_page', '')|default %}
  107.         {% set webpackEntries=webpackEntries|merge(['B31_notificationsbar']) %}
  108.     {% endif %}
  109.     {% set webpackEntries=webpackEntries|merge(['slick-carousel']) %}
  110.     {% if get_config('newsletterblock_page', '')|default %}
  111.         {% set webpackEntries=webpackEntries|merge(['validation_messages_' ~ locale]) %}
  112.         {% set webpackEntries=webpackEntries|merge(['B32_newsletter']) %}
  113.     {% endif %}
  114.     {% if webpackEntries is defined %}
  115.         {% for entry in webpackEntries %}
  116.             {{ encore_entry_script_tags(entry) }}
  117.         {% endfor %}
  118.     {% endif %}
  119. {% endblock %}
  120. <script type="text/javascript">
  121.     {% block javascripts %}
  122.     {{ blockscontentjs|raw }}
  123.     {% if scripts_tracking_precise is defined and scripts_tracking_precise is same as(true) %}
  124.     document.addEventListener("DOMContentLoaded", function () {
  125.         function getCookie(name) {
  126.             const value = `; ${document.cookie}`;
  127.             const parts = value.split(`; ${name}=`);
  128.             if (parts.length === 2) return parts.pop().split(';').shift();
  129.         }
  130.         // Calculate distance between two coordinates in km (Haversine formula)
  131.         function haversineDistance(lat1, lon1, lat2, lon2) {
  132.             const R = 6371; // Earth's radius in km
  133.             const dLat = (lat2 - lat1) * Math.PI / 180;
  134.             const dLon = (lon2 - lon1) * Math.PI / 180;
  135.             const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
  136.                       Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
  137.                       Math.sin(dLon/2) * Math.sin(dLon/2);
  138.             const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  139.             return R * c;
  140.         }
  141.         const LOCATION_VERIFY_INTERVAL = 10 * 60 * 1000;
  142.         let locationVerifyTimer = null;
  143.         function verifyLocationWithBackend() {
  144.             if (!("geolocation" in navigator)) return;
  145.             
  146.             const lastLat = localStorage.getItem('lastLocationLat');
  147.             const lastLon = localStorage.getItem('lastLocationLon');
  148.             if (!lastLat || !lastLon) return;
  149.             
  150.             navigator.geolocation.getCurrentPosition(
  151.                 function(position) {
  152.                     const latitude = position.coords.latitude;
  153.                     const longitude = position.coords.longitude;
  154.                     
  155.                     {% if use_geo_map_tracking is defined and use_geo_map_tracking is same as(true) %}
  156.                     fetch(`/geo-location/verify?lon=${longitude}&lat=${latitude}`)
  157.                         .then(res => res.json())
  158.                         .then(data => {
  159.                             if (data.needs_update) {
  160.                                 fetch(`/geo-location/accept?lon=${longitude}&lat=${latitude}&distance=500`)
  161.                                     .then(res => res.json())
  162.                                     .then(updateData => {
  163.                                         if (!updateData.error) {
  164.                                             localStorage.setItem('lastLocationLat', latitude.toString());
  165.                                             localStorage.setItem('lastLocationLon', longitude.toString());
  166.                                             localStorage.setItem('lastLocationVerify', Date.now().toString());
  167.                                             location.reload();
  168.                                         }
  169.                                     })
  170.                                     .catch(err => console.error('[Location Verify] Update error:', err));
  171.                             } else {
  172.                                 localStorage.setItem('lastLocationVerify', Date.now().toString());
  173.                             }
  174.                         })
  175.                         .catch(() => {});
  176.                     {% endif %}
  177.                 },
  178.                 function() {},
  179.                 { enableHighAccuracy: false, timeout: 15000, maximumAge: 60000 }
  180.             );
  181.         }
  182.         function startLocationVerification() {
  183.             if (locationVerifyTimer) clearInterval(locationVerifyTimer);
  184.             locationVerifyTimer = setInterval(verifyLocationWithBackend, LOCATION_VERIFY_INTERVAL);
  185.             
  186.             document.addEventListener('visibilitychange', function() {
  187.                 if (document.visibilityState === 'visible') {
  188.                     const lastVerify = parseInt(localStorage.getItem('lastLocationVerify') || '0');
  189.                     if (Date.now() - lastVerify > 5 * 60 * 1000) verifyLocationWithBackend();
  190.                 }
  191.             });
  192.         }
  193.         if (localStorage.getItem('lastLocationLat') && localStorage.getItem('lastLocationLon')) {
  194.             startLocationVerification();
  195.         }
  196.         function updateLocationSilently() {
  197.             if (!("geolocation" in navigator)) return;
  198.             
  199.             navigator.geolocation.getCurrentPosition(
  200.                 function (position) {
  201.                     const longitude = position.coords.longitude;
  202.                     const latitude = position.coords.latitude;
  203.                     const distance = 500;
  204.                     const lastLat = parseFloat(localStorage.getItem('lastLocationLat'));
  205.                     const lastLon = parseFloat(localStorage.getItem('lastLocationLon'));
  206.                     
  207.                     if (!isNaN(lastLat) && !isNaN(lastLon)) {
  208.                         const distanceMoved = haversineDistance(lastLat, lastLon, latitude, longitude);
  209.                         if (distanceMoved <= 1) return; // Haven't moved much, skip update
  210.                     }
  211.                     {% if use_geo_map_tracking is defined and use_geo_map_tracking is same as(true) %}
  212.                     fetch(`/geo-location/accept?lon=${longitude}&lat=${latitude}&distance=${distance}`)
  213.                         .then(res => res.json())
  214.                         .then(data => {
  215.                             if (!data.error) {
  216.                                 localStorage.setItem('lastLocationLat', latitude.toString());
  217.                                 localStorage.setItem('lastLocationLon', longitude.toString());
  218.                                 localStorage.setItem('lastLocationVerify', Date.now().toString());
  219.                                 localStorage.removeItem('locationReloaded'); 
  220.                             }
  221.                         })
  222.                         .catch(() => {});
  223.                     {% endif %}
  224.                 },
  225.                 function () {},
  226.                 {enableHighAccuracy: true, timeout: 10000, maximumAge: 0}
  227.             );
  228.         }
  229.         // Removed duplicate visibilitychange listener - now handled by startLocationVerification()
  230.         let cookieConsentGiven = false;
  231.         let locationAsked = false;
  232.         
  233.         function askLocationOnce() {
  234.             if (locationAsked) return;
  235.             if (localStorage.getItem('locationReloaded')) return;
  236.             locationAsked = true;
  237.             cookieConsentGiven = true;
  238.             clearInterval(intervalId);
  239.             tryAskLocation();
  240.         }
  241.         
  242.         function checkForExistingConsent() {
  243.             // Check localStorage for AdOpt consent (most reliable method)
  244.             const adoptConsent = localStorage.getItem('adopt-consent');
  245.             if (adoptConsent) {
  246.                 askLocationOnce();
  247.                 return true;
  248.             }
  249.             
  250.             // Check if banner is not present (consent already given on previous visit)
  251.             const banner = document.getElementById('cookie-banner');
  252.             if (!banner) {
  253.                 // Wait a bit for banner to potentially load
  254.                 setTimeout(function() {
  255.                     const bannerCheck = document.getElementById('cookie-banner');
  256.                     if (!bannerCheck) {
  257.                         askLocationOnce();
  258.                     }
  259.                 }, 2000);
  260.             }
  261.             return false;
  262.         }
  263.         
  264.         function setupCookieBannerListeners() {
  265.             // Listen for AdOpt custom events
  266.             window.addEventListener('adopt:consent', function() {
  267.                 askLocationOnce();
  268.             });
  269.             
  270.             // Listen for localStorage changes (AdOpt stores consent there)
  271.             window.addEventListener('storage', function(e) {
  272.                 if (e.key === 'adopt-consent' && e.newValue) {
  273.                     askLocationOnce();
  274.                 }
  275.             });
  276.             
  277.             document.addEventListener('click', function(e) {
  278.                 const target = e.target;
  279.                 if (target.id === 'adopt-accept-all-button' || 
  280.                     target.id === 'adopt-reject-all-button' ||
  281.                     target.closest('#adopt-accept-all-button') ||
  282.                     target.closest('#adopt-reject-all-button')) {
  283.                     // Small delay to let AdOpt process
  284.                     setTimeout(askLocationOnce, 500);
  285.                 }
  286.             });
  287.             
  288.             const observeBody = new MutationObserver(function(mutations) {
  289.                 mutations.forEach(function(mutation) {
  290.                     mutation.removedNodes.forEach(function(node) {
  291.                         if (node.id === 'cookie-banner' || (node.querySelector && node.querySelector('#cookie-banner'))) {
  292.                             setTimeout(askLocationOnce, 300);
  293.                             observeBody.disconnect();
  294.                         }
  295.                     });
  296.                 });
  297.             });
  298.             observeBody.observe(document.body, { childList: true, subtree: true });
  299.         }
  300.         function tryAskLocation() {
  301.             // if (localStorage.getItem('locationReloaded')) {
  302.             //     return;
  303.             // }
  304.             
  305.             //{#const analyticsCookie = getCookie('{{ get_env("COOKIE_STD_ANALYTICS_NAME") }}');#}
  306.             // if (analyticsCookie === 'accepted') {
  307.                 if ("geolocation" in navigator) {
  308.                     navigator.geolocation.getCurrentPosition(
  309.                         function (position) {
  310.                             const longitude = position.coords.longitude;
  311.                             const latitude = position.coords.latitude;
  312.                             const distance = 500;
  313.                             // Check if user has moved significantly since last location update
  314.                             const lastLat = parseFloat(localStorage.getItem('lastLocationLat'));
  315.                             const lastLon = parseFloat(localStorage.getItem('lastLocationLon'));
  316.                             const locationReloaded = localStorage.getItem('locationReloaded');
  317.                             
  318.                             let shouldUpdate = !locationReloaded;
  319.                             
  320.                             // If we have previous coordinates, check if user moved > 1km
  321.                             if (locationReloaded && !isNaN(lastLat) && !isNaN(lastLon)) {
  322.                                 const distanceMoved = haversineDistance(lastLat, lastLon, latitude, longitude);
  323.                                 if (distanceMoved > 1) { // More than 1km
  324.                                     shouldUpdate = true;
  325.                                     localStorage.removeItem('locationReloaded');
  326.                                 }
  327.                             }
  328.                             {% if use_api_tracking is defined and use_api_tracking is same as(true) %}
  329.                             fetch(`https://api.bigdatacloud.net/data/reverse-geocode-client?latitude=${latitude}&longitude=${longitude}&localityLanguage=pt-PT`)
  330.                                 .then(res => res.json())
  331.                                 .then(data => {
  332.                                     const country = data.countryName;
  333.                                     const principalSubdivision = data.principalSubdivision;
  334.                                     const city = data.city;
  335.                                     const locality = data.locality;
  336.                                     localStorage.setItem('locations', country || '');
  337.                                     localStorage.setItem('municipality', principalSubdivision || '');
  338.                                     localStorage.setItem('city', city || '');
  339.                                     localStorage.setItem('locality', locality || '');
  340.                                     fetch('/ip-geo-location/accept', {
  341.                                         method: 'POST',
  342.                                         headers: {'Content-Type': 'application/json'},
  343.                                         body: JSON.stringify({country, city})
  344.                                     });
  345.                                 });
  346.                             {% endif %}
  347.                             {% if use_geo_map_tracking is defined and use_geo_map_tracking is same as(true) %}
  348.                             fetch(`/geo-location/accept?lon=${longitude}&lat=${latitude}&distance=${distance}`)
  349.                                 .then(res => res.json())
  350.                                 .then(data => {
  351.                                     if (!data.error) {
  352.                                         // Store current coordinates for future comparison
  353.                                         localStorage.setItem('lastLocationLat', latitude.toString());
  354.                                         localStorage.setItem('lastLocationLon', longitude.toString());
  355.                                         localStorage.setItem('lastLocationVerify', Date.now().toString());
  356.                                         
  357.                                         // Start periodic location verification
  358.                                         startLocationVerification();
  359.                                         
  360.                                         if (shouldUpdate) {
  361.                                             localStorage.setItem('locationReloaded', 'true');
  362.                                             location.reload();
  363.                                         }
  364.                                     } else {
  365.                                         console.error('Erro:', data.error);
  366.                                     }
  367.                                 })
  368.                                 .catch(err => {
  369.                                     console.error('Erro na requisição:', err);
  370.                                 });
  371.                             {% endif %}
  372.                         },
  373.                         function (error) {
  374.                             if (error.code === error.PERMISSION_DENIED) {
  375.                                 localStorage.removeItem('locationReloaded');
  376.                                 localStorage.removeItem('lastLocationLat');
  377.                                 localStorage.removeItem('lastLocationLon');
  378.                             }
  379.                             console.error("Error getting location:", error.message);
  380.                         },
  381.                         {enableHighAccuracy: true, timeout: 120000, maximumAge: 0}
  382.                     );
  383.                 } else {
  384.                     console.log("Geolocation is not supported by this browser.");
  385.                 }
  386.             // } else if (analyticsCookie !== undefined && analyticsCookie !== '' && analyticsCookie !== 'accepted') {
  387.             //     clearInterval(intervalId);
  388.             // }
  389.         }
  390.         // Setup listeners for cookie consent
  391.         setupCookieBannerListeners();
  392.         
  393.         const intervalId = setInterval(function() {
  394.             if (checkForExistingConsent()) {
  395.                 clearInterval(intervalId);
  396.             }
  397.         }, 1000);
  398.         
  399.         // Initial check
  400.         checkForExistingConsent();
  401.     });
  402.     {% endif %}
  403.     {% endblock %}
  404. </script>
  405. {{ get_config('scripts_footer',app.request.getLocale())|default|raw }}
  406. {{ scriptsfooter|default|raw }}
  407. </body>
  408. </html>