@thg-agentic/hyper-personalisation-web 3.25.0 → 3.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -9
- package/dist/hp.min.js +3 -3
- package/dist/onsite-answers.min.js +1 -1
- package/dist/onsite-audiences.min.js +1 -0
- package/dist/onsite-render.min.js +1 -1
- package/dist/onsite-wheel.min.js +1 -1
- package/dist/onsite.min.js +1 -1
- package/package.json +4 -3
- package/src/bootstrap.js +55 -19
- package/src/index.js +74 -3
- package/src/onsite/api.js +22 -5
- package/src/onsite/audiences-loader.js +6 -0
- package/src/onsite/counters.js +2 -2
- package/src/onsite/index.js +52 -1
- package/src/onsite/rules.js +20 -5
- package/src/onsite/visit-audiences.js +94 -0
- package/src/shape.js +4 -0
- package/src/spec-version.js +1 -1
- package/src/storage-scope.js +6 -0
- package/src/version.js +1 -1
- package/src/visit-campaign.js +168 -0
- package/types/bootstrap.d.ts +7 -0
- package/types/events.d.ts +30 -2
- package/types/index.d.ts +6 -0
- package/types/onsite.d.ts +9 -0
|
@@ -179,4 +179,4 @@ hr{width:100%;margin:4px 0;border:0;border-top:1px solid var(--ln)}
|
|
|
179
179
|
@keyframes hp-down{from{transform:translateY(-100%)}}
|
|
180
180
|
@keyframes hp-out{to{opacity:0;transform:translateY(12px) scale(.98)}}
|
|
181
181
|
@media (prefers-reduced-motion:reduce){.s .w,.s .ov,.f>*{animation:hp-fade .15s ease both!important}.btn{transition:none}}
|
|
182
|
-
`;var $t=/^#(?:[0-9a-f]{3}){1,2}$/i,He=["popup","fullscreen"],_t=["ok","verify","already"],zt=["stack","split","overlay","image-only"],Be={bar:["bottom","top"],sheet:["bottom-right","bottom-left","bottom"],teaser:["bottom-left","bottom-right","left","right"]},Tt=["xs","sm","md","lg","xl","display"],Ge={xs:4,sm:8,md:16,lg:28,xl:44},Ve={sm:380,md:480,lg:880},Ct=["left","center","right"],Xe={secondary:" b2",link:" no"},Lt=220,Mt=["verify","already","held","fallback","success"],Ot=[500,1500],It=600,Pt=1800,A={email:"Enter a valid email address.",phone:"Enter a valid mobile number.",intl:"Enter a valid mobile number, starting with + and its country code.",consent:"Tick the box to sign up.",failed:"Something went wrong. Please try again.",busy:"Too many tries. Please wait a moment and try again.",spin:"Sign up first to spin.",yours:"Your code",held:"You\u2019re already on the list",resent:"We\u2019ve sent your code to your inbox again.",inbox:"Your code is in the email we sent when you first signed up.",shop:"Continue shopping",closeOffer:"Close offer",code:"We\u2019ll email your code to you.",claimed:"This email address has already claimed its code.",copied:"Copied",thanks:"Thanks, you\u2019re signed up",retry:"You\u2019re signed up, but we couldn\u2019t load your prize. Please try again.",unclaimed:"We couldn\u2019t load your prize right now.",unavailable:"Not available right now.",won:"You won"},P=i=>i!==null&&typeof i=="object"&&!Array.isArray(i),F=(i,o,a)=>i.includes(o)?o:a,I=(i,o,a)=>Number.isFinite(i)?Math.min(Math.max(i,o),a):null,ge=i=>i.type==="date"||i.type==="number",xe=()=>globalThis.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches===!0;function Ze(i){let o=P(i.layout)?i.layout:{},a=P(o.media)?o.media:null,l=F(zt,o.template,"stack"),f=a?.side==="right"?"right":"left";return!a&&P(o.image)&&o.image.side!=="none"&&(a=o.image,o.image.side!=="top"&&(l="split",f=o.image.side==="right"?"right":"left")),(!a||!G(a.asset))&&(a=null,l="stack"),{template:l,media:a,side:f,scrim:I(o.scrim,0,.9)??.45,padding:F(["none","sm","md","lg"],o.padding,"md")}}var Je=(i,o)=>F(["sm","md","lg","full"],i.size,null)??(o.template==="split"||o.template==="overlay"?"lg":"md"),Qe=(i,o,a=1)=>{if(i==="fullscreen"||o==="full")return"100vw";let l=i==="teaser"?220:i==="sheet"?400:Ve[o]??Ve.md;return`(max-width: 639px) 100vw, ${Math.round(l*a)}px`},et=(i,o,a)=>{if(!a||!Array.isArray(i.widths)||!o.endsWith(".webp"))return null;let l=i.widths.filter(f=>Number.isInteger(f)&&f>0&&f<a).sort((f,x)=>f-x);return l.length===0?null:[...l.map(f=>`${o.slice(0,-5)}-${f}w.webp ${f}w`),`${o} ${a}w`].join(",")},tt=(i,o)=>i.format==="inline"?"inline":o.format&&o.format!=="inline"?o.format:i.format,ve=i=>i.kind==="video"||i.t==="video",we={webm:"video/webm",mp4:"video/mp4",m4v:"video/mp4",mov:"video/quicktime",ogv:"video/ogg"},ke=i=>we[i.split(/[?#]/)[0].split(".").pop().toLowerCase()],Nt=(i,o)=>[...new Set([o,...Array.isArray(i.sources)?i.sources.map(G):[]])].filter(Boolean).sort((a,l)=>(ke(l)===we.webm)-(ke(a)===we.webm));function Ae(i,o,a,l=new Set){let f=o.steps.find(k=>k.id===a);if(!f)return Promise.resolve();let x=tt(i,o),m=Ze(f),v=x==="teaser"&&f===o.steps[0],h=x==="teaser"&&!v?"popup":x,T=Je(o.theme,m),E=v?[]:f.blocks.filter(k=>P(k)&&(k.t==="image"||k.t==="video")).map(k=>[k,1]);return m.media&&!(v&&m.template!=="image-only")&&E.push([m.media,m.template==="split"?.46:1]),Promise.all(E.map(([k,Z])=>{let C=G(ve(k)?k.poster:k.asset);if(!C)return null;let L=document.createElement("img"),U=!ve(k)&&et(k,C,I(k.width,1,8192));U&&(L.sizes=Qe(h,T,Z),L.srcset=U);let y=`${L.sizes} ${U||C}`;return l.has(y)?null:(l.add(y),L.src=C,L.decode?.().catch(()=>{}))}))}var jt=0,ye=i=>`hp-${i}-${++jt}`;function u(i,o,a){let l=document.createElement(i);return o&&(l.className=o),a!==void 0&&l.append(We(a)),l}var nt=i=>{let o=i.length===4?[...i.slice(1)].map(a=>a+a).join(""):i.slice(1);return[0,2,4].map(a=>Number.parseInt(o.slice(a,a+2),16))},K=i=>{let[o,a,l]=nt(i).map(f=>{let x=f/255;return x<=.04045?x/12.92:((x+.055)/1.055)**2.4});return .2126*o+.7152*a+.0722*l},Ke=(i,o=4.5)=>{let a=K(i)+.05,l=1.05/a;return l>=o?"#fff":a/(K("#111")+.05)>l?"#111":"#fff"};function qt(i,o){let a=(E,k)=>k&&i.style.setProperty(E,k),l=E=>$t.test(E??"")?E:null;a("--hp-accent",l(o.accent)),a("--hp-bg",l(o.background)),a("--hp-text",l(o.text));let f=I(o.radius,0,48);f!==null&&a("--hp-radius",`${f}px`),a("--hp-font",o.font==="site"?i.ownerDocument.defaultView.getComputedStyle(i.parentElement??i.ownerDocument.body).fontFamily:Object.hasOwn(he,o.font)?he[o.font]:null),l(o.accent)&&(a("--hp-on-accent",Ke(o.accent,3)),a("--hp-on-accent-text",Ke(o.accent))),l(o.background)&&K(o.background)<.18&&(a("--hp-field","#fff"),a("--hp-field-text","#111"));let x=P(o.overlay)?o.overlay:{},m=[l(o.text),l(o.background)].filter(Boolean).sort((E,k)=>K(E)-K(k))[0],[v,h,T]=nt(l(x.colour)??m??"#0b0b0f");a("--hp-ov",`rgb(${v} ${h} ${T} / ${I(x.opacity,0,1)??.6})`)}function Dt(i){try{let o=new CSSStyleSheet;o.replaceSync(be),i.adoptedStyleSheets=[o]}catch{let o=document.createElement("style");o.textContent=be,i.append(o)}}function it(i){let{form:o,creative:a,decision:l,access:f,client:x,api:m,counters:v}=i,h=i.preview??null,T=e=>{let t=e.blocks.find(r=>r?.t==="email"||r?.t==="phone");return t?.t==="phone"||!t&&!o.consent_text?o.sms_consent_text:o.consent_text},E=tt(o,a),k=a.theme,Z=F(Be[E]??[],k.position,Be[E]?.[0]),C=document.createElement("hp-onsite");h&&C.setAttribute("preview",""),qt(C,k);let L=C.attachShadow({mode:"open"});Dt(L);let U=E!=="inline"&&!h,y=u(U?"dialog":E==="inline"?"section":"div"),Se=u("div","ov"),$=u("div","w"),W=u("div","m");h&&(W.dataset.hpMedia="");let Ee=()=>{let e=u("form","f");return e.noValidate=!0,e.addEventListener("submit",gt),e.addEventListener("input",()=>{M.textContent&&S.getAttribute("aria-busy")!=="true"&&N(null)}),e},S=Ee(),M=u("p","e");M.id=ye("err"),M.setAttribute("aria-live","assertive");let re=u("div","hd");re.setAttribute("aria-hidden","true"),$.append(re,W,S),y.append(Se,$);let Y=E!=="inline"&&u("button","x");Y&&(Y.type="button",Y.addEventListener("click",()=>j("close")),$.append(Y),Se.addEventListener("click",()=>j("close"))),L.append(y);let n={step:null,mode:E,size:"md",modal:!1,mobile:h?.device==="mobile",answers:{},sent:new Set,receipt:null,claim:i.coupon?{code:i.coupon}:h?{code:"WELCOME15"}:null,claiming:null,touched:!1,toWarm:new Set,warmed:i.warmed??new Set,warming:!1,owed:!1,unclaimed:!1,misses:0,submitted:!1,pow:null,wheel:null,timers:[],codes:[],videos:[],closed:!1},J=o.locale||document.documentElement.lang,ot=o.questions.some(ge)&&i.loadAnswers().catch(()=>null),$e=new WeakMap,_e=()=>{let e=P(k.button)?k.button:{};y.className=`s ${n.mode}${Z?` p-${Z}`:""} b-${F(["pill","rounded","square"],e.shape,"rounded")}${n.mobile?" mob":""}${h?" pv":""}${e.style==="outline"?" bo":""}${k.caps===!0?" uc":""}`},X=h?null:globalThis.matchMedia?.("(max-width: 639px)"),ze=()=>{n.mobile=X?.matches===!0,le(),_e()};X&&(n.mobile=X.matches===!0,X.addEventListener?.("change",ze));let Q=(e,t)=>{h||!l.decision_id||!f.analytics()||x.slotEngaged({decision_id:l.decision_id,slot:l.slot,arm:l.arm??null,engagement:e,step:t??n.step?.id??null})},N=(e,t)=>{M.className="e",M.textContent=e??"";for(let s of S.querySelectorAll("[aria-invalid]"))s.removeAttribute("aria-invalid");let r=t?.closest("label,fieldset");r&&S.contains(r)?r.after(M):S.append(M),t&&(t.setAttribute("aria-invalid","true"),t.setAttribute("aria-describedby",M.id),t.focus(),t.scrollIntoView?.({block:"nearest"}))},H=e=>{S.setAttribute("aria-busy",String(e));for(let t of S.querySelectorAll("button"))t.disabled=e},Te=()=>h?Promise.resolve(null):(n.pow??(n.pow=m.challenge().then(e=>e.status===200?Ue(e.body):null).catch(()=>null)),n.pow),se=()=>{for(let e of n.videos)try{document.hidden||xe()?e.pause():e.play()?.catch?.(()=>{})}catch{}};document.addEventListener("visibilitychange",se);function Ce(e,t,r,s){let c=G(e.asset);if(!c)return null;let p=typeof e.alt=="string"?e.alt:"",d;if(ve(e)){d=u("video",t),d.muted=d.defaultMuted=d.loop=d.playsInline=!0;let w=G(e.poster);w&&(d.poster=w),p?d.setAttribute("aria-label",p):d.setAttribute("aria-hidden","true"),d.autoplay=!xe()&&!h,d.preload=d.autoplay?"auto":w?"none":"metadata";let _=Nt(e,c);if(_.length>1)for(let z of _){let O=u("source");O.src=z;let q=ke(z);q&&(O.type=q),d.append(O)}else d.src=c;n.videos.push(d)}else{d=u("img",t),d.alt=p,d.decoding="async",d.loading=r?"eager":"lazy",r&&(d.fetchPriority="high");let w=et(e,c,I(e.width,1,8192));w&&(d.sizes=Qe(n.mode,n.size,s),d.srcset=w),d.src=c}let b=I(e.width,1,8192),g=I(e.height,1,8192);return b&&g&&(d.width=b,d.height=g),P(e.focal)&&(d.style.objectPosition=`${I(e.focal.x,0,100)??50}% ${I(e.focal.y,0,100)??50}%`),d}function Le(e,t){let r=u("label","l");r.append(u("span","lt",e.label??(t==="email"?"Email":"Mobile number")));let s=u("input","i");if(s.type=t,s.name=t==="email"?"email":"phone",s.autocomplete=s.inputMode=t,s.required=!0,typeof e.placeholder=="string"&&(s.placeholder=e.placeholder),s.setAttribute("aria-describedby",M.id),s.addEventListener("focus",Te,{once:!0}),t!=="tel")return r.append(s),r;s.id=`${M.id}-p`,r.htmlFor=s.id;let c=fe(u,"Country code","+",Object.entries(ue).map(([d,b])=>[d,`${d} +${b}`]),(e.country||/-(\w\w)$/.exec(J)?.[1]||"").toUpperCase());c.classList.add("cc"),c.name="hp_cc";let p=u("span","ph");return p.append(c,s),r.append(p),r}function rt(e){let t=o.questions.find(b=>b.key===e.question);if(!t||!ge(t)&&!Array.isArray(t.options))return null;let r=u("fieldset");r.dataset.question=t.key,r.append(u("legend","",t.label??""));let s=n.answers[t.key]??[];if(ge(t))return ot.then(b=>{if(!b)return r.append(u("p","sm",A.unavailable));b.answerFields(r,t,u,s[0],J),$e.set(r,()=>b.answerOf(r,t,void 0,J))}),r;let c=t.type==="many",p=F(["list","dropdown"],e.display,"buttons"),d=t.options.filter(b=>P(b)&&typeof b.value=="string");if(p==="dropdown"&&!c)return r.append(fe(u,t.label??t.key,"\u2014",d.map(b=>[b.value,b.label??b.value]),s[0])),r;p!=="buttons"&&(r.className="ls");for(let b of d){let g=u("input");g.value=b.value,g.checked=s.includes(b.value),g.type=c?"checkbox":"radio",g.name=`q_${t.key}`;let w=u("label",p==="buttons"?"ch":"c");w.append(g,u("span","",b.label??b.value)),r.append(w)}return r}function ee(){for(let e of n.codes){if(e.replaceChildren(),!n.claim){n.unclaimed&&e.append(u("p","",A.unclaimed));continue}if(!n.claim.code){let s=n.claim.held?A.claimed:n.claim.fallback===!0?A.code:n.claim.prize?.label;s&&e.append(u("p","",s));continue}n.claim.prize?.label&&e.append(u("p","",n.claim.prize.label));let t=u("output");t.textContent=n.claim.code;let r=u("button","btn cp");r.type="button",r.textContent="Copy code",r.addEventListener("click",()=>{navigator.clipboard?.writeText(n.claim.code).then(()=>{r.textContent=A.copied}).catch(()=>{})}),e.append(t,r)}}function st(e){if(n.claim&&!n.claim.code)return null;let t=u("p","tm");t.setAttribute("role","timer");let r=Date.now()+Math.max(0,Number(e.minutes)||0)*6e4,s=()=>{let p=Math.max(0,Math.round((r-Date.now())/1e3));t.textContent=`${String(Math.floor(p/60)).padStart(2,"0")}:${String(p%60).padStart(2,"0")}`,p===0&&clearInterval(c)},c=setInterval(s,1e3);return n.timers.push(c),s(),t}function ae(e,t){return e.href=t,e.rel="noopener",e.addEventListener("click",r=>{h?r.preventDefault():Q("click")}),e}function at(e){let t=e.label??"Continue";if(e.action==="link"){let s=B(e.href);return s?ae(u("a",`btn${Xe[e.variant]??""}`,t),s):null}let r=u("button",`btn${Xe[e.variant]??""}`,t);return r.type=e.action==="submit"?"submit":"button",r.type==="button"?r.addEventListener("click",()=>ie(e)):r.dataset.submit="",r}let Me=(e,t,r)=>(e.classList.add(`x-${F(Tt,t.size,r)}`),Ct.includes(t.align)&&e.classList.add(`a-${t.align}`),e);function Oe(e){let t=Ce(e,"bi",n.step===a.steps[0]);if(!t)return null;t.style.objectFit=e.fit==="contain"?"contain":"cover";let r=I(e.radius,0,48);r!==null&&(t.style.borderRadius=`${r}px`);let s=I(e.max_height,40,800);if(s!==null&&(t.style.maxHeight=`${s}px`),!t.width&&e.fit!=="contain"&&(t.style.aspectRatio="16 / 9"),e.t==="video"||!B(e.href))return t;let c=ae(u("a","bl"),B(e.href));return c.append(t),c}function lt(e){let t=I(e.threshold,.01,1e7);if(!t)return null;let r=u("div","pg"),s=u("p"),c=u("div","tr"),p=u("i");c.append(p),c.setAttribute("role","progressbar"),c.setAttribute("aria-valuemin","0"),c.setAttribute("aria-valuemax",String(t)),r.append(s,c);let d=g=>g.toFixed(2);try{let g=new Intl.NumberFormat(J||void 0,{style:"currency",currency:e.currency});d=w=>g.format(w)}catch{}let b=()=>{let g=Math.max(0,Number(i.basket?.())||0),w=t-g;s.textContent=w>0?String(e.text??"").replace("{amount}",d(w)):e.done??"",p.style.transform=`scaleX(${Math.min(1,g/t)})`,c.setAttribute("aria-valuenow",String(Math.min(g,t))),s.id||(s.id=ye("pg")),c.setAttribute("aria-labelledby",s.id)};return b(),n.timers.push(setInterval(b,2e3)),r}let Ie={heading(e){let t=Me(u("h2","",e.text),e,"xl");return t.id=ye("h"),t.tabIndex=-1,y.hasAttribute("aria-labelledby")||(y.setAttribute("aria-labelledby",t.id),n.step===a.steps[0]&&He.includes(n.mode)&&!h&&(t.autofocus=!0)),t},text:e=>Me(u("p","",e.text),e,"md"),email:e=>Le(e,"email"),phone:e=>Le(e,"tel"),consent(e){let t=T(n.step)?.text;if(typeof t!="string")return null;if(e.required!==!0)return u("p","sm",t);let r=u("label","c"),s=u("input");return s.type="checkbox",s.name="hp_consent",s.required=!0,s.setAttribute("aria-describedby",M.id),r.append(s,u("span","",t)),r},question:rt,wheel(){let e=u("div","wh");return i.loadWheel().then(t=>{n.closed||(n.wheel=t.mountWheel(e,o.prizes))}).catch(()=>{}),e},code(){let e=u("div","k");return e.setAttribute("aria-live","polite"),n.codes.push(e),e},button:at,decline(e){let t=u("button","btn no",e.label??"No thanks");return t.type="button",t.addEventListener("click",()=>j("decline")),t},countdown:st,progress:lt,image:Oe,video:Oe,spacer(e){let t=u("div","sp");return t.style.height=`${Ge[e.size]??Ge.md}px`,t.setAttribute("aria-hidden","true"),t},divider:()=>u("hr")};function ct(e,t){W.replaceChildren();let r=e.media,s=!r||t&&e.template!=="image-only";if(n.size=Je(k,e),$.className=`w t-${e.template} z-${n.size}${e.side==="right"?" right":""}${k.text_align==="center"?" ta-center":""}${s?" nm":""}`,$.style.setProperty("--sc",String(e.scrim)),S.className=`f pd-${e.padding}`,W.hidden=s,W.hidden)return;let c=Ce(r,"",n.step===a.steps[0],e.template==="split"?.46:1);if(!c)return;if(c.width?$.style.setProperty("--ar",`${c.width} / ${c.height}`):$.style.removeProperty("--ar"),e.template!=="image-only"){c.tagName==="IMG"&&e.template==="overlay"&&(c.alt=""),W.append(c);return}let p=B(r.href),d=p?ae(u("a","io"),p):u("button","io");p||(d.type="button",d.addEventListener("click",()=>ie({action:"next"}))),d.append(c),W.append(d)}function dt(e){let t=e.blocks.find(c=>c?.t==="heading"),r=e.blocks.find(c=>c?.t==="button"&&c.action==="next"),s=u("button","tb");return s.textContent=t?u("b","",t.text).textContent:r?.label??"Open",s.type="button",s.addEventListener("click",()=>ie(r??{action:"next"})),s}function D(e,t=new Set){let r=a.steps.find(z=>z.id===e);if(!r)return j("done");if(r.kind==="question"&&!h&&!f.analytics()&&!t.has(r.id))return D(V(r,n.answers),t.add(r.id));let s=n.step!==null,c=s&&(L.activeElement||document.activeElement===document.body),p=s&&!h?{mode:n.mode,w:$.offsetWidth,h:$.offsetHeight,top:$.offsetTop}:null;n.step=r,n.touched=!1;for(let z of n.timers.splice(0))clearInterval(z);n.codes=[],n.videos=[],n.wheel=null;let d=E==="teaser"&&r===a.steps[0];if(n.mode=E==="teaser"&&!d?"popup":E,E==="teaser"&&v.tab?.(o.slot,d),Y&&Y.setAttribute("aria-label",d?A.closeOffer:"Close"),_e(),y.removeAttribute("aria-labelledby"),p){let z=Ee();S.replaceWith(z),S=z}let b=Ze(r);ct(b,d);let g=p?.mode==="popup"&&n.mode==="popup";if(le(),p?.mode===n.mode&&p.h>0&&!g&&($.style.setProperty("--lw",`${p.w}px`),$.style.setProperty("--lh",`${p.h}px`),$.classList.add("lk")),S.replaceChildren(),d&&b.template!=="image-only")S.append(dt(r));else for(let[z,O]of r.blocks.entries()){let q=P(O)&&Object.hasOwn(Ie,O.t)?Ie[O.t](O):null;q&&(h&&(q.dataset.hpBlock=String(z)),S.append(q))}let w=S.querySelector("[data-submit]"),_=S.querySelector("[name=hp_consent]")?.parentNode;w&&_&&w.before(_),S.hidden=S.childElementCount===0,N(null),ee(),y.hasAttribute("aria-labelledby")?y.removeAttribute("aria-label"):y.setAttribute("aria-label",b.media?.alt?.trim?.()||"Sign up"),g&&p.h>0&&pt(p),s&&Pe(),se(),h||ut(r),c&&S.querySelector("h2")?.focus()}function le(){$.classList.remove("lk","an"),$.style.removeProperty("--tp")}function pt(e){let t=$.offsetHeight;$.classList.add("an");let r=$.offsetTop,s=Math.max(0,e.top-r);if(s+t>y.clientHeight-2*r)return le();$.style.setProperty("--tp",`${s}px`)}function ut(e){let t=e.next??{};for(let c of[t.default,...Object.values(P(t.answers)?t.answers:{}),...e.blocks.map(p=>p?.next),...Mt])typeof c=="string"&&n.toWarm.add(c);if(n.warming)return;n.warming=!0;let r=()=>{if(n.warming=!1,!n.closed&&C.isConnected)for(let c of n.toWarm)Ae(o,a,c,n.warmed);n.toWarm.clear()},s=()=>globalThis.requestIdleCallback?requestIdleCallback(r,{timeout:2e3}):setTimeout(r,200);document.readyState==="complete"?s():window.addEventListener("load",s,{once:!0})}function Pe(){if(!U)return;let e=He.includes(n.mode);if(!(y.open&&n.modal===e)){try{y.open&&y.close()}catch{}if(n.modal=e,y.setAttribute("aria-modal",String(e)),e&&typeof y.showModal=="function")y.showModal();else if(typeof y.show=="function"){let t=document.activeElement;y.show(),t&&t!==document.body?t.focus?.({preventScroll:!0}):C.blur()}else y.setAttribute("open","");!e||typeof y.showModal!="function"?y.setAttribute("role","dialog"):y.removeAttribute("role")}}function ft(){for(let e of S.querySelectorAll("fieldset[data-question]")){let t=e.dataset.question,r=$e.get(e)?.()??{};if(r.error)return r;let s=[r.value,...[...e.querySelectorAll("input:checked,select:not([name])")].map(c=>c.value)].filter(Boolean);s.length?n.answers[t]=s:delete n.answers[t]}}function mt(){let e=[];for(let[r,s]of Object.entries(n.answers)){let c=`${r}=${s.join(",")}`;n.sent.has(c)||(n.sent.add(c),e.push({question:r,values:s}))}let t=n.step.id;if(n.signedUp&&e.length)return void m.answers({anonymousId:f.anonymousId(),sessionId:f.sessionId()??void 0,slot:l.slot,arm:l.arm??void 0,decision_id:l.decision_id??void 0,step:t,...n.signedUp,answers:e,context:Ne()});if(f.analytics())for(let r of e)x.preferencesStated({...r,source:"onsite",slot:l.slot,arm:l.arm??null,decision_id:l.decision_id??null,step:t})}let Ne=()=>({page:{url:f.pageUrl()},locale:f.locale()??void 0,consent:f.consent()}),te=e=>{n.receipt&&!h&&mt(),D(V(n.step,n.answers,e))};async function ht(e){let t=n.step,r=S.querySelector("input[name=email],input[name=phone]");if(!r)return te(e.next);let s=r.name==="email"?"email":"sms",c=S.querySelector("select[name=hp_cc]")?.value,p=s==="email"?Ye(r.value.trim())?r.value.trim():null:Fe(r.value,c);if(!p)return N(s==="email"?A.email:c?A.phone:A.intl,r);let d=S.querySelector("input[name=hp_consent]");if(d&&!d.checked)return N(A.consent,d);N(null),H(!0);let b=await Te();n.pow=null;let g=Object.entries(n.answers).map(([R,de])=>({question:R,values:de})),w=s==="sms"?o.sms_consent_text:o.consent_text,_=await m.capture({anonymousId:f.anonymousId(),sessionId:f.sessionId()??void 0,slot:l.slot,arm:l.arm??void 0,decision_id:l.decision_id??void 0,step:t.id,channel:s,[s==="email"?"email":"phone"]:p,...s==="sms"&&n.signedUp,consent_text:w?{id:w.id,version:w.version}:void 0,...g.length?{answers:g}:{},...b?{altcha:b}:{},context:Ne()}),z=_.body?.status,O=(_.status===202||_.status===200)&&_t.includes(z);if(n.closed&&!O)return;O||H(!1);let q=_.status===400?_.body?.field:null;if(q==="email"||q==="phone")return N(A[q],r);if(!O)return N(_.status===429?A.busy:A.failed,r);r.value="";for(let[R,de]of Object.entries(n.answers))n.sent.add(`${R}=${de.join(",")}`);n.receipt=typeof _.body.receipt=="string"?_.body.receipt:null,s==="email"&&(n.signedUp={email:p,email_receipt:n.receipt}),n.submitted=!0,v.submitted(o.slot),Q("submit",t.id),n.owed=s==="email"&&o.prizes.length>0;let oe=n.owed?ce([]):null;oe||i.emit?.("submitted",{coupon:null});let yt=oe&&await Promise.race([oe,new Promise(R=>setTimeout(R,It))]);if(n.closed)return;if(H(!1),yt?.held)return D(ne("held"));let vt=z!=="ok"&&a.steps.some(R=>R.id===z);D(vt?z:V(t,n.answers,e.next));let wt=n.step;oe?.then(R=>{R?.held&&!n.closed&&n.step===wt&&!n.touched&&D(ne("held"))})}function ne(e){if(a.steps.some(s=>s.id===e))return e;let t={t:"button",label:A.shop,action:"close"},r=e==="unclaimed"?[{t:"heading",text:A.thanks},{t:"text",text:A.unclaimed},t]:e==="fallback"||n.claim?.code?[{t:"heading",text:e==="fallback"?A.thanks:A.yours},{t:"code"}]:[{t:"heading",text:A.held},{t:"text",text:o.code_relayed===!0?A.resent:A.inbox},t];return a.steps.push({id:e,blocks:r}),e}function je(e){n.owed&&(n.owed=!1,i.emit?.("submitted",{coupon:e?{code:e.code??null,prize:e.prize?.key}:null}))}function ce(e=Ot){let t=n.receipt;return n.claiming??(n.claiming=(async()=>{n.unclaimed=!1;let r;for(let d of[0,...e])if(d&&await new Promise(b=>setTimeout(b,d)),r=await m.claim({slot:l.slot,decision_id:l.decision_id??void 0,receipt:t}),r.status!==503)break;let s=r.body,c=s?.fallback===!0&&!s.code;if(r.status!==200||!(P(s?.prize)||c))return n.claiming=null,!e.length&&r.status===503?ce():(je(null),n.unclaimed=!0,n.closed||ee(),null);let p=s.held&&!s.code?v.code?.():null;return p&&(s={...s,code:p}),n.claim=s,typeof s.code=="string"&&v.code?.(s.code),je(s),n.closed||ee(),s})()),n.claiming}async function bt(e){if(!n.receipt)return N(A.spin);H(!0);let t=await ce();if(n.closed)return;if(!t)return H(!1),n.misses+=1,n.misses<2?N(A.retry):D(ne("unclaimed"));let r=t.fallback===!0&&!t.code,s=t.held?-1:o.prizes.findIndex(d=>d.key===t.prize?.key&&d.label===t.prize?.label);if(n.wheel&&s>=0&&!r){if(await n.wheel.spinTo(s),n.closed)return;M.className="e won",M.textContent=`${A.won} ${t.prize.label}`,await new Promise(d=>setTimeout(d,Pt))}if(n.closed)return;H(!1);let c=r?"fallback":s<0?"held":null,p=c?ne(c):V(n.step,n.answers,e.next);p?D(p):ee()}function ie(e){if(e.action==="close")return j("close");let t=ft();return h?te(e.next):t?N(t.error,t.input):e.action==="apply"?(i.emit?.("apply",{coupon:n.claim?.code?{code:n.claim.code}:null}),Q("click"),V(n.step,n.answers,e.next)?te(e.next):j("done")):e.action==="submit"?ht(e):e.action==="spin"?bt(e):te(e.next)}function gt(e){if(e.preventDefault(),S.getAttribute("aria-busy")==="true")return;let t=n.step.blocks.find(r=>r?.t==="button"&&r.action==="submit");ie(t??{action:"next"})}function qe(){n.closed=!0;for(let t of n.timers.splice(0))clearInterval(t);document.removeEventListener("visibilitychange",se),X?.removeEventListener?.("change",ze);let e=()=>{try{y.open&&y.close()}catch{}C.remove()};if(!U||xe())return e();y.classList.add("out"),setTimeout(e,Lt)}function j(e){n.closed||h||(!n.submitted&&e!=="done"&&Q("dismiss"),v.closed(o.slot),v.tab?.(o.slot,!1),qe(),i.onClose?.(e))}for(let e of["pointerdown","keydown","input"])y.addEventListener(e,()=>{n.touched=!0});y.addEventListener("cancel",e=>{e.preventDefault(),j("esc")}),y.addEventListener("keydown",e=>{e.key==="Escape"&&!n.modal&&E!=="inline"&&j("esc"),e.key==="Tab"&&n.modal&&xt(e)});function xt(e){let t=[...L.querySelectorAll("input[type=radio]:checked")],r=new Set,s=[...L.querySelectorAll("a[href],button,input,select,textarea")].filter(g=>{if(g.disabled||!g.getClientRects().length)return!1;if(g.type!=="radio")return!0;let w=t.find(_=>_.name===g.name);return(w?g!==w:r.has(g.name))?!1:(r.add(g.name),!0)});if(!s.length)return;let c=e.shiftKey,p=L.activeElement;p?.type==="radio"&&(p=s.find(g=>g.type==="radio"&&g.name===p.name)??p);let d=s.indexOf(p),b=null;if(d<0){let g=w=>p&&p.compareDocumentPosition(w)&4;b=c?s.findLast(w=>!g(w))??s.at(-1):s.find(g)??s[0]}else(c?d===0:d===s.length-1)&&(b=s.at(c?-1:0));b&&(e.preventDefault(),b.focus())}return re.addEventListener("pointerdown",e=>{if(!n.mobile||n.mode!=="sheet")return;let t=e.clientY,r=0,s=p=>{r=Math.max(0,p.clientY-t),$.style.transform=`translateY(${r}px)`},c=()=>{document.removeEventListener("pointermove",s),document.removeEventListener("pointerup",c),$.style.transform="",r>80&&j("close")};document.addEventListener("pointermove",s),document.addEventListener("pointerup",c)}),D(h?.step&&a.steps.some(e=>e.id===h.step)?h.step:a.steps[0].id),(i.container??document.body).append(C),Pe(),{close:j,root:L,host:C,show:D,step:()=>n.step?.id??null,modal:()=>!n.closed&&n.modal,destroy:()=>!n.closed&&qe()}}window[Symbol.for("@thg-agentic/hyper-personalisation-web.onsite.render")]={mountForm:it,warm:Ae};})();
|
|
182
|
+
`;var _t=/^#(?:[0-9a-f]{3}){1,2}$/i,He=["popup","fullscreen"],$t=["ok","verify","already"],zt=["stack","split","overlay","image-only"],Be={bar:["bottom","top"],sheet:["bottom-right","bottom-left","bottom"],teaser:["bottom-left","bottom-right","left","right"]},Tt=["xs","sm","md","lg","xl","display"],Ge={xs:4,sm:8,md:16,lg:28,xl:44},Ve={sm:380,md:480,lg:880},Ct=["left","center","right"],Xe={secondary:" b2",link:" no"},Lt=220,Mt=["verify","already","held","fallback","success"],Ot=[500,1500],It=600,Pt=1800,A={email:"Enter a valid email address.",phone:"Enter a valid mobile number.",intl:"Enter a valid mobile number, starting with + and its country code.",consent:"Tick the box to sign up.",failed:"Something went wrong. Please try again.",busy:"Too many tries. Please wait a moment and try again.",spin:"Sign up first to spin.",yours:"Your code",held:"You\u2019re already on the list",resent:"We\u2019ve sent your code to your inbox again.",inbox:"Your code is in the email we sent when you first signed up.",shop:"Continue shopping",closeOffer:"Close offer",code:"We\u2019ll email your code to you.",claimed:"This email address has already claimed its code.",copied:"Copied",thanks:"Thanks, you\u2019re signed up",retry:"You\u2019re signed up, but we couldn\u2019t load your prize. Please try again.",unclaimed:"We couldn\u2019t load your prize right now.",unavailable:"Not available right now.",won:"You won"},P=i=>i!==null&&typeof i=="object"&&!Array.isArray(i),F=(i,o,a)=>i.includes(o)?o:a,I=(i,o,a)=>Number.isFinite(i)?Math.min(Math.max(i,o),a):null,ge=i=>i.type==="date"||i.type==="number",xe=()=>globalThis.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches===!0;function Ze(i){let o=P(i.layout)?i.layout:{},a=P(o.media)?o.media:null,l=F(zt,o.template,"stack"),f=a?.side==="right"?"right":"left";return!a&&P(o.image)&&o.image.side!=="none"&&(a=o.image,o.image.side!=="top"&&(l="split",f=o.image.side==="right"?"right":"left")),(!a||!G(a.asset))&&(a=null,l="stack"),{template:l,media:a,side:f,scrim:I(o.scrim,0,.9)??.45,padding:F(["none","sm","md","lg"],o.padding,"md")}}var Je=(i,o)=>F(["sm","md","lg","full"],i.size,null)??(o.template==="split"||o.template==="overlay"?"lg":"md"),Qe=(i,o,a=1)=>{if(i==="fullscreen"||o==="full")return"100vw";let l=i==="teaser"?220:i==="sheet"?400:Ve[o]??Ve.md;return`(max-width: 639px) 100vw, ${Math.round(l*a)}px`},et=(i,o,a)=>{if(!a||!Array.isArray(i.widths)||!o.endsWith(".webp"))return null;let l=i.widths.filter(f=>Number.isInteger(f)&&f>0&&f<a).sort((f,x)=>f-x);return l.length===0?null:[...l.map(f=>`${o.slice(0,-5)}-${f}w.webp ${f}w`),`${o} ${a}w`].join(",")},tt=(i,o)=>i.format==="inline"?"inline":o.format&&o.format!=="inline"?o.format:i.format,ve=i=>i.kind==="video"||i.t==="video",we={webm:"video/webm",mp4:"video/mp4",m4v:"video/mp4",mov:"video/quicktime",ogv:"video/ogg"},ke=i=>we[i.split(/[?#]/)[0].split(".").pop().toLowerCase()],Nt=(i,o)=>[...new Set([o,...Array.isArray(i.sources)?i.sources.map(G):[]])].filter(Boolean).sort((a,l)=>(ke(l)===we.webm)-(ke(a)===we.webm));function Ae(i,o,a,l=new Set){let f=o.steps.find(k=>k.id===a);if(!f)return Promise.resolve();let x=tt(i,o),m=Ze(f),v=x==="teaser"&&f===o.steps[0],h=x==="teaser"&&!v?"popup":x,T=Je(o.theme,m),E=v?[]:f.blocks.filter(k=>P(k)&&(k.t==="image"||k.t==="video")).map(k=>[k,1]);return m.media&&!(v&&m.template!=="image-only")&&E.push([m.media,m.template==="split"?.46:1]),Promise.all(E.map(([k,Z])=>{let C=G(ve(k)?k.poster:k.asset);if(!C)return null;let L=document.createElement("img"),U=!ve(k)&&et(k,C,I(k.width,1,8192));U&&(L.sizes=Qe(h,T,Z),L.srcset=U);let y=`${L.sizes} ${U||C}`;return l.has(y)?null:(l.add(y),L.src=C,L.decode?.().catch(()=>{}))}))}var jt=0,ye=i=>`hp-${i}-${++jt}`;function u(i,o,a){let l=document.createElement(i);return o&&(l.className=o),a!==void 0&&l.append(We(a)),l}var nt=i=>{let o=i.length===4?[...i.slice(1)].map(a=>a+a).join(""):i.slice(1);return[0,2,4].map(a=>Number.parseInt(o.slice(a,a+2),16))},K=i=>{let[o,a,l]=nt(i).map(f=>{let x=f/255;return x<=.04045?x/12.92:((x+.055)/1.055)**2.4});return .2126*o+.7152*a+.0722*l},Ke=(i,o=4.5)=>{let a=K(i)+.05,l=1.05/a;return l>=o?"#fff":a/(K("#111")+.05)>l?"#111":"#fff"};function qt(i,o){let a=(E,k)=>k&&i.style.setProperty(E,k),l=E=>_t.test(E??"")?E:null;a("--hp-accent",l(o.accent)),a("--hp-bg",l(o.background)),a("--hp-text",l(o.text));let f=I(o.radius,0,48);f!==null&&a("--hp-radius",`${f}px`),a("--hp-font",o.font==="site"?i.ownerDocument.defaultView.getComputedStyle(i.parentElement??i.ownerDocument.body).fontFamily:Object.hasOwn(he,o.font)?he[o.font]:null),l(o.accent)&&(a("--hp-on-accent",Ke(o.accent,3)),a("--hp-on-accent-text",Ke(o.accent))),l(o.background)&&K(o.background)<.18&&(a("--hp-field","#fff"),a("--hp-field-text","#111"));let x=P(o.overlay)?o.overlay:{},m=[l(o.text),l(o.background)].filter(Boolean).sort((E,k)=>K(E)-K(k))[0],[v,h,T]=nt(l(x.colour)??m??"#0b0b0f");a("--hp-ov",`rgb(${v} ${h} ${T} / ${I(x.opacity,0,1)??.6})`)}function Dt(i){try{let o=new CSSStyleSheet;o.replaceSync(be),i.adoptedStyleSheets=[o]}catch{let o=document.createElement("style");o.textContent=be,i.append(o)}}function it(i){let{form:o,creative:a,decision:l,access:f,client:x,api:m,counters:v}=i,h=i.preview??null,T=e=>{let t=e.blocks.find(r=>r?.t==="email"||r?.t==="phone");return t?.t==="phone"||!t&&!o.consent_text?o.sms_consent_text:o.consent_text},E=tt(o,a),k=a.theme,Z=F(Be[E]??[],k.position,Be[E]?.[0]),C=document.createElement("hp-onsite");h&&C.setAttribute("preview",""),qt(C,k);let L=C.attachShadow({mode:"open"});Dt(L);let U=E!=="inline"&&!h,y=u(U?"dialog":E==="inline"?"section":"div"),Se=u("div","ov"),_=u("div","w"),W=u("div","m");h&&(W.dataset.hpMedia="");let Ee=()=>{let e=u("form","f");return e.noValidate=!0,e.addEventListener("submit",gt),e.addEventListener("input",()=>{M.textContent&&S.getAttribute("aria-busy")!=="true"&&N(null)}),e},S=Ee(),M=u("p","e");M.id=ye("err"),M.setAttribute("aria-live","assertive");let re=u("div","hd");re.setAttribute("aria-hidden","true"),_.append(re,W,S),y.append(Se,_);let Y=E!=="inline"&&u("button","x");Y&&(Y.type="button",Y.addEventListener("click",()=>j("close")),_.append(Y),Se.addEventListener("click",()=>j("close"))),L.append(y);let n={step:null,mode:E,size:"md",modal:!1,mobile:h?.device==="mobile",answers:{},sent:new Set,receipt:null,claim:i.coupon?{code:i.coupon}:h?{code:"WELCOME15"}:null,claiming:null,touched:!1,toWarm:new Set,warmed:i.warmed??new Set,warming:!1,owed:!1,unclaimed:!1,misses:0,submitted:!1,pow:null,wheel:null,timers:[],codes:[],videos:[],closed:!1},J=o.locale||document.documentElement.lang,ot=o.questions.some(ge)&&i.loadAnswers().catch(()=>null),_e=new WeakMap,$e=()=>{let e=P(k.button)?k.button:{};y.className=`s ${n.mode}${Z?` p-${Z}`:""} b-${F(["pill","rounded","square"],e.shape,"rounded")}${n.mobile?" mob":""}${h?" pv":""}${e.style==="outline"?" bo":""}${k.caps===!0?" uc":""}`},X=h?null:globalThis.matchMedia?.("(max-width: 639px)"),ze=()=>{n.mobile=X?.matches===!0,le(),$e()};X&&(n.mobile=X.matches===!0,X.addEventListener?.("change",ze));let Q=(e,t)=>{h||!l.decision_id||!f.analytics()||x.slotEngaged({decision_id:l.decision_id,slot:l.slot,arm:l.arm??null,engagement:e,step:t??n.step?.id??null})},N=(e,t)=>{M.className="e",M.textContent=e??"";for(let s of S.querySelectorAll("[aria-invalid]"))s.removeAttribute("aria-invalid");let r=t?.closest("label,fieldset");r&&S.contains(r)?r.after(M):S.append(M),t&&(t.setAttribute("aria-invalid","true"),t.setAttribute("aria-describedby",M.id),t.focus(),t.scrollIntoView?.({block:"nearest"}))},H=e=>{S.setAttribute("aria-busy",String(e));for(let t of S.querySelectorAll("button"))t.disabled=e},Te=()=>h?Promise.resolve(null):(n.pow??(n.pow=m.challenge().then(e=>e.status===200?Ue(e.body):null).catch(()=>null)),n.pow),se=()=>{for(let e of n.videos)try{document.hidden||xe()?e.pause():e.play()?.catch?.(()=>{})}catch{}};document.addEventListener("visibilitychange",se);function Ce(e,t,r,s){let c=G(e.asset);if(!c)return null;let p=typeof e.alt=="string"?e.alt:"",d;if(ve(e)){d=u("video",t),d.muted=d.defaultMuted=d.loop=d.playsInline=!0;let w=G(e.poster);w&&(d.poster=w),p?d.setAttribute("aria-label",p):d.setAttribute("aria-hidden","true"),d.autoplay=!xe()&&!h,d.preload=d.autoplay?"auto":w?"none":"metadata";let $=Nt(e,c);if($.length>1)for(let z of $){let O=u("source");O.src=z;let q=ke(z);q&&(O.type=q),d.append(O)}else d.src=c;n.videos.push(d)}else{d=u("img",t),d.alt=p,d.decoding="async",d.loading=r?"eager":"lazy",r&&(d.fetchPriority="high");let w=et(e,c,I(e.width,1,8192));w&&(d.sizes=Qe(n.mode,n.size,s),d.srcset=w),d.src=c}let b=I(e.width,1,8192),g=I(e.height,1,8192);return b&&g&&(d.width=b,d.height=g),P(e.focal)&&(d.style.objectPosition=`${I(e.focal.x,0,100)??50}% ${I(e.focal.y,0,100)??50}%`),d}function Le(e,t){let r=u("label","l");r.append(u("span","lt",e.label??(t==="email"?"Email":"Mobile number")));let s=u("input","i");if(s.type=t,s.name=t==="email"?"email":"phone",s.autocomplete=s.inputMode=t,s.required=!0,typeof e.placeholder=="string"&&(s.placeholder=e.placeholder),s.setAttribute("aria-describedby",M.id),s.addEventListener("focus",Te,{once:!0}),t!=="tel")return r.append(s),r;s.id=`${M.id}-p`,r.htmlFor=s.id;let c=fe(u,"Country code","+",Object.entries(ue).map(([d,b])=>[d,`${d} +${b}`]),(e.country||/-(\w\w)$/.exec(J)?.[1]||"").toUpperCase());c.classList.add("cc"),c.name="hp_cc";let p=u("span","ph");return p.append(c,s),r.append(p),r}function rt(e){let t=o.questions.find(b=>b.key===e.question);if(!t||!ge(t)&&!Array.isArray(t.options))return null;let r=u("fieldset");r.dataset.question=t.key,r.append(u("legend","",t.label??""));let s=n.answers[t.key]??[];if(ge(t))return ot.then(b=>{if(!b)return r.append(u("p","sm",A.unavailable));b.answerFields(r,t,u,s[0],J),_e.set(r,()=>b.answerOf(r,t,void 0,J))}),r;let c=t.type==="many",p=F(["list","dropdown"],e.display,"buttons"),d=t.options.filter(b=>P(b)&&typeof b.value=="string");if(p==="dropdown"&&!c)return r.append(fe(u,t.label??t.key,"\u2014",d.map(b=>[b.value,b.label??b.value]),s[0])),r;p!=="buttons"&&(r.className="ls");for(let b of d){let g=u("input");g.value=b.value,g.checked=s.includes(b.value),g.type=c?"checkbox":"radio",g.name=`q_${t.key}`;let w=u("label",p==="buttons"?"ch":"c");w.append(g,u("span","",b.label??b.value)),r.append(w)}return r}function ee(){for(let e of n.codes){if(e.replaceChildren(),!n.claim){n.unclaimed&&e.append(u("p","",A.unclaimed));continue}if(!n.claim.code){let s=n.claim.held?A.claimed:n.claim.fallback===!0?A.code:n.claim.prize?.label;s&&e.append(u("p","",s));continue}n.claim.prize?.label&&e.append(u("p","",n.claim.prize.label));let t=u("output");t.textContent=n.claim.code;let r=u("button","btn cp");r.type="button",r.textContent="Copy code",r.addEventListener("click",()=>{navigator.clipboard?.writeText(n.claim.code).then(()=>{r.textContent=A.copied}).catch(()=>{})}),e.append(t,r)}}function st(e){if(n.claim&&!n.claim.code)return null;let t=u("p","tm");t.setAttribute("role","timer");let r=Date.now()+Math.max(0,Number(e.minutes)||0)*6e4,s=()=>{let p=Math.max(0,Math.round((r-Date.now())/1e3));t.textContent=`${String(Math.floor(p/60)).padStart(2,"0")}:${String(p%60).padStart(2,"0")}`,p===0&&clearInterval(c)},c=setInterval(s,1e3);return n.timers.push(c),s(),t}function ae(e,t){return e.href=t,e.rel="noopener",e.addEventListener("click",r=>{h?r.preventDefault():Q("click")}),e}function at(e){let t=e.label??"Continue";if(e.action==="link"){let s=B(e.href);return s?ae(u("a",`btn${Xe[e.variant]??""}`,t),s):null}let r=u("button",`btn${Xe[e.variant]??""}`,t);return r.type=e.action==="submit"?"submit":"button",r.type==="button"?r.addEventListener("click",()=>ie(e)):r.dataset.submit="",r}let Me=(e,t,r)=>(e.classList.add(`x-${F(Tt,t.size,r)}`),Ct.includes(t.align)&&e.classList.add(`a-${t.align}`),e);function Oe(e){let t=Ce(e,"bi",n.step===a.steps[0]);if(!t)return null;t.style.objectFit=e.fit==="contain"?"contain":"cover";let r=I(e.radius,0,48);r!==null&&(t.style.borderRadius=`${r}px`);let s=I(e.max_height,40,800);if(s!==null&&(t.style.maxHeight=`${s}px`),!t.width&&e.fit!=="contain"&&(t.style.aspectRatio="16 / 9"),e.t==="video"||!B(e.href))return t;let c=ae(u("a","bl"),B(e.href));return c.append(t),c}function lt(e){let t=I(e.threshold,.01,1e7);if(!t)return null;let r=u("div","pg"),s=u("p"),c=u("div","tr"),p=u("i");c.append(p),c.setAttribute("role","progressbar"),c.setAttribute("aria-valuemin","0"),c.setAttribute("aria-valuemax",String(t)),r.append(s,c);let d=g=>g.toFixed(2);try{let g=new Intl.NumberFormat(J||void 0,{style:"currency",currency:e.currency});d=w=>g.format(w)}catch{}let b=()=>{let g=Math.max(0,Number(i.basket?.())||0),w=t-g;s.textContent=w>0?String(e.text??"").replace("{amount}",d(w)):e.done??"",p.style.transform=`scaleX(${Math.min(1,g/t)})`,c.setAttribute("aria-valuenow",String(Math.min(g,t))),s.id||(s.id=ye("pg")),c.setAttribute("aria-labelledby",s.id)};return b(),n.timers.push(setInterval(b,2e3)),r}let Ie={heading(e){let t=Me(u("h2","",e.text),e,"xl");return t.id=ye("h"),t.tabIndex=-1,y.hasAttribute("aria-labelledby")||(y.setAttribute("aria-labelledby",t.id),n.step===a.steps[0]&&He.includes(n.mode)&&!h&&(t.autofocus=!0)),t},text:e=>Me(u("p","",e.text),e,"md"),email:e=>Le(e,"email"),phone:e=>Le(e,"tel"),consent(e){let t=T(n.step)?.text;if(typeof t!="string")return null;if(e.required!==!0)return u("p","sm",t);let r=u("label","c"),s=u("input");return s.type="checkbox",s.name="hp_consent",s.required=!0,s.setAttribute("aria-describedby",M.id),r.append(s,u("span","",t)),r},question:rt,wheel(){let e=u("div","wh");return i.loadWheel().then(t=>{n.closed||(n.wheel=t.mountWheel(e,o.prizes))}).catch(()=>{}),e},code(){let e=u("div","k");return e.setAttribute("aria-live","polite"),n.codes.push(e),e},button:at,decline(e){let t=u("button","btn no",e.label??"No thanks");return t.type="button",t.addEventListener("click",()=>j("decline")),t},countdown:st,progress:lt,image:Oe,video:Oe,spacer(e){let t=u("div","sp");return t.style.height=`${Ge[e.size]??Ge.md}px`,t.setAttribute("aria-hidden","true"),t},divider:()=>u("hr")};function ct(e,t){W.replaceChildren();let r=e.media,s=!r||t&&e.template!=="image-only";if(n.size=Je(k,e),_.className=`w t-${e.template} z-${n.size}${e.side==="right"?" right":""}${k.text_align==="center"?" ta-center":""}${s?" nm":""}`,_.style.setProperty("--sc",String(e.scrim)),S.className=`f pd-${e.padding}`,W.hidden=s,W.hidden)return;let c=Ce(r,"",n.step===a.steps[0],e.template==="split"?.46:1);if(!c)return;if(c.width?_.style.setProperty("--ar",`${c.width} / ${c.height}`):_.style.removeProperty("--ar"),e.template!=="image-only"){c.tagName==="IMG"&&e.template==="overlay"&&(c.alt=""),W.append(c);return}let p=B(r.href),d=p?ae(u("a","io"),p):u("button","io");p||(d.type="button",d.addEventListener("click",()=>ie({action:"next"}))),d.append(c),W.append(d)}function dt(e){let t=e.blocks.find(c=>c?.t==="heading"),r=e.blocks.find(c=>c?.t==="button"&&c.action==="next"),s=u("button","tb");return s.textContent=t?u("b","",t.text).textContent:r?.label??"Open",s.type="button",s.addEventListener("click",()=>ie(r??{action:"next"})),s}function D(e,t=new Set){let r=a.steps.find(z=>z.id===e);if(!r)return j("done");if(r.kind==="question"&&!h&&!f.analytics()&&!t.has(r.id))return D(V(r,n.answers),t.add(r.id));let s=n.step!==null,c=s&&(L.activeElement||document.activeElement===document.body),p=s&&!h?{mode:n.mode,w:_.offsetWidth,h:_.offsetHeight,top:_.offsetTop}:null;n.step=r,n.touched=!1;for(let z of n.timers.splice(0))clearInterval(z);n.codes=[],n.videos=[],n.wheel=null;let d=E==="teaser"&&r===a.steps[0];if(n.mode=E==="teaser"&&!d?"popup":E,E==="teaser"&&v.tab?.(o.slot,d),Y&&Y.setAttribute("aria-label",d?A.closeOffer:"Close"),$e(),y.removeAttribute("aria-labelledby"),p){let z=Ee();S.replaceWith(z),S=z}let b=Ze(r);ct(b,d);let g=p?.mode==="popup"&&n.mode==="popup";if(le(),p?.mode===n.mode&&p.h>0&&!g&&(_.style.setProperty("--lw",`${p.w}px`),_.style.setProperty("--lh",`${p.h}px`),_.classList.add("lk")),S.replaceChildren(),d&&b.template!=="image-only")S.append(dt(r));else for(let[z,O]of r.blocks.entries()){let q=P(O)&&Object.hasOwn(Ie,O.t)?Ie[O.t](O):null;q&&(h&&(q.dataset.hpBlock=String(z)),S.append(q))}let w=S.querySelector("[data-submit]"),$=S.querySelector("[name=hp_consent]")?.parentNode;w&&$&&w.before($),S.hidden=S.childElementCount===0,N(null),ee(),y.hasAttribute("aria-labelledby")?y.removeAttribute("aria-label"):y.setAttribute("aria-label",b.media?.alt?.trim?.()||"Sign up"),g&&p.h>0&&pt(p),s&&Pe(),se(),h||ut(r),c&&S.querySelector("h2")?.focus()}function le(){_.classList.remove("lk","an"),_.style.removeProperty("--tp")}function pt(e){let t=_.offsetHeight;_.classList.add("an");let r=_.offsetTop,s=Math.max(0,e.top-r);if(s+t>y.clientHeight-2*r)return le();_.style.setProperty("--tp",`${s}px`)}function ut(e){let t=e.next??{};for(let c of[t.default,...Object.values(P(t.answers)?t.answers:{}),...e.blocks.map(p=>p?.next),...Mt])typeof c=="string"&&n.toWarm.add(c);if(n.warming)return;n.warming=!0;let r=()=>{if(n.warming=!1,!n.closed&&C.isConnected)for(let c of n.toWarm)Ae(o,a,c,n.warmed);n.toWarm.clear()},s=()=>globalThis.requestIdleCallback?requestIdleCallback(r,{timeout:2e3}):setTimeout(r,200);document.readyState==="complete"?s():window.addEventListener("load",s,{once:!0})}function Pe(){if(!U)return;let e=He.includes(n.mode);if(!(y.open&&n.modal===e)){try{y.open&&y.close()}catch{}if(n.modal=e,y.setAttribute("aria-modal",String(e)),e&&typeof y.showModal=="function")y.showModal();else if(typeof y.show=="function"){let t=document.activeElement;y.show(),t&&t!==document.body?t.focus?.({preventScroll:!0}):C.blur()}else y.setAttribute("open","");!e||typeof y.showModal!="function"?y.setAttribute("role","dialog"):y.removeAttribute("role")}}function ft(){for(let e of S.querySelectorAll("fieldset[data-question]")){let t=e.dataset.question,r=_e.get(e)?.()??{};if(r.error)return r;let s=[r.value,...[...e.querySelectorAll("input:checked,select:not([name])")].map(c=>c.value)].filter(Boolean);s.length?n.answers[t]=s:delete n.answers[t]}}function mt(){let e=[];for(let[r,s]of Object.entries(n.answers)){let c=`${r}=${s.join(",")}`;n.sent.has(c)||(n.sent.add(c),e.push({question:r,values:s}))}let t=n.step.id;if(n.signedUp&&e.length)return void m.answers({anonymousId:f.anonymousId(),sessionId:f.sessionId()??void 0,slot:l.slot,arm:l.arm??void 0,decision_id:l.decision_id??void 0,step:t,...n.signedUp,answers:e,context:Ne()});if(f.analytics())for(let r of e)x.preferencesStated({...r,source:"onsite",slot:l.slot,arm:l.arm??null,decision_id:l.decision_id??null,step:t})}let Ne=()=>({page:{url:f.pageUrl()},locale:f.locale()??void 0,consent:f.consent()}),te=e=>{n.receipt&&!h&&mt(),D(V(n.step,n.answers,e))};async function ht(e){let t=n.step,r=S.querySelector("input[name=email],input[name=phone]");if(!r)return te(e.next);let s=r.name==="email"?"email":"sms",c=S.querySelector("select[name=hp_cc]")?.value,p=s==="email"?Ye(r.value.trim())?r.value.trim():null:Fe(r.value,c);if(!p)return N(s==="email"?A.email:c?A.phone:A.intl,r);let d=S.querySelector("input[name=hp_consent]");if(d&&!d.checked)return N(A.consent,d);N(null),H(!0);let b=await Te();n.pow=null;let g=Object.entries(n.answers).map(([R,de])=>({question:R,values:de})),w=s==="sms"?o.sms_consent_text:o.consent_text,$=await m.capture({anonymousId:f.anonymousId(),sessionId:f.sessionId()??void 0,slot:l.slot,arm:l.arm??void 0,decision_id:l.decision_id??void 0,step:t.id,channel:s,[s==="email"?"email":"phone"]:p,...s==="sms"&&n.signedUp,consent_text:w?{id:w.id,version:w.version}:void 0,...g.length?{answers:g}:{},...b?{altcha:b}:{},context:Ne()}),z=$.body?.status,O=($.status===202||$.status===200)&&$t.includes(z);if(n.closed&&!O)return;O||H(!1);let q=$.status===400?$.body?.field:null;if(q==="email"||q==="phone")return N(A[q],r);if(!O)return N($.status===429?A.busy:A.failed,r);r.value="";for(let[R,de]of Object.entries(n.answers))n.sent.add(`${R}=${de.join(",")}`);n.receipt=typeof $.body.receipt=="string"?$.body.receipt:null,s==="email"&&(n.signedUp={email:p,email_receipt:n.receipt}),n.submitted=!0,v.submitted(o.slot),Q("submit",t.id),n.owed=s==="email"&&o.prizes.length>0;let oe=n.owed?ce([]):null;oe||i.emit?.("submitted",{coupon:null});let yt=oe&&await Promise.race([oe,new Promise(R=>setTimeout(R,It))]);if(n.closed)return;if(H(!1),yt?.held)return D(ne("held"));let vt=z!=="ok"&&a.steps.some(R=>R.id===z);D(vt?z:V(t,n.answers,e.next));let wt=n.step;oe?.then(R=>{R?.held&&!n.closed&&n.step===wt&&!n.touched&&D(ne("held"))})}function ne(e){if(a.steps.some(s=>s.id===e))return e;let t={t:"button",label:A.shop,action:"close"},r=e==="unclaimed"?[{t:"heading",text:A.thanks},{t:"text",text:A.unclaimed},t]:e==="fallback"||n.claim?.code?[{t:"heading",text:e==="fallback"?A.thanks:A.yours},{t:"code"}]:[{t:"heading",text:A.held},{t:"text",text:o.code_relayed===!0?A.resent:A.inbox},t];return a.steps.push({id:e,blocks:r}),e}function je(e){n.owed&&(n.owed=!1,i.emit?.("submitted",{coupon:e?{code:e.code??null,prize:e.prize?.key}:null}))}function ce(e=Ot){let t=n.receipt;return n.claiming??(n.claiming=(async()=>{n.unclaimed=!1;let r;for(let d of[0,...e])if(d&&await new Promise(b=>setTimeout(b,d)),r=await m.claim({slot:l.slot,decision_id:l.decision_id??void 0,receipt:t}),r.status!==503)break;let s=r.body,c=s?.fallback===!0&&!s.code;if(r.status!==200||!(P(s?.prize)||c))return n.claiming=null,!e.length&&r.status===503?ce():(je(null),n.unclaimed=!0,n.closed||ee(),null);let p=s.held&&!s.code?v.code?.():null;return p&&(s={...s,code:p}),n.claim=s,typeof s.code=="string"&&v.code?.(s.code),je(s),n.closed||ee(),s})()),n.claiming}async function bt(e){if(!n.receipt)return N(A.spin);H(!0);let t=await ce();if(n.closed)return;if(!t)return H(!1),n.misses+=1,n.misses<2?N(A.retry):D(ne("unclaimed"));let r=t.fallback===!0&&!t.code,s=t.held?-1:o.prizes.findIndex(d=>d.key===t.prize?.key&&d.label===t.prize?.label);if(n.wheel&&s>=0&&!r){if(await n.wheel.spinTo(s),n.closed)return;M.className="e won",M.textContent=`${A.won} ${t.prize.label}`,await new Promise(d=>setTimeout(d,Pt))}if(n.closed)return;H(!1);let c=r?"fallback":s<0?"held":null,p=c?ne(c):V(n.step,n.answers,e.next);p?D(p):ee()}function ie(e){if(e.action==="close")return j("close");let t=ft();return h?te(e.next):t?N(t.error,t.input):e.action==="apply"?(i.emit?.("apply",{coupon:n.claim?.code?{code:n.claim.code}:null}),Q("click"),V(n.step,n.answers,e.next)?te(e.next):j("done")):e.action==="submit"?ht(e):e.action==="spin"?bt(e):te(e.next)}function gt(e){if(e.preventDefault(),S.getAttribute("aria-busy")==="true")return;let t=n.step.blocks.find(r=>r?.t==="button"&&r.action==="submit");ie(t??{action:"next"})}function qe(){n.closed=!0;for(let t of n.timers.splice(0))clearInterval(t);document.removeEventListener("visibilitychange",se),X?.removeEventListener?.("change",ze);let e=()=>{try{y.open&&y.close()}catch{}C.remove()};if(!U||xe())return e();y.classList.add("out"),setTimeout(e,Lt)}function j(e){n.closed||h||(!n.submitted&&e!=="done"&&Q("dismiss"),v.closed(o.slot),v.tab?.(o.slot,!1),qe(),i.onClose?.(e))}for(let e of["pointerdown","keydown","input"])y.addEventListener(e,()=>{n.touched=!0});y.addEventListener("cancel",e=>{e.preventDefault(),j("esc")}),y.addEventListener("keydown",e=>{e.key==="Escape"&&!n.modal&&E!=="inline"&&j("esc"),e.key==="Tab"&&n.modal&&xt(e)});function xt(e){let t=[...L.querySelectorAll("input[type=radio]:checked")],r=new Set,s=[...L.querySelectorAll("a[href],button,input,select,textarea")].filter(g=>{if(g.disabled||!g.getClientRects().length)return!1;if(g.type!=="radio")return!0;let w=t.find($=>$.name===g.name);return(w?g!==w:r.has(g.name))?!1:(r.add(g.name),!0)});if(!s.length)return;let c=e.shiftKey,p=L.activeElement;p?.type==="radio"&&(p=s.find(g=>g.type==="radio"&&g.name===p.name)??p);let d=s.indexOf(p),b=null;if(d<0){let g=w=>p&&p.compareDocumentPosition(w)&4;b=c?s.findLast(w=>!g(w))??s.at(-1):s.find(g)??s[0]}else(c?d===0:d===s.length-1)&&(b=s.at(c?-1:0));b&&(e.preventDefault(),b.focus())}return re.addEventListener("pointerdown",e=>{if(!n.mobile||n.mode!=="sheet")return;let t=e.clientY,r=0,s=p=>{r=Math.max(0,p.clientY-t),_.style.transform=`translateY(${r}px)`},c=()=>{document.removeEventListener("pointermove",s),document.removeEventListener("pointerup",c),_.style.transform="",r>80&&j("close")};document.addEventListener("pointermove",s),document.addEventListener("pointerup",c)}),D(h?.step&&a.steps.some(e=>e.id===h.step)?h.step:a.steps[0].id),(i.container??document.body).append(C),Pe(),{close:j,root:L,host:C,show:D,step:()=>n.step?.id??null,modal:()=>!n.closed&&n.modal,destroy:()=>!n.closed&&qe()}}window[Symbol.for("@thg-agentic/hyper-personalisation-web.onsite.render")]={mountForm:it,warm:Ae};})();
|
package/dist/onsite-wheel.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{function L(e,i,s=5){let n=360/i;return s*360+(360-(e+.5)*n)}var
|
|
1
|
+
(()=>{function L(e,i,s=5){let n=360/i;return s*360+(360-(e+.5)*n)}var P="http://www.w3.org/2000/svg",z=4500,S=.22,F=.95,k=.105,v=.082,A=.062,I=.62,O=1.15,N="var(--hp-accent,#111)",R="var(--hp-on-accent,#fff)",g="var(--hp-bg,#fff)",T="var(--hp-text,#111)";function c(e,i={}){let s=document.createElementNS(P,e);for(let[n,o]of Object.entries(i))s.setAttribute(n,String(o));return s}function f(e,i,s,n=1){return e.style.fill=i,n<1&&(e.style.fillOpacity=String(n)),s&&(e.style.stroke=s),e}var j=()=>globalThis.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches===!0,$=(e,i=1)=>{let s=(e-90)*Math.PI/180;return`${(i*Math.cos(s)).toFixed(4)} ${(i*Math.sin(s)).toFixed(4)}`};function B(e,i){let s=F-S,n=2*.35*Math.sin(Math.min(Math.PI/i,Math.PI/2)),o=t=>Math.max(v,Math.min(k,n/(t*O))),a=t=>s/(Math.max(1,t.length)*I),r=[...e.matchAll(/ /g)].map(t=>t.index),u=e.length/2,p=r.length?r.reduce((t,l)=>Math.abs(l-u)<Math.abs(t-u)?l:t):-1,h=p<0?null:[e.slice(0,p),e.slice(p+1)];for(let t of[v,A]){let l=a(e);if(l>=t)return{lines:[e],size:Math.min(o(1),l)};if(h){let m=Math.min(o(2),...h.map(a));if(m>=t)return{lines:h,size:m}}}let d=Math.floor(s/(A*I));return{lines:[`${e.slice(0,d-1).trimEnd()}\u2026`],size:A}}function w(e){let i=F-S,s=n=>n.getComputedTextLength?.()??0;for(let n of e){let o=[...n.querySelectorAll("tspan")],a=Math.max(0,...o.map(s));if(!(a>i))continue;let r=Math.max(A,Number(n.getAttribute("font-size"))*i/a);n.setAttribute("font-size",r.toFixed(4)),o.forEach((u,p)=>{u.setAttribute("y",((p-(o.length-1)/2)*r*O).toFixed(4)),s(u)>i&&(u.setAttribute("textLength",i.toFixed(4)),u.setAttribute("lengthAdjust","spacingAndGlyphs"))})}}function C(e,i){let s=(Array.isArray(i)?i:[]).map(d=>String(d?.label??d?.key??"")),n=s.length;if(n<2)return null;let o=360/n,a=c("svg",{viewBox:"-1.2 -1.2 2.4 2.4",role:"img","aria-label":`Prize wheel: ${s.join(", ")}`}),r=c("g");r.style.transformBox="fill-box",r.style.transformOrigin="50% 50%";let u=[[1,R],[.14,T],[.72,R]];r.append(f(c("circle",{r:1}),g));let p=[],h=[];return s.forEach((d,t)=>{let[l,m]=u[n%2===1&&t===n-1?2:t%2];r.append(f(c("path",{d:`M0 0L${$(t*o)}A1 1 0 ${o>180?1:0} 1 ${$((t+1)*o)}Z`,"stroke-width":.012}),N,g,l));let b=(t+.5)*o-90,x=B(d,n),_=f(c("text",{transform:`rotate(${b}) translate(${(S+F)/2} 0)${b>90&&b<270?" rotate(180)":""}`,"text-anchor":"middle","dominant-baseline":"central","font-size":x.size.toFixed(4),"font-weight":700,"aria-hidden":"true"}),m);x.lines.forEach((E,M)=>{let y=c("tspan",{x:0,y:((M-(x.lines.length-1)/2)*x.size*O).toFixed(4)});y.textContent=E,_.append(y)}),r.append(_),h.push(_);for(let E of[t*o,(t+.5)*o]){let[M,y]=$(E,1.075).split(" ");p.push(f(c("circle",{cx:M,cy:y,r:.024}),g))}}),a.append(f(c("circle",{r:1.13}),T),...p,r,f(c("circle",{r:.17,"stroke-width":.035}),g,T),f(c("circle",{r:.065}),N),f(c("path",{d:"M-0.12 -1.2L0.12 -1.2L0 -0.86Z","stroke-width":.03,"stroke-linejoin":"round"}),N,g)),e.append(a),w(h),globalThis.requestAnimationFrame?.(()=>w(h)),{spinTo(d){let t=j();return r.style.transition=t?"none":`transform ${z}ms cubic-bezier(.15,.7,.1,1)`,r.style.transform=`rotate(${L(d,s.length,t?0:5)}deg)`,t?Promise.resolve():new Promise(l=>{let m=setTimeout(l,z+200);r.addEventListener("transitionend",()=>{clearTimeout(m),l()},{once:!0})})},remove:()=>a.remove()}}window[Symbol.for("@thg-agentic/hyper-personalisation-web.onsite.wheel")]={mountWheel:C};})();
|
package/dist/onsite.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{function P(e){let s=typeof document>"u"?null:document.currentScript?.src;return s?new URL(e,s).href:null}var Y=new Map;function O(e,s){return window[s]?Promise.resolve(window[s]):e?(Y.has(s)||Y.set(s,new Promise((n,r)=>{let d=document.createElement("script");d.src=e,d.async=!0,d.onload=()=>window[s]?n(window[s]):r(new Error(`${e} did not register`)),d.onerror=()=>r(new Error(`${e} did not load`)),document.head.append(d)}).finally(()=>Y.delete(s))),Y.get(s)):Promise.reject(new Error("the CDN script\u2019s own URL is unknown"))}var Ne=P("onsite-answers.min.js"),se=()=>O(Ne,Symbol.for("@thg-agentic/hyper-personalisation-web.onsite.answers"));var ke="/v1/capture/challenge",De=e=>typeof e=="string"&&/^\/v1\/[\w/-]+$/.test(e)?e:ke;function oe(e,s={}){let n=s.fetch??globalThis.fetch?.bind(globalThis),r=s.servingHost??e.servingHost,d=s.gatewayHost??e.gatewayHost;async function o(l,{method:p="GET",body:i,consent:c=!1,timeoutMs:u}={}){if(!n)return{status:0,body:null};try{let w=await n(l,{method:p,credentials:"omit",signal:u&&AbortSignal.timeout?.(u),headers:{accept:"application/json",authorization:`Bearer ${e.writeKey}`,...i?{"content-type":"application/json"}:{},...c?e.headers():{}},...i?{body:JSON.stringify(i)}:{}}),b=null;try{b=await w.json()}catch{}return{status:w.status,body:b}}catch{return{status:0,body:null}}}return{decide:(l,p)=>o(`${r}/v1/decisions`,{method:"POST",consent:!0,body:{slots:[p?{key:l,pin:{experiment:p[0],arm:p[1],split:p[2]}}:l],identifier_value:e.anonymousId()??void 0,session_id:e.sessionId()??void 0,...e.preview?{preview:e.preview}:{}}}),challenge:()=>o(`${d}${De(s.challenge)}`),capture:l=>o(`${d}/v1/capture`,{method:"POST",body:l}),answers:l=>o(`${d}/v1/capture/answers`,{method:"POST",body:l}),claim:l=>o(`${r}/v1/offers/claim`,{method:"POST",consent:!0,body:l,timeoutMs:8e3})}}function ie(e,s){let n={},r=()=>{try{let o=JSON.parse(e().getItem(s));o&&typeof o=="object"&&(n=o)}catch{}return n};return{read:r,write:o=>{let l=r();o(l),n=l;try{e().setItem(s,JSON.stringify(l))}catch{}}}}function re(e,s=()=>!0){let n=ie(()=>sessionStorage,e),r=ie(()=>localStorage,e),d=()=>s()?r:n,o=()=>{let i=r.read();(i.sub!==void 0||i.k!==void 0)&&r.write(c=>{delete c.sub,delete c.k})},l=()=>s()?[n.read(),r.read()]:(o(),[n.read()]),p=(i,c)=>{var u;return i.f??(i.f={}),(u=i.f)[c]??(u[c]={}),i.f[c]};return{seen(i){let c=r.read().f?.[i]??{};return{session:n.read().f?.[i]?.n??0,lifetime:c.n??0,closedAt:c.c??null,submitted:c.s===1}},subscribed:()=>l().some(i=>i.sub===1),shown(i){n.write(c=>{let u=p(c,i);u.n=(u.n??0)+1}),r.write(c=>{let u=p(c,i);u.n=(u.n??0)+1})},closed(i,c=Date.now()){r.write(u=>{p(u,i).c=c})},tab(i,c){n.write(u=>{let w=p(u,i);c?w.t=1:delete w.t})},tabOut:i=>n.read().f?.[i]?.t===1,pin(i,c){if(c===void 0)return n.read().f?.[i]?.p??null;n.write(u=>{p(u,i).p=c})},coveredAt:()=>n.read().o??null,covered(i=Date.now()){n.write(c=>{c.o=i})},code(i,c=Date.now()){if(i===void 0){let[u]=l().flatMap(w=>w.k?[w.k]:[]).sort((w,b)=>b.at-w.at);return u&&c-u.at<14*864e5?u.c:null}return d().write(u=>{u.k={c:i,at:c}}),i},submitted(i){r.write(c=>{p(c,i).s=1}),d().write(c=>{c.sub=1})}}}var Le=P("onsite-render.min.js"),le=()=>O(Le,Symbol.for("@thg-agentic/hyper-personalisation-web.onsite.render"));var de=["popup","sheet","bar","teaser","inline","fullscreen"],Fe=["entry","exit","scroll","time","idle","inline","manual"],q=e=>e!=="inline",pe=e=>e==="popup"||e==="sheet"||e==="fullscreen",S=e=>e!==null&&typeof e=="object"&&!Array.isArray(e),D=e=>Array.isArray(e)?e.filter(s=>typeof s=="string"):[],ce=e=>Number.isInteger(e)&&e>=0?e:null;function fe(e){if(!S(e)||typeof e.slot!="string"||e.slot==="")return null;let s=S(e.trigger)?e.trigger:{};if(!de.includes(e.format)||!Fe.includes(s.type))return null;let n=S(e.caps)?e.caps:{};return{...e,trigger:s,priority:Number.isFinite(e.priority)?e.priority:0,pages:S(e.pages)?e.pages:{},devices:D(e.devices),aliases:D(e.aliases),audiences:D(e.audiences),caps:{per_session:ce(n.per_session),lifetime:ce(n.lifetime),after_close_days:Number.isFinite(n.after_close_days)?n.after_close_days:null},window:S(e.window)?e.window:{},questions:Array.isArray(e.questions)?e.questions.filter(S):[],prizes:Array.isArray(e.prizes)?e.prizes.filter(S):[]}}var We=/^[a-z][a-z0-9_-]{0,31}$/;function he(e){if(!S(e)||e.v!==1||!Array.isArray(e.steps))return null;let s=e.steps.filter(n=>S(n)&&We.test(n.id)&&Array.isArray(n.blocks));return s.length===0?null:{format:de.includes(e.format)?e.format:null,theme:S(e.theme)?e.theme:{},steps:s}}function ae(e,s){let n=String(e).split("*").map(r=>r.replace(/[.+?^${}()|[\]\\]/g,"\\$&")).join(".*");return new RegExp(`^${n}$`,"i").test(s)}function je(e,s){let n=D(e?.include);return(!n.length||n.some(r=>ae(r,s)))&&!D(e?.exclude).some(r=>ae(r,s))}function we(e){return e.matchMedia?.("(hover: none) and (pointer: coarse)")?.matches===!0||e.innerWidth<768?"mobile":"desktop"}var ue=e=>typeof e=="string"?Date.parse(e):Number.NaN,L=e=>e.trigger.type==="manual";function J(e,s){let n=[];je(e.pages,s.path)||n.push("page not included"),e.devices.length&&!e.devices.includes(s.device)&&n.push(`not on ${s.device}`);let r=ue(e.window.starts_at),d=ue(e.window.ends_at);if((s.now<r||s.now>=d)&&n.push("outside its dates"),e.audiences.length&&(s.personalisation?s.audiences&&!e.audiences.some(p=>s.audiences.includes(p))&&n.push("not in its audiences"):n.push("audiences need personalisation consent")),s.preview||s.asked||L(e))return n;let{seen:o}=s,{caps:l}=e;return o.submitted&&n.push("already submitted"),e.exclude_subscribed===!0&&s.subscribed&&n.push("already subscribed"),l.per_session!==null&&o.session>=l.per_session&&n.push("per_session cap"),l.lifetime!==null&&o.lifetime>=l.lifetime&&n.push("lifetime cap"),l.after_close_days!==null&&o.closedAt&&s.now-o.closedAt<l.after_close_days*864e5&&n.push("closed recently"),n}var ge=(e,s)=>s.priority-e.priority;var Ue=["mousemove","pointerdown","keydown","scroll","touchstart","wheel"];function Ke(){let e=[];return{on:(r,d,o,l={passive:!0})=>{r.addEventListener(d,o,l),e.push(()=>r.removeEventListener(d,o,l))},later:(r,d)=>{let o=setTimeout(r,d);e.push(()=>clearTimeout(o))},stop:()=>{for(let r of e.splice(0))r()}}}var ye=(e,s)=>{let n=s.documentElement.scrollHeight||0;return n>0?(e.scrollY+e.innerHeight)/n:0},Ye=e=>{let s=e.activeElement;return!!(s&&(/^(INPUT|TEXTAREA|SELECT)$/.test(s.tagName)||s.isContentEditable))};function He({on:e,later:s},n,r,d,o){let l=!1,p=!1,i=null,c=0;s(()=>{l=!0},r.delay_ms??5e3),e(o,"mousemove",u=>{u.clientY>d.innerHeight*.1&&(p=!0),i!==null&&(c=u.clientY-i),i=u.clientY}),e(o,"mouseout",u=>{l&&p&&!u.relatedTarget&&u.clientY<=0&&c<0&&!Ye(o)&&n("exit")})}function ze({on:e,later:s},n,r,d,o){let l=!1,p=0,i=d.scrollY,c=Date.now(),u=null,w=null;s(()=>{l=!0},r.delay_ms??5e3),e(d,"scroll",()=>{let b=d.scrollY,A=Date.now();if(p=Math.max(p,ye(d,o)),b<i){(!u||A-u.t>300)&&(u={y:i,t:c});let _=u.y-b;l&&p>=.3&&_>=120&&_/Math.max(1,A-u.t)>=.5&&n("exit_scroll")}else u=null;i=b,c=A}),e(o,"visibilitychange",()=>{o.visibilityState==="hidden"?w=Date.now():w!==null&&Date.now()-w>=1e4&&n("return"),o.visibilityState!=="hidden"&&(w=null)})}function me(e,s,{device:n,win:r=window,doc:d=document}){let o=Ke(),l=(e.seconds??30)*1e3;if(e.type==="entry"&&o.later(()=>s("entry"),e.delay_ms??0),e.type==="time"&&o.later(()=>s("time"),l),e.type==="exit"&&(n==="mobile"?ze:He)(o,s,e,r,d),e.type==="scroll"){let p=e.depth??.5;o.on(r,"scroll",()=>ye(r,d)>=p&&s("scroll"))}if(e.type==="idle"){let p=null,i=()=>{clearTimeout(p),p=setTimeout(()=>s("idle"),l)};i();for(let c of Ue)o.on(c==="scroll"?r:d,c,i);return o.on(d,"visibilitychange",i),()=>{clearTimeout(p),o.stop()}}return o.stop}var Xe=P("onsite-wheel.min.js"),be=()=>O(Xe,Symbol.for("@thg-agentic/hyper-personalisation-web.onsite.wheel"));var _e=Symbol.for("@thg-agentic/hyper-personalisation-web.onsite-access"),F=Symbol.for("@thg-agentic/hyper-personalisation-web.onsite"),Be=Symbol.for("@thg-agentic/hyper-personalisation-web.onsite.pending"),Ge=Symbol.for("@thg-agentic/hyper-personalisation-web.onsite.listeners"),Se=Symbol.for("@thg-agentic/hyper-personalisation-web.onsite.suppressed"),Ae={seen:()=>({session:0,lifetime:0,closedAt:null,submitted:!1}),subscribed:()=>!1,shown(){},closed(){},submitted(){},tab(){},tabOut:()=>!1,pin:()=>null,coveredAt:()=>null,covered(){},code:()=>null},Ve=50,qe=300,Je=()=>{try{return new URLSearchParams(location.search).get("hp_debug")==="onsite"}catch{return!1}};function Ee(e,s={}){if(typeof window>"u"||typeof document>"u")return null;if(window[F])return window[F];let n=typeof e?.[_e]=="function"?e[_e]():null;if(!n)return console.warn("[hp] onsite: startOnsite needs the client bootstrap or createAnalytics made"),null;let r=s.settings??n.settings??{},d=oe(n,{...s,challenge:r.capture?.challenge}),o=n.preview?Ae:re(n.storageKey,n.personalisation),l=new Map,p=()=>window[Se]?.size>0,i=(t,a)=>{for(let f of window[Ge]?.[t]??[])try{f(a)}catch(h){console.warn(`[hp] onsite ${t} listener failed:`,h)}},c=we(window),u=n.debug||s.debug===!0||Je(),w=new Map,b=new Map,A=[];for(let t of Array.isArray(r.forms)?r.forms:[]){let a=fe(t);a?A.push(a):w.set(String(t?.slot??`form ${w.size+1}`),{slot:String(t?.slot??""),state:"invalid",reasons:["not a form this SDK can show"]})}let _=new Map,W=new Map,x=null,Z=new Set,ve=t=>{for(let a of _.keys()){let f=l.get(a);if(!t||!f||f.modal?.())return a}return null},j=[],H=Number.isInteger(r.overlay_gap_minutes)?r.overlay_gap_minutes:0,xe=()=>{let t=o.coveredAt();if(!(H>0)||typeof t!="number")return null;let a=Math.max(0,Math.floor((Date.now()-t)/6e4));return a<H?`a popup showed ${a} min ago; ${H} min between them`:null},C=new Set,U=new Map,g=(t,a,f=[])=>(w.set(t.slot,{slot:t.slot,format:t.format,trigger:t.trigger.type,priority:t.priority,state:a,reasons:f}),u&&console.info(`[hp] onsite ${t.slot}: ${a}${f.length?` (${f.join("; ")})`:""}`),a),Te=()=>{try{let t=s.audiences?.();return Array.isArray(t)?t:null}catch{return null}},Q=t=>({path:location.pathname,device:c,now:Date.now(),seen:o.seen(t.slot),subscribed:o.subscribed()||s.subscribed?.()===!0,personalisation:n.personalisation(),preview:!!n.preview,audiences:Te()}),z=t=>{b.get(t.slot)?.(),b.delete(t.slot)};function R(t,a,f=!1,h=L(t)){return l.has(t.slot)?Promise.resolve("shown"):(W.has(t.slot)||W.set(t.slot,Ie(t,a,f,h).finally(()=>W.delete(t.slot))),W.get(t.slot))}async function Ie(t,a,f,h){if(p())return g(t,"not shown",[`suppressed: ${[...window[Se]].join(", ")}`]);let T=J(t,{...Q(t),...f?{seen:Ae.seen()}:{},asked:h});if(T.length)return g(t,"not eligible",T);let E=pe(t.format)&&!f,K=E&&!h&&xe();if(K)return g(t,"not shown",[K]);if(E&&!n.preview&&n.consentAnswered?.()===!1)return U.set(t,h),g(t,"not shown",["waiting for the consent banner"]);let v=q(t.format),k=v&&ve(h);if(k)return g(t,"not shown",[`${k} is showing`]);if(v&&x&&!h)return g(t,"not shown",[`${x} already showed on this page view`]);let I=null;if(!v){try{I=document.querySelector(t.trigger.selector??"")}catch{I=null}if(!I)return g(t,"not shown",["no element matches its selector"])}v&&_.set(t.slot,t),z(t),g(t,"asking for a decision",[a]);let Pe=le().catch(m=>(console.warn("[hp] onsite renderer not loaded:",m?.message??m),null)),$=await d.decide(t.slot,o.pin(t.slot)),y=$.status===200?$.body?.decisions?.find(m=>m?.slot===t.slot):null;y?.experiment&&y.arm&&y.split&&o.pin(t.slot,[y.experiment,y.arm,y.split]);let M=y&&y.holdout!==!0?he(y.payload):null,te=M?.steps[0].blocks??[],ne=y?.offer?.code??(n.preview?"PREVIEW":o.code()),Oe=n.basketValue?.()??null,B=te.some(m=>m?.t==="code")&&!ne&&"no code to remind of"||te.some(m=>m?.t==="progress")&&!(Oe>0)&&"the basket is empty";if(B)return _.delete(t.slot),B==="the basket is empty"&&C.add(t),g(t,"not shown",[B]);if(C.delete(t),!M)return y?.holdout===!0&&n.analytics()&&e.recordExposure($.body),_.delete(t.slot),v&&y?.holdout===!0&&(x??(x=t.slot)),y?.holdout===!0&&!h&&i("held",{slot:t.slot,arm:y.arm??null,format:t.format}),g(t,y?.holdout===!0?"held out":"no decision",[$.status===200?"no creative for this visitor":`decisions answered ${$.status}`]);let G=await Pe;if(!G)return _.delete(t.slot),g(t,"not shown",["the renderer did not load"]);if(await Promise.race([G.warm?.(t,M,M.steps[0].id,Z),new Promise(m=>setTimeout(m,qe))]),p())return _.delete(t.slot),g(t,"not shown",["suppressed"]);f||o.shown(t.slot),E&&o.covered(),v&&(x??(x=t.slot));let V=(m,Re={})=>i(m,{slot:t.slot,arm:y.arm??null,format:M.format??t.format,...Re}),Ce=G.mountForm({form:t,creative:M,decision:y,access:n,client:e,api:d,counters:o,loadWheel:be,loadAnswers:se,container:I,warmed:Z,coupon:ne,basket:()=>n.basketValue?.()??null,emit:V,onClose(m){l.delete(t.slot),_.delete(t.slot),g(t,"closed",[m]),V("closed",{reason:m})}});return l.set(t.slot,Ce),n.analytics()&&e.recordExposure($.body),g(t,"shown",[a]),V("shown"),"shown"}function X(t,a,f=L(t)){if(!q(t.format))return R(t,a,!1,f);j.push([t,a,f]),!(j.length>1)&&setTimeout(async()=>{let h=j.sort(([T],[E])=>ge(T,E));j=[];for(let[T,[E,K,v]]of h.entries()){let k=await R(E,K,!1,v);if(k==="shown"||k==="held out"){for(let[I]of h.slice(T+1))g(I,"not shown",[`${E.slot} has a higher priority`]);return}}},Ve)}for(let t of A){if(t.format==="teaser"&&o.tabOut(t.slot)){R(t,"tab kept from an earlier page",!0);continue}let a=J(t,Q(t));if(a.length){g(t,"not eligible",a);continue}let f=t.trigger.type;f==="manual"?g(t,"waiting for hp.onsite.open"):f==="inline"||t.format==="inline"?R(t,"inline"):ee(t)}function ee(t){z(t),b.set(t.slot,me(t.trigger,a=>{z(t),X(t,a)},{device:c})),g(t,"armed",[`${t.trigger.type} on ${c}`])}let $e=n.onConsentAnswered?.(()=>{let t=[...U];U.clear();for(let[a,f]of t)l.has(a.slot)||(f?X(a,"manual",f):ee(a))}),Me=n.onBasket?.(()=>{if(!((n.basketValue?.()??0)>0))return;let t=[...C];C.clear();for(let a of t)l.has(a.slot)||X(a,"the basket changed")}),N=Object.freeze({open(t){let a=A.find(h=>h.slot===t),f=a??A.find(h=>h.aliases.includes(t));return f?l.has(f.slot)?Promise.resolve(!0):R(f,"manual",!1,L(f)||!a).then(h=>h==="shown"):Promise.resolve(!1)},suppress(){for(let[t,a]of l){a.destroy(),l.delete(t),_.delete(t);let f=A.find(h=>h.slot===t);f&&g(f,"closed",["suppressed"])}},debug:()=>[...w.values()].map(t=>({...t,reasons:[...t.reasons]})),stop(){for(let t of b.values())t();b.clear(),Me?.(),$e?.(),C.clear(),U.clear(),window[F]===N&&delete window[F]}});window[F]=N;for(let{slot:t,resolve:a}of window[Be]?.splice(0)??[])a(N.open(t));return u&&console.table?.(N.debug()),N}window[Symbol.for("@thg-agentic/hyper-personalisation-web.onsite.module")]={startOnsite:Ee};})();
|
|
1
|
+
(()=>{function T(e){let s=typeof document>"u"?null:document.currentScript?.src;return s?new URL(e,s).href:null}var H=new Map;function I(e,s){return window[s]?Promise.resolve(window[s]):e?(H.has(s)||H.set(s,new Promise((n,r)=>{let d=document.createElement("script");d.src=e,d.async=!0,d.onload=()=>window[s]?n(window[s]):r(new Error(`${e} did not register`)),d.onerror=()=>r(new Error(`${e} did not load`)),document.head.append(d)}).finally(()=>H.delete(s))),H.get(s)):Promise.reject(new Error("the CDN script\u2019s own URL is unknown"))}var Ke=T("onsite-answers.min.js"),ae=()=>I(Ke,Symbol.for("@thg-agentic/hyper-personalisation-web.onsite.answers"));var Ye="/v1/capture/challenge",He=e=>typeof e=="string"&&/^\/v1\/[\w/-]+$/.test(e)?e:Ye;function ce(e,s={}){let n=s.fetch??globalThis.fetch?.bind(globalThis),r=s.servingHost??e.servingHost,d=s.gatewayHost??e.gatewayHost;async function o(a,{method:p="GET",body:i,consent:l=!1,timeoutMs:c}={}){if(!n)return{status:0,body:null};try{let w=await n(a,{method:p,credentials:"omit",signal:c&&AbortSignal.timeout?.(c),headers:{accept:"application/json",authorization:`Bearer ${e.writeKey}`,...i?{"content-type":"application/json"}:{},...l?e.headers():{}},...i?{body:JSON.stringify(i)}:{}}),b=null;try{b=await w.json()}catch{}return{status:w.status,body:b}}catch{return{status:0,body:null}}}return{decide:(a,p,{visitAudiences:i,visitCampaign:l}={})=>o(`${r}/v1/decisions`,{method:"POST",consent:!0,body:{slots:[p?{key:a,pin:{experiment:p[0],arm:p[1],split:p[2]}}:a],identifier_value:e.anonymousId()??void 0,session_id:e.sessionId()??void 0,identity_token:e.identityToken?.()??void 0,...e.preview?{preview:e.preview}:{},...i?{visit_audiences:i}:{},...l?{visit_campaign:l}:{}}}),datafile:()=>o(`${r}/v1/audiences/datafile`,{timeoutMs:1500}),challenge:()=>o(`${d}${He(s.challenge)}`),capture:a=>o(`${d}/v1/capture`,{method:"POST",body:a}),answers:a=>o(`${d}/v1/capture/answers`,{method:"POST",body:a}),claim:a=>o(`${r}/v1/offers/claim`,{method:"POST",consent:!0,body:a,timeoutMs:8e3})}}var Xe=T("onsite-audiences.min.js"),ue=()=>I(Xe,Symbol.for("@thg-agentic/hyper-personalisation-web.onsite.audiences"));function de(e,s){let n={},r=()=>{try{let o=JSON.parse(e().getItem(s));o&&typeof o=="object"&&(n=o)}catch{}return n};return{read:r,write:o=>{let a=r();o(a),n=a;try{e().setItem(s,JSON.stringify(a))}catch{}}}}function pe(e,s=()=>!0){let n=de(()=>sessionStorage,e),r=de(()=>localStorage,e),d=()=>s()?r:n,o=()=>{let i=r.read();(i.sub!==void 0||i.k!==void 0)&&r.write(l=>{delete l.sub,delete l.k})},a=()=>s()?[n.read(),r.read()]:(o(),[n.read()]),p=(i,l)=>{var c;return i.f??(i.f={}),(c=i.f)[l]??(c[l]={}),i.f[l]};return{seen(i){let l=r.read().f?.[i]??{};return{session:n.read().f?.[i]?.n??0,lifetime:l.n??0,closedAt:l.c??null,submitted:l.s===1}},subscribed:()=>a().some(i=>i.sub===1),shown(i){n.write(l=>{let c=p(l,i);c.n=(c.n??0)+1}),r.write(l=>{let c=p(l,i);c.n=(c.n??0)+1})},closed(i,l=Date.now()){r.write(c=>{p(c,i).c=l})},tab(i,l){n.write(c=>{let w=p(c,i);l?w.t=1:delete w.t})},tabOut:i=>n.read().f?.[i]?.t===1,pin(i,l){if(l===void 0)return n.read().f?.[i]?.p??null;n.write(c=>{p(c,i).p=l})},coveredAt:()=>n.read().o??null,covered(i=Date.now()){n.write(l=>{l.o=i})},code(i,l=Date.now()){if(i===void 0){let[c]=a().flatMap(w=>w.k?[w.k]:[]).sort((w,b)=>b.at-w.at);return c&&l-c.at<14*864e5?c.c:null}return d().write(c=>{c.k={c:i,at:l}}),i},submitted(i){r.write(l=>{p(l,i).s=1}),d().write(l=>{l.sub=1})}}}var ze=T("onsite-render.min.js"),fe=()=>I(ze,Symbol.for("@thg-agentic/hyper-personalisation-web.onsite.render"));var Ve=["source","medium","campaign","content","term"];var he=e=>String(e).trim().toLowerCase();function ge(e,s){return(Array.isArray(e)?e:[]).every(n=>{let r=s?.[n?.field];if(!Ve.includes(n?.field)||typeof r!="string")return!1;let d=he(r);return[].concat(n.values??[]).some(o=>{let a=he(o);return n.match==="is"?d===a:n.match==="contains"&&a!==""&&d.includes(a)})})}var be=["popup","sheet","bar","teaser","inline","fullscreen"],Ge=["entry","exit","scroll","time","idle","inline","manual"],Z=e=>e!=="inline",Se=e=>e==="popup"||e==="sheet"||e==="fullscreen",S=e=>e!==null&&typeof e=="object"&&!Array.isArray(e),k=e=>Array.isArray(e)?e.filter(s=>typeof s=="string"):[],me=e=>Number.isInteger(e)&&e>=0?e:null,Be={field:null,match:null,values:[]},qe=e=>e==null?[]:Array.isArray(e)&&e.every(S)?e:[Be];function _e(e){if(!S(e)||typeof e.slot!="string"||e.slot==="")return null;let s=S(e.trigger)?e.trigger:{};if(!be.includes(e.format)||!Ge.includes(s.type))return null;let n=S(e.caps)?e.caps:{};return{...e,trigger:s,priority:Number.isFinite(e.priority)?e.priority:0,pages:S(e.pages)?e.pages:{},devices:k(e.devices),aliases:k(e.aliases),audiences:k(e.audiences),arrived_from:qe(e.arrived_from),caps:{per_session:me(n.per_session),lifetime:me(n.lifetime),after_close_days:Number.isFinite(n.after_close_days)?n.after_close_days:null},window:S(e.window)?e.window:{},questions:Array.isArray(e.questions)?e.questions.filter(S):[],prizes:Array.isArray(e.prizes)?e.prizes.filter(S):[]}}var Je=/^[a-z][a-z0-9_-]{0,31}$/;function Ae(e){if(!S(e)||e.v!==1||!Array.isArray(e.steps))return null;let s=e.steps.filter(n=>S(n)&&Je.test(n.id)&&Array.isArray(n.blocks));return s.length===0?null:{format:be.includes(e.format)?e.format:null,theme:S(e.theme)?e.theme:{},steps:s}}function we(e,s){let n=String(e).split("*").map(r=>r.replace(/[.+?^${}()|[\]\\]/g,"\\$&")).join(".*");return new RegExp(`^${n}$`,"i").test(s)}function Ze(e,s){let n=k(e?.include);return(!n.length||n.some(r=>we(r,s)))&&!k(e?.exclude).some(r=>we(r,s))}function ve(e){return e.matchMedia?.("(hover: none) and (pointer: coarse)")?.matches===!0||e.innerWidth<768?"mobile":"desktop"}var ye=e=>typeof e=="string"?Date.parse(e):Number.NaN,F=e=>e.trigger.type==="manual";function Q(e,s){let n=[];Ze(e.pages,s.path)||n.push("page not included"),e.devices.length&&!e.devices.includes(s.device)&&n.push(`not on ${s.device}`),ge(e.arrived_from,s.campaign)||n.push("not from its campaign");let r=ye(e.window.starts_at),d=ye(e.window.ends_at);if((s.now<r||s.now>=d)&&n.push("outside its dates"),e.audiences.length&&!s.preview&&(s.personalisation?s.audiences&&!e.audiences.some(p=>s.audiences.includes(p))&&n.push("not in its audiences"):n.push("audiences need personalisation consent")),s.preview||s.asked||F(e))return n;let{seen:o}=s,{caps:a}=e;return o.submitted&&n.push("already submitted"),e.exclude_subscribed===!0&&s.subscribed&&n.push("already subscribed"),a.per_session!==null&&o.session>=a.per_session&&n.push("per_session cap"),a.lifetime!==null&&o.lifetime>=a.lifetime&&n.push("lifetime cap"),a.after_close_days!==null&&o.closedAt&&s.now-o.closedAt<a.after_close_days*864e5&&n.push("closed recently"),n}var Ee=(e,s)=>s.priority-e.priority;var Qe=["mousemove","pointerdown","keydown","scroll","touchstart","wheel"];function et(){let e=[];return{on:(r,d,o,a={passive:!0})=>{r.addEventListener(d,o,a),e.push(()=>r.removeEventListener(d,o,a))},later:(r,d)=>{let o=setTimeout(r,d);e.push(()=>clearTimeout(o))},stop:()=>{for(let r of e.splice(0))r()}}}var xe=(e,s)=>{let n=s.documentElement.scrollHeight||0;return n>0?(e.scrollY+e.innerHeight)/n:0},tt=e=>{let s=e.activeElement;return!!(s&&(/^(INPUT|TEXTAREA|SELECT)$/.test(s.tagName)||s.isContentEditable))};function nt({on:e,later:s},n,r,d,o){let a=!1,p=!1,i=null,l=0;s(()=>{a=!0},r.delay_ms??5e3),e(o,"mousemove",c=>{c.clientY>d.innerHeight*.1&&(p=!0),i!==null&&(l=c.clientY-i),i=c.clientY}),e(o,"mouseout",c=>{a&&p&&!c.relatedTarget&&c.clientY<=0&&l<0&&!tt(o)&&n("exit")})}function st({on:e,later:s},n,r,d,o){let a=!1,p=0,i=d.scrollY,l=Date.now(),c=null,w=null;s(()=>{a=!0},r.delay_ms??5e3),e(d,"scroll",()=>{let b=d.scrollY,_=Date.now();if(p=Math.max(p,xe(d,o)),b<i){(!c||_-c.t>300)&&(c={y:i,t:l});let A=c.y-b;a&&p>=.3&&A>=120&&A/Math.max(1,_-c.t)>=.5&&n("exit_scroll")}else c=null;i=b,l=_}),e(o,"visibilitychange",()=>{o.visibilityState==="hidden"?w=Date.now():w!==null&&Date.now()-w>=1e4&&n("return"),o.visibilityState!=="hidden"&&(w=null)})}function Te(e,s,{device:n,win:r=window,doc:d=document}){let o=et(),a=(e.seconds??30)*1e3;if(e.type==="entry"&&o.later(()=>s("entry"),e.delay_ms??0),e.type==="time"&&o.later(()=>s("time"),a),e.type==="exit"&&(n==="mobile"?st:nt)(o,s,e,r,d),e.type==="scroll"){let p=e.depth??.5;o.on(r,"scroll",()=>xe(r,d)>=p&&s("scroll"))}if(e.type==="idle"){let p=null,i=()=>{clearTimeout(p),p=setTimeout(()=>s("idle"),a)};i();for(let l of Qe)o.on(l==="scroll"?r:d,l,i);return o.on(d,"visibilitychange",i),()=>{clearTimeout(p),o.stop()}}return o.stop}var ot=T("onsite-wheel.min.js"),Ie=()=>I(ot,Symbol.for("@thg-agentic/hyper-personalisation-web.onsite.wheel"));var Me=Symbol.for("@thg-agentic/hyper-personalisation-web.onsite-access"),j=Symbol.for("@thg-agentic/hyper-personalisation-web.onsite"),it=Symbol.for("@thg-agentic/hyper-personalisation-web.onsite.pending"),rt=Symbol.for("@thg-agentic/hyper-personalisation-web.onsite.listeners"),Oe=Symbol.for("@thg-agentic/hyper-personalisation-web.onsite.suppressed"),Ce={seen:()=>({session:0,lifetime:0,closedAt:null,submitted:!1}),subscribed:()=>!1,shown(){},closed(){},submitted(){},tab(){},tabOut:()=>!1,pin:()=>null,coveredAt:()=>null,covered(){},code:()=>null},lt=1500,at=50,ct=300,ut=()=>{try{return new URLSearchParams(location.search).get("hp_debug")==="onsite"}catch{return!1}};function Pe(e,s={}){if(typeof window>"u"||typeof document>"u")return null;if(window[j])return window[j];let n=typeof e?.[Me]=="function"?e[Me]():null;if(!n)return console.warn("[hp] onsite: startOnsite needs the client bootstrap or createAnalytics made"),null;let r=s.settings??n.settings??{},d=ce(n,{...s,challenge:r.capture?.challenge}),o=n.preview?Ce:pe(n.storageKey,n.personalisation),a=()=>n.campaign?.()??null,p=new Map,i=()=>window[Oe]?.size>0,l=(t,u)=>{for(let f of window[rt]?.[t]??[])try{f(u)}catch(g){console.warn(`[hp] onsite ${t} listener failed:`,g)}},c=ve(window),w=n.debug||s.debug===!0||ut(),b=new Map,_=new Map,A=[];for(let t of Array.isArray(r.forms)?r.forms:[]){let u=_e(t);u?A.push(u):b.set(String(t?.slot??`form ${b.size+1}`),{slot:String(t?.slot??""),state:"invalid",reasons:["not a form this SDK can show"]})}let ee=()=>ue().catch(t=>(console.warn("[hp] onsite audiences not loaded:",t?.message??t),null));n.personalisation()&&A.some(t=>t.audiences.length>0)&&ee().then(t=>t?.prefetch(d));let v=new Map,U=new Map,M=null,te=new Set,$e=t=>{for(let u of v.keys()){let f=p.get(u);if(!t||!f||f.modal?.())return u}return null},W=[],X=Number.isInteger(r.overlay_gap_minutes)?r.overlay_gap_minutes:0,Ne=()=>{let t=o.coveredAt();if(!(X>0)||typeof t!="number")return null;let u=Math.max(0,Math.floor((Date.now()-t)/6e4));return u<X?`a popup showed ${u} min ago; ${X} min between them`:null},N=new Set,K=new Map,m=(t,u,f=[])=>(b.set(t.slot,{slot:t.slot,format:t.format,trigger:t.trigger.type,priority:t.priority,state:u,reasons:f}),w&&console.info(`[hp] onsite ${t.slot}: ${u}${f.length?` (${f.join("; ")})`:""}`),u),ne=()=>{try{let t=s.audiences?.();return Array.isArray(t)?t:null}catch{return null}},se=t=>({path:location.pathname,device:c,campaign:a(),now:Date.now(),seen:o.seen(t.slot),subscribed:o.subscribed()||s.subscribed?.()===!0,personalisation:n.personalisation(),preview:!!n.preview,audiences:ne()}),z=t=>{_.get(t.slot)?.(),_.delete(t.slot)};function R(t,u,f=!1,g=F(t)){return p.has(t.slot)?Promise.resolve("shown"):(U.has(t.slot)||U.set(t.slot,Re(t,u,f,g).finally(()=>U.delete(t.slot))),U.get(t.slot))}async function Re(t,u,f,g){if(i())return m(t,"not shown",[`suppressed: ${[...window[Oe]].join(", ")}`]);let O=Q(t,{...se(t),...f?{seen:Ce.seen()}:{},asked:g});if(O.length)return m(t,"not eligible",O);let E=Se(t.format)&&!f,Y=E&&!g&&Ne();if(Y)return m(t,"not shown",[Y]);if(E&&!n.preview&&n.consentAnswered?.()===!1)return K.set(t,g),m(t,"not shown",["waiting for the consent banner"]);let x=Z(t.format),L=x&&$e(g);if(L)return m(t,"not shown",[`${L} is showing`]);if(x&&M&&!g)return m(t,"not shown",[`${M} already showed on this page view`]);let C=null;if(!x){try{C=document.querySelector(t.trigger.selector??"")}catch{C=null}if(!C)return m(t,"not shown",["no element matches its selector"])}x&&v.set(t.slot,t),z(t),m(t,"asking for a decision",[u]);let ke=fe().catch(h=>(console.warn("[hp] onsite renderer not loaded:",h?.message??h),null)),G=ne()??[],ie=[...new Set([...t.audiences,...G])].filter(h=>G.includes(h)).slice(0,100),Fe=t.audiences.length>0&&!n.preview&&n.personalisation()?await Promise.race([ee().then(h=>h?h.visitAudiences(d,n.sessionSignals,t.audiences,G):ie),new Promise(h=>setTimeout(h,lt,ie))]):null,P=await d.decide(t.slot,o.pin(t.slot),{visitAudiences:Fe,visitCampaign:t.arrived_from.length?a():null}),y=P.status===200?P.body?.decisions?.find(h=>h?.slot===t.slot):null;y?.experiment&&y.arm&&y.split&&o.pin(t.slot,[y.experiment,y.arm,y.split]);let $=y&&y.holdout!==!0?Ae(y.payload):null,re=$?.steps[0].blocks??[],le=y?.offer?.code??(n.preview?"PREVIEW":o.code()),je=n.basketValue?.()??null,B=re.some(h=>h?.t==="code")&&!le&&"no code to remind of"||re.some(h=>h?.t==="progress")&&!(je>0)&&"the basket is empty";if(B)return v.delete(t.slot),B==="the basket is empty"&&N.add(t),m(t,"not shown",[B]);if(N.delete(t),!$)return y?.holdout===!0&&n.analytics()&&e.recordExposure(P.body),v.delete(t.slot),x&&y?.holdout===!0&&(M??(M=t.slot)),y?.holdout===!0&&!g&&l("held",{slot:t.slot,arm:y.arm??null,format:t.format}),m(t,y?.holdout===!0?"held out":"no decision",[P.status===200?"no creative for this visitor":`decisions answered ${P.status}`]);let q=await ke;if(!q)return v.delete(t.slot),m(t,"not shown",["the renderer did not load"]);if(await Promise.race([q.warm?.(t,$,$.steps[0].id,te),new Promise(h=>setTimeout(h,ct))]),i())return v.delete(t.slot),m(t,"not shown",["suppressed"]);f||o.shown(t.slot),E&&o.covered(),x&&(M??(M=t.slot));let J=(h,We={})=>l(h,{slot:t.slot,arm:y.arm??null,format:$.format??t.format,...We}),Ue=q.mountForm({form:t,creative:$,decision:y,access:n,client:e,api:d,counters:o,loadWheel:Ie,loadAnswers:ae,container:C,warmed:te,coupon:le,basket:()=>n.basketValue?.()??null,emit:J,onClose(h){p.delete(t.slot),v.delete(t.slot),m(t,"closed",[h]),J("closed",{reason:h})}});return p.set(t.slot,Ue),n.analytics()&&e.recordExposure(P.body),m(t,"shown",[u]),J("shown"),"shown"}function V(t,u,f=F(t)){if(!Z(t.format))return R(t,u,!1,f);W.push([t,u,f]),!(W.length>1)&&setTimeout(async()=>{let g=W.sort(([O],[E])=>Ee(O,E));W=[];for(let[O,[E,Y,x]]of g.entries()){let L=await R(E,Y,!1,x);if(L==="shown"||L==="held out"){for(let[C]of g.slice(O+1))m(C,"not shown",[`${E.slot} has a higher priority`]);return}}},at)}for(let t of A){if(t.format==="teaser"&&o.tabOut(t.slot)){R(t,"tab kept from an earlier page",!0);continue}let u=Q(t,se(t));if(u.length){m(t,"not eligible",u);continue}let f=t.trigger.type;f==="manual"?m(t,"waiting for hp.onsite.open"):f==="inline"||t.format==="inline"?R(t,"inline"):oe(t)}function oe(t){z(t),_.set(t.slot,Te(t.trigger,u=>{z(t),V(t,u)},{device:c})),m(t,"armed",[`${t.trigger.type} on ${c}`])}let De=n.onConsentAnswered?.(()=>{let t=[...K];K.clear();for(let[u,f]of t)p.has(u.slot)||(f?V(u,"manual",f):oe(u))}),Le=n.onBasket?.(()=>{if(!((n.basketValue?.()??0)>0))return;let t=[...N];N.clear();for(let u of t)p.has(u.slot)||V(u,"the basket changed")}),D=Object.freeze({open(t){let u=A.find(g=>g.slot===t),f=u??A.find(g=>g.aliases.includes(t));return f?p.has(f.slot)?Promise.resolve(!0):R(f,"manual",!1,F(f)||!u).then(g=>g==="shown"):Promise.resolve(!1)},suppress(){for(let[t,u]of p){u.destroy(),p.delete(t),v.delete(t);let f=A.find(g=>g.slot===t);f&&m(f,"closed",["suppressed"])}},debug:()=>[...b.values()].map(t=>({...t,reasons:[...t.reasons]})),stop(){for(let t of _.values())t();_.clear(),Le?.(),De?.(),N.clear(),K.clear(),window[j]===D&&delete window[j]}});window[j]=D;for(let{slot:t,resolve:u}of window[it]?.splice(0)??[])u(D.open(t));return w&&console.table?.(D.debug()),D}window[Symbol.for("@thg-agentic/hyper-personalisation-web.onsite.module")]={startOnsite:Pe};})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thg-agentic/hyper-personalisation-web",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.26.0",
|
|
4
4
|
"description": "Browser SDK for the THG Hyper-Personalisation event specification: event tracking from a write key and remote settings, strict CMP-agnostic consent, a GA4 dataLayer bridge and in-session audience evaluation. Dependency-free ESM on the Segment wire protocol, a CDN script (dist/hp.min.js), and an optional @segment/analytics-next plugin path.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -60,7 +60,8 @@
|
|
|
60
60
|
"dist/onsite.min.js",
|
|
61
61
|
"dist/onsite-render.min.js",
|
|
62
62
|
"dist/onsite-wheel.min.js",
|
|
63
|
-
"dist/onsite-answers.min.js"
|
|
63
|
+
"dist/onsite-answers.min.js",
|
|
64
|
+
"dist/onsite-audiences.min.js"
|
|
64
65
|
],
|
|
65
66
|
"sideEffects": false,
|
|
66
67
|
"license": "MIT",
|
|
@@ -90,7 +91,7 @@
|
|
|
90
91
|
"esbuild": "^0.28.2",
|
|
91
92
|
"jsdom": "^30.1.1",
|
|
92
93
|
"typescript": "^7.0.2",
|
|
93
|
-
"@thg-agentic/hyper-personalisation-spec": "1.
|
|
94
|
+
"@thg-agentic/hyper-personalisation-spec": "1.20.0"
|
|
94
95
|
},
|
|
95
96
|
"scripts": {
|
|
96
97
|
"test": "node --test tests/*.test.mjs",
|
package/src/bootstrap.js
CHANGED
|
@@ -57,7 +57,7 @@ import {
|
|
|
57
57
|
readSettings,
|
|
58
58
|
resolveApiHost,
|
|
59
59
|
} from './settings.js';
|
|
60
|
-
import { realId, uuid } from './shape.js';
|
|
60
|
+
import { realId, tokenOf, uuid } from './shape.js';
|
|
61
61
|
import {
|
|
62
62
|
configureStorageNames,
|
|
63
63
|
migrateLegacyStorage,
|
|
@@ -195,8 +195,35 @@ function consentAdapter(consent, settings, preset) {
|
|
|
195
195
|
return reportingPurposes(factory(options), settings.consentPurposes);
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
/**
|
|
199
|
-
|
|
198
|
+
/**
|
|
199
|
+
* Who an identify named, as the session remembers it: `userId|email_sha256`, then `|v` once one for
|
|
200
|
+
* them carried an identity token (ADR 0067).
|
|
201
|
+
*/
|
|
202
|
+
const identifyMarker = (userId, email, verified) =>
|
|
203
|
+
`${userId ?? ''}|${email ?? ''}${verified ? '|v' : ''}`;
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Whether the session already sent this identify: for the same person, and verified, or not and
|
|
207
|
+
* this one has no token either. So a token is sent once, when it first appears for them, and a page
|
|
208
|
+
* without one (served from a shared cache) never sends them again.
|
|
209
|
+
*/
|
|
210
|
+
const identifiedAlready = (stored, userId, email, verified) =>
|
|
211
|
+
stored === identifyMarker(userId, email, true) ||
|
|
212
|
+
(!verified && stored === identifyMarker(userId, email, false));
|
|
213
|
+
|
|
214
|
+
const withoutToken = (event) => {
|
|
215
|
+
if (event.context?.identity_token === undefined) return event;
|
|
216
|
+
const { identity_token: _, ...context } = event.context;
|
|
217
|
+
return { ...event, context };
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
const readIdentified = (key) => {
|
|
221
|
+
try {
|
|
222
|
+
return sessionStorage.getItem(key);
|
|
223
|
+
} catch {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
};
|
|
200
227
|
|
|
201
228
|
/** The traits to identify with on this page, or null when this session already identified them. */
|
|
202
229
|
function pendingIdentify(propertyId, identity) {
|
|
@@ -204,13 +231,19 @@ function pendingIdentify(propertyId, identity) {
|
|
|
204
231
|
const email = normaliseSha256(identity?.emailSha256);
|
|
205
232
|
if (!userId && !email) return null;
|
|
206
233
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
234
|
+
// No session storage: identify on every page rather than never.
|
|
235
|
+
const stored = readIdentified(
|
|
236
|
+
storageKey(storageName('identified'), propertyId),
|
|
237
|
+
);
|
|
238
|
+
if (
|
|
239
|
+
identifiedAlready(
|
|
240
|
+
stored,
|
|
241
|
+
userId,
|
|
242
|
+
email,
|
|
243
|
+
userId !== null && tokenOf(identity?.token) !== null,
|
|
244
|
+
)
|
|
245
|
+
)
|
|
246
|
+
return null;
|
|
214
247
|
return {
|
|
215
248
|
...(userId ? { userId } : {}),
|
|
216
249
|
...(email ? { email_sha256: email } : {}),
|
|
@@ -465,6 +498,7 @@ async function start(config, options, carry) {
|
|
|
465
498
|
: undefined,
|
|
466
499
|
// Every page carries the signed-in user; only the identify itself is once per session.
|
|
467
500
|
getUserId: () => userId,
|
|
501
|
+
identityToken: identity?.token,
|
|
468
502
|
beforeSend: options.beforeSend,
|
|
469
503
|
...options.extend,
|
|
470
504
|
onConsentStatus(status) {
|
|
@@ -489,20 +523,22 @@ async function start(config, options, carry) {
|
|
|
489
523
|
// arrives later in the session is still identified. Any identify counts, including one the
|
|
490
524
|
// page sends itself at sign-in, so the next page of the session does not repeat it.
|
|
491
525
|
if (event.type === 'identify') {
|
|
492
|
-
const
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
526
|
+
const key = storageKey(storageName('identified'), propertyId);
|
|
527
|
+
const user = realId(event.userId);
|
|
528
|
+
const email = normaliseSha256(event.traits?.email_sha256);
|
|
529
|
+
// One without a token never unsays an earlier verified one for the same person.
|
|
530
|
+
const verified =
|
|
531
|
+
Boolean(event.context?.identity_token) ||
|
|
532
|
+
readIdentified(key) === identifyMarker(user, email, true);
|
|
496
533
|
try {
|
|
497
|
-
sessionStorage.setItem(
|
|
498
|
-
storageKey(storageName('identified'), propertyId),
|
|
499
|
-
marker,
|
|
500
|
-
);
|
|
534
|
+
sessionStorage.setItem(key, identifyMarker(user, email, verified));
|
|
501
535
|
} catch {
|
|
502
536
|
/* identify again next page */
|
|
503
537
|
}
|
|
504
538
|
}
|
|
505
|
-
|
|
539
|
+
// The observer passed to bootstrap never sees the token: it vouches for the shopper until
|
|
540
|
+
// it expires. A host's own beforeSend sees the event as sent.
|
|
541
|
+
options.extend?.onEvent?.(withoutToken(event));
|
|
506
542
|
},
|
|
507
543
|
});
|
|
508
544
|
|
package/src/index.js
CHANGED
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
getCookie,
|
|
51
51
|
localeTag,
|
|
52
52
|
perRequest,
|
|
53
|
+
readCampaign,
|
|
53
54
|
scrubHref,
|
|
54
55
|
} from './context.js';
|
|
55
56
|
import { createDecisionMemory, servedDecisions } from './decisions.js';
|
|
@@ -82,6 +83,7 @@ import {
|
|
|
82
83
|
PAGE_TYPES,
|
|
83
84
|
pruneProperties,
|
|
84
85
|
realId,
|
|
86
|
+
tokenOf,
|
|
85
87
|
uuid,
|
|
86
88
|
} from './shape.js';
|
|
87
89
|
import {
|
|
@@ -96,6 +98,12 @@ import {
|
|
|
96
98
|
byteLength as utf8Bytes,
|
|
97
99
|
} from './transport.js';
|
|
98
100
|
import { LIB, VERSION } from './version.js';
|
|
101
|
+
import {
|
|
102
|
+
clearVisitCampaign,
|
|
103
|
+
keepVisitCampaign,
|
|
104
|
+
readVisitCampaign,
|
|
105
|
+
visitCampaign,
|
|
106
|
+
} from './visit-campaign.js';
|
|
99
107
|
|
|
100
108
|
/** The surfaces a `Personalisation Exposed` names, as the public API's exposures do. */
|
|
101
109
|
const EXPOSURE_SURFACES = new Set([
|
|
@@ -426,6 +434,28 @@ export function createAnalytics(options) {
|
|
|
426
434
|
storageName('preview'),
|
|
427
435
|
cfg.consentCookieDomain ?? null,
|
|
428
436
|
);
|
|
437
|
+
/** The session kept on the device (the host's, or the SDK's cookie); null while in memory only. */
|
|
438
|
+
const keptSession = () =>
|
|
439
|
+
realId(perRequest(hostSession, null)) ?? getCookie(storageName('session'));
|
|
440
|
+
/**
|
|
441
|
+
* The tags the page loaded with, read now so a later `replaceState` cannot take them away, and
|
|
442
|
+
* the visit's campaign kept from them when the visit has none (visit-campaign.js).
|
|
443
|
+
*/
|
|
444
|
+
const landingCampaign = visitCampaign(
|
|
445
|
+
typeof location === 'undefined' ? null : readCampaign(location.search),
|
|
446
|
+
);
|
|
447
|
+
/**
|
|
448
|
+
* A page or an event of the visit, as it is collected whatever consent will say of sending it: the
|
|
449
|
+
* visit's campaign lasts as its session does. A trader's preview is not a shopper's visit: it
|
|
450
|
+
* reads its own URL's tags and keeps none.
|
|
451
|
+
*/
|
|
452
|
+
const keepCampaign = (landing = null) => {
|
|
453
|
+
if (!previewing)
|
|
454
|
+
keepVisitCampaign(cfg.propertyId, landing, {
|
|
455
|
+
sessionId: keptSession(),
|
|
456
|
+
keepSession: granted(),
|
|
457
|
+
});
|
|
458
|
+
};
|
|
429
459
|
|
|
430
460
|
/** Delivery problems, logged with `debug`. */
|
|
431
461
|
const reportError = (message, err) =>
|
|
@@ -489,6 +519,12 @@ export function createAnalytics(options) {
|
|
|
489
519
|
let identifiedUserId = null;
|
|
490
520
|
/** The user bootstrap's `identity` option named, only to warn when the host names another form. */
|
|
491
521
|
let optionsUserId = null;
|
|
522
|
+
/**
|
|
523
|
+
* The signed-in user's identity token (ADR 0067), the one copy of it: from the `identityToken`
|
|
524
|
+
* option for the user `getUserId` named, then whatever `identify` passes for its user. Another
|
|
525
|
+
* user, `reset()` or a sign-out clears it, so nobody else's token outlives their sign-in.
|
|
526
|
+
*/
|
|
527
|
+
let identityToken = userId ? tokenOf(cfg.identityToken) : null;
|
|
492
528
|
|
|
493
529
|
/** The call being replayed: its first event keeps the messageId and time it was made with. */
|
|
494
530
|
let replaying = null;
|
|
@@ -521,6 +557,7 @@ export function createAnalytics(options) {
|
|
|
521
557
|
/** Tracking never throws into the host: an event that fails to build or deliver is dropped. */
|
|
522
558
|
function emit(partial, ctxOverrides, force = false) {
|
|
523
559
|
noteBasket(partial);
|
|
560
|
+
keepCampaign();
|
|
524
561
|
try {
|
|
525
562
|
return compose(partial, ctxOverrides, force);
|
|
526
563
|
} catch (err) {
|
|
@@ -665,6 +702,7 @@ export function createAnalytics(options) {
|
|
|
665
702
|
exposedTokens.clear();
|
|
666
703
|
device?.forget();
|
|
667
704
|
forgetKeptVisit(true);
|
|
705
|
+
clearVisitCampaign();
|
|
668
706
|
}
|
|
669
707
|
|
|
670
708
|
function deliver(event, force) {
|
|
@@ -701,6 +739,8 @@ export function createAnalytics(options) {
|
|
|
701
739
|
};
|
|
702
740
|
};
|
|
703
741
|
|
|
742
|
+
// Before the gate starts, so a withdrawal it finds on this page clears the landing tags too.
|
|
743
|
+
keepCampaign(landingCampaign);
|
|
704
744
|
if (strict) {
|
|
705
745
|
gate = createConsentGate({
|
|
706
746
|
adapter: cfg.consent,
|
|
@@ -758,7 +798,10 @@ export function createAnalytics(options) {
|
|
|
758
798
|
if (state?.personalisation !== true)
|
|
759
799
|
forgetKeptVisit(previous?.personalisation === true);
|
|
760
800
|
// Events collected under the grant are not sent after it is withdrawn: only the withdrawal.
|
|
761
|
-
if (withdrawal)
|
|
801
|
+
if (withdrawal) {
|
|
802
|
+
transport.discardQueued?.();
|
|
803
|
+
clearVisitCampaign();
|
|
804
|
+
}
|
|
762
805
|
emit(
|
|
763
806
|
{
|
|
764
807
|
type: 'track',
|
|
@@ -772,6 +815,8 @@ export function createAnalytics(options) {
|
|
|
772
815
|
},
|
|
773
816
|
});
|
|
774
817
|
gate.start();
|
|
818
|
+
// Only what survived the gate: a visitor already granted keeps the session id with it.
|
|
819
|
+
keepCampaign();
|
|
775
820
|
}
|
|
776
821
|
|
|
777
822
|
/** The property's holdout split from the settings, as a serving response would state it. */
|
|
@@ -859,6 +904,7 @@ export function createAnalytics(options) {
|
|
|
859
904
|
userId = null;
|
|
860
905
|
identifiedUserId = null;
|
|
861
906
|
optionsUserId = null;
|
|
907
|
+
identityToken = null;
|
|
862
908
|
return event;
|
|
863
909
|
}
|
|
864
910
|
|
|
@@ -903,8 +949,17 @@ export function createAnalytics(options) {
|
|
|
903
949
|
identify(traits, ctx, source) {
|
|
904
950
|
const { userId: id, ...rest } =
|
|
905
951
|
traits && typeof traits === 'object' ? traits : {};
|
|
952
|
+
// The token the site's server signed for this user (ADR 0067): without it the identity graph
|
|
953
|
+
// records the sign-in and never joins this device to the user's others.
|
|
954
|
+
const passed = tokenOf(contextOverrides(ctx)?.identity_token);
|
|
906
955
|
if (id !== undefined) {
|
|
907
956
|
const next = realId(id);
|
|
957
|
+
// Another user's sign-in brings its own token or none; the same user's keeps the last.
|
|
958
|
+
identityToken = !next
|
|
959
|
+
? null
|
|
960
|
+
: next === userId
|
|
961
|
+
? (passed ?? identityToken)
|
|
962
|
+
: passed;
|
|
908
963
|
if (source === IDENTITY_OPTION) {
|
|
909
964
|
optionsUserId = next;
|
|
910
965
|
} else if (identifiedUserId && next && next !== identifiedUserId) {
|
|
@@ -924,10 +979,12 @@ export function createAnalytics(options) {
|
|
|
924
979
|
}
|
|
925
980
|
userId = next;
|
|
926
981
|
if (next && source !== IDENTITY_OPTION) identifiedUserId = next;
|
|
927
|
-
}
|
|
982
|
+
} else if (passed && userId) identityToken = passed;
|
|
983
|
+
// Only the current user's token is sent: one passed with nobody to keep it for goes nowhere.
|
|
984
|
+
const { identity_token: _, ...context } = contextOverrides(ctx) ?? {};
|
|
928
985
|
return emit(
|
|
929
986
|
{ type: 'identify', traits: identifyTraits(rest, cfg.debug) },
|
|
930
|
-
|
|
987
|
+
identityToken ? { ...context, identity_token: identityToken } : context,
|
|
931
988
|
);
|
|
932
989
|
},
|
|
933
990
|
|
|
@@ -941,6 +998,7 @@ export function createAnalytics(options) {
|
|
|
941
998
|
userId = null;
|
|
942
999
|
identifiedUserId = null;
|
|
943
1000
|
optionsUserId = null;
|
|
1001
|
+
identityToken = null;
|
|
944
1002
|
writeLastPageMessageId('');
|
|
945
1003
|
},
|
|
946
1004
|
|
|
@@ -1120,6 +1178,8 @@ export function createAnalytics(options) {
|
|
|
1120
1178
|
preview: previewing,
|
|
1121
1179
|
anonymousId: () => realId(perRequest(cfg.getAnonymousId, null)),
|
|
1122
1180
|
sessionId: () => realId(perRequest(cfg.getSessionId, null)),
|
|
1181
|
+
// Only where it is used: a reminder's code is answered with personalisation granted.
|
|
1182
|
+
identityToken: () => (personalisationGranted() ? identityToken : null),
|
|
1123
1183
|
analytics: granted,
|
|
1124
1184
|
personalisation: personalisationGranted,
|
|
1125
1185
|
consent: () => cfg.getConsent(),
|
|
@@ -1129,6 +1189,11 @@ export function createAnalytics(options) {
|
|
|
1129
1189
|
? null
|
|
1130
1190
|
: scrubHref(location.href, cfg),
|
|
1131
1191
|
locale: () => localeTag(perRequest(cfg.getLocale, cfg.locale)),
|
|
1192
|
+
/** The visit's campaign for "arrived from"; a preview's is its own URL's. */
|
|
1193
|
+
campaign: () =>
|
|
1194
|
+
previewing
|
|
1195
|
+
? landingCampaign
|
|
1196
|
+
: readVisitCampaign(cfg.propertyId, { sessionId: keptSession() }),
|
|
1132
1197
|
/**
|
|
1133
1198
|
* A basket bar's progress: the basket this page reported, else the last one this visit
|
|
1134
1199
|
* kept (under personalisation consent), else null.
|
|
@@ -1137,6 +1202,12 @@ export function createAnalytics(options) {
|
|
|
1137
1202
|
const value = getSessionSignals().basketValue;
|
|
1138
1203
|
return pageBasket ?? (Number.isFinite(value) ? value : null);
|
|
1139
1204
|
},
|
|
1205
|
+
/** This visit's session signals, kept only under personalisation consent; else null. */
|
|
1206
|
+
sessionSignals: () => {
|
|
1207
|
+
if (!personalisationGranted()) return null;
|
|
1208
|
+
scopeVisit();
|
|
1209
|
+
return getSessionSignals();
|
|
1210
|
+
},
|
|
1140
1211
|
/** Calls `listener` whenever the page reports its basket; answers how to stop. */
|
|
1141
1212
|
onBasket: (listener) => {
|
|
1142
1213
|
basketListeners.add(listener);
|