1/** 2 * @file 3 * Experiment funnel event tracking. 4 * 5 * Fires non-fatal beacons for funnel steps when experiment cookies are present. 6 * All tracking is fire-and-forget, deduped per session via sessionStorage. 7 */ 8(function (Drupal, drupalSettings) { 9 'use strict'; 10 11 var abConfig = drupalSettings.abExperiment || {}; 12 var IMPRESSIONS_URL = abConfig.impressionsUrl; 13 var API_KEY = abConfig.apiKey; 14 15 if (!IMPRESSIONS_URL || !API_KEY) return; 16 17 function getCookie(name) { 18 try { 19 var cookies = document.cookie.split(';'); 20 for (var i = 0; i < cookies.length; i++) { 21 var cookie = cookies[i].replace(/^\s+/, ''); 22 if (cookie.indexOf(name + '=') === 0) { 23 return decodeURIComponent(cookie.substring(name.length + 1)); 24 } 25 } 26 } catch (e) {} 27 return ''; 28 } 29 30 function fireFunnelEvent(type) { 31 try { 32 var experimentId = getCookie('gg_experiment_id'); 33 var variantId = getCookie('gg_variant'); 34 var visitorId = getCookie('gg_visitor_id'); 35 if (!experimentId || !variantId || !visitorId) return; 36 37 var dedupeKey = 'gg_funnel_' + type; 38 if (sessionStorage.getItem(dedupeKey)) return; 39 sessionStorage.setItem(dedupeKey, '1'); 40 41 var payload = { 42 experimentId: experimentId, 43 variantId: variantId, 44 visitorId: visitorId, 45 type: type 46 }; 47 48 // Piggyback the authenticated user's email on the beacon so the 49 // trackImpressions Lambda can persist an email â variant mapping. 50 // This is the durable fallback path: Drupal's ConversionTrackingService 51 // hashes the order email at subscription time and looks up this mapping. 52 // Deduped per experiment per session to avoid hammering Lambda. 53 var userMail = drupalSettings.user && drupalSettings.user.mail; 54 if (userMail) { 55 var attrKey = 'gg_attr_sent_' + experimentId; 56 if (!sessionStorage.getItem(attrKey)) { 57 payload.email = userMail; 58 // Tell the Lambda whether this user is already a paying member. If 59 // they are, the beacon's funnel event must NOT create a first-touch 60 // attribution row â they already converted, so it cannot be the 61 // first touch of a FUTURE purchase (gg-f9ij). The counter still 62 // records the raw event; only the attribution write is suppressed. 63 payload.alreadyMember = !!(drupalSettings.user && drupalSettings.user.isMember); 64 // Whether the user already OWNS a Teleport (the top tier). gg-s5e3j: 65 // the Lambda gates ONLY top-tier members out of attribution; a 2.0 66 // subscriber (alreadyMember=true but isTeleportMember=false) IS a 67 // valid first-touch for a FUTURE Teleport upgrade, tagged 68 // source='upgrade_candidate'. Forwarding this distinguishes the two. 69 payload.isTeleportMember = !!(drupalSettings.user && drupalSettings.user.isTeleportMember); 70 try { sessionStorage.setItem(attrKey, '1'); } catch (e) {} 71 } 72 } 73 74 fetch(IMPRESSIONS_URL, { 75 method: 'POST', 76 headers: { 'Content-Type': 'application/json', 'x-api-key': API_KEY }, 77 body: JSON.stringify(payload) 78 }).catch(function () {}); 79 } catch (e) {} 80 } 81 82 // Bail early if no experiment cookie. 83 if (!getCookie('gg_experiment_id')) return; 84 85 var funnel = drupalSettings.ggExperimentFunnel || {}; 86 87 if (funnel.justRegistered) { 88 fireFunnelEvent('registration'); 89 } 90 91 if (funnel.lessonView) { 92 fireFunnelEvent('course_start'); 93 } 94 95 // Detect lesson_complete flag via AJAX command interception. 96 if (Drupal.AjaxCommands && Drupal.AjaxCommands.prototype) { 97 var originalFlash = Drupal.AjaxCommands.prototype.actionLinkFlash; 98 Drupal.AjaxCommands.prototype.actionLinkFlash = function (ajax, response, status) { 99 if (response.selector && response.selector.indexOf('js-flag-lesson-complete') !== -1) { 100 fireFunnelEvent('course_complete'); 101 } 102 if (originalFlash) { 103 originalFlash.call(this, ajax, response, status); 104 } 105 }; 106 } 107 108})(Drupal, drupalSettings);
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.