PageSourceSearch

https://hammernutrition.com/cdn/shop/t/126/assets/subscription-pdp.js?v=45142307375296174991787047160

js hammernutrition.com collected 2026-10-01 11:59:19 UTC 36,740 bytes, 57 lines download raw bytes

1(function(){if(window.customElements&&customElements.get("subscription-pdp"))return;const POLL_MS=5e3,PENDING_MAX_MS=6e4,POLL_BACKGROUND_MS=2e4,FLAG_TTL_MS=432e5,FLAG_TTL_NEGATIVE_MS=36e5,CHARGES_TTL_MS=12e4,OPTIMISTIC_MAX_MS=6e5;class SubscriptionPdp extends HTMLElement{constructor(){super(),this.endpoint=this.dataset.endpoint,this.customerId=this.dataset.customerId,this.productId=this.dataset.productId,this.section=this.dataset.section,this.loggedIn=this.dataset.loggedIn==="true",this.enablePdp=this.dataset.enablePdp==="true",this.enableQuickshop=this.dataset.enableQuickshop==="true",this.pollEnable=this.dataset.pollEnable!=="false",this.autoclose=this.dataset.autoclose==="true",this.instantSuccess=this.dataset.instantSuccess!=="false",this.ordersCount=this.dataset.ordersCount||"",this.toggleEnable=this.dataset.toggleEnable!=="false",this.subscriptionOnly=this.dataset.subscriptionOnly==="true",this.groupItems=this.dataset.groupItems!=="false",this.qtyDiscount=this.dataset.qtyDiscount!=="false",this.onetimeDiscount=parseFloat(this.dataset.onetimeDiscount)||0,this.productHasSub=this.dataset.productHasSub==="true",this.text={subscriptionLabel:this.dataset.textSubscriptionLabel||"Add to every order",onetimeLabel:this.dataset.textOnetimeLabel||"Add to next order only",success:this.dataset.textSuccess||"Product added to your subscription",processing:this.dataset.textProcessing||"It can take about 5\u201320 seconds to appear in your order.",error:this.dataset.textError||"Something went wrong. Please try again.",empty:this.dataset.textEmpty||"You have no upcoming subscription orders.",oos:this.dataset.textOos||"Out of Stock"},this.charges=[],this.groups=[],this.selectedGroupIndex=null}connectedCallback(){if(this._initialized)return;if(this._initialized=!0,this.quickShopHost=this.closest("#quick-buy-modal"),this.inQuickShop=!!this.quickShopHost,!(this.inQuickShop?this.enableQuickshop:this.enablePdp)){this.style.display="none";return}if(this.cacheDom(),this.parseVariants(),!this.loggedIn){this.setupLoginRedirect(),this.initWidgetMirror();return}!this.endpoint||!this.trigger||!this.popup||(this.popupHost=this.inQuickShop?this.quickShopHost:document.body,this.popup.parentElement!==this.popupHost&&this.popupHost.appendChild(this.popup),this.bindEvents(),this.initWidgetMirror(),this.initChargesState())}disconnectedCallback(){clearTimeout(this._closeTimer),clearTimeout(this._syncTimer),clearTimeout(this._onceTimer),clearTimeout(this._statusHideTimer),clearInterval(this._pollTimer),this._widgetRaf&&cancelAnimationFrame(this._widgetRaf),this._widgetTimers&&this._widgetTimers.forEach(t=>clearTimeout(t)),this._widgetObserver&&this._widgetObserver.disconnect(),this.popup&&this.popup.parentElement&&this.popup.parentElement!==this&&this.popup.remove(),this._onKeydown&&document.removeEventListener("keydown",this._onKeydown),this._onVariantChange&&window.removeEventListener("custom:variant-changed",this._onVariantChange),this._onWidgetVariant&&window.removeEventListener("custom:variant-changed",this._onWidgetVariant)}setupLoginRedirect(){const links=this.querySelectorAll(".subscription-pdp__login-prompt a");if(!links.length)return;const returnUrl=encodeURIComponent(window.location.pathname+window.location.search);links.forEach(a=>{const href=a.getAttribute("href")||"";!/login|customer_authentication|\/account(\/|$)/i.test(href)||/return_url=/i.test(href)||a.setAttribute("href",href+(href.indexOf("?")===-1?"?":"&")+"return_url="+returnUrl)})}cacheDom(){this.trigger=this.querySelector(".subscription-pdp__trigger"),this.popup=this.querySelector(".subscription-pdp__popup"),this.variantBox=this.querySelector(".subscription-pdp__variant"),this.qtyInput=this.querySelector(".subscription-pdp__qty-input"),this.toggleInput=this.querySelector(".subscription-pdp__toggle-input"),this.toggleText=this.querySelector(".subscription-pdp__toggle-text"),this.chargesBox=this.querySelector(".subscription-pdp__charges"),this.message=this.querySelector(".subscription-pdp__message"),this.confirmBtn=this.querySelector(".subscription-pdp__confirm"),this.statusBox=this.querySelector(".subscription-pdp__status"),this.promptBox=this.querySelector(".subscription-pdp__login-prompt"),this.form=document.getElementById("product-form-"+this.section)}parseVariants(){this.variants=[];const dataEl=this.querySelector(".subscription-pdp__variants-data");if(dataEl)try{const parsed=JSON.parse(dataEl.textContent);this.variants=parsed.variants||[]}
1catch(e){console.error("subscription-pdp: invalid variants JSON",e)}}bindEvents(){this.trigger.addEventListener("click",()=>this.open()),this.popup.querySelectorAll("[data-spdp-close]").forEach(el=>el.addEventListener("click",()=>this.close())),this._onKeydown=e=>{e.key==="Escape"&&this.isOpen()&&this.close()},document.addEventListener("keydown",this._onKeydown),this.toggleInput.addEventListener("change",()=>{this.updateToggleText(),this.renderVariant()}),this.popup.querySelectorAll("[data-spdp-qty]").forEach(btn=>btn.addEventListener("click",()=>this.stepQty(btn.dataset.spdpQty))),this.qtyInput.addEventListener("input",()=>this.renderVariant()),this.confirmBtn.addEventListener("click",()=>this.submit()),this._onVariantChange=()=>this.refreshOpenPopup(),window.addEventListener("custom:variant-changed",this._onVariantChange)}flagKey(){return"spdp_has_subs_"+(this.customerId||"anon")}loadFlag(){let data=null;try{const raw=window.localStorage.getItem(this.flagKey());data=raw?JSON.parse(raw):null}catch{data=null}if(!data||typeof data.has!="boolean"||String(data.orders)!==String(this.ordersCount))return null;const ttl=data.has?FLAG_TTL_MS:FLAG_TTL_NEGATIVE_MS;return Date.now()-(data.ts||0)>ttl?null:data}saveFlag(has){try{window.localStorage.setItem(this.flagKey(),JSON.stringify({has:!!has,orders:String(this.ordersCount),ts:Date.now()}))}catch{}}initChargesState(){const cached=this.loadFlag();if(cached){this.hasCharges=cached.has,this.updateTriggerVisibility(),this.loadPending().some(e=>String(e.productId)===String(this.productId))?this.fetchCharges().then(()=>this.resumePending()):this.resumePending();return}this.fetchCharges().then(()=>this.resumePending())}fetchCharges(chargeId){let url=this.endpoint;return chargeId&&(url+=(url.indexOf("?")===-1?"?":"&")+"charge_id="+encodeURIComponent(chargeId)),fetch(url,{method:"GET",headers:{"X-Requested-With":"XMLHttpRequest",Accept:"application/json"},credentials:"same-origin"}).then(r=>r.ok?r.json():Promise.reject(r.status)).then(data=>{const list=Array.isArray(data)?data:data&&typeof data=="object"?[data]:[];this._fetchFailed=!1,chargeId?this.mergeCharge(list,chargeId):(this.charges=list,this.chargesLoaded=!0,this._chargesTs=Date.now());const found=this.buildGroups().length>0;return chargeId&&!this.chargesLoaded?found&&(this.hasCharges=!0,this.saveFlag(!0)):(this.hasCharges=found,this.saveFlag(found)),this.applyOptimistic(),this.updateTriggerVisibility(),this.charges}).catch(e=>(console.error("subscription-pdp: failed to load charges",e),this._fetchFailed=!0,this.charges||[]))}mergeCharge(list,chargeId){if(list.length>1){this.charges=list,this.chargesLoaded=!0,this._chargesTs=Date.now();return}if(list.length===1&&String(this.chargeIdOf(list[0]))!==String(chargeId))return;const current=this.charges||[],index=current.findIndex(c=>String(this.chargeIdOf(c))===String(chargeId));if(index===-1){this.charges=current.concat(list);return}this.charges=current.slice(0,index).concat(list,current.slice(index+1))}chargeIdOf(charge){const id=charge&&charge.charge_id;return id==null||id===""?null:id}loadChargesForOpen(){this.chargesLoaded&&Date.now()-(this._chargesTs||0)<CHARGES_TTL_MS||this._loadingCharges||(this._loadingCharges=!0,this.showChargesLoading(),this.fetchCharges().then(()=>{if(this._loadingCharges=!1,!(!this.isOpen()||this.added)){if(this._fetchFailed&&!this.chargesLoaded){this.showChargesError();return}this.renderCharges()}}))}showChargesLoading(){this.chargesBox&&(this.confirmBtn.disabled=!0,this.chargesBox.innerHTML='<p class="subscription-pdp__loading"><span class="subscription-pdp__spinner" aria-hidden="true"></span><span>Loading your orders\u2026</span></p>')}showChargesError(){this.chargesBox&&(this.confirmBtn.disabled=!0,this.chargesBox.innerHTML='<p class="subscription-pdp__empty">'+this.escape(this.text.error)+"</p>")}getSelectedVariantId(){const vr=this.scope().querySelector("mtn-variant-radios");if(vr&&vr.currentVariant&&vr.currentVariant.id!=null)return String(vr.currentVariant.id);const input=this.form&&this.form.querySelector('[name="id"]');return input&&input.value?String(input.value):this.variants.length?String(this.variants[0].id):null}getSelectedVariant(){const id=this.getSelectedVariantId();return this.variants.find(v=>String(v.id)===id)||this.variants[0]||null}isVariantOrderable(){const scope=this.scope(),addBtn=this.form&&this.form.querySelector('[name="add"]')||scope.querySelector('[name="add"]');return addBtn&&addBtn.classList.contains("is-invisible")?!1:!!this.getSelectedVariant()}resolveTypeMode(){const variant=this.getSelectedVariant();return variant&&!variant.has_sub?"onetime":!this.toggleEnable||this.subscriptionOnly?"subscription":"toggle"}effectiveIsSubscription(){const mode=this.resolveTypeMode();return mode==="onetime"?!1:mode==="subscription"?!0:this.toggleInput.checked}initWidgetMirror(){this.widgetScope=this.inQuickShop&&this.quickShopHost?this.quickShopHost:this.form&&this.form.closest(".shopify-section")||this,this._onWidgetVariant=()=>this.scheduleWidgetUpdate(),window.addEventListener("custom:variant-changed",this._onWidgetVariant),this.scheduleWidgetUpdate(),this._widgetTimers=[300,800,1500,3e3].map(ms=>setTimeout(()=>this.scheduleWidgetUpdate(),ms))}runWidgetUpdate(){this.loggedIn?(this.updateTriggerVisibility(),this.isOpen()&&(this.isVariantOrderable()?(this.getSelectedVariantId()!==this._renderedVariantId||this.resolveTypeMode()!==this._typeMode)&&this.refreshOpenPopup():this.popup.classList.contains("is-open")&&this.close())):this.updatePromptVisibility()}scheduleWidgetUpdate(){this._widgetRaf||(this._widgetRaf=requestAnimationFrame(()=>{this._widgetRaf=null,this.attachWidgetObserver(),this.runWidgetUpdate()}))}attachWidgetObserver(){if(this._widgetObserver)return;const target=this.widgetScope||this.form&&this.form.closest(".shopify-section")||document;!target||!window.MutationObserver||(this._widgetObserver=new MutationObserver(()=>this.scheduleWidgetUpdate()),this._widgetObserver.observe(target,{subtree:!0,childList:!0,attributes:!0,attributeFilter:["class"]}))}updateTriggerVisibility(){if(!this.trigger)return;const show=this.hasCharges&&this.isVariantOrderable();
1this.trigger.hidden=!show,this.trigger.style.display=show?"inline-flex":"none"}updatePromptVisibility(){this.promptBox&&(this.promptBox.style.display=this.isVariantOrderable()?"":"none")}renderVariant(){const variant=this.getSelectedVariant();if(!variant){this.variantBox.innerHTML="";return}const productTitle=this.dataset.productTitle||"",showVariantTitle=variant.title&&variant.title.toLowerCase()!=="default title";this.variantBox.innerHTML=`
2        ${this.imgTag(variant.image,"subscription-pdp__variant-img",60)}
3        <div class="subscription-pdp__variant-info">
4          <span class="subscription-pdp__variant-title">${this.escape(productTitle)}</span>
5          ${showVariantTitle?`<span class="subscription-pdp__variant-option">${this.escape(variant.title)}</span>`:""}
6          ${this.priceMarkup(variant)}
7        </div>`}priceMarkup(variant){const isSubscription=this.toggleInput.checked,base=variant.price_amount!=null?variant.price_amount/100:null;if(isSubscription){if(variant.sub_price&&variant.sub_amount!=null&&variant.price_amount!=null&&variant.sub_amount<variant.price_amount){const percent=Math.round((1-variant.sub_amount/variant.price_amount)*100);return this.priceBlock(variant.sub_price,variant.price,percent,"")}return variant.price?`<span class="subscription-pdp__variant-price">${this.escape(variant.price)}</span>`:""}const qty=Math.max(1,parseInt(this.qtyInput.value,10)||1),tiers=this.onetimeTiers(variant);let upcoming=null;for(let i=0;i<tiers.length;i++)if(tiers[i].from>qty){upcoming=tiers[i];break}const salePrice=this.onetimeUnitPrice(variant,qty);if(salePrice!=null){const percent=Math.round((1-salePrice/base)*100),note=upcoming&&upcoming.price<salePrice?"("+upcoming.from+"+ for "+this.formatMoney(upcoming.price)+")":"";return this.priceBlock(this.formatMoney(salePrice),variant.price,percent,note)}if(upcoming&&variant.price){const note="("+upcoming.from+"+ for "+this.formatMoney(upcoming.price)+")";return`
8          <span class="subscription-pdp__variant-price">
9            <span class="subscription-pdp__price-each">${this.escape(variant.price)} EACH</span>
10            <span class="subscription-pdp__price-tier">${this.escape(note)}</span>
11          </span>`}return variant.price?`<span class="subscription-pdp__variant-price">${this.escape(variant.price)}</span>`:""}onetimeTiers(variant){const base=variant.price_amount!=null?variant.price_amount/100:null;if(base==null)return[];const tiers=this.getQtyTiers(variant).filter(t=>t.price<base);return this.qtyDiscount?tiers:tiers.filter(t=>t.from<=1)}onetimeUnitPrice(variant,qty){const base=variant.price_amount!=null?variant.price_amount/100:null;if(base==null)return null;let price=null;if(this.onetimeTiers(variant).forEach(t=>{qty>=t.from&&(price=t.price)}),this.onetimeDiscount>0&&this.onetimeDiscount<100){const meta=base*(1-this.onetimeDiscount/100);(price==null||meta<price)&&(price=meta)}return price}quotedUnitPrice(variant,qty,isSubscription){const base=variant.price_amount!=null?variant.price_amount/100:null;if(isSubscription)return variant.sub_amount!=null&&variant.price_amount!=null&&variant.sub_amount<variant.price_amount?variant.sub_amount/100:base;const sale=this.onetimeUnitPrice(variant,qty);return sale??base}priceBlock(salePrice,wasPrice,percent,note){return`
12        <span class="subscription-pdp__variant-price">
13          <span class="subscription-pdp__price-sub">${this.escape(salePrice)}</span>
14          ${wasPrice?`<span class="subscription-pdp__price-was">${this.escape(wasPrice)}</span>`:""}
15          ${percent>0?`<span class="subscription-pdp__price-badge">${percent}% OFF</span>`:""}
16          ${note?`<span class="subscription-pdp__price-tier">${this.escape(note)}</span>`:""}
17        </span>`}getQtyTiers(variant){const priceEl=this.scope().querySelector(".c-price[data-discount]");if(!priceEl)return[];const parts=(priceEl.getAttribute("data-discount")||"").split(":"),group=(priceEl.getAttribute("data-customer-group")||"").toLowerCase();if(parts.length<=3||parts[0]!=="discount")return[];if(parts[1].toLowerCase()!==group)return[];const target=parts[2];return target!=="product"&&String(parseInt(target,10))!==String(variant&&variant.id)?[]:parts.slice(3).map(r=>{const seg=String(r).split("-");return{from:parseInt(seg[0],10),price:parseFloat(seg[1])}}).filter(t=>!isNaN(t.from)&&!isNaN(t.price)).sort((a,b)=>a.from-b.from)}buildGroups(){const groups=[];
17return(this.charges||[]).forEach(charge=>{this.splitCharge(charge).forEach(g=>groups.push(g))}),groups}splitCharge(charge){const lineItems=charge.line_items||[],byKey={},groups=[],onetimes=[];return lineItems.forEach(li=>{const freq=li.order_interval_frequency;if(!(li.type!=="onetime"&&!!freq)){onetimes.push(li);return}const key="s:"+freq+"|"+(li.order_interval_unit||"");byKey[key]||(byKey[key]={charge,interval:{frequency:freq,unit:li.order_interval_unit},lineItems:[]},groups.push(byKey[key])),byKey[key].lineItems.push(li)}),groups.sort((a,b)=>a.interval.frequency-b.interval.frequency),onetimes.length&&groups.length&&(groups[0].lineItems=groups[0].lineItems.concat(onetimes)),groups}renderCharges(){if(!this.chargesLoaded){this.showChargesLoading();return}if(this.groups=this.buildGroups(),!this.groups.length){this.chargesBox.innerHTML=`<p class="subscription-pdp__empty">${this.escape(this.text.empty)}</p>`;return}this.chargesBox.innerHTML=this.groups.map((group,index)=>{const charge=group.charge,addr=charge.shipping_address||charge.billing_address||{},name=[addr.first_name,addr.last_name].filter(Boolean).join(" "),addressLine=[addr.address1,addr.city,addr.province,addr.zip].filter(Boolean).join(", "),lineItems=group.lineItems||[],badge=group.interval?this.intervalBadge(group.interval.frequency,group.interval.unit):'<span class="subscription-pdp__charge-onetime">One-time</span>',items=this.groupLineItems(lineItems).map(li=>this.chargeItemRow(li,charge.currency)).join(""),itemCount=lineItems.reduce((sum,li)=>sum+(li.quantity||1),0);return`
18            <label class="subscription-pdp__charge">
19              <input type="radio" name="spdp-charge" class="subscription-pdp__charge-radio" value="${index}" data-index="${index}">
20              <span class="subscription-pdp__charge-body">
21                <span class="subscription-pdp__charge-head">
22                  <span class="subscription-pdp__charge-meta">
23                    <span class="subscription-pdp__charge-key">Next order:</span>
24                    <span class="subscription-pdp__charge-val subscription-pdp__charge-date">${this.formatDate(charge.scheduled_at)}</span>
25                  </span>
26                  ${badge}
27                </span>
28                ${name||addressLine?`<span class="subscription-pdp__charge-meta">
29                         <span class="subscription-pdp__charge-key">Ship to:</span>
30                         <span class="subscription-pdp__charge-val subscription-pdp__charge-val--address">${this.escape([name,addressLine].filter(Boolean).join(", "))}</span>
31                       </span>`:""}
32                ${this.paymentMarkup(charge.payment_method)}
33                <span class="subscription-pdp__charge-items">
34                  <span class="subscription-pdp__items">
35                    <span class="subscription-pdp__items-head">
36                      <span class="subscription-pdp__items-title">In this order<span class="subscription-pdp__items-count">${itemCount} ${itemCount===1?"item":"items"}</span></span>
37                      <span class="subscription-pdp__items-col">Qty</span>
38                      <span class="subscription-pdp__items-col">Subtotal</span>
39                    </span>
40                    ${items}
41                  </span>
42                </span>
43              </span>
44            </label>`}).join(""),this.chargesBox.querySelectorAll(".subscription-pdp__charge-radio").forEach(radio=>radio.addEventListener("change",()=>{this.added||(this.selectedGroupIndex=parseInt(radio.value,10),this.confirmBtn.disabled=!1)}));const firstRadio=this.chargesBox.querySelector(".subscription-pdp__charge-radio");firstRadio&&!this.added&&(firstRadio.checked=!0,this.selectedGroupIndex=parseInt(firstRadio.value,10),this.confirmBtn.disabled=!1)}chargeItemRow(li,currency){const price=this.lineMoney(li),badge=li.type==="onetime"?'<span class="subscription-pdp__charge-onetime">One-time</span>':"",meta=badge?`<span class="subscription-pdp__item-meta">${badge}</span>`:"",variant=li.variant_title&&String(li.variant_title).toLowerCase()!=="default title"?`<span class="subscription-pdp__item-variant">${this.escape(li.variant_title)}</span>`:"";return`
45        <span class="subscription-pdp__item">
46          <span class="subscription-pdp__item-product">
47            ${this.imgTag(li.image,"subscription-pdp__item-img",40)}
48            <span class="subscription-pdp__item-text">
49              <span class="subscription-pdp__item-title">${this.escape(li.title||"")}</span>
50              ${variant}
51              ${meta}
52            </span>
53          </span>
54          <span class="subscription-pdp__item-qty">${li.quantity||1}</span>
55          <span class="subscription-pdp__item-price">${this.escape(this.formatMoney(price,currency))}</span>
56        </span>`}imgTag(src,className,size){return!src||typeof src!="string"?"":`<img class="${className}" src="${this.escape(src)}" alt="" width="${size}" height="${size}" loading="lazy" onerror="this.remove()">`}intervalBadge(freq,unit){const plural=freq>1?"s":"";return`<span class="subscription-pdp__charge-interval">Every ${this.escape(String(freq))} ${this.escape(unit||"")}${plural}</span>`}groupLineItems(lineItems){const list=lineItems||[];if(!this.groupItems)return list;const map={},order=[];return list.forEach((li,i)=>{const pid=li.shopify_product_id,vid=li.shopify_variant_id,key=pid!=null&&pid!==""&&vid!=null&&vid!==""?"g:"+(li.type||"")+"|"+pid+"|"+vid:"u:"+i;if(map[key]){const sum=this.lineMoney(map[key])+this.lineMoney(li);map[key].quantity=(map[key].quantity||0)+(li.quantity||0),isNaN(sum)?delete map[key].total_price:map[key].total_price=sum}else map[key]=Object.assign({},li),order.push(key)}),order.map(k=>map[k])}lineMoney(li){return li.total_price!=null?Number(li.total_price):li.unit_price!=null?Number(li.unit_price)*(li.quantity||1):NaN}paymentMarkup(pm){if(!pm||!pm.details)return"";const d=pm.details,card=(d.brand?this.titleCase(d.brand):this.titleCase(pm.type||"Card"))+(d.last4?" \u2022\u2022\u2022\u2022"+this.escape(String(d.last4)):""),expires=d.exp_month&&d.exp_year?this.pad2(d.exp_month)+"/"+this.escape(String(d.exp_year)):"";return'<span class="subscription-pdp__charge-meta"><span class="subscription-pdp__charge-key">Payment:</span><span class="subscription-pdp__charge-val subscription-pdp__charge-payment"><span class="subscription-pdp__charge-payment-card">'+this.escape(card)+"</span>"+(expires?'<span class="subscription-pdp__charge-payment-exp">Expires: '+expires+"</span>":"")+"</span></span>"}formatMoney(amount,currency){const n=Number(amount);if(isNaN(n))return"";try{return new Intl.NumberFormat(void 0,{style:"currency",currency:currency||"USD"}).format(n)}catch{return"$"+n.toFixed(2)}}titleCase(str){return String(str||"").replace(/[_-]+/g," ").replace(/\b\w/g,c=>c.toUpperCase())}pad2(value){const n=parseInt(value,10);return isNaN(n)?this.escape(String(value)):n<10?"0"+n:""+n}updateToggleText(){this.toggleText.textContent=this.toggleInput.checked?this.text.subscriptionLabel:this.text.onetimeLabel}scope(){return this.inQuickShop&&this.quickShopHost?this.quickShopHost:document}getById(id){return this.scope().querySelector('[id="'+id+'"]')}validateSelection(){const notificationBlock=this.getById("FormNotification-"+this.section),variantRadios=this.scope().querySelector("mtn-variant-radios");if(variantRadios&&typeof variantRadios.getOptions=="function"){const options=variantRadios.getOptions();if(!options||options.some(o=>typeof o>"u")){const errorTpl=this.getById("FormNotification-error-"+this.section);return notificationBlock&&errorTpl&&(notificationBlock.innerHTML="",notificationBlock.append(errorTpl.cloneNode(!0)),notificationBlock.style.display="inline-block"),typeof variantRadios.toggleAddButton=="function"&&variantRadios.toggleAddButton(!0,"",!0),!1}}const variant=this.getSelectedVariant();return variant&&variant.available===!1?(this.showStockError(notificationBlock),!1):(notificationBlock&&(notificationBlock.innerHTML="",notificationBlock.style.display="none"),!0)}showStockError(notificationBlock){notificationBlock&&(notificationBlock.innerHTML='<div class="product-form__notifications" role="alert" aria-live="assertive"><span>'+this.escape(this.text.oos)+"</span></div>",notificationBlock.style.display="inline-block")}isOpen(){return this.popup&&!this.popup.hidden}refreshOpenPopup(){this.isOpen()&&(this.applyToggleMode(),this.renderVariant(),this._renderedVariantId=this.getSelectedVariantId())}applyToggleMode(){const prev=this._typeMode||null,mode=this.resolveTypeMode();this._typeMode=mode;const wrap=this.toggleInput.closest(".subscription-pdp__toggle");mode==="onetime"?(this.toggleInput.checked=!1,wrap&&(wrap.style.display="",wrap.classList.add("subscription-pdp__toggle_locked"))):mode==="subscription"?(this.toggleInput.checked=!0,wrap&&(wrap.style.display="none")):(prev&&prev!=="toggle"&&(this.toggleInput.checked=!0),wrap&&(wrap.style.display="",wrap.classList.remove("subscription-pdp__toggle_locked"))),this.toggleInput.disabled=!!this._formLocked||mode!=="toggle",this.updateToggleText()}open(){if(!this.validateSelection())return;clearTimeout(this._syncTimer),this.added=!1,this.setFormDisabled(!1),this.resetMessage(),this.confirmBtn.classList.remove("loading"),this.confirmBtn.disabled=!0,this.selectedGroupIndex=null,this._typeMode=null,this.toggleInput.checked=!0,this.applyToggleMode();const pdpQty=this.scope().querySelector('[id="Quantity-'+this.section+'"]');this.qtyInput.value=pdpQty&&Number(pdpQty.value)>0?pdpQty.value:1,this.renderVariant(),this._renderedVariantId=this.getSelectedVariantId(),this.renderCharges(),clearTimeout(this._closeTimer),this.popup.hidden=!1,this.popup.setAttribute("aria-hidden","false"),document.documentElement.classList.add("subscription-pdp-open"),this.popup.offsetWidth,this.popup.classList.add("is-open"),this.loadChargesForOpen()}close(){this.popup.classList.remove("is-open"),this.popup.setAttribute("aria-hidden","true"),document.documentElement.classList.remove("subscription-pdp-open"),clearTimeout(this._closeTimer),this._closeTimer=setTimeout(()=>{this.popup.hidden=!0},280)}stepQty(direction){let value=parseInt(this.qtyInput.value,10);isNaN(value)&&(value=1),value=direction==="plus"?value+1:value-1,value<1&&(value=1),this.qtyInput.value=value,this.renderVariant()}submit(){const group=this.groups[this.selectedGroupIndex];if(!group)return;const charge=group.charge,variant=this.getSelectedVariant();if(!charge||!variant)return;const isSubscription=this.effectiveIsSubscription(),quantity=Math.max(1,parseInt(this.qtyInput.value,10)||1);this._submitted={charge,group,variant,quantity,isSubscription};const payload={type:isSubscription?"subscription":"onetime",address_id:charge.address_id,next_charge_scheduled_at:charge.scheduled_at,product_id:Number(this.productId),variant_id:Number(variant.id),quantity};if(isSubscription){const interval=group.interval||this.resolveInterval(charge);interval&&(payload.order_interval_frequency=interval.frequency,payload.order_interval_unit=interval.unit)}this.setLoading(!0),this.resetMessage(),fetch(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json","X-Requested-With":"XMLHttpRequest"},credentials:"same-origin",body:JSON.stringify(payload)}).then(r=>r.ok?r.json().catch(()=>({})):r.text().then(body=>{const err=new Error("HTTP "+r.status);throw err.status=r.status,err.body=body,err})).then(()=>this.onAddSuccess()).catch(e=>{console.error("subscription-pdp: add failed",{status:e&&e.status,response:e&&e.body,payload,error:e}),this.setLoading(!1),this.showMessage(this.text.error,!0)})}onAddSuccess(){this.added=!0,this.setFormDisabled(!0),this.clearChargeSelection(),this.confirmBtn.classList.remove("loading"),this.confirmBtn.disabled=!0;const submitted=this._submitted||{}
56,variant=submitted.variant||this.getSelectedVariant(),pending={productId:String(this.productId),variantId:String(variant?variant.id:""),quantity:submitted.quantity||Math.max(1,parseInt(this.qtyInput.value,10)||1),chargeId:this.chargeIdOf(submitted.charge),addressId:submitted.charge?submitted.charge.address_id:null,scheduledAt:submitted.charge?submitted.charge.scheduled_at:null,ts:Date.now()};if(pending.baseline=this.pendingQty(this.charges,pending)+this.reservedQty(pending),this._chargesTs=0,this.autoclose&&this.close(),this.instantSuccess){this.recordOptimistic(submitted,pending),this.autoclose||(this.added=!1,this.setFormDisabled(!1),this.renderCharges(),this.clearChargeSelection(),this.confirmBtn.disabled=!0,this.showSuccessMessage()),this.showDoneStatus(),clearTimeout(this._statusHideTimer),this._statusHideTimer=setTimeout(()=>this.hideStatus(),8e3),this.pollEnable&&(this.addPending(pending),this.startPolling());return}if(this.autoclose||this.showProcessingMessage(),this.pollEnable||this.autoclose){this.addPending(pending),this.showSyncingStatus(),this.setTriggerDisabled(!0),this.startPolling();return}clearTimeout(this._onceTimer),this._onceTimer=setTimeout(()=>{this.fetchCharges().then(()=>this.onPendingDone())},5e3)}optimisticKey(){return"spdp_optimistic_"+(this.customerId||"anon")}loadOptimistic(){let arr=null;try{const raw=window.localStorage.getItem(this.optimisticKey());arr=raw?JSON.parse(raw):null}catch{arr=null}Array.isArray(arr)||(arr=this._optMem||[]);const now=Date.now(),live=arr.filter(e=>now-(e.ts||0)<OPTIMISTIC_MAX_MS);return this._optMem=live,live}saveOptimistic(arr){this._optMem=(arr||[]).slice();try{arr&&arr.length?window.localStorage.setItem(this.optimisticKey(),JSON.stringify(arr)):window.localStorage.removeItem(this.optimisticKey())}catch{}}recordOptimistic(submitted,pending){const variant=submitted.variant,charge=submitted.charge;if(!variant||!charge)return;const interval=submitted.isSubscription?submitted.group&&submitted.group.interval||this.resolveInterval(charge):null,unit=this.quotedUnitPrice(variant,pending.quantity,submitted.isSubscription),arr=this.loadOptimistic();arr.push({chargeId:pending.chargeId,addressId:charge.address_id,scheduledAt:charge.scheduled_at,variantId:String(variant.id),baseline:pending.baseline,ts:Date.now(),item:{spdpOptimistic:!0,title:this.dataset.productTitle||"",variant_title:variant.title||"",image:variant.image||null,quantity:pending.quantity,shopify_product_id:this.productId,shopify_variant_id:variant.id,type:submitted.isSubscription?"subscription":"onetime",order_interval_frequency:interval?interval.frequency:null,order_interval_unit:interval?interval.unit:null,unit_price:unit,total_price:unit!=null?unit*pending.quantity:null}}),this.saveOptimistic(arr),this.applyOptimistic()}applyOptimistic(){(this.charges||[]).forEach(c=>{Array.isArray(c.line_items)&&(c.line_items=c.line_items.filter(li=>!li.spdpOptimistic))});const entries=this.loadOptimistic();if(!entries.length)return;const stays=[];entries.forEach(e=>{const target=this.findCharge(e);if(!target){stays.push(e);return}const claimed=(e.baseline||0)+(e.item&&e.item.quantity||1);this.variantTotalQty([target],e.variantId)>=claimed||(Array.isArray(target.line_items)||(target.line_items=[]),target.line_items.push(e.item),stays.push(e))}),this.saveOptimistic(stays)}findCharge(entry,charges){const list=charges||this.charges||[];if(entry.chargeId){const byId=list.find(c=>String(this.chargeIdOf(c))===String(entry.chargeId));if(byId)return byId}return list.find(c=>String(c.address_id)===String(entry.addressId)&&String(c.scheduled_at)===String(entry.scheduledAt))||null}showSuccessMessage(){this.message.hidden=!1,this.message.className="subscription-pdp__message subscription-pdp__message_success",this.message.innerHTML='<span class="subscription-pdp__message-text"><strong>'+this.escape(this.text.success)+"</strong></span>"}showProcessingMessage(){this.message.hidden=!1,this.message.className="subscription-pdp__message subscription-pdp__message_processing",this.message.innerHTML='<span class="subscription-pdp__spinner" aria-hidden="true"></span><span class="subscription-pdp__message-text"><strong>'+this.escape(this.text.success)+'</strong><span class="subscription-pdp__message-note">'+this.escape(this.text.processing)+"</span></span>"}pendingKey(){return"spdp_pending_"+(this.customerId||"anon")}loadPending(){let arr=null;try{const raw=window.localStorage.getItem(this.pendingKey());arr=raw?JSON.parse(raw):null}catch{arr=null}Array.isArray(arr)||(arr=this._mem||[]);const now=Date.now(),pruned=arr.filter(e=>now-(e.ts||0)<864e5);return this._mem=pruned,pruned}savePending(arr){this._mem=(arr||[]).slice();try{arr&&arr.length?window.localStorage.setItem(this.pendingKey(),JSON.stringify(arr)):window.localStorage.removeItem(this.pendingKey())}catch{}}addPending(entry){const arr=this.loadPending();arr.push(entry),this.savePending(arr)}reservedQty(target){return(this.instantSuccess?this.loadOptimistic():this.loadPending()).filter(e=>String(e.variantId)===String(target.variantId)&&this.sameTarget(e,target)).reduce((sum,e)=>sum+((e.item?e.item.quantity:e.quantity)||1),0)}sameTarget(a,b){return a.chargeId&&b.chargeId?String(a.chargeId)===String(b.chargeId):String(a.addressId)===String(b.addressId)&&String(a.scheduledAt)===String(b.scheduledAt)}pendingQty(charges,entry){if(!entry.chargeId&&!entry.scheduledAt)return this.variantTotalQty(charges,entry.variantId);const charge=this.findCharge(entry,charges);return this.variantTotalQty(charge?[charge]:charges,entry.variantId)}variantTotalQty(charges,variantId){let total=0;
56return(charges||[]).forEach(c=>(c.line_items||[]).forEach(li=>{li.spdpOptimistic||String(li.shopify_variant_id)===String(variantId)&&(total+=li.quantity||0)})),total}refreshPendingState(charges){const mine=this.loadPending().filter(e=>String(e.productId)===String(this.productId));if(!mine.length){this.stopPolling(),this._syncing&&this.onPendingDone();return}const now=Date.now(),resolved=[],stillPending=[];if(mine.forEach(e=>{const appeared=this.pendingQty(charges,e)>=(e.baseline||0)+(e.quantity||1),expired=now-(e.ts||0)>PENDING_MAX_MS;(appeared||expired?resolved:stillPending).push(e)}),resolved.length){const stays=this.loadPending().filter(e=>!resolved.some(r=>r.ts===e.ts&&String(r.variantId)===String(e.variantId)));this.savePending(stays)}stillPending.length?(this.instantSuccess||(this.showSyncingStatus(),this.setTriggerDisabled(!0)),this.startPolling()):(this.stopPolling(),this.onPendingDone())}startPolling(){this._pollTimer||(this._pollTimer=setInterval(()=>{this.fetchCharges(this.pendingChargeId()).then(charges=>this.refreshPendingState(charges))},this.instantSuccess?POLL_BACKGROUND_MS:POLL_MS))}pendingChargeId(){const mine=this.loadPending().filter(e=>String(e.productId)===String(this.productId)&&e.chargeId);return mine.length===1?mine[0].chargeId:null}stopPolling(){clearInterval(this._pollTimer),this._pollTimer=null}resumePending(){!this.pollEnable&&!this.autoclose||this.refreshPendingState(this.charges)}onPendingDone(){const wasAdded=this.added;this._syncing=!1,this.added=!1,this.setTriggerDisabled(!1),this.setFormDisabled(!1),this.isOpen()&&wasAdded&&(this.renderCharges(),this.clearChargeSelection(),this.confirmBtn.disabled=!0,this.showSuccessMessage()),!this.instantSuccess&&(this.showDoneStatus(),clearTimeout(this._statusHideTimer),this._statusHideTimer=setTimeout(()=>this.hideStatus(),6e3))}clearChargeSelection(){this.selectedGroupIndex=null,this.chargesBox&&this.chargesBox.querySelectorAll(".subscription-pdp__charge-radio").forEach(r=>{r.checked=!1})}showSyncingStatus(){this._syncing=!0,this.statusBox&&(this.statusBox.hidden=!1,this.statusBox.className="subscription-pdp__status subscription-pdp__status_syncing",this.statusBox.innerHTML='<span class="subscription-pdp__spinner" aria-hidden="true"></span><span>'+this.escape(this.text.processing)+"</span>")}showDoneStatus(){this.statusBox&&(this.statusBox.hidden=!1,this.statusBox.className="subscription-pdp__status subscription-pdp__status_done",this.statusBox.innerHTML="<span>"+this.escape(this.text.success)+"</span>")}hideStatus(){this._syncing=!1,this.statusBox&&(this.statusBox.hidden=!0,this.statusBox.innerHTML="")}setTriggerDisabled(state){this.trigger&&(this.trigger.disabled=state,this.trigger.classList.toggle("subscription-pdp__trigger_disabled",state))}setFormDisabled(state){this._formLocked=state,this.toggleInput.disabled=state||this._typeMode!=null&&this._typeMode!=="toggle",this.qtyInput.disabled=state,this.popup.querySelectorAll("[data-spdp-qty]").forEach(b=>b.disabled=state),this.chargesBox.querySelectorAll(".subscription-pdp__charge-radio").forEach(r=>r.disabled=state),this.popup.classList.toggle("is-locked",state)}resolveInterval(charge){const items=charge.line_items||[],source=items.find(li=>li.type==="subscription"&&li.order_interval_frequency)||items.find(li=>li.order_interval_frequency);return source?{frequency:source.order_interval_frequency,unit:source.order_interval_unit}:null}setLoading(state){this.confirmBtn.classList.toggle("loading",state),this.confirmBtn.disabled=state||this.added||this.selectedGroupIndex==null}showMessage(text,isError){this.message.textContent=text,this.message.classList.toggle("subscription-pdp__message_error",isError),this.message.classList.toggle("subscription-pdp__message_success",!isError),this.message.hidden=!1}resetMessage(){this.message.hidden=!0,this.message.textContent=""}formatDate(value){if(!value)return"";const date=new Date(value);return isNaN(date.getTime())?this.escape(value):date.toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"})}escape(str){return String(str??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}}customElements.define("subscription-pdp",SubscriptionPdp)})();
57//# sourceMappingURL=/cdn/shop/t/126/assets/subscription-pdp.js.map?v=4514230737529617499
571787047160

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.