cxense.js (16721B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 /** 8 * Bug 1713721 - Shim Cxense 9 * 10 * Sites relying on window.cX can experience breakage if it is blocked. 11 * Stubbing out the API in a shim can mitigate this breakage. There are 12 * two versions of the API, one including window.cX.CCE, but both appear 13 * to be very similar so we use one shim for both. 14 */ 15 16 if (window.cX?.getUserSegmentIds === undefined) { 17 const callQueue = window.cX?.callQueue || []; 18 const callQueueCCE = window.cX?.CCE?.callQueue || []; 19 20 function getRandomString(l = 16) { 21 const v = crypto.getRandomValues(new Uint8Array(l)); 22 const s = Array.from(v, c => c.toString(16)).join(""); 23 return s.slice(0, l); 24 } 25 26 const call = (cb, ...args) => { 27 if (typeof cb !== "function") { 28 return; 29 } 30 try { 31 cb(...args); 32 } catch (e) { 33 console.error(e); 34 } 35 }; 36 37 const invokeOn = lib => { 38 return (fn, ...args) => { 39 try { 40 lib[fn](...args); 41 } catch (e) { 42 console.error(e); 43 } 44 }; 45 }; 46 47 const userId = getRandomString(); 48 const cxUserId = `cx:${getRandomString(25)}:${getRandomString(12)}`; 49 const topLeft = { left: 0, top: 0 }; 50 const margins = { left: 0, top: 0, right: 0, bottom: 0 }; 51 const ccePushUrl = 52 "https://comcluster.cxense.com/cce/push?callback={{callback}}"; 53 const displayWidget = (divId, a, ctx, callback) => call(callback, ctx, divId); 54 const getUserSegmentIds = a => call(a?.callback, a?.defaultValue || []); 55 const init = (a, b, c, d, callback) => call(callback); 56 const render = (a, data, ctx, callback) => call(callback, data, ctx); 57 const run = (params, ctx, callback) => call(callback, params, ctx); 58 const runCtrlVersion = (a, b, callback) => call(callback); 59 const runCxVersion = (a, data, b, ctx, callback) => call(callback, data, ctx); 60 const runTest = (a, divId, b, c, ctx, callback) => call(callback, divId, ctx); 61 const sendConversionEvent = (a, options) => call(options?.callback, {}); 62 const sendEvent = (a, b, args) => call(args?.callback, {}); 63 64 const getDivId = className => { 65 const e = document.querySelector(`.${className}`); 66 if (e) { 67 return `${className}-01`; 68 } 69 return null; 70 }; 71 72 const getDocumentSize = () => { 73 const width = document.body.clientWidth; 74 const height = document.body.clientHeight; 75 return { width, height }; 76 }; 77 78 const getNowSeconds = () => { 79 return Math.round(new Date().getTime() / 1000); 80 }; 81 82 const getPageContext = () => { 83 return { 84 location: location.href, 85 pageViewRandom: "", 86 userId, 87 }; 88 }; 89 90 const getWindowSize = () => { 91 const width = window.innerWidth; 92 const height = window.innerHeight; 93 return { width, height }; 94 }; 95 96 const isObject = i => { 97 return typeof i === "object" && i !== null && !Array.isArray(i); 98 }; 99 100 const runMulti = widgets => { 101 widgets?.forEach(({ widgetParams, widgetContext, widgetCallback }) => { 102 call(widgetCallback, widgetParams, widgetContext); 103 }); 104 }; 105 106 let testGroup = -1; 107 let snapPoints = []; 108 const startTime = new Date(); 109 110 const library = { 111 addCustomerScript() {}, 112 addEventListener() {}, 113 addExternalId() {}, 114 afterInitializePage() {}, 115 allUserConsents() {}, 116 backends: { 117 production: { 118 baseAdDeliveryUrl: "http://adserver.cxad.cxense.com/adserver/search", 119 secureBaseAdDeliveryUrl: 120 "https://s-adserver.cxad.cxense.com/adserver/search", 121 }, 122 sandbox: { 123 baseAdDeliveryUrl: 124 "http://adserver.sandbox.cxad.cxense.com/adserver/search", 125 secureBaseAdDeliveryUrl: 126 "https://s-adserver.sandbox.cxad.cxense.com/adserver/search", 127 }, 128 }, 129 calculateAdSpaceSize(adCount, adUnitSize, marginA, marginB) { 130 return adCount * (adUnitSize + marginA + marginB); 131 }, 132 cdn: { 133 template: { 134 direct: { 135 http: "http://cdn.cxpublic.com/", 136 https: "https://cdn.cxpublic.com/", 137 }, 138 mapped: { 139 http: "http://cdn-templates.cxpublic.com/", 140 https: "https://cdn-templates.cxpublic.com/", 141 }, 142 }, 143 }, 144 cint() {}, 145 cleanUpGlobalIds: [], 146 clearBaseUrl: "https://scdn.cxense.com/sclear.html", 147 clearCustomParameters() {}, 148 clearIdUrl: "https://scomcluster.cxense.com/public/clearid", 149 clearIds() {}, 150 clickTracker: (a, b, callback) => call(callback), 151 clientStorageUrl: "https://clientstorage.cxense.com", 152 combineArgs: () => Object.create(), 153 combineKeywordsIntoArray: () => [], 154 consentClasses: ["pv", "segment", "ad", "recs"], 155 consentClassesV2: ["geo", "device"], 156 cookieSyncRUrl: "csyn-r.cxense.com", 157 createDelegate() {}, 158 csdUrls: { 159 domainScriptUrl: "//csd.cxpublic.com/d/", 160 customerScriptUrl: "//csd.cxpublic.com/t/", 161 }, 162 cxenseGlobalIdIframeUrl: "https://scdn.cxense.com/sglobal.html", 163 cxenseUserIdUrl: "https://id.cxense.com/public/user/id", 164 decodeUrlEncodedNameValuePairs: () => Object.create(), 165 defaultAdRenderer: () => "", 166 deleteCookie() {}, 167 denyWithoutConsent: { 168 addExternalId: "pv", 169 getUserSegmentIds: "segment", 170 insertAdSpace: "ad", 171 insertMultipleAdSpaces: "ad", 172 sendEvent: "pv", 173 sendPageViewEvent: "pv", 174 sync: "ad", 175 }, 176 dmpPushUrl: "https://comcluster.cxense.com/dmp/push?callback={{callback}}", 177 emptyWidgetUrl: "https://scdn.cxense.com/empty.html", 178 eventReceiverBaseUrl: "https://scomcluster.cxense.com/Repo/rep.html", 179 eventReceiverBaseUrlGif: "https://scomcluster.cxense.com/Repo/rep.gif", 180 getAllText: () => "", 181 getClientStorageVariable() {}, 182 getCookie: () => null, 183 getCxenseUserId: () => cxUserId, 184 getDocumentSize, 185 getElementPosition: () => topLeft, 186 getHashFragment: () => location.hash.substr(1), 187 getLocalStats: () => Object.create(), 188 getNodeValue: n => n.nodeValue, 189 getNowSeconds, 190 getPageContext, 191 getRandomString, 192 getScrollPos: () => topLeft, 193 getSessionId: () => "", 194 getSiteId: () => "", 195 getTimezoneOffset: () => new Date().getTimezoneOffset(), 196 getTopLevelDomain: () => location.hostname, 197 getUserId: () => userId, 198 getUserSegmentIds, 199 getWindowSize, 200 hasConsent: () => true, 201 hasHistory: () => true, 202 hasLocalStorage: () => true, 203 hasPassiveEventListeners: () => true, 204 hasPostMessage: () => true, 205 hasSessionStorage() {}, 206 initializePage() {}, 207 insertAdSpace() {}, 208 insertMultipleAdSpaces() {}, 209 insertWidget() {}, 210 invoke: invokeOn(library), 211 isAmpIFrame() {}, 212 isArray() {}, 213 isCompatModeActive() {}, 214 isConsentRequired() {}, 215 isEdge: () => false, 216 isFirefox: () => true, 217 isIE6Or7: () => false, 218 isObject, 219 isRecsDestination: () => false, 220 isSafari: () => false, 221 isTextNode: n => n?.nodeType === 3, 222 isTopWindow: () => window === top, 223 jsonpRequest: () => false, 224 loadScript() {}, 225 m_accountId: "0", 226 m_activityEvents: false, 227 m_activityState: { 228 activeTime: startTime, 229 currScrollLeft: 0, 230 currScrollTop: 0, 231 exitLink: "", 232 hadHIDActivity: false, 233 maxViewLeft: 1, 234 maxViewTop: 1, 235 parentMetrics: undefined, 236 prevActivityTime: startTime + 2, 237 prevScreenX: 0, 238 prevScreenY: 0, 239 prevScrollLeft: 0, 240 prevScrollTop: 0, 241 prevTime: startTime + 1, 242 prevWindowHeight: 1, 243 prevWindowWidth: 1, 244 scrollDepthPercentage: 0, 245 scrollDepthPixels: 0, 246 }, 247 m_atfr: null, 248 m_c1xTpWait: 0, 249 m_clientStorage: { 250 iframeEl: null, 251 iframeIsLoaded: false, 252 iframeOrigin: "https://clientstorage.cxense.com", 253 iframePath: "/clientstorage_v2.html", 254 messageContexts: {}, 255 messageQueue: [], 256 }, 257 m_compatMode: {}, 258 m_compatModeActive: false, 259 m_compatPvSent: false, 260 m_consentVersion: 1, 261 m_customParameters: [], 262 m_documentSizeRequestedFromChild: false, 263 m_externalUserIds: [], 264 m_globalIdLoading: { 265 globalIdIFrameEl: null, 266 globalIdIFrameElLoaded: false, 267 }, 268 m_isSpaRecsDestination: false, 269 m_knownMessageSources: [], 270 m_p1Complete: false, 271 m_prevLocationHash: "", 272 m_previousPageViewReport: null, 273 m_rawCustomParameters: {}, 274 m_rnd: getRandomString(), 275 m_scriptStartTime: startTime, 276 m_siteId: "0", 277 m_spaRecsClickUrl: null, 278 m_thirdPartyIds: true, 279 m_usesConsent: false, 280 m_usesIabConsent: false, 281 m_usesSecureCookies: true, 282 m_usesTcf20Consent: false, 283 m_widgetSpecs: {}, 284 Object, 285 onClearIds() {}, 286 onFFP1() {}, 287 onP1() {}, 288 p1BaseUrl: "https://scdn.cxense.com/sp1.html", 289 p1JsUrl: "https://p1cluster.cxense.com/p1.js", 290 parseHashArgs: () => Object.create(), 291 parseMargins: () => margins, 292 parseUrlArgs: () => Object.create(), 293 postMessageToParent() {}, 294 publicWidgetDataUrl: "https://api.cxense.com/public/widget/data", 295 removeClientStorageVariable() {}, 296 removeEventListener() {}, 297 renderContainedImage: () => "<div/>", 298 renderTemplate: () => "<div/>", 299 reportActivity() {}, 300 requireActivityEvents() {}, 301 requireConsent() {}, 302 requireOnlyFirstPartyIds() {}, 303 requireSecureCookies() {}, 304 requireTcf20() {}, 305 sendEvent, 306 sendSpaRecsClick: (a, callback) => call(callback), 307 setAccountId() {}, 308 setAllConsentsTo() {}, 309 setClientStorageVariable() {}, 310 setCompatMode() {}, 311 setConsent() {}, 312 setCookie() {}, 313 setCustomParameters() {}, 314 setEventAttributes() {}, 315 setGeoPosition() {}, 316 setNodeValue() {}, 317 setRandomId() {}, 318 setRestrictionsToConsentClasses() {}, 319 setRetargetingParameters() {}, 320 setSiteId() {}, 321 setUserProfileParameters() {}, 322 setupIabCmp() {}, 323 setupTcfApi() {}, 324 shouldPollActivity() {}, 325 startLocalStats() {}, 326 startSessionAnnotation() {}, 327 stopAllSessionAnnotations() {}, 328 stopSessionAnnotation() {}, 329 sync() {}, 330 trackAmpIFrame() {}, 331 trackElement() {}, 332 trim: s => s.trim(), 333 tsridUrl: "https://tsrid.cxense.com/lookup?callback={{callback}}", 334 userSegmentUrl: 335 "https://api.cxense.com/profile/user/segment?callback={{callback}}", 336 }; 337 338 const libraryCCE = { 339 "__cx-toolkit__": { 340 isShown: true, 341 data: [], 342 }, 343 activeSnapPoint: null, 344 activeWidgets: [], 345 ccePushUrl, 346 clickTracker: () => "", 347 displayResult() {}, 348 displayWidget, 349 getDivId, 350 getTestGroup: () => testGroup, 351 init, 352 insertMaster() {}, 353 instrumentClickLinks() {}, 354 invoke: invokeOn(libraryCCE), 355 noCache: false, 356 offerProductId: null, 357 persistedQueryId: null, 358 prefix: null, 359 previewCampaign: null, 360 previewDiv: null, 361 previewId: null, 362 previewTestId: null, 363 processCxResult() {}, 364 render, 365 reportTestImpression() {}, 366 run, 367 runCtrlVersion, 368 runCxVersion, 369 runMulti, 370 runTest, 371 sendConversionEvent, 372 sendPageViewEvent: (a, b, c, callback) => call(callback), 373 setSnapPoints(x) { 374 snapPoints = x; 375 }, 376 setTestGroup(x) { 377 testGroup = x; 378 }, 379 setVisibilityField() {}, 380 get snapPoints() { 381 return snapPoints; 382 }, 383 startTime, 384 get testGroup() { 385 return testGroup; 386 }, 387 testVariant: null, 388 trackTime: 0.5, 389 trackVisibility() {}, 390 updateRecsClickUrls() {}, 391 utmParams: [], 392 version: "2.42", 393 visibilityField: "timeHalf", 394 }; 395 396 const CCE = { 397 activeSnapPoint: null, 398 activeWidgets: [], 399 callQueue: callQueueCCE, 400 ccePushUrl, 401 clickTracker: () => "", 402 displayResult() {}, 403 displayWidget, 404 getDivId, 405 getTestGroup: () => testGroup, 406 init, 407 insertMaster() {}, 408 instrumentClickLinks() {}, 409 invoke: invokeOn(libraryCCE), 410 library: libraryCCE, 411 noCache: false, 412 offerProductId: null, 413 persistedQueryId: null, 414 prefix: null, 415 previewCampaign: null, 416 previewDiv: null, 417 previewId: null, 418 previewTestId: null, 419 processCxResult() {}, 420 render, 421 reportTestImpression() {}, 422 run, 423 runCtrlVersion, 424 runCxVersion, 425 runMulti, 426 runTest, 427 sendConversionEvent, 428 sendPageViewEvent: (a, b, c, callback) => call(callback), 429 setSnapPoints(x) { 430 snapPoints = x; 431 }, 432 setTestGroup(x) { 433 testGroup = x; 434 }, 435 setVisibilityField() {}, 436 get snapPoints() { 437 return snapPoints; 438 }, 439 startTime, 440 get testGroup() { 441 return testGroup; 442 }, 443 testVariant: null, 444 trackTime: 0.5, 445 trackVisibility() {}, 446 updateRecsClickUrls() {}, 447 utmParams: [], 448 version: "2.42", 449 visibilityField: "timeHalf", 450 }; 451 452 window.cX = { 453 addCustomerScript() {}, 454 addEventListener() {}, 455 addExternalId() {}, 456 afterInitializePage() {}, 457 allUserConsents: () => undefined, 458 Array, 459 calculateAdSpaceSize: () => 0, 460 callQueue, 461 CCE, 462 cint: () => undefined, 463 clearCustomParameters() {}, 464 clearIds() {}, 465 clickTracker: () => "", 466 combineArgs: () => Object.create(), 467 combineKeywordsIntoArray: () => [], 468 createDelegate() {}, 469 decodeUrlEncodedNameValuePairs: () => Object.create(), 470 defaultAdRenderer: () => "", 471 deleteCookie() {}, 472 getAllText: () => "", 473 getClientStorageVariable() {}, 474 getCookie: () => null, 475 getCxenseUserId: () => cxUserId, 476 getDocumentSize, 477 getElementPosition: () => topLeft, 478 getHashFragment: () => location.hash.substr(1), 479 getLocalStats: () => Object.create(), 480 getNodeValue: n => n.nodeValue, 481 getNowSeconds, 482 getPageContext, 483 getRandomString, 484 getScrollPos: () => topLeft, 485 getSessionId: () => "", 486 getSiteId: () => "", 487 getTimezoneOffset: () => new Date().getTimezoneOffset(), 488 getTopLevelDomain: () => location.hostname, 489 getUserId: () => userId, 490 getUserSegmentIds, 491 getWindowSize, 492 hasConsent: () => true, 493 hasHistory: () => true, 494 hasLocalStorage: () => true, 495 hasPassiveEventListeners: () => true, 496 hasPostMessage: () => true, 497 hasSessionStorage() {}, 498 initializePage() {}, 499 insertAdSpace() {}, 500 insertMultipleAdSpaces() {}, 501 insertWidget() {}, 502 invoke: invokeOn(library), 503 isAmpIFrame() {}, 504 isArray() {}, 505 isCompatModeActive() {}, 506 isConsentRequired() {}, 507 isEdge: () => false, 508 isFirefox: () => true, 509 isIE6Or7: () => false, 510 isObject, 511 isRecsDestination: () => false, 512 isSafari: () => false, 513 isTextNode: n => n?.nodeType === 3, 514 isTopWindow: () => window === top, 515 JSON, 516 jsonpRequest: () => false, 517 library, 518 loadScript() {}, 519 Object, 520 onClearIds() {}, 521 onFFP1() {}, 522 onP1() {}, 523 parseHashArgs: () => Object.create(), 524 parseMargins: () => margins, 525 parseUrlArgs: () => Object.create(), 526 postMessageToParent() {}, 527 removeClientStorageVariable() {}, 528 removeEventListener() {}, 529 renderContainedImage: () => "<div/>", 530 renderTemplate: () => "<div/>", 531 reportActivity() {}, 532 requireActivityEvents() {}, 533 requireConsent() {}, 534 requireOnlyFirstPartyIds() {}, 535 requireSecureCookies() {}, 536 requireTcf20() {}, 537 sendEvent, 538 sendPageViewEvent: (a, callback) => call(callback, {}), 539 sendSpaRecsClick() {}, 540 setAccountId() {}, 541 setAllConsentsTo() {}, 542 setClientStorageVariable() {}, 543 setCompatMode() {}, 544 setConsent() {}, 545 setCookie() {}, 546 setCustomParameters() {}, 547 setEventAttributes() {}, 548 setGeoPosition() {}, 549 setNodeValue() {}, 550 setRandomId() {}, 551 setRestrictionsToConsentClasses() {}, 552 setRetargetingParameters() {}, 553 setSiteId() {}, 554 setUserProfileParameters() {}, 555 setupIabCmp() {}, 556 setupTcfApi() {}, 557 shouldPollActivity() {}, 558 startLocalStats() {}, 559 startSessionAnnotation() {}, 560 stopAllSessionAnnotations() {}, 561 stopSessionAnnotation() {}, 562 sync() {}, 563 trackAmpIFrame() {}, 564 trackElement() {}, 565 trim: s => s.trim(), 566 }; 567 568 window.cxTest = window.cX; 569 570 window.cx_pollActiveTime = () => undefined; 571 window.cx_pollActivity = () => undefined; 572 window.cx_pollFragmentMessage = () => undefined; 573 574 const execQueue = (lib, queue) => { 575 return () => { 576 const invoke = invokeOn(lib); 577 setTimeout(() => { 578 queue.push = cmd => { 579 setTimeout(() => invoke(...cmd), 1); 580 }; 581 for (const cmd of queue) { 582 invoke(...cmd); 583 } 584 }, 25); 585 }; 586 }; 587 588 window.cx_callQueueExecute = execQueue(library, callQueue); 589 window.cxCCE_callQueueExecute = execQueue(libraryCCE, callQueueCCE); 590 591 window.cx_callQueueExecute(); 592 window.cxCCE_callQueueExecute(); 593 }