1function initArticleContent(container=document){const articleContent=container.querySelector(".article-container .article-body .article-content");moveArticleBannerMobile(),articleContent&&(replaceTableBadge(articleContent),replaceRatingsCard(articleContent),replaceProductCard(articleContent),productSetIframeStyleInject(articleContent))}function moveArticleBannerMobile(){const articleBannerMobile=document.querySelector(".article-banner-mobile"),breadcrumbs=document.querySelector(".snippet-breadcrumbs");!articleBannerMobile||!breadcrumbs||breadcrumbs.parentNode.insertBefore(articleBannerMobile,breadcrumbs)}document.addEventListener("DOMContentLoaded",()=>{initArticleContent(document)}),document.addEventListener("shopify:section:load",event=>{initArticleContent(event.target)});function replaceProductCard(articleContent){let articleCardContent=document.getElementById("article-card_content")?.value||"";const shortcodeRegex=/\[product\s+handle="(.*?)"(?:\s+rating="(.*?)")?(?:\s+slogan="(.*?)")?\]/g,loadingHtml=articleContent.innerHTML.replace(shortcodeRegex,(match,handle,rating,slogan)=>`<div class="product-card-placeholder" 2 data-product-handle="${handle}" 3 data-product-rating="${rating||"5"}" 4 data-product-slogan="${slogan||""}">loading...</div>`);articleContent.innerHTML=loadingHtml,articleContent.querySelectorAll(".product-card-placeholder").forEach(placeholder=>{const handle=placeholder.getAttribute("data-product-handle"),shortcodeRating=placeholder.getAttribute("data-product-rating"),slogan=placeholder.getAttribute("data-product-slogan");fetchProductData(handle,shortcodeRating,placeholder,slogan)});function fetchProductData(handle,shortcodeRating,placeholder,slogan){fetch(`/products/${handle}.js`).then(response=>{if(!response.ok)throw new Error("The product does not exist.");return response.json()}).then(async product=>{const badgeHtml=await getJudgeBadge(handle);placeholder.innerHTML=renderProductCard(product,shortcodeRating,slogan,badgeHtml),bindAddToCartEvents(placeholder,product)}).catch(error=>{const errorMsg=`Product loading failed: ${error.message}`;placeholder.innerHTML=`<div class="product-card-error">${errorMsg}</div>`})}function renderProductCard(product,shortcodeRating,slogan,badgeHtml){const variant=product.variants?.[0]||product,imageUrl=product.featured_image||"",starObj={rating:shortcodeRating?parseFloat(shortcodeRating):5},starsHtml=generateStarsHtml(starObj.rating),formatMoney=(amount,format)=>{if(!amount)return"$0.00";const price2=(amount/100).toFixed(2);return format?format.replace("{{amount}}",price2):`$${price2}`},price=window.theme?.Currency?.formatMoney?window.theme.Currency.formatMoney(variant.price,window.theme.strings?.moneyFormat||"${{amount}}"):formatMoney(variant.price);let comparePrice="";variant.compare_at_price&&variant.price<variant.compare_at_price&&(comparePrice=window.theme?.Currency?.formatMoney?window.theme.Currency.formatMoney(variant.compare_at_price,window.theme.strings?.moneyFormat||"${{amount}}"):formatMoney(variant.compare_at_price));const sloganHtml=slogan?`<div class="product-slogan">${slogan}</div>`:"",descriptionUl=new DOMParser().parseFromString(product.description,"text/html").querySelector("ul");descriptionUl&&descriptionUl.querySelectorAll("li").forEach((li,index)=>{index>=3&&li.remove()});const descriptionHtml=descriptionUl?.outerHTML||"";return` 5 <div class="blog-product-container ${articleContent?"has_ul":""}"> 6 <div class="blog-product-card"> 7 <div class="product-info-image"> 8 <a href="/products/${product.handle}" target="_blank" > 9 <img src="${imageUrl}" alt="${product.title}" style="width: 100%; height: auto;" loading="lazy"/> 10 </a> 11 </div> 12 <div class="product-info-content"> 13 ${sloganHtml} 14 <a href="/products/${product.handle}" target="_blank" class="title-h3"> 15 <h3>${product.title}</h3> 16 </a> 17 <div class="product-info-stars"> 18 <div class="jdgm-widget jdgm-preview-badge"> 19 ${badgeHtml} 20 </div> 21 </div> 22 <div class="product-info-description"> 23 ${descriptionHtml} 24 </div> 25 <p class="product-price">
26 <span class="on-sale-price">${price}</span> 27 ${comparePrice?`<span class="compare-at-price">${comparePrice}</span>`:""} 28 </p> 29 <div class="product-actions"> 30 <button class="buy-now" data-variant-id="${variant.id}" style="display: none;">Shop Now</button> 31 <button class="add-to-cart" data-variant-id="${variant.id}" style="display: none;">Add To Cart</button> 32 <a href="/products/${product.handle}" target="_blank" class="buy-now">View Product</a> 33 </div> 34 </div> 35 </div> 36 <div class="blog-product-promotion-banner">${articleCardContent}</div> 37 </div> 38 `}function generateStarsHtml(rating){let starsHtml="<div class='card-star'>",current=Math.min(Math.max(Number(rating)||0,0),5),starIndex=0;const clipIdPrefix=`article-star-clip-${Date.now()}-${Math.random().toString(36).slice(2)}`,renderStarSvg=fillRatio=>{const safeFillRatio=Math.min(Math.max(fillRatio,0),1),starPath="M9 12.9525L13.635 15.75L12.405 10.4775L16.5 6.93L11.1075 6.4725L9 1.5L6.8925 6.4725L1.5 6.93L5.595 10.4775L4.365 15.75L9 12.9525Z";if(safeFillRatio>=1)return`<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" fill="none" aria-hidden="true"><path d="${starPath}" fill="#F5A623"/></svg>`;starIndex+=1;const clipId=`${clipIdPrefix}-${starIndex}`,clipWidth=(18*safeFillRatio).toFixed(2);return`<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" fill="none" aria-hidden="true"><defs><clipPath id="${clipId}"><rect x="0" y="0" width="${clipWidth}" height="18"/></clipPath></defs><path d="${starPath}" fill="#F5A623" clip-path="url(#${clipId})"/></svg>`};for(;current>0;)current>=1?starsHtml+=`<div class='star'>${renderStarSvg(1)}</div>`:starsHtml+=`<div class='star'>${renderStarSvg(current)}</div>`,current--;return starsHtml+="</div>",starsHtml}function bindAddToCartEvents(card,product){card.querySelector(".add-to-cart").addEventListener("click",function(e){const variantId=this.getAttribute("data-variant-id");addToCart(variantId,1,()=>{alert("Added To Cart\uFF01")})}),card.querySelector(".buy-now").addEventListener("click",function(e){const variantId=this.getAttribute("data-variant-id");addToCart(variantId,1,()=>{window.location.href="/checkout"})})}function addToCart(variantId,quantity,callback){fetch("/cart/add.js",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:variantId,quantity})}).then(response=>{if(response.ok)return callback();throw new Error("Add purchase failed")}).catch(error=>{alert("error adding to cart"),console.error(error)})}}function replaceRatingsCard(articleContent){const shortcodeRegex=/\[ratings\b(?:\s+"[^"]+"\s*=\s*"[^"]*")+\s*\]/g,attributeRegex=/"([^"]+)"\s*=\s*"([^"]*)"/g,newContentHtml=articleContent.innerHTML.replace(shortcodeRegex,code=>{const attributes=[...code.matchAll(attributeRegex)].map(([,key,value])=>({key:key.trim(),value:value.trim()})),cardTitle=attributes.find(({key})=>key.toLowerCase()==="ratingscardtitle")?.value||"",ratings=attributes.filter(({key})=>key.toLowerCase()!=="ratingscardtitle").filter(({value})=>isNumericRating(value)).map(({key,value})=>({key,rawValue:value,numberValue:Number(value)})).filter(({numberValue})=>Number.isFinite(numberValue));if(!cardTitle&&ratings.length===0)return"";const ratingRowsHtml=ratings.map(({key,rawValue,numberValue})=>{const percentage=Math.min(Math.max(numberValue,0),10)*10;return` 39 <div class="ratings-card-row"> 40 <div class="ratings-card-label">${escapeHtml(key)}</div> 41 <div class="ratings-card-track"> 42 <div class="ratings-card-progress" style="width: ${percentage}%;"></div> 43 </div> 44 <div class="ratings-card-value">${escapeHtml(rawValue)}</div> 45 </div> 46 `}).join("");return` 47 <div class="ratings-card"> 48 <div class="ratings-card-title">${escapeHtml(cardTitle)}</div> 49 <div class="ratings-card-list"> 50 ${ratingRowsHtml} 51 </div> 52 </div> 53 `});articleContent.innerHTML=newContentHtml}function replaceTableBadge(articleContent){const shortcodeRegex=/\[badge\b[\s\S]*?\]/g,attributeRegex=/(?:"([^"]+)"|([^\s="]+))\s*=\s*"([^"]*)"/g,newContentHtml=articleContent.innerHTML.replace(shortcodeRegex,code=>{const badgeText=[...code.replace(/[ââ]/g,'"').matchAll(attributeRegex)].map(([,quotedKey,unquotedKey,value])=>({key:(quotedKey||unquotedKey).trim(),value:value.trim()})).find(({key})=>key.toLowerCase()==="text")?.value||"";return badgeText?`
54 <span class="table-badge"> 55 <span class="table-badge-text">${escapeHtml(badgeText)}</span> 56 </span> 57 `:""});articleContent.innerHTML=newContentHtml}function escapeHtml(value){const escapeMap={"&":"&","<":"<",">":">",'"':""","'":"'"};return String(value).replace(/[&<>"']/g,char=>escapeMap[char])}function isNumericRating(value){return/^-?(?:\d+|\d*\.\d+)$/.test(String(value).trim())}async function getJudgeBadge(handle){try{const response=await fetch(`/products/${handle}`);if(!response.ok)return"";const html=await response.text(),badge=new DOMParser().parseFromString(html,"text/html").querySelector(".jdgm-preview-badge");return badge?badge.innerHTML:""}catch(e){return console.error("Load Judge.me badge failed",e),""}}class ArticleNav extends HTMLElement{connectedCallback(){this.isConnected&&this.render()}render(){const navList=this.querySelector(".article-nav-lists"),articleContent=this.closest(".article-body")?.querySelector(".article-content")||document.querySelector(".article-content"),visibleHeadings=(articleContent?Array.from(articleContent.querySelectorAll("h2[data-blog-title], h3[data-blog-title]")):[]).filter(heading=>heading.textContent.trim());if(!navList||!articleContent||visibleHeadings.length===0){this.hidden=!0;return}this.hidden=!1,navList.replaceChildren();const headingSet=new Set(visibleHeadings),usedIds=new Set(Array.from(document.querySelectorAll("[id]")).filter(element=>!headingSet.has(element)).map(element=>element.id)),navTree=this.createNavTree(visibleHeadings.map((heading,index)=>{const level=Number(heading.tagName.slice(1));return{id:this.ensureHeadingId(heading,index,usedIds),level,text:heading.textContent.trim(),children:[]}}));this.appendNavItems(navTree,navList)}ensureHeadingId(heading,index,usedIds){if(heading.id&&!usedIds.has(heading.id))return usedIds.add(heading.id),heading.id;const baseId=this.slugify(heading.id||heading.textContent)||`article-heading-${index+1}`;let id=baseId,duplicateIndex=2;for(;usedIds.has(id);)id=`${baseId}-${duplicateIndex}`,duplicateIndex+=1;return heading.id=id,usedIds.add(id),id}slugify(text){return text.trim().toLowerCase().normalize("NFKD").replace(/[\u0300-\u036f]/g,"").replace(/&/g," and ").replace(/[^a-z0-9\u4e00-\u9fa5]+/g,"-").replace(/^-+|-+$/g,"")}createNavTree(items){const root={level:1,children:[]},stack=[root];return items.forEach(item=>{for(;stack.length>1&&item.level<=stack[stack.length-1].level;)stack.pop();stack[stack.length-1].children.push(item),stack.push(item)}),root.children}appendNavItems(items,list){items.forEach(item=>{const listItem=document.createElement("li"),link=document.createElement("a");if(listItem.className=`article-nav-item article-nav-item--h${item.level}`,link.className="article-nav-link",link.href=`#${item.id}`,link.textContent=item.text,listItem.appendChild(link),item.children.length>0){const childList=document.createElement("ul");childList.className="article-nav-sublist",this.appendNavItems(item.children,childList),listItem.appendChild(childList)}list.appendChild(listItem)})}}customElements.get("article-nav")||customElements.define("article-nav",ArticleNav);function productSetIframeStyleInject(container=document){const root=container instanceof Element?container:document.body;if(!root)return;const styleId="article-product-set-iframe-style",styleContent=` 58@font-face { 59 font-family: 'MiSans Latin'; 60 src: url('https://cdn.shopify.com/s/files/1/0553/1320/3405/files/MiSansLatinVF.ttf?v=1765343549'); 61 62 font-display: swap; 63} 64 65.shopify-buy__collection-products { 66 margin-left: 0; 67 display: grid; 68 69 grid-template-columns: repeat(4, 1fr); 70 gap: 16px; 71} 72 73.shopify-buy__collection-products div.shopify-buy__product { 74 min-width: unset; 75 max-width: unset; 76 width: 100%; 77 border: 1px solid #E5E2DB; 78 border-radius: 12px; 79 background: #FFF; 80 margin-left: 0; 81 margin-top: 0; 82 display: flex; 83 flex-direction: column; 84} 85 86.shopify-buy__product__variant-img { 87 margin-bottom: 16px; 88} 89 90.shopify-buy__product__title { 91 padding: 0 20px; 92 text-align: start; 93 margin-bottom: 20px; 94 font-family: 'MiSans Latin'; 95 color: #5A5A5A; 96 font-size: 16px; 97 font-style: normal; 98 font-weight: 630; 99 line-height: 175%; 100 flex: 1; 101} 102 103.shopify-buy__product__price { 104 padding: 0 20px; 105 margin-bottom: 20px; 106 text-align: start; 107} 108 109.shopify-buy__product__actual-price { 110 color: #5A5A5A; 111 font-family: "MiSans Latin"; 112 font-size: 16px; 113 font-style: normal; 114 font-weight: 630; 115 line-height: 175%; 116} 117 118.shopify-buy__product__compare-price { 119 color: #606060; 120 font-family: "MiSans Latin"; 121 font-size: 12px; 122 font-style: normal; 123 font-weight: 330; 124 line-height: 175%; 125 text-decoration-line: line-through; 126 opacity: 1; 127} 128 129.shopify-buy__product .shopify-buy__btn-wrapper { 130 padding: 0 20px; 131 margin-bottom: 20px; 132} 133 134.shopify-buy__btn { 135 border-radius: 6px; 136 background: #1A1A1A; 137 background-color: #1A1A1A; 138 padding: 9px; 139 display: flex; 140 justify-content: center; 141 color: #FFF; 142 text-align: center; 143 font-family: "MiSans Latin"; 144 font-size: 16px; 145 font-style: normal; 146 font-weight: 630; 147 line-height: 131.25%; 148 letter-spacing: 0.36px; 149 width: 100%; 150} 151@media (min-width: 597px) and (max-width: 776px) {
152 .shopify-buy__collection-products { 153 grid-template-columns: 1fr 1fr 1fr; 154 } 155} 156@media (min-width: 508px) and (max-width: 596px) { 157 .shopify-buy__collection-products { 158 grid-template-columns: 1fr 1fr; 159 } 160} 161@media (max-width: 507px) { 162 .shopify-buy__collection-products { 163 grid-template-columns: 1fr; 164 gap: 3.1vw; 165 } 166 167 .shopify-buy__product__variant-img { 168 margin-bottom: 2.1vw; 169 } 170 171 .shopify-buy__product__title { 172 font-weight: 700; 173 font-size: clamp(20px, 4.26vw, 32px); 174 line-height: 153%; 175 } 176 177 178 .shopify-buy__product__actual-price { 179 font-weight: 700; 180 font-size: clamp(18px, 3.73vw, 28px); 181 } 182 183 .shopify-buy__product__compare-price { 184 font-weight: 380; 185 font-size: clamp(12px, 3vw, 16px); 186 } 187 188 .shopify-buy__product .shopify-buy__btn-wrapper { 189 margin-bottom: 8vw; 190 padding: 0 2.66vw; 191 } 192 193 .shopify-buy__btn { 194 letter-spacing: 0.48px; 195 font-weight: 700; 196 font-size: clamp(14px, 2.66vw, 20px); 197 line-height: 140%; 198 } 199} 200 `,injectStyle=iframe=>{try{const iframeDocument=iframe.contentDocument||iframe.contentWindow?.document;if(!iframeDocument?.head||iframeDocument.getElementById(styleId))return;const style=iframeDocument.createElement("style");style.id=styleId,style.textContent=styleContent,iframeDocument.head.appendChild(style)}catch(error){console.warn("Unable to inject product set iframe styles.",error)}},handleIframe=iframe=>{if(iframe.dataset.articleProductSetStyleBound==="true")return;iframe.dataset.articleProductSetStyleBound="true";let iframeDocument;try{iframeDocument=iframe.contentDocument||iframe.contentWindow?.document}catch{iframeDocument=null}if(iframeDocument?.readyState==="complete"){injectStyle(iframe);return}iframe.addEventListener("load",()=>injectStyle(iframe),{once:!0})};if(root.querySelectorAll(".shopify-buy-frame--productSet iframe").forEach(handleIframe),root.dataset.articleProductSetIframeObserver==="true")return;root.dataset.articleProductSetIframeObserver="true",new MutationObserver(mutations=>{mutations.forEach(mutation=>{mutation.addedNodes.forEach(node=>{node instanceof Element&&(node.matches(".shopify-buy-frame--productSet iframe")&&handleIframe(node),node.querySelectorAll(".shopify-buy-frame--productSet iframe").forEach(handleIframe))})})}).observe(root,{childList:!0,subtree:!0})} 201//# sourceMappingURL=/cdn/shop/t/361/assets/section-article-template.js.map?v=148227051081225239971782787794
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.