1/* Shared first-party analytics context. Never an authentication identifier. */ 2(()=>{'use strict'; 3 const key='wp_journey_v1',ttl=30*60*1000,allowed=['utm_source','utm_medium','utm_campaign','utm_content','utm_term','utm_id']; 4 let consent={analytics:false,marketing:false},state=null,page=null; 5 const validId=s=>typeof s==='string'&&/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(s); 6 const domain=location.hostname==='wikipoint.com'||location.hostname.endsWith('.wikipoint.com')?'; Domain=wikipoint.com':''; 7 function clear(){document.cookie=key+'=; Path=/; Max-Age=0; SameSite=Lax; Secure'+domain;state=null;page=null} 8 function campaign(){const p=new URLSearchParams(location.search),out={};for(const k of allowed){const v=p.get(k);if(v&&/^[a-zA-Z0-9_.~-]{1,150}$/.test(v))out[k]=v}return out} 9 function context(){ 10 if(!consent.analytics&&!consent.marketing)return null; 11 if(state&&state.expires<=Date.now()){state=null;page=null} 12 if(!state){try{const raw=document.cookie.split(';').map(x=>x.trim()).find(x=>x.startsWith(key+'='));const v=JSON.parse(decodeURIComponent(raw?.slice(key.length+1)||''));if(v.version===1&&validId(v.id)&&v.expires>Date.now()&&v.expires<=Date.now()+ttl&&v.campaign&&typeof v.campaign==='object'){const safe={};for(const k of allowed)if(typeof v.campaign[k]==='string'&&/^[a-zA-Z0-9_.~-]{1,150}$/.test(v.campaign[k]))safe[k]=v.campaign[k];state={id:v.id,campaign:safe}}}catch{}} 13 const incoming=campaign(); 14 if(!state)state={id:crypto.randomUUID(),campaign:incoming}; 15 if(incoming.utm_source&&incoming.utm_content&&(state.campaign.utm_content!==incoming.utm_content||state.campaign.utm_source!==incoming.utm_source)){state={id:crypto.randomUUID(),campaign:incoming};page=null} 16 state.expires=Date.now()+ttl; 17 document.cookie=key+'='+encodeURIComponent(JSON.stringify({version:1,...state}))+'; Path=/; Max-Age=1800; SameSite=Lax; Secure'+domain; 18 return state; 19 } 20 function event(){const s=context();return s?{journey_id:s.id,wp_event_id:crypto.randomUUID(),social_source:s.campaign.utm_source||'',social_campaign:s.campaign.utm_campaign||'',social_post_id:s.campaign.utm_content||''}:{};} 21 function pageEvent(){if(!context())return {};return page||(page=event())} 22 function setConsent(a,m){consent={analytics:a===true,marketing:m===true};if(!consent.analytics&&!consent.marketing)clear();else context()} 23 function send(ga,meta,standard=false,extra={}){const params={...event(),...extra};window.WikipointAnalytics?.track(ga,params);window.WikipointMeta?.track(meta,params,standard)} 24 window.WikipointJourney=Object.freeze({setConsent,pageEvent,version:1}); 25 document.addEventListener('click',e=>{const el=e.target.closest?.('a,button');if(!el)return; 26 if(el.hasAttribute('data-open-contact'))send('talk_click','ContactClick'); 27 if(!el.href)return;let u;try{u=new URL(el.href,location.href)}catch{return} 28 if(u.hostname!=='app.wikipoint.com'||u.pathname!=='/onboarding')return; 29 const plan=u.searchParams.get('selectedPlanKey'),section=el.closest('section')?.id; 30 const extra={placement:section||'other'};if(['maker','trial_7d'].includes(plan))extra.plan_name=plan==='maker'?'Maker':'Free'; 31 // Exactly one action and one common ID, regardless of placement. 32 send(section==='plans'?'select_plan':'create_wikipoint_click','OnboardingClick',false,extra); 33 },true); 34 let leadSent=false;document.addEventListener('wikipoint:contact-success',e=>{if(e.detail?.confirmed!==true||leadSent||!context())return;leadSent=true;send('generate_lead','Lead',true,{form_id:'contactForm'})}); 35})();
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.