PageSourceSearch

https://www.royalblackheath.com/javascript/cookie-consent.js

js royalblackheath.com collected 2026-10-02 10:30:51 UTC 6,080 bytes, 162 lines download raw bytes

1/**
2 * GDPR Cookie Consent Banner
3 * Provides Accept All / Necessary Only / Decline options
4 * Stores consent level in cc_cookie_consent cookie
5 */
6(function () {
7  'use strict';
8
9  // The consent cookie (cc_cookie_consent) is HttpOnly + Secure and is only ever
10  // written server-side (backend.php?action=setGDPRCookie). It is never read or
11  // written from JS. The current level is delivered inline at page render time
12  // via window.__ccConsentLevel and kept up to date in memory after a choice.
13
14  function getConsent() {
15    return window.__ccConsentLevel || null;
16  }
17
18  // Persist the chosen level server-side; onDone (optional) fires when the
19  // HttpOnly cookie has been committed.
20  function setConsent(level, onDone) {
21    window.__ccConsentLevel = level;
22
23    var xhr = new XMLHttpRequest();
24    xhr.open('GET', '/backend.php?action=setGDPRCookie&level=' + encodeURIComponent(level), true);
25    if (onDone) {
26      xhr.onreadystatechange = function () {
27        if (xhr.readyState === 4) onDone();
28      };
29    }
30    xhr.send();
31  }
32
33  function removeAnalyticsCookies() {
34    var hostname = window.location.hostname;
35    var secure = location.protocol === 'https:' ? ';secure' : '';
36    // Build list of domains to try: hostname, .hostname, and parent domain levels
37    // e.g. for club.intelligentgolf.co.uk: try .club.intelligentgolf.co.uk, .intelligentgolf.co.uk, .co.uk
38    var domains = ['', '.' + hostname];
39    var parts = hostname.split('.');
40    for (var d = 1; d < parts.length - 1; d++) {
41      domains.push('.' + parts.slice(d).join('.'));
42    }
43    // Known GA cookie names
44    var gaCookies = ['_ga', '_gid', '_gat', '__utma', '__utmb', '__utmc', '__utmz'];
45    // Also find any _ga_XXXXX cookies (GA4 measurement ID cookies)
46    var allCookies = document.cookie.split(';');
47    for (var j = 0; j < allCookies.length; j++) {
48      var name = allCookies[j].split('=')[0].trim();
49      if (name.indexOf('_ga_') === 0 && gaCookies.indexOf(name) === -1) {
50        gaCookies.push(name);
51      }
52    }
53    var expired = '=;expires=Thu, 01 Jan 1970 00:00:00 GMT';
54    for (var i = 0; i < gaCookies.length; i++) {
55      for (var k = 0; k < domains.length; k++) {
56        var domainPart = domains[k] ? ';domain=' + domains[k] : '';
57        document.cookie = gaCookies[i] + expired + ';path=/' + domainPart;
58        document.cookie = gaCookies[i] + expired + ';path=/' + domainPart + secure;
59      }
60    }
61  }
62
63  function hideBanner() {
64    var banner = document.getElementById('cc-consent-banner');
65    if (banner) {
66      banner.style.opacity = '0';
67      setTimeout(function () {
68        banner.parentNode.removeChild(banner);
69      }, 300);
70    }
71  }
72
73  // Tracks what consent was before the settings panel was opened
74  var _previousLevel = null;
75
76  function handleConsent(level) {
77    var previousLevel = _previousLevel || getConsent();
78    _previousLevel = null;
79    // If changing away from 'all', reload to stop already-loaded GA scripts.
80    // Wait for the server to commit the HttpOnly cookie before reloading so the
81    // reloaded page sees the new consent level.
82    var needsReload = previousLevel === 'all' && level !== 'all';
83    setConsent(level, needsReload ? function () { window.location.reload(); } : null);
84    if (level !== 'all') {
85      removeAnalyticsCookies();
86    }
87    if (!needsReload) {
88      hideBanner();
89    }
90  }
91
92  function showBanner(policyLink) {
93    // Don't show if consent already given
94    if (getConsent()) return;
95
96    var banner = document.createElement('div');
97    banner.id = 'cc-consent-banner';
98    banner.className = 'cc-consent-banner';
99    banner.setAttribute('role', 'dialog');
100    banner.setAttribute('aria-label', 'Cookie consent');
101
102    banner.innerHTML =
103      '<div class="cc-consent-content">' +
104        '<p class="cc-consent-message">' +
105          'We use cookies to ensure the website works correctly and to improve your experience. ' +
106          'Some cookies are essential for the site to function, while others help us understand how you use the site. ' +
107          '<a href="' + policyLink + '" class="cc-consent-link">Read our cookie policy</a>' +
108        '</p>' +
109        '<div class="cc-consent-buttons">' +
110          '<button type="button" class="cc-btn cc-btn-accept" data-consent="all">Accept All</button>' +
111          '<button type="button" class="cc-btn cc-btn-necessary" data-consent="necessary">Necessary Only</button>' +
112          '<button type="button" class="cc-btn cc-btn-decline" data-consent="declined">Decline All</button>' +
113        '</div>' +
114      '</div>';
115
116    document.body.appendChild(banner);
117
118    // Force reflow then show
119    banner.offsetHeight;
120    banner.style.opacity = '1';
121
122    // Bind button clicks
123    var buttons = banner.querySelectorAll('.cc-btn');
124    for (var i = 0; i < buttons.length; i++) {
125      buttons[i].addEventListener('click', function () {
126        handleConsent(this.getAttribute('data-consent'));
127      });
128    }
129  }
130
131  function showSettingsPanel(policyLink) {
132    // Remove existing if present
133    var existing = document.getElementById('cc-consent-banner');
134    if (existing) existing.parentNode.removeChild(existing);
135
136    // Remember current level before clearing, so handleConsent knows whether to reload
137    _previousLevel = getConsent();
138
139    // Clear the in-memory consent so the banner shows. The server cookie is
140    // overwritten once the user makes a new choice (cannot be cleared from JS
141    // as it is HttpOnly).
142    window.__ccConsentLevel = null;
143
144    showBanner(policyLink);
145  }
146
147  // On page load, clean up any analytics cookies that shouldn't be present
148  // This catches cookies re-set by GA scripts during the reload race
149  var currentConsent = getConsent();
150  if (currentConsent && currentConsent !== 'all') {
151    removeAnalyticsCookies();
152  }
153
154  // Public API
155  window.CookieConsent = {
156    show: showBanner,
157    showSettings: showSettingsPanel,
158    getLevel: getConsent,
159    hasConsented: function () { return getConsent() !== null; },
160    analyticsAllowed: function () { return getConsent() === 'all'; }
161  };
162})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.