1/* global CookieControl */ 2/* eslint-disable */ 3 4/** 5 * Civic CookieControl reads its `CookieControl` cookie and runs an UNGUARDED 6 * JSON.parse on the value during load(). A corrupt cookie (truncated, wrong 7 * format, junk prepended) therefore throws, and because it happens inside the 8 * library's own promise chain a try/catch around CookieControl.load() cannot 9 * catch it. The only reliable fix is to detect a bad cookie and delete it 10 * BEFORE calling load(), so the value never reaches the parser. 11 */ 12 13// Read a single cookie's raw (still url-encoded) value from a cookie string. 14// The (?:^|;\s*) boundary stops us matching a cookie whose NAME merely ends in 15// the target name (e.g. XCookieControl). The caller passes document.cookie, 16// which a privacy extension can hand back as undefined even when 17// navigator.cookieEnabled reports true, so an absent string is not an error. 18function getCookieValue(cookieString, name) { 19 if (!cookieString) return undefined; 20 var match = cookieString.match(new RegExp('(?:^|;\\s*)' + name + '=([^;]*)')); 21 return match ? match[1] : undefined; 22} 23 24// Validate the cookie the way load() needs it. An absent cookie is fine (load() 25// handles "no stored consent"). Otherwise the value must decode, parse as JSON, 26// AND be a non-empty plain object, which is the shape Cookie Control expects. 27// Valid JSON that is a primitive (e.g. a bare number), an array, or an empty 28// object still crashes load() when it reads properties off it, so those are 29// treated as bad. 30function isValidCookie(raw) { 31 if (raw === undefined) return true; 32 var value; 33 try { 34 value = JSON.parse(decodeURIComponent(raw)); 35 } catch (e) { 36 return false; 37 } 38 return ( 39 typeof value === 'object' && 40 value !== null && 41 !Array.isArray(value) && 42 Object.keys(value).length > 0 43 ); 44} 45 46// Every domain scope a CookieControl cookie could live on for the given host. 47// With subDomains:true the cookie is written to the registrable domain 48// (.shelter.org.uk), but on localhost / Netlify previews it is host-only. A 49// delete only works if its domain matches how the cookie was set, so we cover 50// every suffix of the current host.
51function cookieClearDomains(host) { 52 var domains = ['', host, '.' + host]; // '' = host-only (localhost / preview case) 53 var parts = host.split('.'); 54 for (var i = 1; i < parts.length - 1; i++) { 55 domains.push('.' + parts.slice(i).join('.')); // .shelter.org.uk, etc. 56 } 57 return domains; 58} 59 60// Expire the CookieControl cookie across every plausible domain scope. 61function clearCookieControlCookie() { 62 var base = 'CookieControl=; Max-Age=0; path=/'; 63 cookieClearDomains(window.location.hostname).forEach(function (d) { 64 document.cookie = base + (d ? '; domain=' + d : ''); 65 }); 66} 67 68(function () { 69 if (!window.dataLayer) window.dataLayer = []; 70 71 var onRevokeCategory = function () { 72 CookieControl.cookieCategoryRevokedNeedRefresh = true; 73 }; 74 75 function gtag() { 76 dataLayer.push(arguments); 77 } 78 79 gtag('consent', 'default', { 80 ad_storage: 'denied', 81 analytics_storage: 'denied', 82 ad_user_data: 'denied', 83 ad_personalization: 'denied', 84 functionality_storage: 'granted', 85 security_storage: 'granted', 86 }); 87 88 var cookiePolicyUrl = 89 window.location.host.indexOf('scot') !== -1 90 ? 'https://scotland.shelter.org.uk/about_us/about_this_website/cookies' 91 : 'https://england.shelter.org.uk/contact_us/cookies'; 92 93 var ccConfig = { 94 apiKey: '10a22203c863d759dabbeb158635f6193b03a3ea', 95 branding: { 96 fontFamily: 97 'Barlow, -apple-system, BlinkMacSystemFont, Roboto, sans-serif', 98 fontSizeTitle: '1.5em', 99 fontSizeHeaders: '1.3em', 100 fontSize: '0.9em', 101 fontColor: '#333', 102 notifyFontColor: '#FFF', 103 backgroundColor: '#FFF', 104 notifyBackgroundColor: '#262626', 105 acceptText: '#FFF', 106 acceptBackground: '#EB001F', 107 rejectText: '#333', 108 rejectBackground: '#FFF', 109 closeBackground: '#262626', 110 toggleText: '#FFF', 111 toggleColor: '#FFF',
112 toggleBackground: '#262626', 113 removeAbout: true, 114 removeIcon: true, 115 }, 116 notifyDismissButton: false, 117 closeStyle: 'button', 118 consentCookieExpiry: 365, 119 initialState: 'notify', 120 layout: 'slideout', 121 position: 'left', 122 logConsent: true, 123 product: 'PRO_MULTISITE', 124 setInnerHTML: true, 125 statement: { 126 updated: '14/10/2021', 127 }, 128 subDomains: true, 129 text: { 130 title: 'Help us improve your experience with Shelter', 131 intro: 132 'Cookies are needed for us to understand how our visitors use our website. By accepting our recommended cookies, youâre helping improve this website for everyone, and your own experience.<br/><br/> You can change your cookie settings and find more information on our <a href=' + 133 cookiePolicyUrl + 134 ' style="color:#336DF5!important;">cookie policy page</a>.', 135 136 acceptSettings: 'I accept cookies', 137 rejectSettings: 'I reject cookies', 138 closeLabel: 'Save and close', 139 necessaryTitle: 'Necessary', 140 necessaryDescription: 141 'Our website needs these to run. You can only turn them off using your browser settings.', 142 notifyTitle: 'Help us improve your experience with Shelter', 143 notifyDescription: 144 'By accepting our recommended cookies, you will help us improve your own experience by remembering your settings', 145 accept: 'I accept cookies', 146 reject: 'I reject cookies', 147 settings: 'Cookie settings', 148 }, 149 theme: 'dark',
150 necessaryCookies: [ 151 'DntSession', 152 'has_js', 153 'SnapABugChatSession', 154 'SnapABugNoProactiveChat', 155 'SnapABugChatPoll', 156 'SnapABugChatView', 157 'SnapABugBanned', 158 'SnapABugChatWindow', 159 'SnapABugMinimizeStashCookie', 160 'SnapABugAgentAvatar', 161 'SnapABugApproval', 162 'SnapABugChatMessage', 163 'SnapABugHistory', 164 'SnapABugRef', 165 'SnapABugUserAlias', 166 'SnapABugUserEmail', 167 'SnapABugVisit', 168 '_GRECAPTCHA', 169 '_secure_session_id', 170 '_shopify_country', 171 '_shopify_m', 172 '_shopify_tm', 173 '_shopify_tw', 174 '_storefront_u', 175 '_tracking_consent', 176 'c', 177 'cart', 178 'cart_currency', 179 'cart_sig', 180 'cart_ts', 181 'cart_ver', 182 'checkout', 183 'checkout_token', 184 'dynamic_checkout_shown_on_cart', 185 'hide_shopify_pay_for_checkout', 186 'keep_alive', 187 'master_device_id', 188 'previous_step', 189 'remember_me', 190 'secure_customer_sig', 191 'shopify_pay', 192 'shopify_pay_redirect', 193 'storefront_digest', 194 'tracked_start_checkout', 195 'javascript', 196 'starvale_session', 197 'webform-*', 198 '_landing_page', 199 '_orig_referrer', 200 'exp_*', 201 '__stripe_sid', 202 '__stripe_mid', 203 'dnt_amount', 204 'dnt_coords', 205 'checkout_one_experiment', 206 'checkout_session_lookup', 207 'checkout_session_token_*', 208 '_checkout_queue_checkout_token', 209 '_checkout_queue_token', 210 'preview_theme', 211 'SSESSed*', 212 'split_test_*', 213 ], 214 optionalCookies: [ 215 { 216 name: 'functional', 217 label: 'Functional', 218 description: 'This helps each part of our website work properly.', 219 cookies: [ 220 'adiLP', 221 '__adiCookieCheck', 222 'adiErr', 223 'adiS', 224 'adiV', 225 'adiVi', 226 'JSESSIONID', 227 'localization', 228 ], 229 onAccept: function () { 230 window.dataLayer.push({ 231 civic_cookies_functional: 'consent_given', 232 event: 'functional_consent_given', 233 }); 234 }, 235 onRevoke: function () { 236 window.dataLayer.push({ 237 civic_cookies_functional: 'consent_revoked', 238 }); 239 onRevokeCategory(); 240 }, 241 }, 242 { 243 name: 'analytics', 244 label: 'Analytics', 245 description: 246 'This improves our website by collecting anonymous information on how people use it.', 247 cookies: [ 248 'ethnio_displayed', 249 '_ga*', 250 'gcl_au', 251 '_gid', 252 'DV', 253 '_BEAMER_FIRST_VISIT_*', 254 '_BEAMER_LAST_UPDATE_*', 255 '_BEAMER_USER_ID_*', 256 '_hjAbsoluteSessionInProgress', 257 '_hjFirstSeen', 258 '_hjid', 259 '_hjIncludedInPageviewSample', 260 '_hjIncludedInSessionSample', 261 '_hjKB', 262 '_hjMinimizedPolls', 263 'ajs_anonymous_id', 264 'ajs_user_id', 265 'shelterEmployee', 266 'VISITOR_INFO1_LIVE', 267 'webform_tracking', 268 'YSC', 269 '_s', 270 '_shopify_d', 271 '_shopify_s', 272 '_shopify_sa_p', 273 '_shopify_sa_t', 274 '_shopify_y', 275 '_y', 276 '_shopify_evids', 277 'nf_ab', 278 '_clck', 279 '_clsk', 280 'check', 281 '_hjSessionRejected', 282 '_hjSession_*', 283 '_hjSessionUser_*', 284 '_gat_*', 285 '_shopify_ga', 286 '__Secure-ENID', 287 'AEC', 288 'survey_user_id', 289 ], 290 onAccept: function () { 291 gtag('consent', 'update', { analytics_storage: 'granted' }); 292 window.dataLayer.push({ 293 civic_cookies_analytics: 'consent_given', 294 event: 'analytics_consent_given', 295 }); 296 297 if (window.generateSurveyId) window.generateSurveyId(); 298 299 // If the current site is Impact Stack 300 var subDomain = window.location.host.split('.')[0]; 301 if (subDomain === 'act' || subDomain === 'campaigns') { 302 document.dispatchEvent(new Event('analytics_consent_given')); 303 } 304 }, 305 onRevoke: function () { 306 gtag('consent', 'update', { analytics_storage: 'denied' }); 307 window.dataLayer.push({ 308 civic_cookies_analytics: 'consent_revoked', 309 }); 310 onRevokeCategory(); 311 }, 312 }, 313 { 314 name: 'marketing', 315 label: 'Marketing', 316 description: 317 'By accepting our marketing cookies, you give Google products such as Google Analytics and Google Ads permission to gather data, to help us improve your online experience. They also send information to our social media channels for marketing purposes', 318 cookies: [ 319 'anj', 320 'uuid2', 321 'IDE', 322 '_fbp', 323 'c_user', 324 'datr', 325 'fr', 326 'sb', 327 'spin', 328 'xs', 329 '__Secure-1PAPISID', 330 '__Secure-1PSID', 331 '1P_JAR', 332 'AID', 333 'APISID', 334 'CONSENT', 335 'HSID', 336 'OGPC', 337 'OTZ', 338 'SAPISID', 339 'SEARCH_SAMESITE', 340 'SID', 341 'SIDCC', 342 'outbrain_cid_fetch', 343 'obuid', 344 'auid', 345 '_pin_unauth', 346 '_pinterest_ct_ua', 347 '_pinterest_sess', 348 '_pinterest_ct', 349 '_epik', 350 '_derived_epik', 351 '_scid', 352 'sc_at', 353 'X-AB', 354 'tt_csrf_token', 355 'tt_webid', 356 'tt_webid_v2', 357 'ct0', 358 'guest_id', 359 'personalization_id', 360 '__Secure-3PAPISID', 361 '__Secure-3PSID', 362 '__Secure-3PSIDCC', 363 'LOGIN_INFO', 364 'PREF', 365 'SSID', 366 '_gcl_au',
367 'cookie-consent', 368 'ttwid', 369 'NID', 370 'MUID', 371 '_uetsid', 372 '_uetvid', 373 'ndclid', 374 '_uetsid_exp', 375 '_uetvid_exp', 376 '_tt_enable_cookie', 377 '_ttp', 378 '_rdt_uuid', 379 '_sctr', 380 '_tt_sessionId', 381 ], 382 onAccept: function () { 383 gtag('consent', 'update', { 384 ad_storage: 'granted', 385 ad_personalization: 'granted', 386 ad_user_data: 'granted', 387 }); 388 window.dataLayer.push({ 389 civic_cookies_marketing: 'consent_given', 390 event: 'marketing_consent_given', 391 }); 392 }, 393 onRevoke: function () { 394 gtag('consent', 'update', { 395 ad_storage: 'denied', 396 ad_user_data: 'denied', 397 ad_personalization: 'denied', 398 }); 399 window.dataLayer.push({ 400 civic_cookies_marketing: 'consent_revoked', 401 }); 402 onRevokeCategory(); 403 }, 404 }, 405 ], 406 }; 407 408 if (navigator.cookieEnabled) { 409 var headTag = document.getElementsByTagName('head')[0]; 410 411 var ccScript = document.createElement('script'); 412 ccScript.src = 413 'https://cc.cdn.civiccomputing.com/9/cookieControl-9.x.min.js'; 414 415 ccScript.addEventListener('load', function () { 416 // If the stored cookie is invalid, remove it so load() starts from a 417 // clean slate and the banner re-shows. Healthy cookies are left untouched. 418 if (!isValidCookie(getCookieValue(document.cookie, 'CookieControl'))) { 419 clearCookieControlCookie(); 420 } 421 422 // The load event fires even when the CDN answers with a non-script body, 423 // so the library may not exist. Deliberately below the cookie handling, 424 // which still has to run. No banner means consent stays denied. 425 if (typeof CookieControl === 'undefined') return; 426 427 CookieControl.load(ccConfig); 428 }); 429 430 headTag.appendChild(ccScript); 431 432 // The styles below are hardcoded overrides that ensure the consent banner 433 // displays correctly across the third-party platforms that load this file 434 // (e.g. iRaiser, Shelter Shop), where the host page's own CSS would 435 // otherwise interfere with Cookie Control's default styling. 436 var ccStyle = document.createElement('style'); 437 438 const acceptBtn = '#ccc .ccc-notify-button.ccc-accept-button'; 439 const rejectBtnBar = '#ccc #ccc-notify-reject'; 440 const rejectBtnPanel = '#ccc #ccc-reject-settings'; 441 const saveAndCloseBtn = '#ccc #ccc-content #ccc-dismiss-button'; 442 443 ccStyle.textContent = ` 444 #ccc-overlay { 445 background: rgba(0,0,0,.5)!important; 446 } 447 448 #ccc .checkbox-toggle:focus-within { 449 outline: 0;box-shadow: 0 0 0 2px #fff,0 0 0 4px #262626 !important; 450 } 451 452 .checkbox-toggle--slider .checkbox-toggle-off{ 453 opacity:1!important; 454 } 455 456 #ccc h1#ccc-title { 457 color: #333 458 } 459 460 h2#ccc-title { 461 margin-top: 0 !important; 462 } 463 464 #shelter-online-shop #ccc p { font-size:16px!important; } 465 #shelter-online-shop #ccc h2 { font-size: 24px !important; } 466 #shelter-online-shop #ccc h3 { font-size: 21px !important; } 467 #shelter-online-shop #ccc .ccc-notify-button { font-size: 16px !important; } 468 469 .ccc-notify-button { 470 border-style: none !important; 471 border-radius: 0 !important; 472 font-weight:700! important; 473 text-transform:initial! important; 474 } 475 476 .ccc-notify-button:focus { 477 outline: 0; 478 box-shadow: 0 0 0 2px #fff,0 0 0 4px #262626 !important; 479 } 480 481 ${acceptBtn}:hover, ${acceptBtn}:hover span { 482 background-color: #c8001a !important; 483 } 484 485 ${acceptBtn}:focus, ${acceptBtn}:focus span { 486 background-color: #c8001a !important; 487 } 488 489 ${acceptBtn}:focus { 490 box-shadow: rgb(255, 255, 255) 0px 0px 0px 2px, rgb(38, 38, 38) 0px 0px 0px 4px !important 491 } 492 493 ${rejectBtnBar}, ${rejectBtnBar} span { 494 color: #FFF !important; 495 background-color: transparent !important; 496 } 497 498 ${rejectBtnBar} { 499 box-shadow: rgb(255, 255, 255) 0px 0px 0px 2px inset; 500 } 501 502 ${rejectBtnBar}:hover, ${rejectBtnBar}:hover span, ${rejectBtnBar}:focus, ${rejectBtnBar}:focus span { 503 color: #ff4760 !important; 504 } 505 506 ${rejectBtnBar}:hover { 507 box-shadow: rgb(255, 71, 96) 0px 0px 0px 2px inset !important; 508 } 509 510 ${rejectBtnBar}:focus { 511 box-shadow: rgb(255, 71, 96) 0px 0px 0px 2px inset, rgb(255, 255, 255) 0px 0px 0px 2px, rgb(38, 38, 38) 0px 0px 0px 4px !important; 512 } 513 514 ${rejectBtnPanel} { 515 box-shadow: rgb(51, 51, 51) 0px 0px 0px 2px inset !important; 516 } 517 518 ${rejectBtnPanel}:hover, ${rejectBtnPanel}:hover span, ${rejectBtnPanel}:focus, ${rejectBtnPanel}:focus span { 519 color: #EB001F !important; 520 } 521 522 ${rejectBtnPanel}:hover { 523 box-shadow: rgb(235, 0, 31) 0px 0px 0px 2px inset !important; 524 } 525 526 ${rejectBtnPanel}:focus { 527 box-shadow: rgb(235, 0, 31) 0px 0px 0px 2px inset, rgb(255, 255, 255) 0px 0px 0px 2px, rgb(38, 38, 38) 0px 0px 0px 4px !important; 528 } 529 530 ${saveAndCloseBtn}:hover, ${saveAndCloseBtn}:focus { 531 color: #fff !important; 532 background-color: #EB001F !important; 533 } 534 535 ${saveAndCloseBtn}:focus { 536 box-shadow: rgb(255, 255, 255) 0px 0px 0px 2px, rgb(38, 38, 38) 0px 0px 0px 4px !important; 537 } 538 539 ${saveAndCloseBtn}:hover span, ${saveAndCloseBtn}:focus span { 540 background-color: #EB001F !important; 541 } 542 543 `; 544 545 headTag.appendChild(ccStyle); 546 } 547})(); 548 549/* Exposed for unit tests (Jest/CommonJS); ignored in the browser where 550 `module` is undefined. */ 551if (typeof module !== 'undefined' && module.exports) { 552 module.exports = { 553 getCookieValue: getCookieValue, 554 isValidCookie: isValidCookie, 555 cookieClearDomains: cookieClearDomains,
556 clearCookieControlCookie: clearCookieControlCookie, 557 }; 558}
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.