PageSourceSearch

https://ecpr.eu/Scripts/cookieconsent-config.js?v=3

js ecpr.eu collected 2026-09-24 08:36:28 UTC 9,907 bytes, 204 lines download raw bytes

1import 'https://cdn.jsdelivr.net/gh/orestbida/[email protected]/dist/cookieconsent.umd.js';
2
3// Which services this instance actually runs, emitted server-side by ThirdPartyScripts
4// .CookieConsentScript() ahead of this module (e.g. APSA has no Google Ads, so it gets no
5// advertising category). Fall back to everything-on if the flags are missing: over-disclosing
6// is the safe failure direction for consent copy.
7var services = window.ecprConsent || { companyName: "", cookieName: "", cookieDomain: "", googleAnalytics: true, googleAds: true, microsoftClarity: true };
8
9// One consent cookie per deployment. Production sets cookieDomain to the registrable domain
10// (ecpr.eu) so a single cookie covers both the main site and events.ecpr.eu - without that, each
11// host writes its own copy, the older one shadows the newer on reads (document.cookie hides
12// domains), and the banner re-appears on every load. Test sites get a host-suffixed cookieName
13// (TestMode) so they neither read nor write production's cookie: consent never leaks between
14// environments. Blank domain = host-only (local dev, test sites).
15var cookieOptions = { name: services.cookieName || "site_consent" };
16if (services.cookieDomain) {
17    cookieOptions.domain = services.cookieDomain;
18}
19
20// Cookies each consent category is responsible for. GA/Clarity are analytics; the Google Ads
21// conversion linker (_gcl_*) is advertising. (Tawk.to live chat is click-to-load - user-requested,
22// so outside consent categories entirely.)
23var CATEGORY_COOKIE_PATTERNS = {
24    analytics: [/^_ga/, /^_clck/, /^_clsk/],
25    advertising: [/^_gcl/]
26};
27
28// GA writes _ga / _ga_* to the registrable domain (e.g. .ecpr.eu), which CookieConsent's autoClear
29// (scoped to location.hostname) can't delete. Expire the category's cookies across the current host and
30// every parent domain so withdrawal actually removes them on production, not just on localhost.
31function clearCategoryCookies(category) {
32    var patterns = CATEGORY_COOKIE_PATTERNS[category] || [];
33    var hostname = window.location.hostname;
34    var hostParts = hostname.split(".");
35    // "" = host-only (no domain attribute); the bare hostname covers cookies written with an explicit
36    // domain=<host> (e.g. localhost); the dotted suffixes cover the registrable domain GA uses (.ecpr.eu).
37    var domains = ["", hostname];
38    for (var i = 0; i < hostParts.length - 1; i++) {
39        domains.push("." + hostParts.slice(i).join("."));
40    }
41    document.cookie.split(";").forEach(function (entry) {
42        var name = entry.split("=")[0].trim();
43        if (!patterns.some(function (p) { return p.test(name); })) return;
44        domains.forEach(function (domain) {
45            document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/" +
46                (domain ? ";domain=" + domain : "");
47        });
48    });
49}
50
51// Google Consent Mode: the layouts queue a 'default: denied' before gtag.js loads; this sends the
52// matching 'update' whenever consent is granted or withdrawn. Analytics and advertising consent are
53// independent: GA storage follows the analytics category, the ad_* signals follow advertising (which,
54// when the instance runs no ads, simply never exists and so stays denied). On pages without GA the
55// gtag global doesn't exist, hence the guard.
56function updateGtagConsent() {
57    if (typeof window.gtag !== "function") return;
58    var analytics = CookieConsent.acceptedCategory("analytics") ? "granted" : "denied";
59    var advertising = CookieConsent.acceptedCategory("advertising") ? "granted" : "denied";
60    window.gtag("consent", "update", {
61        analytics_storage: analytics,
62        ad_storage: advertising,
63        ad_user_data: advertising,
64        ad_personalization: advertising
65    });
66}
67
68// --- Copy and structure assembled from the instance's services ---------------------------------
69
70var analyticsServiceNames = [];
71if (services.googleAnalytics) { analyticsServiceNames.push("Google Analytics"); }
72if (services.microsoftClarity) { analyticsServiceNames.push("Microsoft Clarity"); }
73
74var overviewDescription = "We use necessary cookies to make our site work."
75    + (analyticsServiceNames.length
76        ? " We'd also like to set analytics cookies that help us make improvements by measuring how you use the site"
77            + (services.googleAds ? ", and advertising cookies to measure the effectiveness of our advertising" : "")
78            + "."
79        : (services.googleAds ? " We'd also like to set advertising cookies to measure the effectiveness of our advertising." : ""))
80    + ((analyticsServiceNames.length || services.googleAds) ? " These will be set only if you accept." : "");
81
82var categories = {
83    necessary: {
84        readOnly: true
85    },
86    functionality: {},
87    analytics: {
88        autoClear: {
89            cookies: [
90                { name: /^_ga/ },
91                { name: /^_clck/ },
92                { name: /^_clsk/ }
93            ]
94        }
95    }
96};
97
98var sections = [
99    {
100        title: "Our use of cookies",
101        description: overviewDescription
102    },
103    {
104        title: "Strictly Necessary Cookies <span class=\"pm__badge\">Always Enabled</span>",
105        description: "Necessary cookies enable core functionality such as security, network management, and accessibility. You may disable these by changing your browser settings, but this may affect how the website functions.",
106        linkedCategory: "necessary"
107    }
108];
109
110if (analyticsServiceNames.length) {
111    sections.push({
112        title: "Analytics Cookies",
113        description: "We'd like to set " + analyticsServiceNames.join(" and ") + " cookies to help us improve our website by collecting and reporting information on how you use it. The cookies collect information in a way that does not directly identify anyone. For more information on how these cookies work please see our <a href='/Privacy'>Privacy Notice</a>.",
114        linkedCategory: "analytics"
115    });
116}
117
118if (services.googleAds) {
119    categories.advertising = {
120        autoClear: {
121            cookies: [
122                { name: /^_gcl/ }
123            ]
124        }
125    };
126    sections.push({
127        title: "Advertising Cookies",
128        description: "We'd like to set Google Ads cookies to measure the effectiveness of our advertising. Google may also use these cookies to personalise the ads you see on other websites. For more information on how these cookies work please see our <a href='/Privacy'>Privacy Notice</a>.",
129        linkedCategory: "advertising"
130    });
131}
132
133CookieConsent.run({
134    cookie: cookieOptions,
135    // Bumped when the consent scope changes (v1: advertising split out of analytics) so returning
136    // visitors are re-prompted and re-consent under the current category descriptions.
137    revision: 1,
138    // Accept-time sync. Without this, the only consent update gtag ever sees is the 'denied' pushed by
139    // the load-time sync below, and the user's acceptance does nothing until the next page load.
140    onFirstConsent: function () {
141        updateGtagConsent();
142    },
143    // Reactivating a blocked script (text/plain -> text/javascript) loads it, but withdrawal can't
144    // unload an already-running script (GA, Clarity keep sending hits until the page is gone). Reload
145    // on revocation so the scripts return to their blocked state and autoClear takes effect.
146    // The consent 'update: denied' must go first: it stops live gtag writing cookies, closing the race
147    // where GA re-set _ga_* between the delete and the reload.
148    onChange: function ({ changedCategories, cookie }) {
149        updateGtagConsent();
150        var revoked = ["analytics", "advertising"].filter(function (category) {
151            return changedCategories.includes(category) && !cookie.categories.includes(category);
152        });
153        if (revoked.length) {
154            revoked.forEach(clearCategoryCookies);
155            window.location.reload();
156        }
157    },
158    guiOptions: {
159        consentModal: {
160            layout: "bar",
161            position: "bottom",
162            equalWeightButtons: true,
163            flipButtons: true
164        },
165        preferencesModal: {
166            layout: "bar",
167            position: "right",
168            equalWeightButtons: false,
169            flipButtons: true
170        }
171    },
172    categories: categories,
173    language: {
174        default: "en",
175        autoDetect: "browser",
176        translations: {
177            en: {
178                consentModal: {
179                    title: "Our use of cookies",
180                    description: overviewDescription,
181                    acceptAllBtn: "Accept all",
182                    acceptNecessaryBtn: "Reject all",
183                    showPreferencesBtn: "Manage preferences",
184                    footer: "<a href='/Privacy'>Privacy Notice</a>"
185                        + (services.companyName ? "\n<a href='/'>" + services.companyName + "</a>" : "")
186                },
187                preferencesModal: {
188                    title: "Consent Preferences Center",
189                    acceptAllBtn: "Accept all",
190                    acceptNecessaryBtn: "Reject all",
191                    savePreferencesBtn: "Save preferences",
192                    closeIconLabel: "Close modal",
193                    serviceCounterLabel: "Service|Services",
194                    sections: sections
195                }
196            }
197        }
198    }
199}).then(function () {
200    // Sync gtag with the stored choice on every page load. Deliberately after run() resolves rather
201    // than in an onConsent callback: the callback proved unreliable on reloads with existing consent,
202    // leaving gtag stuck on the 'denied' defaults (hits sent with gcs=G100, no _ga cookies).
203    updateGtagConsent();
204});

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.