PageSourceSearch

https://www.dreametech.com/cdn/shop/t/361/assets/section-article-template.js?v=148227051081225239971782787794

js dreametech.com collected 2026-09-27 20:55:45 UTC 16,532 bytes, 201 lines download raw bytes

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={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};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.