1// This must stay as plain browser JavaScript loaded from /public so it can run 2// as a classic head script before Builder's inline personalization code in the 3// page body evaluates. An Astro-bundled or module script would run too late. 4(function () { 5 var userDataStorageKey = "userData"; 6 var cartStorageKey = "cart"; 7 var builderCookieName = "builder.userAttributes"; 8 var builderUserAttributesCookieLifetimeDays = 30; 9 10 function normaliseStringValue(value) { 11 if (typeof value !== "string") { 12 return null; 13 } 14 15 var trimmedValue = value.trim(); 16 17 if (!trimmedValue) { 18 return null; 19 } 20 21 return trimmedValue; 22 } 23 24 function normaliseAppealSegment(value) { 25 var trimmedValue = normaliseStringValue(value); 26 27 if (!trimmedValue) { 28 return null; 29 } 30 31 return trimmedValue.charAt(0); 32 } 33 34 function normaliseCampaignId(value) { 35 return normaliseStringValue(value); 36 } 37 38 function getUrlPath() { 39 var pathname = window.location.pathname; 40 41 return ( 42 pathname 43 .replace(/\/index\.html$/, "/") 44 .replace(/\.html$/, "") 45 .replace(/\/$/, "") || "/" 46 ); 47 } 48 49 function getRawCookie(name) { 50 var cookiePrefix = name + "="; 51 var cookies = document.cookie.split(";"); 52 53 for (var index = 0; index < cookies.length; index += 1) { 54 var cookie = cookies[index].trim(); 55 56 if (cookie.indexOf(cookiePrefix) === 0) { 57 return cookie.substring(cookiePrefix.length); 58 } 59 } 60 61 return null; 62 } 63 64 function getCookieExpiresString(daysToLive) { 65 if (typeof daysToLive !== "number" || daysToLive <= 0) { 66 return ""; 67 } 68 69 var expiresAt = new Date(); 70 expiresAt.setTime(expiresAt.getTime() + daysToLive * 24 * 60 * 60 * 1000); 71 72 return "; expires=" + expiresAt.toUTCString(); 73 } 74 75 function writeBuilderUserAttributes(attributes) { 76 var expiresString = getCookieExpiresString( 77 builderUserAttributesCookieLifetimeDays, 78 ); 79 80 document.cookie = 81 builderCookieName + 82 "=" + 83 JSON.stringify(attributes) + 84 expiresString + 85 "; path=/; SameSite=Lax"; 86 } 87 88 function getBuilderUserAttributes() { 89 var cookieValue = getRawCookie(builderCookieName); 90 91 if (!cookieValue) { 92 return {}; 93 } 94 95 try { 96 var parsedAttributes = JSON.parse(cookieValue); 97 return parsedAttributes && typeof parsedAttributes === "object" 98 ? parsedAttributes 99 : {}; 100 } catch { 101 return {}; 102 } 103 } 104 105 function getCurrentBuilderStringAttribute(attributeName, normaliseValue) { 106 return normaliseValue(getBuilderUserAttributes()[attributeName]); 107 } 108 109 function persistBuilderStringAttribute( 110 attributeName, 111 attributeValue, 112 normaliseValue, 113 ) { 114 var normalisedAttributeValue = normaliseValue(attributeValue); 115 116 if (!normalisedAttributeValue) { 117 return null; 118 } 119 120 var nextAttributes = getBuilderUserAttributes(); 121 nextAttributes[attributeName] = normalisedAttributeValue; 122 123 writeBuilderUserAttributes(nextAttributes); 124 125 return normalisedAttributeValue; 126 } 127 128 function setBuilderStringAttribute( 129 attributeName, 130 attributeValue, 131 normaliseValue, 132 ) { 133 var normalisedAttributeValue = normaliseValue(attributeValue); 134 135 if (!normalisedAttributeValue) { 136 return null; 137 } 138 139 if ( 140 getCurrentBuilderStringAttribute(attributeName, normaliseValue) === 141 normalisedAttributeValue 142 ) { 143 return normalisedAttributeValue; 144 } 145 146 return persistBuilderStringAttribute( 147 attributeName, 148 normalisedAttributeValue, 149 normaliseValue, 150 ); 151 } 152 153 function getAppealSegmentFromSessionUserData() { 154 try { 155 var sessionUserData = window.sessionStorage.getItem(userDataStorageKey); 156 157 if (!sessionUserData) { 158 return null; 159 } 160 161 var parsedUserData = JSON.parse(sessionUserData); 162 return normaliseAppealSegment( 163 parsedUserData?.supporters?.[0]?.appealSegment, 164 ); 165 } catch { 166 return null; 167 } 168 } 169 170 function getAppealSegmentFromUrl() { 171 return normaliseAppealSegment( 172 new URLSearchParams(window.location.search).get("appealSegment"), 173 ); 174 } 175 176 function getStoredCartCampaignId() { 177 try { 178 var rawCart = window.localStorage.getItem(cartStorageKey); 179 180 if (!rawCart) { 181 return null; 182 } 183 184 var parsedCart = JSON.parse(rawCart); 185 return normaliseCampaignId(parsedCart?.campaign); 186 } catch { 187 return null; 188 } 189 } 190 191 function getCampaignIdFromUrl() { 192 return normaliseCampaignId( 193 new URLSearchParams(window.location.search).get("cid"), 194 ); 195 } 196 197 function setAppealSegment(appealSegment) { 198 return setBuilderStringAttribute( 199 "appealSegment", 200 appealSegment, 201 normaliseAppealSegment, 202 ); 203 } 204 205 function setCampaignId(campaignId) { 206 return setBuilderStringAttribute( 207 "campaignId", 208 campaignId, 209 normaliseCampaignId, 210 ); 211 } 212 213 function setUrlPath(urlPath) { 214 return setBuilderStringAttribute("urlPath", urlPath, normaliseStringValue); 215 } 216 217 function persistAppealSegment(appealSegment) { 218 return persistBuilderStringAttribute( 219 "appealSegment", 220 appealSegment, 221 normaliseAppealSegment, 222 ); 223 } 224 225 function persistCampaignId(campaignId) { 226 return persistBuilderStringAttribute( 227 "campaignId", 228 campaignId, 229 normaliseCampaignId, 230 ); 231 } 232 233 function persistUrlPath(urlPath) { 234 return persistBuilderStringAttribute( 235 "urlPath", 236 urlPath, 237 normaliseStringValue, 238 ); 239 } 240 241 function applyResolvedAppealSegment() { 242 var resolvedAppealSegment = 243 getAppealSegmentFromSessionUserData() || getAppealSegmentFromUrl(); 244 245 if (resolvedAppealSegment) { 246 setAppealSegment(resolvedAppealSegment); 247 } 248 249 return resolvedAppealSegment; 250 } 251 252 function applyResolvedCampaignId() { 253 var resolvedCampaignId = 254 getCampaignIdFromUrl() || getStoredCartCampaignId(); 255 256 if (resolvedCampaignId) { 257 setCampaignId(resolvedCampaignId); 258 } 259 260 return resolvedCampaignId; 261 } 262 263 // The head script owns browser-specific parsing and Builder cookie writes. 264 // Hydrated code should reuse these helpers instead of reimplementing them. 265 window.__compassionBuilderAppealSegment = { 266 getAppealSegmentFromUrl: getAppealSegmentFromUrl, 267 normaliseAppealSegment: normaliseAppealSegment, 268 persistAppealSegment: persistAppealSegment, 269 setAppealSegment: setAppealSegment, 270 }; 271 272 window.__compassionBuilderCampaignId = { 273 getCampaignIdFromUrl: getCampaignIdFromUrl, 274 getStoredCartCampaignId: getStoredCartCampaignId, 275 normaliseCampaignId: normaliseCampaignId,
276 persistCampaignId: persistCampaignId, 277 setCampaignId: setCampaignId, 278 }; 279 280 window.__compassionBuilderUrlPath = { 281 getUrlPath: getUrlPath, 282 persistUrlPath: persistUrlPath, 283 setUrlPath: setUrlPath, 284 }; 285 286 applyResolvedAppealSegment(); 287 applyResolvedCampaignId(); 288 setUrlPath(getUrlPath()); 289})();
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.