PageSourceSearch

https://www.lyleandscott.com/cdn/shop/t/458/assets/lyle-main-product.js?v=80058892663077569011788364386

js lyleandscott.com collected 2026-09-24 23:00:15 UTC 19,783 bytes, 2 lines download raw bytes

1import{hiddenSaleLineItemProperties,metafieldValue,parseJson}from"@lyle/algolia-product-utils";import{bindProductColourNav}from"@lyle/product-colour-nav";import{getLocalisedRoute}from"@lyle/weglot";class LyleMainProduct extends HTMLElement{#variants=[];#tags=[];#inventory={};#changeHandler=null;#sizeBtnHandler=null;#siblingHandler=null;#submitHandler=null;#buyNowHandler=null;#atcResetTimer=null;#formatter=null;#llCustomerTierId=null;connectedCallback(){bindProductColourNav();const script=this.querySelector("[data-product-variants-json]");if(script)try{this.#variants=JSON.parse(script.textContent)}catch{this.#variants=[]}const invScript=this.querySelector("[data-product-inventory-json]");if(invScript)try{this.#inventory=JSON.parse(invScript.textContent)}catch{this.#inventory={}}const tagsScript=this.querySelector("[data-product-tags-json]");this.#tags=parseJson(tagsScript?.textContent)||[],this.#initLoyaltyBanner(),this.#variants.length>0&&(this.#changeHandler=e=>{e.target.matches("[data-option-position]")&&this.#onOptionChange()},this.addEventListener("change",this.#changeHandler),this.#sizeBtnHandler=e=>{const btn=e.target.closest("[data-size-btn]");if(!btn||btn.disabled)return;const optionPosition=btn.dataset.optionPosition,value=btn.dataset.optionValue;if(optionPosition==null||value==null)return;const select=this.querySelector(`[data-option-position="${optionPosition}"].main-product__option-select--hidden`);select&&(select.value=value,select.dispatchEvent(new Event("change",{bubbles:!0})));const group=btn.closest("[data-size-buttons]");group&&group.querySelectorAll("[data-size-btn]").forEach(b=>{const active=b.dataset.optionValue===value;b.setAttribute("aria-pressed",String(active)),b.toggleAttribute("data-selected",active)})},this.addEventListener("click",this.#sizeBtnHandler));const form=this.querySelector("#main-product-form");form&&(this.#submitHandler=e=>{e.preventDefault(),this.#handleAddToCart().catch(()=>{})},form.addEventListener("submit",this.#submitHandler));const buyNowBtn=this.querySelector("[data-buy-now]");if(buyNowBtn&&(this.#buyNowHandler=()=>this.#handleBuyNow().catch(()=>{}),buyNowBtn.addEventListener("click",this.#buyNowHandler)),this.#siblingHandler=e=>
1this.#renderSiblingGroups(e.detail),document.addEventListener("colour-swatches:siblings",this.#siblingHandler),this.#variants.length>0){const initialVariant=this.#getSelectedVariant(),hasSizeOption=!!this.querySelector("[data-size-buttons]"),hasVariantParam=new URLSearchParams(window.location.search).has("variant");!hasSizeOption||hasVariantParam?(this.#updateSizeBtnActiveState(initialVariant),this.#updateButton(initialVariant),this.#updateBuyNowVisibility(initialVariant),this.#updateUrl(initialVariant)):this.#updateBuyNowVisibility(null),this.#updateStockIndicator(!hasSizeOption||hasVariantParam?initialVariant:null),this.#broadcastVariant(!hasSizeOption||hasVariantParam?initialVariant:null)}}disconnectedCallback(){this.#changeHandler&&(this.removeEventListener("change",this.#changeHandler),this.#changeHandler=null),this.#sizeBtnHandler&&(this.removeEventListener("click",this.#sizeBtnHandler),this.#sizeBtnHandler=null);const form=this.querySelector("#main-product-form");form&&this.#submitHandler&&form.removeEventListener("submit",this.#submitHandler),this.#submitHandler=null,this.#atcResetTimer&&(clearTimeout(this.#atcResetTimer),this.#atcResetTimer=null),this.#siblingHandler&&(document.removeEventListener("colour-swatches:siblings",this.#siblingHandler),this.#siblingHandler=null),this.#buyNowHandler&&(this.querySelector("[data-buy-now]")?.removeEventListener("click",this.#buyNowHandler),this.#buyNowHandler=null),this.#variants=[],this.#inventory={},this.#formatter=null}#onOptionChange(){const variant=this.#getSelectedVariant();this.#updateSizeBtnActiveState(variant),this.#updateVariantInput(variant),this.#updateUrl(variant),this.#updatePrice(variant),this.#updateButton(variant),this.#broadcastVariant(variant),this.#updateStockIndicator(variant)}async#handleAddToCart(){if(this.dataset.comingSoon==="true"){const link=this.dataset.comingSoonLink;link&&(window.location.href=getLocalisedRoute(link));return}const selected=this.#getSelectedVariant();if(!selected?.available)return;const variantId=this.querySelector("[data-variant-id-input]")?.value;if(!variantId)return;const quantity=1,btn=this.querySelector("[data-add-to-cart]"),buyNow=this.querySelector("[data-buy-now]"),errorEl=this.querySelector("[data-product-form-error]"),addingText=this.dataset.addingText??"";if(btn&&(this.#setButtonDisabled(btn,!0),addingText)){const textEl=btn.querySelector(".button__label")??btn.querySelector("[data-atc-text]")??btn;textEl.textContent=addingText}buyNow&&this.#setButtonDisabled(buyNow,!0),errorEl&&(errorEl.hidden=!0),document.dispatchEvent(new CustomEvent("cart:add",{bubbles:!1,detail:{optimistic:this.#optimisticCartItem(selected,quantity)}}));try{const res=await fetch(`${window.Shopify?.routes?.root??"/"}cart/add.js`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:Number(variantId),quantity,properties:this.#lineItemProperties(),sections:"cart-drawer"})});if(!res.ok){const data=await res.json().catch(()=>({}));throw new Error(data.description??this.dataset.errorText??"")}const cart=await res.json(),addedText=this.dataset.addedText??this.dataset.addToCartText??"";if(btn){const textEl=btn.querySelector(".button__label")??btn.querySelector("[data-atc-text]")??btn;textEl.textContent=addedText}document.dispatchEvent(new CustomEvent("cart:add",{bubbles:!1,detail:{sections:cart.sections}})),this.#atcResetTimer&&clearTimeout(this.#atcResetTimer),this.#atcResetTimer=setTimeout(()=>{this.#atcResetTimer=null;const variant=this.#getSelectedVariant();this.#updateButton(variant)},2e3)}catch(err){document.dispatchEvent(new CustomEvent("cart:add",{bubbles:!1,detail:{rollback:!0}}));const variant=this.#getSelectedVariant();this.#updateButton(variant),errorEl&&(errorEl.textContent=err.message,errorEl.hidden=!1)}}#optimisticCartItem(variant,quantity){const title=this.querySelector(".main-product__title")?.textContent?.trim()||document.querySelector(".breadcrumbs__label-text")?.textContent?.trim()||document.title,galleryImage=document.querySelector(`[data-media-id="${CSS.escape(String(variant.featured_image?.id??""))}"] img`)??document.querySelector("[data-product-gallery-carousel] img"),url=new URL(window.location.href);return url.searchParams.set("variant",String(variant.id)),{imageAlt:variant.featured_image?.alt||galleryImage?.alt||title,imageUrl:variant.featured_image?.src||galleryImage?.currentSrc||galleryImage?.src||"",options:variant.options||[],price:this.#formatMoney(this.#memberDisplayPrice(variant)),quantity,title,url:url.toString()}}async#handleBuyNow(){if(!this.#getSelectedVariant()?.available)return;const variantId=this.querySelector("[data-variant-id-input]")?.value;if(!variantId)return;const btn=this.querySelector("[data-buy-now]"),atcBtn=this.querySelector("[data-add-to-cart]"),errorEl=this.querySelector("[data-product-form-error]");btn&&this.#setButtonDisabled(btn,!0),atcBtn&&this.#setButtonDisabled(atcBtn,!0),errorEl&&(errorEl.hidden=!0);try{const res=await fetch(`${window.Shopify?.routes?.root??"/"}cart/add.js`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:Number(variantId),quantity:1,properties:this.#lineItemProperties()})});if(!res.ok){const data=await res.json().catch(()=>({}));throw new Error(data.description??this.dataset.errorText??"")}window.location.href=`${window.Shopify?.routes?.root??"/"}checkout`}catch(err){const variant=this.#getSelectedVariant();this.#updateButton(variant),errorEl&&(errorEl.textContent=err.message,errorEl.hidden=!1)}}#lineItemProperties(){const form=this.querySelector("#main-product-form"),properties=hiddenSaleLineItemProperties(this.#tags);if(!form)return properties;for(const[name,value]of new FormData(form)){const match=name.match(/^properties\[(.+)]$/);match&&value!==""&&(properties[match[1]]=value)}return properties}#renderSiblingGroups({products,currentHandle}){const container=this.querySelector("[data-size-siblings]");if(!container)return;const currentProduct=products.find(p=>p.handle===currentHandle);if(!currentProduct)return;const sizeFamilyTag=currentProduct.tags?.find(t=>t.startsWith("ProductSizeFamily-"))??"";if(!sizeFamilyTag)return;const currentSwatchCode=metafieldValue(currentProduct,"swatch_code");if(!currentSwatchCode)return;const sizeProducts=products.filter(p=>p.tags?.includes(sizeFamilyTag)&&metafieldValue(p,"swatch_code")===currentSwatchCode);if(!sizeProducts.length)return;const seen=new Set,toggleItems=[];for(const p of sizeProducts){const sizeTag=p.tags?.find(t=>t.startsWith("ProductSize-")&&!t.startsWith("ProductSizeFamily-"))??"",label=sizeTag?sizeTag.split("-")[1]:"";!label||seen.has(label)||(seen.add(label),toggleItems.push({label,url:p.url,isActive:p.handle===currentHandle}))}if(toggleItems.length<=1)return;toggleItems.sort((a,b)=>b.label.localeCompare(a.label));let html='<div class="main-product__size-toggle">';
1for(const{label,url,isActive}of toggleItems)if(isActive)html+=`<button class="main-product__size-toggle-btn is-active text-body-sm" aria-pressed="true" aria-current="page" disabled>${LyleMainProduct.#esc(label)}</button>`;else{const safeHref=/^https?:\/\/|^\//i.test(url)?LyleMainProduct.#esc(url):"#";html+=`<a class="main-product__size-toggle-btn text-body-sm" href="${safeHref}" data-product-colour-nav>${LyleMainProduct.#esc(label)}</a>`}html+="</div>",container.hidden=!1,container.innerHTML=html}#updateSizeBtnActiveState(variant){variant&&this.querySelectorAll("[data-size-buttons]").forEach(group=>{const position=parseInt(group.dataset.optionPosition??"0",10),selectedValue=variant.options?.[position]??variant[`option${position+1}`]??"";group.querySelectorAll("[data-size-btn]").forEach(btn=>{const active=btn.dataset.optionValue===selectedValue;btn.setAttribute("aria-pressed",String(active)),btn.toggleAttribute("data-selected",active)});const labelEl=group.closest(".main-product__option-group")?.querySelector("[data-size-label]");if(labelEl&&selectedValue){const optionName=labelEl.dataset.sizeOptionName??"";labelEl.textContent=`${optionName}: ${selectedValue}`}})}#updateStockIndicator(variant){const el=this.querySelector("[data-stock-indicator]");if(!el)return;const threshold=parseInt(this.dataset.lowStockThreshold??"10",10),invData=variant?this.#inventory[variant.id]??null:null,inv=invData?.quantity??variant?.inventory_quantity??0,managed=(invData?.management??variant?.inventory_management)==="shopify",policy=invData?.policy??variant?.inventory_policy??"",available=variant?.available??!1,showSoldOut=variant&&!available,showWarning=managed&&policy!=="continue"&&available&&inv>0&&inv<=threshold;if(el.hidden=!showWarning&&!showSoldOut,el.classList.toggle("stock-indicator--low",showWarning),el.classList.toggle("stock-indicator--out",showSoldOut),showWarning){const template=this.dataset.lowStockText??"";el.textContent=template.replace("__COUNT__",String(inv))}else showSoldOut?el.textContent=this.dataset.soldOutText??"":el.textContent=""}#broadcastVariant(variant){document.dispatchEvent(new CustomEvent("product-gallery:variant",{detail:{mediaId:variant?.featured_image?.id??null}}));const hasSizeOption=!!this.querySelector("[data-size-buttons]"),sizeSelected=!!this.querySelector("[data-size-btn][data-selected]"),hasVariantParam=new URLSearchParams(window.location.search).has("variant"),optionValues=[];if(!hasSizeOption||sizeSelected||hasVariantParam){if(variant)for(let i=1;i<=3;i+=1){const value=variant[`option${i}`];value&&optionValues.push(value)}const selectedBtn=this.querySelector("[data-size-btn][data-selected]");if(selectedBtn?.dataset.optionValue){const sizeValue=selectedBtn.dataset.optionValue;optionValues.includes(sizeValue)||optionValues.unshift(sizeValue)}}document.dispatchEvent(new CustomEvent("product:variant-change",{bubbles:!1,detail:{variant,optionValues}}))}#getSelectedVariant(){if(this.#variants.length===0)return null;const selects=this.querySelectorAll("select[data-option-position]");if(!selects.length)return this.#variants[0]??null;const opts=Array.from(selects).map(s=>s.value);return this.#variants.find(v=>opts.every((opt,i)=>v[`option${i+1}`]===opt))??null}#updateVariantInput(variant){const input=this.querySelector("[data-variant-id-input]");input&&(input.value=variant?.id??"")}#updateUrl(variant){const url=new URL(window.location.href);variant?.id?url.searchParams.set("variant",String(variant.id)):url.searchParams.delete("variant"),history.replaceState(history.state||{},"",url.toString())}#updateBuyNowVisibility(variant){const buyNow=this.querySelector("[data-buy-now]");if(!buyNow)return;if(this.dataset.comingSoon==="true"){buyNow.hidden=!0,this.#setButtonDisabled(buyNow,!0);return}const hasSizeOption=!!this.querySelector("[data-size-buttons]"),sizeSelected=!!this.querySelector("[data-size-btn][data-selected]"),show=(!hasSizeOption||sizeSelected)&&!!variant?.available;buyNow.hidden=!show,this.#setButtonDisabled(buyNow,!show)}#isSizeSelected(){return!this.querySelector("[data-size-buttons]")?!0:!!this.querySelector("[data-size-btn][data-selected]")}#updatePrice(variant){if(!variant)return;const html=this.#buildPriceHtml(variant),main=this.querySelector("[data-main-product-prices]");main&&(main.innerHTML=html);const memberBadge=this.querySelector("[data-member-price-badge]");memberBadge&&(memberBadge.hidden=!this.#hasMemberPrice(variant));const klarnaAmount=this.querySelector("[data-klarna-amount]");
1if(klarnaAmount&&variant?.price!=null){const display=this.#memberDisplayPrice(variant);klarnaAmount.textContent=this.#formatMoney(Math.round(display/3))}this.#updateLionPrice(variant),this.#updateLoyaltyBanner(variant)}#memberDiscount(){return Number(this.dataset.memberDiscount||0)}#isCustomer(){return this.dataset.isCustomer==="true"}#hasMemberPrice(variant){const discount=this.#memberDiscount();return this.#isCustomer()&&discount>0&&variant?.price!=null}#memberDisplayPrice(variant){const price=variant?.price;return this.#hasMemberPrice(variant)?Math.round(price-price*this.#memberDiscount()):price}#buildPriceHtml(variant){if(!variant)return"";const available=variant.available;let price=variant.price,compareAt=variant.compare_at_price;const hasMemberPrice=this.#hasMemberPrice(variant);hasMemberPrice&&(compareAt=compareAt&&compareAt>price?compareAt:price,price=this.#memberDisplayPrice(variant));const onSale=compareAt&&price<compareAt;let compareHtml="";onSale&&(compareHtml=`<span class="product-prices__compare-at-price main-product__compare-at-price">${this.#formatMoney(compareAt)}</span>`);const priceClass=onSale&&!hasMemberPrice?"product-prices__price product-prices__price--on-sale main-product__price main-product__price--on-sale":"product-prices__price main-product__price";let priceHtml;return price<=0?priceHtml=`<span class="${priceClass}">${LyleMainProduct.#esc(window.Shopify?.i18n?.translations?.products?.prices?.free??"Free")}</span>`:priceHtml=`<span class="${priceClass}">${this.#formatMoney(price)}</span>`,`<p class="product-prices main-product__prices text-body-lg${hasMemberPrice?" product-prices--member":""}">${compareHtml}${priceHtml}</p>`}#updateLionPrice(variant){const el=this.querySelector("[data-lion-price]");!el||variant?.price==null||(el.textContent=this.#formatMoney(this.#memberDisplayPrice(variant)))}#initLoyaltyBanner(){if(!this.querySelector("[data-loyalty-pdp-banner]"))return;const variant=this.#getSelectedVariant()??this.#variants[0];if(this.#updateLoyaltyBanner(variant),!!this.#isCustomer()){if(window._llCustomerDataReady){this.#applyCustomerLoyaltyData();return}window._llCustomerDataCallbacks=window._llCustomerDataCallbacks||[],window._llCustomerDataCallbacks.push(()=>this.#applyCustomerLoyaltyData())}}#applyCustomerLoyaltyData(){this.#llCustomerTierId=window._llCustomerTierId??null;const variant=this.#getSelectedVariant()??this.#variants[0];this.#updateLoyaltyBanner(variant)}#loyaltyTierRate(){const tierId=this.#llCustomerTierId??window._llCustomerTierId,mapped=tierId&&window._llTierPointsMap?.[String(tierId)];return mapped!=null?Number(mapped):Number(this.dataset.loyaltyTier1Points||3)}#updateLoyaltyBanner(variant){const banner=this.querySelector("[data-loyalty-pdp-banner]");if(!banner)return;const price=variant?.price??0,rate=this.#loyaltyTierRate(),earnPoints=price?Math.round(price/100*rate):0,earnEl=banner.querySelector("[data-loyalty-earn]");earnEl&&(earnEl.textContent=String(earnPoints));const pointValueEl=banner.querySelector("[data-ll-point-value]");if(pointValueEl){const currency=window.Shopify?.currency?.active||window._llBaseCurrency||"GBP",lang=document.documentElement.lang||"en",ratio=parseFloat(window.Shopify?.currency?.rate)||1,formatted=new Intl.NumberFormat(lang,{style:"currency",currency,minimumFractionDigits:2,maximumFractionDigits:2}).format(ratio),pointsLabel=this.dataset.loyaltyPointsLabel||"points";pointValueEl.textContent=`${rate} ${pointsLabel} = ${formatted}`}if(!this.#isCustomer())return;const tierId=this.#llCustomerTierId??window._llCustomerTierId,tierName=tierId&&window._llTierMap?.[String(tierId)]||"",balanceEl=banner.querySelector("[data-loyalty-balance]");balanceEl&&window._llCustomerPoints!==void 0&&(balanceEl.textContent=new Intl.NumberFormat(document.documentElement.lang||"en").format(window._llCustomerPoints));const color=tierId&&window._llTierColorMap?.[String(tierId)]||tierName&&window._llTierNameColorMap?.[tierName]||"";color&&(banner.style.backgroundColor=color),tierName&&window._llCustomerPoints!==void 0&&banner.querySelector("[data-loyalty-balance-line]")?.removeAttribute("hidden")}#updateButton(variant){this.#setButtonFromVariant(this.querySelector("[data-add-to-cart]"),variant),this.#updateBuyNowVisibility(variant)}#setButtonFromVariant(btn,variant){if(!btn)return;const textEl=btn.querySelector(".button__label")??btn.querySelector("[data-atc-text]")??btn;if(this.dataset.comingSoon==="true"){const link=this.dataset.comingSoonLink||"";this.#setButtonDisabled(btn,!link),textEl.textContent=this.dataset.comingSoonText??"";return}const hasSizeOption=!!this.querySelector("[data-size-buttons]"),sizeSelected=this.#isSizeSelected();if(hasSizeOption&&!sizeSelected){this.#setButtonDisabled(btn,!0),this.#setButtonUnavailableSize(btn,!1),textEl.textContent=this.dataset.selectSizeText??"";return}if(!variant){this.#setButtonDisabled(btn,!0),this.#setButtonUnavailableSize(btn,!1),textEl.textContent=this.dataset.selectSizeText??"";return}if(!variant.available){this.#setButtonDisabled(btn,!0),this.#setButtonUnavailableSize(btn,!0),textEl.textContent=this.dataset.unavailableText??"";return}this.#setButtonDisabled(btn,!1),this.#setButtonUnavailableSize(btn,!1),textEl.textContent=this.dataset.addToCartText??""}#setButtonDisabled(btn,disabled){btn&&(btn.disabled=disabled,btn.classList.toggle("is-disabled",disabled))}#setButtonUnavailableSize(btn,active){if(!btn)return;btn.classList.toggle("is-unavailable-size",active),btn.classList.toggle("button--no-icon",active);const icon=btn.querySelector(".button__icon");icon&&(icon.hidden=active),btn.toggleAttribute("aria-disabled",active)}
1#formatMoney(cents){if(!this.#formatter){const currency=window.Shopify?.currency?.active??"GBP";this.#formatter=new Intl.NumberFormat(window.Shopify?.locale??"en-GB",{style:"currency",currency,minimumFractionDigits:2})}return this.#formatter.format(cents/100)}static#esc(s){return String(s??"").replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}}customElements.get("lyle-main-product")||customElements.define("lyle-main-product",LyleMainProduct);
2//# sourceMappingURL=/cdn/shop/t/458/assets/lyle-main-product.js.map?v=80058892663077569011788364386

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.