1const visitPages = [ 2 { 3 path: '/', 4 event: 'visit_homepage', 5 }, 6 { 7 path: '/wallet/', 8 event: 'visit_wallet', 9 }, 10 { 11 path: '/investorenkonto/', 12 event: 'visit_account_overview', 13 }, 14 { 15 path: '/order/', 16 event: 'visit_orders', 17 }, 18] 19 20const getUserType = () => { 21 const cookie = document.cookie 22 const user_account = cookie.split('conda_user_profile=')[1].split(';')[0] 23 return user_account 24} 25 26const getUserToken = () => { 27 const cookie = document.cookie 28 const user_token = cookie.split('conda_user_token=')[1].split(';')[0] 29 return user_token 30} 31 32document.addEventListener('DOMContentLoaded', () => { 33 setTimeout(async () => { 34 sendEventOnPageVisit() 35 if (window.location.pathname.includes('/campaign/') && !window.location.pathname.includes('investieren')) { 36 sendReadFullCampaignEvent() 37 sendEventOnCampaignTabChange() 38 sendEventOnContactDetailsClick() 39 } 40 }, 1000) 41}) 42 43// Events 44const sendEventOnPageVisit = () => { 45 const requestBody = { 46 event: '', 47 data: {}, 48 } 49 const pathname = window.location.pathname 50 51 const campaignMatch = pathname.match(/^\/campaign\/([^/]+)\/?$/) 52 if (campaignMatch) { 53 requestBody.event = 'visit_campaign' 54 requestBody.data = { campaign_id: window.campaign.asset_data.asset_var_uid } 55 sendEvent(requestBody) 56 } else { 57 if (visitPages.find((page) => page.path === pathname)) { 58 const page = visitPages.find((page) => page.path === pathname) 59 requestBody.event = page.event 60 sendEvent(requestBody) 61 } 62 } 63} 64 65const sendEventOnContactDetailsClick = () => { 66 const companyEmail = document.getElementById('company-email') 67 if (companyEmail) { 68 console.log('companyEmail', companyEmail) 69 companyEmail.addEventListener('click', () => { 70 sendEvent({ 71 event: 'contact_details_click', 72 data: { campaign_id: window.campaign.asset_data.asset_var_uid, contact_detail: 'email' }, 73 }) 74 }) 75 } 76 77 const companyPhone = document.getElementById('company-phone') 78 if (companyPhone) { 79 console.log('companyPhone', companyPhone) 80 companyPhone.addEventListener('click', () => { 81 sendEvent({ 82 event: 'contact_details_click', 83 data: { campaign_id: window.campaign.asset_data.asset_var_uid, contact_detail: 'phone' }, 84 }) 85 }) 86 } 87} 88 89const sendReadFullCampaignEvent = () => { 90 const main = document.querySelector('main') 91 if (!main) return 92 93 const requestBody = { 94 event: 'read_full_campaign', 95 data: { campaign_id: window.campaign.asset_data.asset_var_uid }, 96 } 97 98 let fired = false 99 const segmentPx = 120 // pick a value between 100 and 150 100 101 const tryFire = async () => { 102 if (fired) return 103 if (isLastSegmentInView(main, segmentPx)) { 104 fired = true 105 window.removeEventListener('scroll', onScroll, { passive: true }) 106 window.removeEventListener('resize', onResize) 107 sendEvent(requestBody) 108 } 109 } 110 111 const onScroll = () => tryFire() 112 const onResize = () => tryFire() 113 114 // Initial check and then listen 115 tryFire() 116 if (!fired) { 117 window.addEventListener('scroll', onScroll, { passive: true }) 118 window.addEventListener('resize', onResize) 119 } 120} 121 122const sendEventOnCampaignTabChange = () => { 123 const requestBody = { 124 event: 'campaign_tab_change', 125 data: { campaign_id: window.campaign.asset_data.asset_var_uid, tab: '' }, 126 } 127 const campaignTabs = document.querySelectorAll('.single-campaign-tabs > li') 128 129 if (!campaignTabs || campaignTabs.length === 0) return 130 131 const observer = new MutationObserver(async (mutationsList) => { 132 for (const mutation of mutationsList) { 133 if ( 134 mutation.type === 'attributes' && 135 mutation.attributeName === 'class' && 136 mutation.target.classList.contains('active') 137 ) { 138 requestBody.payload.tab = mutation.target.getAttribute('data-target-tab') 139 sendEvent(requestBody) 140 } 141 } 142 }) 143
144 campaignTabs.forEach((tab) => { 145 observer.observe(tab, { attributes: true }) 146 }) 147} 148 149// Helpers 150const isLastSegmentInView = (element, segmentPx) => { 151 const rect = element.getBoundingClientRect() 152 const viewportHeight = window.innerHeight || document.documentElement.clientHeight 153 154 // Element not in viewport at all 155 if (rect.bottom < 0 || rect.top > viewportHeight) return false 156 157 // Bottom of element lies within the bottom `segmentPx` of viewport 158 const bottomWithinSegment = rect.bottom <= viewportHeight && rect.bottom >= viewportHeight - segmentPx 159 160 // Ensure at least some of that bottom segment is visible 161 const elementHeight = rect.height 162 const segmentTop = rect.bottom - segmentPx 163 const visibleSegmentTop = Math.max(segmentTop, 0) 164 const visibleSegmentHeight = rect.bottom - visibleSegmentTop 165 166 return bottomWithinSegment && visibleSegmentHeight > 0 && elementHeight >= segmentPx 167} 168 169const sendEvent = async (requestBody) => { 170 const body = { 171 ...requestBody, 172 platform_name: window.platformSettings.platform_name, 173 trackable_type: getUserType(), 174 } 175 const baseUrl = window.condaApiEndpoint 176 await fetch(`${baseUrl.replace(/\/?$/, '/')}user-tracking/`, { 177 method: 'POST', 178 headers: { 179 'Content-Type': 'application/json', 180 'Accept': 'application/json', 181 'Authorization': `Bearer ${getUserToken()}`, 182 }, 183 body: JSON.stringify(body), 184 }) 185}
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.