1// ============================================================ 2// [íì¼] ts-plp-timedeal.js 3// [ìí ] PLP íìë ì¹´ë í · ì§ì´êµ¬ì¡°ìì íìë ì¹´ë를 ê°ì§í´ li.is-timedeal + Event ë±ì§ 주ì , ê°ê²©ì¤ ìì ì ë ¬ 4// [ë¡ë©] layout.html + main.html ì head ì§ì script defer (?v ìºìë²ì¤í¸). ì¤íì¼ì ts-plp-timedeal.css ì ë´ 5// [ì ì©ë²ì] .prdList li[id^=anchorBoxId] (Cafe24 ì§ì´ ì¹´ë li). ê°ì§ë ì¹´ëë§ is-timedeal 6// [ìì ì 주ì] ì ë í°ê° Cafe24 ì§ì´ DOM(anchorBoxId · spec_price · sale_box)ì ìì¡´ â ì§ì´ëª¨ë ë³ê²½ ì ì¬íì¸. ë ¸ë ì´ëë§ íê³ ìì /모ëë³ì ë³ê²½ ê¸ì§. ìì í ?v ê°±ì (G-6) 7// [ì°ê´] ts-plp-timedeal.css(ë¼ì íì´ë¨¸ë° ì¤íì¼) · ts-plp-name.css(ê°ê²©ì¤ ì¨ê¹/íµì¼ ê·ì¹) 8// 9// [Figma 919:858 · Cafe24 ë¤ì´í°ë¸ íìì¸ì¼(wp-timer) 기ë°] 10// - í¸ë¦¬ê±°: ì¹´ëì .wp-timer(ë¤ì´í°ë¸ íìì¸ì¼ íì´ë¨¸) ëë .prd_price_sale(í ì¸í매ê°)ê° ìì¼ë©´ íìë 11// - ì²ë¦¬: li.is-timedeal ë¶ì¬ + Event ë±ì§(.ts-td-event) 주ì + ìµì¢ í ì¸ê°ë¥¼ í ì¸ì¨(%) ìì¼ë¡ ì´ë 12// - wp-timer ë ì±ì´ async 주ì â í´ë§ì¼ë¡ ì§ì° ëì. ë§í¬ì /모ë ë³ì ë¶ë³(ë¶ê° í´ëì¤/ììÂ·ë ¸ëììë§) 13// ============================================================ 14(function () { 15 'use strict'; 16 17 /* [TODO-467] íì ì¡°í ì ì© íë¡ë¸ â detail.html ì 방문ì í¸ëí½ì¼ë¡ ì¬ë¬ ë³í(ì¿ í¤Â·UA)ì´ 18 ìºìë¼ ê´ë¦¬ì ë³ê²½ ì§í ë¡ì ì¬ë³¸ ë³µê¶ì´ ë¤ìê° ëë©´ ë¤ìê²°ë 못 ì´ê¸´ë¤(ì¤ì¸¡: ì§íìí¨ ì í í 19 PDP ìë³µê¹ì§ 10ë¶+). td_probe.html ì ì¤í¬ë¦½í¸ë§ ë²ì¤í°ë¡ ì¡°ííë¯ë¡ ìºì ì¤ì¼ì´ ìì´ 20 íì ì ì í ë ë를 ë°ëë¤ â ê°ì ì¤í í(í ì¸í매ê°Â·í ì¸ ê¸°ê°)ì´ë¼ íìë ê·¸ëë¡ë¤. */ 21 var PROBE_URL = '/product/td_probe.html?product_no='; 22 23 function num(el) { 24 if (!el) return NaN; 25 var t = (el.textContent || '').replace(/[^0-9]/g, ''); 26 return t ? parseInt(t, 10) : NaN; 27 } 28 29 /* íì ë±ê¸ í ì¸ê°(ì: "ì°ì»´ í ì¸ê°") li 를 ì°¾ëë¤ â Cafe24 ê° í´ëì¤ë¥¼ ì£¼ì§ ìëë¤(ì¤ì¸¡ `class=" xans-record-"`). 30 `.spec` ì§ê³ li ì¤ spec_* / sale_box ê° ìëê³ , ë¼ë²¨(strong.title)ì 'í ì¸ê°' ê° ë ê². 31 'í ì¸ ê¸°ê°' li ë `.discountPeriod` 를 ê°ê³ display:none ì´ë¼ ì ì¸ëë¤. 32 ë±ê¸ëª ì´ ìì ë¶ì´(ì°ì»´/í¸ë¦´ë¦¬ì¨/ë¹ë¦¬ì¸â¦) ë¼ë²¨ ì 체를 못 ë°ì¼ë¯ë¡ 'í ì¸ê°' ë¶ë¶ë§ 본ë¤. */ 33 function findMemberPrice(spec) { 34 if (!spec) return null; 35 var found = null; 36 Array.prototype.forEach.call(spec.children, function (el) { 37 if (found) return; 38 var cls = el.className || ''; 39 if (/spec_info|spec_consumer|spec_price|sale_box/.test(cls)) return; 40 if (el.querySelector('.discountPeriod')) return; 41 var label = el.querySelector('.title'); 42 if (label && /í ì¸ê°/.test(label.textContent || '')) found = el; 43 }); 44 return found; 45 } 46 47 /* ê°ê²© li ì í ì¤í¸ìì **ì쪽 ê¸ì¡**ë§ ì½ëë¤. 48 "í ì¸íë§¤ê° : 13,750ì ( 150ì í ì¸)" ì²ë¼ ì«ìê° ëì´ë©´ ë¤ì í ì¸ì¡(150)ì ì¡ë ìê° 49 í ì¸ì¨ì´ ìë±í´ì§ë¯ë¡ 첫 ë²ì§¸ `Nì` ë§ ì´ë¤. ë¼ë²¨(ìë¹ìê°Â·í매ê°Â·í ì¸í매ê°)ì ì«ìê° ìì´ ìì . */ 50 function firstWon(el) { 51 if (!el) return 0; 52 var m = String(el.textContent || '').replace(/\s+/g, ' ').match(/([\d,]+)\s*ì/); 53 return m ? parseInt(m[1].replace(/,/g, ''), 10) : 0; 54 } 55 56 /* ââ í ì¸ì¨ ë±ì§(sale_box) ì¬ê³ì° (2026-09-01 ë°ì£¼ì² ì§ì) ââââââââââââââââââ 57 Cafe24 ì % ë **í ì¸ ì í매ê°** 기ì¤ì¼ë¡ ê³ì°í´ ëê³ , ê¸ì¡ì **í ì¸ ì ì©ê°**를 ë³´ì¬ì¤ë¤. 58 ì¤ì¸¡: ìë¹ìê° 19,000 / íë§¤ê° 13,900 / í ì¸íë§¤ê° 13,750 â ë±ì§ `27%` 59 27% ë 13,900 ì í ì¸ì¨(26.8%)ì´ë¼ íë©´ì ì°í 13,750(27.6% â 28%)ê³¼ ì´ê¸ëë¤. 60 â íë©´ì ì¤ì ë¡ ë³´ì´ë **ìµì¢ ê° ê¸°ì¤**ì¼ë¡ ë¤ì ì´ë¤. PDP íìë ë°ì¤ë ê°ì ê·ì¹ì´ë¼ ë íë©´ì´ ì¼ì¹íë
60¤. 61 â ï¸ìë¹ìê°Â·ìµì¢ ê° ì¤ íëë¼ë 못 ì½ì¼ë©´ **ìëì§ ìëë¤**(fail-open â Cafe24 ê° ì ì§). 62 â ï¸mark() ìììë§ í¸ì¶ = íìë ì¹´ë íì . ì¼ë° ìí ë±ì§ë ê±´ëë¦¬ì§ ìëë¤. */ 63 function recomputeRate(spec, saleBox) { 64 if (!spec || !saleBox) return; 65 var consumer = firstWon(spec.querySelector('.spec_consumer')); 66 var finalEl = spec.querySelector('.ts-td-final'); /* íì ë±ê¸ í ì¸ê° ì°ì */ 67 if (!finalEl) { 68 var ps = spec.querySelectorAll('.spec_price'); 69 if (ps.length >= 2) finalEl = ps[ps.length - 1]; /* ë§ì§ë§ = í ì¸íë§¤ê° */ 70 } 71 /* [F2] ìì ì /ì¢ ë£ ìë³µ ìíìì ë ê°ê²©ì¤ì ts-td-over ê° ë¶ëë¤ â ê·¸ ìíì ë±ì§ë 72 setCardPriceDeal/markEnded ê° ê´ë¦¬íë¯ë¡ ì¬ê¸°ì ì¨ê²¨ì§ ëê° ê¸°ì¤ì¼ë¡ ëë리면 ì ëë¤ 73 (ì¤ì¦: ë보기·load ì¬ì¤íì´ 27% 를 28% ë¡ ìíìí¬ ì ììë¤). */ 74 if (finalEl && finalEl.classList && finalEl.classList.contains('ts-td-over')) return; 75 var fin = firstWon(finalEl); 76 if (!consumer || !fin || consumer <= fin) return; 77 var rate = Math.round((consumer - fin) / consumer * 100); 78 if (!rate) return; 79 var txt = rate + '%'; 80 /* ê°ì¼ë©´ ì°ì§ ìëë¤ â í´ë§ ì¬ì¤íìë idempotent */ 81 if (String(saleBox.textContent).replace(/\s+/g, '') !== txt) saleBox.textContent = txt; 82 } 83 84 function mark(li) { 85 if (li.classList.contains('ts-td-ended')) return; /* ì¢ ë£ íì ì¹´ëë ë¤ì ì¹ íì§ ìëë¤(í´ë§ ì¬ì¤í ëë¹) */ 86 /* â ï¸íì ì ì© ê¸°ê°í ì¸ì íì´ë¨¸(.sale_countdown) ìì´ **í ì¸ê° íë§** ì¤ë ë ëê° ìë¤(ì¤ì¸¡). 87 ê·¸ëë íìë ì¹´ëë¡ ì²ë¦¬í´ì¼ ê°ê²©ì¤ì´ ì 리ëë¤ â íì ì íì í ì¸ê°ë¥¼ í¬í¨íë¤. */ 88 var specEl = li.querySelector('.description .spec'); 89 var memberPriceEl = findMemberPrice(specEl); 90 var isTd = li.querySelector('.sale_countdown, .wp-timer, .prd_price_sale') || memberPriceEl; 91 if (!isTd) return; 92 if (!li.classList.contains('is-timedeal')) li.classList.add('is-timedeal'); 93 94 /* Event ë±ì§ (ì 목 ì) */ 95 var name = li.querySelector('.description .name'); 96 if (name && !name.querySelector('.ts-td-event')) { 97 var ev = document.createElement('span'); 98 ev.className = 'ts-td-event'; 99 ev.textContent = 'Event'; 100 name.insertBefore(ev, name.firstChild); 101 } 102 103 /* ì´ì¤í ì¸ ê°ê²©ì¤ íµì¼: ìµì¢ í ì¸í매ê°(ë§ì§ë§ spec_price)를 %(sale_box) ìì¼ë¡ ì´ë 104 â ì¼ë°ì¹´ëì ëì¼í [ì ê°(ì·¨ìì ) â í ì¸ê°(ë³¼ë) â í ì¸ì¨ë±ì§] ìì. 105 ì¤ê° í매ê°Â·ë¼ë²¨Â·"(Nì í ì¸)" 문구ë ts-plp-name.css ê° ì¨ê¹. ë§í¬ì /모ëë³ì ë¶ë³(ë ¸ë ììë§ ì¡°ì , ìì X). */ 106 var spec = li.querySelector('.description .spec'); 107 if (spec) { 108 var saleBox = spec.querySelector('.sale_box'); 109 var prices = spec.querySelectorAll('.spec_price'); 110 if (saleBox && prices.length >= 2) { 111 var finalPrice = prices[prices.length - 1]; /* ë§ì§ë§ spec_price = í ì¸í매ê°(ìµì¢ ê°) */ 112 /* ìµì¢ ê°ê° %(sale_box) ë¤ì ìì¼ë©´ % ìì¼ë¡ ì´ë(ì´ë¯¸ ìì´ë©´ 무ëì â í´ë§ ì¬ì¤íìë idempotent) */ 113 if (saleBox.compareDocumentPosition(finalPrice) & Node.DOCUMENT_POSITION_FOLLOWING) { 114 spec.insertBefore(finalPrice, saleBox); 115 } 116 } 117 118 /* ââ íì ë±ê¸ í ì¸ê°(ì: "ì°ì»´ í ì¸ê°") ì²ë¦¬ (2026-09-01 ë°ì£¼ì² ì ë³´) ââ 119 íì ì ì© ê¸°ê°í ì¸ì ì `í ì¸í매ê°`(.spec_price) ì **ë§í¬ì ì´ ë¤ë¥´ë¤**. ì¤ì¸¡(ë¡ê·¸ì¸ ìí): 120 li.spec_price "íë§¤ê° : 29,900ì" 121 li.sale_box "57%" 122 li." xans-record-" "ì°ì»´ í ì¸ê° : 20,000ì ( 9,900ì í ì¸)" â **í´ëì¤ê° ìë¤** 123 ê·¸ëì `.spec_price` ë§ ë³´ë 기존 ê·ì¹ì´ ì ë¶ ë¹ëê° í매ê°Â·í ì¸ê°ê° **ë ë¤ ë³´ì´ê³ ì¤ë°ê¿**ëë¤. 124 íì : `.spec` ì§ê³ li ì¤ spec_* / sale_box ê° ìëê³ , ë¼ë²¨(strong.title)ì 'í ì¸ê°' ê° ë ê². 125 'í ì¸ ê¸°ê°' li ë `.discountPeriod` 를 ê°ê³ ì´ë¯¸ display:none ì´ë¼ ì ì
125¸ëë¤. 126 ë±ê¸ëª ì´ ìì ë¶ì´(ì°ì»´/í¸ë¦´ë¦¬ì¨/ë¹ë¦¬ì¸â¦) ë¼ë²¨ ì 체를 못 ë°ì¼ë¯ë¡ 'í ì¸ê°' ë¶ë¶ë§ 본ë¤. 127 ì°¾ì¼ë©´ ì°ë¦¬ í´ëì¤(ts-td-final)를 ë¶ì´ê³ %(sale_box) ìì¼ë¡ ì®ê¸´ë¤ â CSS ë ê·¸ í´ëì¤ë§ 본ë¤. */ 128 var memberPrice = findMemberPrice(spec); 129 if (memberPrice) { 130 if (!memberPrice.classList.contains('ts-td-final')) memberPrice.classList.add('ts-td-final'); 131 if (saleBox && (saleBox.compareDocumentPosition(memberPrice) & Node.DOCUMENT_POSITION_FOLLOWING)) { 132 spec.insertBefore(memberPrice, saleBox); /* ìì: ìë¹ìê° â í ì¸ê° â % */ 133 } 134 } 135 136 recomputeRate(spec, saleBox); 137 138 /* [TODO-475·Bì] íì ì ì© ëì ë¹ë¡ê·¸ì¸ì¼ë¡ ë³´ë ê²½ì° â ê¸°ê° í(.discountPeriod)ì ì¤ì§ë§ 139 í ì¸ê° íì´ ìì´ ê°ê²©ì´ íìê° ê·¸ëë¡ë¤. ì¤í´ ë°©ì§ + ê°ì ì ëë¡ "íì ì ì© í¹ê°" ë¼ë²¨ì ë¨ë¤. 140 ë¡ê·¸ì¸(í ì¸ê° í ì¡´ì¬)ì´ë íì+ë¹íì ëìë ë¶ì§ ìëë¤. */ 141 var hasPeriodRow = !!spec.querySelector('.discountPeriod'); 142 var hasDealPrice = !!(memberPrice || spec.querySelectorAll('.spec_price').length >= 2); 143 var oldLabel = spec.querySelector('.ts-td-mlabel'); 144 if (hasPeriodRow && !hasDealPrice) { 145 if (!oldLabel) { 146 var ml = document.createElement('li'); 147 ml.className = ' xans-record- ts-td-mlabel'; 148 ml.textContent = 'íì ì ì© í¹ê°'; 149 if (saleBox) spec.insertBefore(ml, saleBox); else spec.appendChild(ml); 150 } 151 } else if (oldLabel && oldLabel.parentNode) { 152 oldLabel.parentNode.removeChild(oldLabel); /* ë¡ê·¸ì¸ ë±ì¼ë¡ ê°ê²©ì´ ì기면 ë¼ë²¨ ì ê±° */ 153 } 154 } 155 } 156 157 // ââ ì¤ìº: Cafe24 ì§ì´ ì¹´ë li(anchorBoxId ì ë id)를 íì´ mark() ì ì©. í´ë§/ëë³´ê¸°ë¡ ë°ë³µ í¸ì¶ëë¯ë¡ idempotent ââ 158 /* ââ ìì ì íìë íì´ë¨¸ ì¨ê¹ (2026-09-01 ë°ì£¼ì² ì§ì) ââââââââââââââââââ 159 Cafe24 ë ííì 'ì§íí¨' ì¼ë¡ ë±ë¡í ìê°ë¶í° ì¢ ë£ìê°ê¹ì§ ì¹´ì´í¸ë¤ì´ì ë ¸ì¶íë¤. 160 ê·¸ëì **ìì ì ì¸ë° "N ì¢ ë£"** ë¡ ë³´ì¬ ì´ë¯¸ ì§í ì¤ì¸ ê²ì²ë¼ ì¤í´ëë¤ 161 (ì¤ì¸¡: 13:00 ìì ííì´ 11:52 ì ì´ë¯¸ `0ì¼ 04:07:43 ì¢ ë£` ë¡ ë ¸ì¶). 162 â¶PDP ë ìì¸ì ë³´ "í ì¸ ê¸°ê°" íì Cafe24 ê° ìì ì ìí를 ì§ì ì¤ë¤: 163 .product_promotion_date = "0ì¼ 01ìê° 1ë¶ ì ì ëë¤." â 'ì ì ëë¤' ê° ìì ì ì í¸ 164 .period = "2026-09-01 13:00 ~ 2026-09-01 16:00" 165 â¶ëª©ë¡ ì¹´ëìë ê·¸ ì ë³´ê° ìë¤(ì¤ì¸¡: `<div class="sale_countdown">` í´ëì¤ë¿, ìì± 0ê°). 166 ê·¸ëì í´ë¹ ìí ìì¸ë¥¼ **1íë§** ì¡°íí´ íë¨íê³ ìíë²í¸ë¡ ìºìíë¤. 167 â ï¸íì ì¤í¨Â·ì¡°í ì¤í¨Â·ìê°ì´ê³¼ë **ë³´ì´ë 쪽ì¼ë¡ ëë린ë¤(fail-open)** â 168 ì§í ì¤ì¸ ëì ê°ë ¤ 매ì¶ì ë§ë ìª½ì´ í¨ì¬ ëìë¤. */ 169 var preStartCache = {}; /* ìíë²í¸ â true(ììì ) / false(ì§íì¤) */ 170 var endedCache = {}; /* ìíë²í¸ â true(ì¢ ë£ë¨). ì본 ì¡°íë¡ë§ ì±ì´ë¤ */ 171 var inflight = {}; 172 173 /* â ï¸íì ì **ì ëìê°(.period) ì´ 1ìì**ë¤. 174 `.product_promotion_date`("N ì ì ëë¤.")ë ìë²ê° ë ë ìì 기ì¤ì¼ë¡ ê³ì°í´ ë£ë ìë ë¬¸êµ¬ë¼ 175 **ìºìë ìëµììë ë¡ì ê°**ì´ ì¨ë¤(ì¤ì¸¡: ìì íìë 목ë¡ì´ "ì ì ëë¤" 를 ì½ì´ ê³ì ì¨ê²¼ë¤). 176 `.period` ë `2026-09-01 12:30 ~ 16:00` ê°ì ì ëìê°ì´ë¼ ìºìë¼ë ê°ì´ ìíì§ ìëë¤. 177 ìë 문구ë `.period` ê° ìì ëë§ ë³´ì¡°ë¡ ì´ë¤. */ 178 /* `.period` ì ìììê°(ms). ìì¼ë©´ null */ 179 function startMsFrom(root) { 180 var period = root.querySelector('.period'); 181 if (!period) return null; 182 var m = (period.textContent || '').match(/(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2})/); 183 if (!m) return null; 184 return new Date(+m[1], +m[2] - 1, +m[3], +m[4], +m[5], 0).getTime(); 185 } 186
187 /* `.period` = "2026-09-01 15:20 ~ 2026-09-01 17:50" ìì **ë¤ìª½(ì¢ ë£) ìê°**. 188 startMsFrom ì 첫 ë²ì§¸ë§ ì½ì¼ë¯ë¡ ì¢ ë£ íì ìë ì¸ ì ìë¤. */ 189 function endMsFrom(root) { 190 var period = root.querySelector('.period'); 191 if (!period) return null; 192 var all = String(period.textContent || '').match(/(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2})/g); 193 if (!all || all.length < 2) return null; 194 var m = all[all.length - 1].match(/(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2})/); 195 return new Date(+m[1], +m[2] - 1, +m[3], +m[4], +m[5], 0).getTime(); 196 } 197 198 /* ââ ì¢ ë£ë ë íì (2026-09-01 ë°ì£¼ì² ì ë³´) âââââââââââââââââââââââââââ 199 ë°ì£¼ì²ê° ëì **ìì ë³´ë¤ ì¼ì° ê°ì ì¢ ë£**íì, ì본(cache MISS)ì ì ìì¸ë° 200 **ì£ì§ ìºìë PLP ê° ì½ 20ë¶ê° ì íë©´ì ê³ì ìë¹**íë¤(ì¤ì¸¡ 16:50): 201 PLP 19,000 / 13,750 / 28% + íì´ë¨¸ "0ì¼ 00:59:29 ì¢ ë£"(ì 17:50 기ì¤) 202 PDP 19,000 / 27% / 13,900 â ì´ë¯¸ ì ì 203 â 목ë¡ì í ì¸ê°, ë¤ì´ê°ë©´ ì ìê°. ê²°ì ë ìë²ê° ë¤ì ê³ì°íë¯ë¡ ê¸ì¡ ì¬ê³ ë ìì§ë§ 204 ê³ ê°ìê²ë "ê°ê²©ì´ ë¤ë¥´ë¤"ë¡ ë³´ì¸ë¤. 205 기존 ê²ì´í¸ë **ìì ì ì¨ê¹ë§** íê³ ì¢ ë£ë ìì ë³´ì§ ììë¤. ì¬ê¸°ì ë«ëë¤. 206 â ï¸`.period` ì ì¢ ë£ìê°ì **ê°ì ì¢ ë£ì ë¬´ë ¥**íë¤(ìºìë 문ìì ì ì¢ ë£ìê°ì´ ë°í ìë¤). 207 ê·¸ëì ìºì를 ì°íí **ì본 ì¡°í ê²°ê³¼**를 1ììë¡ ì´ë¤. */ 208 function dealGoneFrom(doc) { 209 /* 먼ì ì´ ë¬¸ìê° ì ì ìì¸íì´ì§ì¸ì§ íì¸ â íì± ì¤í¨Â·ìë¬íì´ì§ë©´ íë¨íì§ ìëë¤ */ 210 if (!doc.querySelector('#span_product_price_text, .xans-product-detail')) return null; 211 if (doc.querySelector('.period')) return false; /* í ì¸ ê¸°ê° íì´ ìì¼ë©´ ë ìì */ 212 if (doc.querySelector('.product_promotion_date')) return false; 213 if (doc.querySelector('.sale_countdown_detail')) return false; /* ìì¸ íì´ë¨¸ê° ìì¼ë©´ ë ìì */ 214 var sale = doc.querySelector('#span_product_price_sale, #span_optimum_discount_price'); 215 if (sale && String(sale.textContent || '').replace(/\s/g, '')) return false; 216 return true; /* ë íì 0 = ì¢ ë£ë¨ */ 217 } 218 219 /* ëª©ë¡ ì¹´ëìì ë íì ì ê±·ì´ë¸ë¤. 220 âë íìë **ì ë¶ `li.is-timedeal` ì¤ì½í**ë¼ ê·¸ í´ëì¤ë§ ë¼ë©´ ë¼ì íì´ë¨¸ë°Â·Event ë±ì§ ì¤íì¼Â· 221 ì¤ê° íë§¤ê° ì¨ê¹Â·í ì¸ê° ê°ì¡°Â·ì´ë¡ % ìì½ì´ í꺼ë²ì ìë³µëë¤. ë¨ë 3ê°ì§ë§ ìì¼ë¡ ì²ë¦¬íë¤. */ 222 /* ì본 문ì íë를 'ì§ê¸ ì´ë¤ ìíë'ë¡ ìì½íë¤: 'gone'(ë ìì/ì¢ ë£) · 'pre'(ìì ì ) · 'run'(ì§í ì¤) */ 223 /* â ï¸ì본 ì¡°íë ë³µê¶ì´ë¤ â ê´ë¦¬ìê° ê¸°ê°ì ë°ê¾¼ ì§íì **ì ê¸°ê° ì¬ë³¸Â·ê³µë°±ê¸° ì¬ë³¸**ì´ ìì¬ ì¨ë¤ 224 (2026-09-02 ì¤ì¸¡ 2ê±´: â 공백기 ì¬ë³¸ 'gone' ë³µê¶ì ì§í ì¤ ëì´ êº¼ì§ â¡ììì ë¤ë¡ 미루ì 225 ì ê¸°ê° ì¬ë³¸ 'run' ë³µê¶ì ìì ì ëì´ ì¼ì§ â ë¶ì íì ë§ í©ì를 ë°ë ë¹ëì¹ ê·ì¹ì ìí¨ê³¼). 226 'run' ë 'pre' ë 'gone' ë ì´ë 쪽ì´ë ë¡ì ì¬ë³¸ì¼ ì ìë¤ â ë°©í¥ ë¹ëì¹ì ë²ë¦¬ê³ 227 **첫 íì ì 2/3 ë¤ìê²°**ë¡ íì íë¤: 1ë° â 1.2ì´ ë¤ 2ë°(ì¼ì¹ ì íì ) â ë¶ì¼ì¹ë©´ 3ë°(ë¤ìê²°). 228 3ì ì ì ë¶ì¼ì¹ë ë³´ì´ë 쪽(fail-open run). ì´íì íë¤ë¦¼ì 45/60ì´ ì¬ê²ì¦ 루í(2ì°ì í©ì)ê° ì¡ëë¤. */ 229 function fetchVerdict(key, cb) { 230 window.fetch(PROBE_URL + key + '&_td=' + Date.now(), { credentials: 'same-origin', cache: 'reload' }) 231 .then(function (r) { return r.text(); }) 232 .then(function (html) { 233 var doc = new DOMParser().parseFromString(html, 'text/html'); 234 cb(verdictFrom(doc), doc); 235 }) 236 .catch(function () { cb(undefined, null); }); 237 } 238 239 function settleVerdict(key, v1, doc1, apply) { 240 if (v1 === null || !/^\d+$/.test(String(key))) { apply(v1, doc1); return; } 241 window.setTimeout(function () { 242 fetchVerdict(key, function (v2, doc2) { 243 if (v2 === v1) { apply(v1, doc2 || doc1); return; } 244 window.setTimeout(function () { 245 fetchVerdict(key, function (v3, doc3) { 246 if (v3 === v1) { apply(v1, doc3 || doc1); return; } 247 if (v3 === v2 && v2 != null) { apply(v2, doc3 || doc2); return; } 248 apply('run', doc1); /* ì ì ë¶ì¼ì¹ â ë³´ì´ë 쪽 */ 249 }); 250 }, 1200); 251 }); 252 }, 1200); 253 } 254 255 function verdictFrom(doc) { 256 if (dealGoneFrom(doc) === true) return 'gone'; 257 var eMs = endMsFrom(doc); 258 if (eMs !== null && Date.now() >= eMs) return 'gone'; 259 var sMs = startMsFrom(doc); 260 if (sMs !== null) return Date.now() < sMs ? 'pre' : 'run'; 261 var pre = preStartFrom(doc); 262 if (pre === true) return 'pre'; 263 if (pre === false) return 'run'; 264 return null; 265 } 266 267 /* markEnded 를 ëëë¦°ë¤ â ê²ì¦ 루íê° 'ì§í ì¤' í©ìì ëë¬íì ëë§ ì´ë¤. */ 268 function unmarkEnded(li) { 269 if (!li || !li.classList.contains('ts-td-ended')) return; 270 li.classList.remove('ts-td-ended'); 271 var t = li.querySelector('.sale_countdown, .wp-timer'); 272 if (t) t.classList.remove('ts-td-over'); 273 var spec = li.querySelector('.description .spec'); 274 if (spec) { 275 var over = spec.querySelectorAll('.ts-td-over'); 276 for (var i = 0; i < over.length; i++) over[i].classList.remove('ts-td-over'); 277 var sb = spec.querySelector('.sale_box'); 278 var keep = sb && sb.getAttribute('data-td-rate'); 279 if (keep) sb.textContent = keep; 280 } 281 try { mark(li); } catch (e) {} /* Event ë±ì§Â·ê°ê²©ì¤ ì¬êµ¬ì± */ 282 } 283 284 function markEnded(li) { 285 if (!li || li.classList.contains('ts-td-ended')) return; 286 li.classList.remove('is-timedeal', 'ts-td-checking-card', 'ts-td-pre'); 287 li.classList.add('ts-td-ended'); 288 289 var t = li.querySelector('.sale_countdown, .wp-timer'); /* â íì´ë¨¸ ìì ìì²´ */ 290 if (t) { t.classList.remove('ts-td-checking', 'ts-td-prestart'); t.classList.add('ts-td-over'); clearSchedules(t); } 291 292 var ev = li.querySelector('.description .name .ts-td-event'); /* â¡ì°ë¦¬ê° ë£ì Event ë±ì§ */ 293 if (ev && ev.parentNode) ev.parentNode.removeChild(ev); 294 295 var spec = li.querySelector('.description .spec'); /* â¢í ì¸íë§¤ê° ì¤ */ 296 if (!spec) return; 297 var fin = spec.querySelector('.ts-td-final'); 298 if (!fin) { var ps = spec.querySelectorAll('.spec_price'); if (ps.length >= 2) fin = ps[ps.length - 1]; } 299 if (fin) fin.classList.add('ts-td-over'); 300 301 /* í ì¸ì¨ì ì´ì **ë¨ì ìë í매ê°** 기ì¤ì¼ë¡ ëë린ë¤(28% â 27%). 302 ì½ì§ 못íë©´ ìëì§ ìëë¤ â í린 %ê° ë¨ëë¼ë ê°ê²©ì¤ì 깨ë¨ë¦¬ë ê²ë³´ë¨ ë«ë¤. */ 303 var saleBox = spec.querySelector('.sale_box'); 304 var consumer = firstWon(spec.querySelector('.spec_consumer')); 305 var visPrice = null, all = spec.querySelectorAll('.spec_price'); 306 for (var i = 0; i < all.length; i++) { if (all[i] !== fin) { visPrice = all[i]; break; } } 307 var now = firstWon(visPrice); 308 if (saleBox && consumer && now && consumer > now) { 309 var rate = Math.round((consumer - now) / consumer * 100); 310 if (rate > 0) saleBox.textContent = rate + '%'; 311 } 312 } 313 314 /* ìì¸íì´ì§: íì´ë¨¸ë§ ê°ì¶ë©´ pdp_buy_sheet.js ì P6 ë°ì¤ê° ì¹´ì´í¸ë¤ì´ computed display 를 315 ë³´ê³ ì¤ì¤ë¡ ë«ëë¤(#slide_thumbnail MutationObserver). ê¸ì¡(ìµì í)ì íëê·¸ë¡ ì린ë¤. */ 316 function markDetailEnded() { 317 unshadowDetailTimer(); 318 var el = document.querySelector('.xans-product-detail .sale_countdown_detail'); 319 if (el) { el.classList.remove('ts-td-checking', 'ts-td-prestart'); el.classList.add('ts-td-over'); } 320 window.__tsDealLive = null; /* ëì´ë¦° ë°ì¤(ìë setDealLive)ë í¨ê» ëë¤ */ 321 setDetailDealOff(true); 322 } 323 324 /* ââ [TODO-463] ë ë§í¬ì ì´ ìë ìºì íì´ì§ìì ë°ì¤ ëì´ë¦¬ê¸° âââââââââââââ 325 ëì ìë¡ ê±¸ë©´ ì£ì§ê° **ë ìì ì ì¬ë³¸**ì 주ë ëì PDP ë ê°ì ìë¡ê³ 침í´ë 326 ëì´ ì ë¬ë¤(ë°ì£¼ì² ì ë³´ â PLP ë ì±ì´ íì´ë¨¸ë¥¼ ë¼ì´ë¸ 주ì í´ í ë²ì ë¨ëë° PDP ë§ ë¦ì). 327 íì´ì§ì ë§í¬ì ì´ ìì´ë **ì본 ì¡°íê° 'ì§í ì¤'ì´ë¼ë©´** ì°ë¦¬ ë°ì¤(#ts-pdp-timedeal-price)ì 328 ìµì í ê¸ì¡ì ì´ë¦´ ì ìë¤ â ê°ê²©Â·ì¢ ë£ìê°ì ì본 문ììì ê°ì ¸ì íëê·¸ë¡ ë긴ë¤.
329 ë¼ì íì´ë¨¸ë°ë ì± ì£¼ì ì´ë¼ ì´ ê²½ë¡ë¡ë ì ì긴ë¤(ë°ì¤+ê°ê²©ì´ ì¤ì§ì´ë¼ ìì©). */ 330 function dealPriceFromDoc(doc) { 331 var el = doc.querySelector('#span_product_price_sale') || doc.querySelector('#span_optimum_discount_price'); 332 if (!el) return 0; 333 var first = (el.firstChild && el.firstChild.nodeType === 3) ? el.firstChild.textContent : el.textContent; 334 var m = String(first || '').match(/([\d,]+)\s*ì/); 335 return m ? (parseInt(m[1].replace(/,/g, ''), 10) || 0) : 0; 336 } 337 338 /* [TODO-468] PDP ì¹´ì´í¸ë¤ì´ "ì«ì" êµì â ì±ì íì´ì§ì ë°í(ìºì본ì´ë©´ ë¡ì) ë°ì´í°ë¡ 339 ë§¤ì´ ì«ì를 그린ë¤. ì§ì°ê±°ë ê°ë¦¬ë ëì , ì±ì´ ì¸ ëë§ë¤ MutationObserver ë¡ 340 **íì¸í¸ ì ì**(ê°ì íë ìì ë§ì´í¬ë¡íì¤í¬) ì본 ì¢ ë£ìê° ê¸°ì¤ ê°ì¼ë¡ ê³ ì³ ì´ë¤ â 341 íë©´ì ì°ë¦¬ ê°ë§ ë³´ì´ê³ ê¹ë¹¡ìì´ ìë¤. ê°ì ê°ì´ë©´ 무ì ì´ì´ë¼ 무í 루íë ìë¤. 342 íìì ì±ê³¼ ëì¼("0ì¼ HH:MM:SS ì¢ ë£"). PLP 쪽 wp-timer ë ë´ë¶ ë§í¬ì ë³íì´ ìì´ ì ì¸. */ 343 function fmtLeft(endMs) { 344 var left = endMs - Date.now(); 345 if (left <= 0) return null; 346 var sec = Math.floor(left / 1000); 347 var d = Math.floor(sec / 86400); sec -= d * 86400; 348 var h = Math.floor(sec / 3600); sec -= h * 3600; 349 var mi = Math.floor(sec / 60); sec -= mi * 60; 350 var pad = function (n) { return (n < 10 ? '0' : '') + n; }; 351 return d + 'ì¼ ' + pad(h) + ':' + pad(mi) + ':' + pad(sec) + ' ì¢ ë£'; 352 } 353 354 function shadowDetailTimer(endMs) { 355 var el = document.querySelector('.xans-product-detail .sale_countdown_detail'); 356 if (!el || !endMs || typeof MutationObserver === 'undefined') return; 357 var t = timersOf(el); 358 if (t.shadowEnd === endMs && t.shadow) return; /* ê°ì ì¢ ë£ìê°ì¼ë¡ ì´ë¯¸ ê°ë ì¤ */ 359 if (t.shadow) { t.shadow.disconnect(); t.shadow = null; } 360 t.shadowEnd = endMs; 361 function fix() { 362 var want = fmtLeft(endMs); 363 if (want === null) { unshadowDetailTimer(); return; } /* ì¢ ë£ â ì´íë markDetailEnded 몫 */ 364 if (el.textContent.trim() !== want) el.textContent = want; 365 } 366 t.shadow = new MutationObserver(fix); 367 t.shadow.observe(el, { childList: true, characterData: true, subtree: true }); 368 fix(); 369 } 370 371 function unshadowDetailTimer() { 372 var el = document.querySelector('.xans-product-detail .sale_countdown_detail'); 373 if (!el) return; 374 var t = timersOf(el); 375 if (t.shadow) { t.shadow.disconnect(); t.shadow = null; } 376 t.shadowEnd = null; 377 } 378 379 function setDealLive(endMs, price) { 380 window.__tsDealLive = { endMs: endMs || 0, price: price || 0 }; 381 setDetailDealOff(false); 382 try { document.dispatchEvent(new CustomEvent('ts:deallive')); } catch (e) {} 383 scheduleEnd(document.documentElement, endMs, markDetailEnded); /* ì¢ ë£ ì ìë ìë± */ 384 } 385 386 /* [S6] ì§í ì¤ ê°ê²© ë³ê²½ ëì â ì¹´ëì ëê° **í ì¤í¸**를 ì본 ì¡°í ê°ì¼ë¡ ë기ííë¤. 387 íì´ì§ ë§í¬ì ì ìºìë³¸ì¼ ì ìì´(ê°ì ìë¡ê³ 침ì¼ë¡ë ì ë«ë¦¼) ì ê°ê²©ì´ ë¨ëë¤. 388 ë¼ë²¨ì ì«ìê° ìì¼ë¯ë¡ fin ìì 첫 `Nì` í ì¤í¸ ë ¸ëë§ ë°ê¾¼ë¤. ê°ì¼ë©´ 무ì ì´. */ 389 function syncCardDealPrice(li, price) { 390 if (!price) return; 391 var spec = li && li.querySelector('.description .spec'); 392 if (!spec) return; 393 var fin = spec.querySelector('.ts-td-final'); 394 if (!fin) { var ps = spec.querySelectorAll('.spec_price'); if (ps.length >= 2) fin = ps[ps.length - 1]; } 395 if (!fin || firstWon(fin) === price) return; 396 var node = (function find(el) { 397 for (var i = 0; i < el.childNodes.length; i++) { 398 var n = el.childNodes[i]; 399 if (n.nodeType === 3 && /[\d,]+\s*ì/.test(n.textContent)) return n; 400 if (n.nodeType === 1) { var r = find(n); if (r) return r; } 401 } 402 return null; 403 })(fin); 404 if (!node) return; 405 node.textContent = node.textContent.replace(/[\d,]+\s*ì/, price.toLocaleString('k
405o-KR') + 'ì'); 406 try { recomputeRate(spec, spec.querySelector('.sale_box')); } catch (e) {} 407 } 408 409 /* ëª©ë¡ ì¹´ëì **ê°ê²©ì¤**ì ë ì ì©/í´ì ë¡ í ê¸íë¤. 410 â ï¸ë ì§í ì¤ì ìºìë 목ë¡ì Cafe24 ê° ì´ë¯¸ í ì¸ê°ë¡ ê·¸ë ¤ëì, íì´ë¨¸Â·ë±ì§ë§ ê°ì¶ë©´ 411 `13,750ì / 28%` ê° ê·¸ëë¡ ë¨ëë¤(2026-09-01 ì¤ì¸¡ â ë°ì£¼ì² "PLPë ê³ì ë ¸ì¶ ì¤"). 412 ëë릴 ì ìì´ì¼ íë¯ë¡ `markEnded()` ì²ë¼ í´ëì¤ë¥¼ ë¼ì§ ìê³ , í ì¸ê°ë§ ê°ì¶ê³ 413 %ë ìë ê°ì `data-td-rate` ì ë³´ê´íë¤ê° ë³µìíë¤. */ 414 function setCardPriceDeal(li, on) { 415 var spec = li && li.querySelector('.description .spec'); 416 if (!spec) return; 417 var fin = spec.querySelector('.ts-td-final'); 418 if (!fin) { var ps = spec.querySelectorAll('.spec_price'); if (ps.length >= 2) fin = ps[ps.length - 1]; } 419 if (!fin) return; /* ë ê°ê²©ì¤ì´ ìì¼ë©´ ìë ê²ì´ ìë¤(ì ì ë ë) */ 420 var saleBox = spec.querySelector('.sale_box'); 421 if (on) { 422 fin.classList.remove('ts-td-over'); 423 var keep = saleBox && saleBox.getAttribute('data-td-rate'); 424 if (keep && saleBox.textContent.trim() !== keep) saleBox.textContent = keep; 425 return; 426 } 427 fin.classList.add('ts-td-over'); 428 if (!saleBox) return; 429 if (!saleBox.getAttribute('data-td-rate')) saleBox.setAttribute('data-td-rate', saleBox.textContent.trim()); 430 /* ë¨ì ìë íë§¤ê° ê¸°ì¤ì¼ë¡ í ì¸ì¨ ì¬ê³ì°(28% â 27%). 못 ì½ì¼ë©´ ìëì§ ìëë¤. */ 431 var consumer = firstWon(spec.querySelector('.spec_consumer')); 432 var visPrice = null, all = spec.querySelectorAll('.spec_price'); 433 for (var i = 0; i < all.length; i++) { if (all[i] !== fin) { visPrice = all[i]; break; } } 434 var now = firstWon(visPrice); 435 if (!consumer || !now || consumer <= now) return; 436 var rate = Math.round((consumer - now) / consumer * 100); 437 if (rate > 0) saleBox.textContent = rate + '%'; 438 } 439 440 /* ìì¸íì´ì§ìì **ë ê¸ì¡ì ì°ë©´ ì ëë ìí**(ìì ì · ì¢ ë£ í)를 pdp_buy_sheet.js ì ì린ë¤. 441 â ï¸ì¢ ë£ë¿ ìëë¼ **ìì ì **ë í¬í¨í´ì¼ íë¤ â ìºìë ìì¸ë ì ëì í ì¸ì ì©ê° 442 (`#span_product_price_sale`)를 ê·¸ëë¡ ê°ê³ ìì´, ìì ì ì¸ë° ìµì íì´ ë ê°ê²©ì ì°ëë¤ 443 (ì¤ì¸¡ 캡ì²: ìµì 13,750ìì¸ë° ì´ ìíê¸ì¡ 13,900ì). */ 444 function setDetailDealOff(off) { 445 if (off) window.__tsDealLive = null; /* off ìíìì ì본 ë기í ê°ê²©ì´ ë¨ì¼ë©´ ì ëë¤ */ 446 if (window.__tsDealOff === off) return; 447 window.__tsDealOff = off; 448 try { document.dispatchEvent(new CustomEvent('ts:dealstate', { detail: { off: off } })); } catch (e) {} 449 } 450 451 /* [F3] ìì½ íì´ë¨¸ ë³´ê´ì â íì ë§ë¤ **clear í ì¬ìì½**(ì¬ë¬´ì¥) íë¤. 452 ì¢ ì ì ìì· ìì± ê°ë(data-td-release/endset)ë ê´ë¦¬ìê° ê¸°ê°ì ë°ê¾¸ë©´ **ì ìê°ì ë°í**íê³ 453 ì ìê° ì¬ìì½ì´ ë§íë¤(TODO-460 êµíì´ ì´ë²¤í¸ ì¹´ëìë§ ìê³ ì´ íì¼ì ë¹ ì ¸ ìë ê²). */ 454 var timerStore = (typeof WeakMap !== 'undefined') ? new WeakMap() : null; 455 function timersOf(el) { 456 if (!timerStore) { el.__tsTimers = el.__tsTimers || {}; return el.__tsTimers; } 457 var t = timerStore.get(el); 458 if (!t) { t = {}; timerStore.set(el, t); } 459 return t; 460 } 461 function clearSchedules(el) { 462 if (!el) return; 463 var t = timersOf(el); 464 if (t.rel) { window.clearTimeout(t.rel); t.rel = null; } 465 if (t.end) { window.clearTimeout(t.end); t.end = null; } 466 } 467 468 /* ì¢ ë£ ìê°ì ë§ì¶° ì¤ì¤ë¡ ë«ëë¤ â ë ì¤ì ì´ì´ë íì´ ì¢ ë£ íìë ëì ê³ì ëì°ë ê² ë°©ì§. 469 (ê°ì ì¢ ë£ë ì´ ê²½ë¡ë¡ 못 ì¡ëë¤ â ì본 ì¡°íê° ë´ë¹) */ 470 function scheduleEnd(el, endMs, fn) { 471 if (!el) return; 472 var t = timersOf(el); 473 if (t.end) { window.clearTimeout(t.end); t.end = null; } /* ì¬ë¬´ì¥ */ 474 if (endMs === null) return; 475 var wait = endMs - Date.now(); 476 if (wait <= 0 || wait > 24 * 3600 * 1000) return; 477 t.end = window.setTimeout(function () { t.end = null; fn(); }, wait + 1500); 478 } 479 480 function preStartFrom(root) { 481 var ms = startMsFrom(root); 482 if (ms !== null) return Date.now() < ms; 483 var promo = root.querySelector('.product_promotion_date'); 484 if (promo && /ì ì ëë¤/.test(promo.textContent || '')) return true; 485 if (promo && (promo.textContent || '').trim()) return false;
486 return null; /* íë¨ ë¶ê° â í¸ì¶ë¶ìì ë³´ì ì²ë¦¬(fail-open) */ 487 } 488 489 /* ìì ì ìë íì´ë¨¸ë¿ ìëë¼ **Event ë±ì§ë í¨ê» ê°ì¶ë¤** (ë°ì£¼ì² ì§ì 2026-09-01) 490 â ë±ì§ë§ ë¨ì¼ë©´ ìì§ ìì ì í ëì´ ì§í ì¤ì²ë¼ ë³´ì¸ë¤. 491 PDP ì "íìë ííê°" ë°ì¤ë pdp_buy_sheet.js ê° ì¹´ì´í¸ë¤ì´ì computed display 를 492 ë³´ê³ ì¼ê³ ëë¯ë¡(P6) ì¬ê¸°ì íì´ë¨¸ë§ ê°ì¶ë©´ ìëì¼ë¡ í¨ê» ì¬ë¼ì§ë¤. */ 493 /* â ï¸ìì ìê°ì´ ì§ëë©´ **ìë¡ê³ 침 ìì´ ì¤ì¤ë¡ í¼ë¤** (2026-09-01 ë°ì£¼ì² ì ë³´). 494 íìë ìì ì ì íì´ì§ë¥¼ ì° ë¸ë¼ì°ì ë Cafe24 ê° ìºìë HTML ì ê³ì 주기 ë문ì 495 ê°ì ìë¡ê³ 침ì í´ë ë¡ì ìí ê·¸ëë¡ìë¤(ë¤ë¥¸ ë¸ë¼ì°ì ììë ì ì â ì¤ì¸¡ ì ë³´). 496 `.period` ë ì ëìê°ì´ë¼ ê·¸ ìì ì ì ì ìì¼ë¯ë¡, ë¨ì ìê°ë§í¼ íì´ë¨¸ë¥¼ ê±¸ì´ í´ì íë¤. 497 ì¶ê°ë¡ 30ì´ë§ë¤ ë¤ì íì í´ ìê³Â·ìºì ì´ê¸ë¨ê¹ì§ í¡ìíë¤. */ 498 function scheduleRelease(el, startMs) { 499 if (!el) return; 500 var t = timersOf(el); 501 if (t.rel) { window.clearTimeout(t.rel); t.rel = null; } /* ì¬ë¬´ì¥([F3]) */ 502 if (startMs === null) return; 503 var wait = startMs - Date.now(); 504 if (wait <= 0 || wait > 24 * 3600 * 1000) return; /* ì´ë¯¸ ì§ë¬ê±°ë í루 ëê² ë¨ì¼ë©´ ìì½íì§ ìëë¤ */ 505 t.rel = window.setTimeout(function () { t.rel = null; setTimerHidden(el, false); }, wait + 1500); 506 } 507 508 function setTimerHidden(el, hidden) { 509 el.classList.remove('ts-td-checking'); 510 if (hidden) el.classList.add('ts-td-prestart'); 511 else el.classList.remove('ts-td-prestart'); 512 var li = el.closest ? el.closest('li[id^="anchorBoxId"]') : null; 513 if (li && !li.classList.contains('ts-td-ended')) { /* ended ìíë unmarkEnded ë¡ë§ ëë린ë¤([F3] ìì ë§) */ 514 li.classList.remove('ts-td-checking-card'); 515 if (hidden) li.classList.add('ts-td-pre'); 516 else li.classList.remove('ts-td-pre'); 517 try { setCardPriceDeal(li, !hidden); } catch (e) {} /* ê°ê²©ì¤ë í¨ê» */ 518 } 519 /* ìì¸ íì´ë¨¸ë©´ ê¸ì¡ íë그·ì ì°¨ë¨ í´ëì¤ë ê°ì´ ìì§ì¸ë¤. ì¢ ë£(ts-td-over)ë ëëë¦¬ì§ ìëë¤. */ 520 if (el.classList.contains('sale_countdown_detail')) { 521 setDetailDealOff(hidden || el.classList.contains('ts-td-over')); 522 if (!hidden) document.documentElement.classList.remove('ts-td-pre-doc'); 523 } 524 } 525 526 /* â ï¸ìì¸íì´ì§ë **ì본 íì ì ë°ë¥¸ë¤** (2026-09-01 ë°ì£¼ì² ì ë³´ â ìì ì ì¸ë° PDP ì ëì´ ë´ë¤). 527 PLP ì¹´ëë ì²ìë¶í° ìì¸ë¥¼ ì¡°íí´ íì íì§ë§ **PDP ë ì기 문ìë§ ë´¤ë¤.** ê·¸ëì 528 **ì ëì´ ì§í ì¤ì´ë ìì ì ìºìë ìì¸**를 ë°ì¼ë©´ `.period` ì ìììê°ì´ ì´ë¯¸ ì§ë ê²ì²ë¼ 529 ë³´ì¬ "ì§í ì¤"ì¼ë¡ ì¤ííë¤(ì¤ì¸¡ 캡ì²: íì´ë¨¸ `0ì¼ 00:12:51 ì¢ ë£` + ìµì 13,750ìì¸ë° 530 ì´ ìíê¸ì¡ì 13,900ì â ì ëì ìì§ ìì ì ì´ìë¤). 531 â ï¸'ëì´ ìëë'ë§ ë¬»ë ê²ì¼ë¡ë ë¶ì¡±íë¤ â ì본ì ì ëì´ **ë±ë¡ë§** ë¼ ìì´ë ëì ì¡´ì¬íë¯ë¡ 532 ì¢ ë£ íì ë§ì¼ë¡ë ì´ ê²½ì°ë¥¼ 못 ì¡ëë¤. **ì본ì ììÂ·ì¢ ë£ ìê°ì¼ë¡ ìí ì체를 ë¤ì íì **íë¤. */ 533 var originState = null; /* ì본 íì ì¤ë ì· { gone, startMs, endMs, preFallback } */ 534 535 /* ì본 ê¸°ì¤ 'ìì ì ' ì¬ë¶. `.period` ê° ìì ëë§ ë¬¸êµ¬ ê¸°ë° í´ë°±ì ì´ë¤. */ 536 function originPre() { 537 if (!originState) return null; 538 if (originState.startMs !== null) return Date.now() < originState.startMs; 539 return originState.preFallback; 540 } 541 function gateDetailTimer() { 542 var el = document.querySelector('.xans-product-detail .sale_countdown_detail'); 543 if (!el) { 544 /* ë ë§í¬ì ì´ ìë íì´ì§(ìºì ì¬ë³¸ or ì¤ì ë¡ ë ìì) â ë°ì¤ê° ìë PDP ë©´ ì본ì¼ë¡ íì¸ */ 545 if (document.getElementById('ts-pdp-timedeal-price')) probeDetail(); 546 return; 547 } 548 549 /* â ìì ì¢ ë£ìê°ì´ ì´ë¯¸ ì§ë¬ì¼ë©´ ì¦ì ë«ëë¤(ë¤í¸ìí¬ ë¶íì). 550 [F3] ì본 ì¤ë ì·ì´ ìì¼ë©´ **ì본ì ì¢ ë£ìê°ì ì°ì ** â ë¡ì»¬ 문ìë ìºìë³¸ì¼ ì ìë¤. */ 551 var endMs = originState ? originState.endMs : endMsFrom(document); 552 if (endMs !== null && Date.now() >= endMs) { markDetailEnded(); return; } 553 554 if (!el.getAttribute('data-td-gated')) { 555 el.setAttribute('data-td-gated', '1'); 556 var pre = preStartFrom(document); 557 setTimerHidden(el, pre === true); 558 if (pre === true) scheduleRelease(el, startMsFrom(document)); 559 } 560 /* â¡ ë ì¤ì ì´ì´ë íì´ ì¢ ë£ íìë ê³ì ëì°ì§ ìëë¡ ì¢ ë£ ìê°ì ìì½ */ 561 scheduleEnd(el, endMs, markDetailEnded); 562 563 /* ⢠ì본 ì¡°í â ìí íì ì ìµì¢ 근거. ì¤í¨Â·íë¨ë¶ê°ë 무ì(fail-open). */ 564 probeDetail(); 565 } 566 567 /* ìì¸ ì본 ì¡°í. **`cache:'reload'`(ë¤í¸ìí¬ ê°ì )** ë¡ ë¬»ëë¤ â no-store ë ì 문ì를 ë°ìë¤(ì¤ì¸¡). 568 â ï¸1íë¡ ëë´ì§ ìëë¤: ì¡°íê° ìºì본ì ê±¸ë ¤ 'ìì ì 'ì¼ë¡ êµ³ì¼ë©´ **ì§í ì¤ì¸ ëì´ ê³ì ê°ë ¤ì§ë¤.** 569 ìì ì ì¼ë¡ ì¨ê¸´ ëììë 30ì´ ì¬íì ì´ ë¤ì ë¶ë¥¸ë¤(ìí ìì). */ 570 var detailProbes = 0; 571 var probeBusy = false;
572 var probeLastAt = 0; 573 function probeDetail() { 574 if (detailProbes >= 12 || !window.fetch) return; 575 /* â ï¸run() ì´ 400ms í´ë§ì¼ë¡ ì´ í¨ì를 ë°ë³µ í¸ì¶íë¤ â ì¤ë¡í ìì´ë 첫 5ì´ì 576 ìí 12í(Ã240KB)를 ë¤ íì´ë¤(ì¤ì¬ì© ëë¹). ì§í ì¤ 1ê±´ + ìµì 25ì´ ê°ê²©. */ 577 if (probeBusy || Date.now() - probeLastAt < 25000) return; 578 probeBusy = true; 579 probeLastAt = Date.now(); 580 detailProbes++; 581 var pno = (location.search.match(/product_no=(\d+)/) || [])[1] || 582 (location.pathname.match(/\/(\d+)\/(?:category|display)/) || [])[1]; 583 var base = pno ? PROBE_URL + pno + '&' : location.href.split('#')[0] + (location.href.indexOf('?') >= 0 ? '&' : '?'); 584 window.fetch(base + '_td=' + Date.now(), { credentials: 'same-origin', cache: 'reload' }) 585 .then(function (r) { return r.text(); }) 586 .then(function (html) { 587 var doc = new DOMParser().parseFromString(html, 'text/html'); 588 probeBusy = false; 589 /* [F1] ì본ë 'ë ìì'ì´ê³ **ì´ íì´ì§ìë ë íì ì´ ìì¼ë©´** ì¬ê¸°ì ë â 590 ë ê²ì´ ìëë° markDetailEnded ë¡ __tsDealOff 를 ì¸ì°ë©´ 45ì´ ê²ì¦ 루í ê°ëê° ë«ë ¤ 591 ë ìë 모ë ìí íì´ì§ê° 15íÃ240KB 를 ê³ì ì¡°ííë¤(ì¤ì¸¡ 110ì´ 4í). í©ìì·ë ìëµ. */ 592 if (verdictFrom(doc) === 'gone' && dealGoneFrom(document) === true && !window.__tsDealLive) return; 593 var pno2 = (location.search.match(/product_no=(\d+)/) || [])[1] || 594 (location.pathname.match(/\/(\d+)\/(?:category|display)/) || [])[1]; 595 /* 첫 íì ì 2/3 ë¤ìê²°(settleVerdict) â ì´ë ë°©í¥ì´ë ë³µê¶ 1ì¥ì ìí를 ë°ê¾¸ì§ ìëë¤ */ 596 settleVerdict(pno2 || '', verdictFrom(doc), doc, function (v, doc2) { 597 if (!doc2) return; 598 if (v === 'gone') { markDetailEnded(); return; } 599 originState = { 600 startMs: startMsFrom(doc2), 601 endMs: endMsFrom(doc2), 602 preFallback: preStartFrom(doc2), 603 price: dealPriceFromDoc(doc2) 604 }; 605 applyOriginVerdict(); 606 }); 607 }) 608 .catch(function () { probeBusy = false; }); 609 } 610 611 /* ì본 ì¤ë ì·ì¼ë¡ íì¬ ìí를 ë¤ì ì¹ íë¤ â ë¡ì»¬(ìºìë) 문ì íì ì ë®ì´ì´ë¤. */ 612 function applyOriginVerdict() { 613 var el = document.querySelector('.xans-product-detail .sale_countdown_detail'); 614 if (!originState) return; 615 if (originState.endMs !== null && Date.now() >= originState.endMs) { markDetailEnded(); return; } 616 var pre = originPre(); 617 if (pre === null) return; /* íë¨ ë¶ê° â ë¡ì»¬ íì ì ì§(fail-open) */ 618 if (!el) { 619 /* ìºì ì¬ë³¸ì´ë¼ ë§í¬ì ì´ ìë¤ â ì§í ì¤ì´ë©´ ë°ì¤Â·ìµì ê°ë¼ë ëì´ë¦°ë¤ */ 620 if (pre === false && originState.price) setDealLive(originState.endMs, originState.price); 621 return; 622 } 623 setTimerHidden(el, pre === true); 624 if (pre === true) scheduleRelease(el, originState.startMs); 625 else { 626 scheduleEnd(el, originState.endMs, markDetailEnded); 627 /* [S6] ë§í¬ì ì´ ìì´ë **ì본 ê°ê²©ì ì°ì ** â ìºìë íì´ì§ì ì ê°ê²©ì´ ë°ì¤Â·ìµì ì ë¨ì§ ìê² */ 628 if (originState.price) setDealLive(originState.endMs, originState.price); 629 if (originState.endMs) shadowDetailTimer(originState.endMs); /* [468] ì«ìë ì본 ê¸°ì¤ */ 630 } 631 } 632 633 /* ëª©ë¡ ì¹´ë: ìí ìì¸ë¥¼ 1í ì¡°íí´ íë¨ */ 634 function gateCardTimer(li) { 635 var el = li.querySelector('.sale_countdown, .wp-timer'); 636 if (!el || el.getAttribute('data-td-gated')) return; 637 var a = li.querySelector('a[href*="/product/"]'); 638 var href = a && a.getAttribute('href'); 639 var m = href && href.match(/\/(\d+)\/(?:category|display)/); 640 var key = m ? m[1] : href; 641 if (!href || !key) return; /* 주ì를 못 ì°¾ì¼ë©´ ê·¸ëë¡ ëë¤(ë³´ì) */ 642 el.setAttribute('data-td-gated', '1'); 643 644 if (endedCache[key]) { markEnded(li); return; } 645 if (preStartCache[key] !== undefined) { setTimerHidden(el, preStartCache[key]); return; } 646 647 el.classList.add('ts-td-checking'); /* íì ì ê¹ì§ë íì´ë¨¸Â·ë±ì§ë¥¼ ì ì ê°ì¶ë¤ */ 648 li.classList.add('ts-td-checking-card'); 649 window.setTimeout(function () { /* ìê°ì´ê³¼ fail-open */ 650 el.classList.remove('ts-td-checking'); 651 li.classList.remove('ts-td-checking-card'); 652 }, 2500); 653 if (inflight[key]) return; 654 inflight[key] = 1; 655 if (!window.fetch) { el.classList.remove('ts-td-checking'); li.classList.remove('ts-td-checking-card'); return; } 656 /* â ï¸ì¡°í 주ì·ìºì모ë를 ì못 ì¡ì¼ë©´ **ì 문ì**를 ë°ì ì§í ì¤ì¸ ëì ê°ë¦°ë¤(2026-09-01 ì¤ì¸¡ ì¬ê³ ). 657 ê°ì ìê° ê°ì 주ìì ëí´: 658 pretty URL + cache:'no-store' â ê¸°ê° `19:20`(ìê²) â 659 pretty URL + cache:'reload' â ê¸°ê° `17:20` â 660 detail.html?product_no= + _td â ê¸°ê° `17:20` â 661 â **ìíë²í¸ê° ìì¼ë©´ detail.html íì**ì¼ë¡ ë¬»ê³ , ìºì모ëë **reload**(ë¤í¸ìí¬ ê°ì )ë¡ ê³ ì . */ 662 var probeUrl = (/^\d+$/.test(key) ? PROBE_URL + key + '&' : href + (href.indexOf('?') >= 0 ? '&' : '?')) + '_td=' + Date.now(); 663 window.fetch(probeUrl, { credentials: 'same-origin', cache: 'reload' }) 664 .then(function (r) { return r.text(); }) 665 .then(function (html) { 666 var doc = new DOMParser().parseFromString(html, 'text/html'); 667 /* 첫 íì ì 2/3 ë¤ìê²°(ì settleVerdict 주ì) â ì´ë ë°©í¥ì´ë ë³µê¶ 1ì¥ì ìí를 ë°ê¾¸ì§ ìëë¤ */ 668 settleVerdict(key, verdictFrom(doc), doc, function (v, doc2) { 669 if (v === null || !doc2) v = 'run';
669 /* íë¨ ë¶ê° â ë³´ì´ë 쪽(fail-open) */ 670 endedCache[key] = (v === 'gone'); 671 preStartCache[key] = (v === 'pre'); 672 var endMs = endMsFrom(doc2); 673 var all = document.querySelectorAll('.sale_countdown, .wp-timer'); 674 for (var i = 0; i < all.length; i++) { 675 var host = all[i].closest ? all[i].closest('li[id^="anchorBoxId"]') : null; 676 var ha = host && host.querySelector('a[href*="/product/"]'); 677 var hm = ha && (ha.getAttribute('href') || '').match(/\/(\d+)\/(?:category|display)/); 678 if (!hm || hm[1] !== key) continue; 679 if (v === 'gone') { markEnded(host); continue; } 680 setTimerHidden(all[i], v === 'pre'); 681 if (v === 'pre') scheduleRelease(all[i], startMsFrom(doc2)); 682 else { try { syncCardDealPrice(host, dealPriceFromDoc(doc2)); } catch (e) {} } /* [S6] */ 683 /* ìì ì¢ ë£ìê°ì´ ì§ëë©´ ëª©ë¡ ì¹´ëë ì¤ì¤ë¡ ë«ëë¤(í ì´ì´ë ê²½ì°) */ 684 (function (h) { scheduleEnd(all[i], endMs, function () { markEnded(h); }); })(host); 685 } 686 }); 687 }) 688 .catch(function () { /* fail-open */ 689 el.classList.remove('ts-td-checking'); 690 li.classList.remove('ts-td-checking-card'); 691 }); 692 } 693 694 /* ââ [TODO-467â¡] PLP ì¹´ë ëì´ë¦¬ê¸° â íì´ì§ ì¬ë³¸ì ë ë§í¬ì ì´ ìì ìì ë âââââââ 695 PLP íìë ìë² ë§í¬ì (í ì¸íë§¤ê° í·íì´ë¨¸)ì´ ì¬ë£ë¼, ë ìì ì ì¬ë³¸ì ë°ì¼ë©´ 696 그릴 ì¬ë£ê° ìì´ ê°ì ìë¡ê³ 침ìë ì ë¬ë¤(ì¤ì¸¡: ì§íí¨ ì í í PDP 3.3ì´ vs PLP ë¯¸ë ¸ì¶). 697 â ì ì í event_items ë°ì´í°($cache ìì·ë²ì¤í°)ë¡ "ì§ê¸ í ì¸ ì ì© ì¤"ì¸ ìíì ììë´ê³ , 698 ê·¸ ì¹´ëì ì°ë¦¬ ìì(íì´ë¨¸Â·í ì¸ê° í)를 ë§ë¤ì´ ë¶ì¸ë¤. 기존 CSS ê³ì½ ì¬ì¬ì©: 699 is-timedeal + .sale_countdown(ë¼ìë°) + .ts-td-final(ëê°Â·íë§¤ê° ìë ì¨ê¹) + mark()ì ë±ì§Â·%. 700 ì¢ ë£Â·ì·¨ìë 기존 ì¥ì¹ê° ì²ë¦¬(markEnded ê° ì£¼ì ììë ê±·ëë¤ Â· 60ì´ ê²ì¦ 루í ëì). */ 701 var resurrectDone = false; 702 function plpCateNo() { 703 var m = location.pathname.match(/\/category\/[^\/]*\/(\d+)/) || location.search.match(/cate_no=(\d+)/); 704 return m ? m[1] : null; 705 } 706 function cardTick(el, endMs) { 707 var t = timersOf(el); 708 if (t.tick) { window.clearInterval(t.tick); t.tick = null; } 709 function draw() { 710 var left = endMs - Date.now(); 711 if (left <= 0) { window.clearInterval(t.tick); t.tick = null; return; } 712 var s = Math.floor(left / 1000); 713 var d = Math.floor(s / 86400); s -= d * 86400; 714 var h = Math.floor(s / 3600); s -= h * 3600; 715 var mi = Math.floor(s / 60); s -= mi * 60; 716 var pad = function (n) { return (n < 10 ? '0' : '') + n; }; 717 el.textContent = d + 'ì¼ ' + pad(h) + ':' + pad(mi) + ':' + pad(s) + ' ì¢ ë£'; 718 } 719 draw(); 720 t.tick = window.setInterval(draw, 1000); 721 } 722 function resurrectCard(li, price) { 723 if (li.getAttribute('data-td-made')) return; 724 li.setAttribute('data-td-made', '1'); 725 var no = li.id.replace('anchorBoxId_', ''); 726 fetchVerdict(no, function (v, doc) { 727 if (v !== 'run' || !doc) return; /* íë¡ë¸ë ì ì â ë¨ë° ì 뢰 */ 728 var endMs = endMsFrom(doc); 729 var op = dealPriceFromDoc(doc) || price; 730 var thumb = li.querySelector('.thumbnail'); 731 var spec = li.querySelector('.description .spec'); 732 if (!thumb || !spec) return; 733 if (!li.querySelector('.sale_countdown, .wp-timer')) { 734 var bar = document.createElement('div'); 735 bar.className = 'sale_countdown'; 736 thumb.insertBefore(bar, thumb.firstChild); 737 if (endMs) { cardTick(bar, endMs); scheduleEnd(bar, endMs, function () { markEnded(li); }); } 738 } 739 if (!spec.querySelector('.ts-td-final') && spec.querySelectorAll('.spec_price').length < 2) { 740 var row = document.createElement('li'); 741 row.className = ' xans-record- ts-td-final'; 742 var lab = document.createElement('strong'); 743 lab.className = 'title displaynone'; 744 lab.textContent = 'í ì¸íë§¤ê° :'; 745 var val = document.createElement('span');
746 val.textContent = ' ' + op.toLocaleString('ko-KR') + 'ì'; 747 row.appendChild(lab); row.appendChild(val); 748 var sb = spec.querySelector('.sale_box'); 749 if (sb) spec.insertBefore(row, sb); else spec.appendChild(row); 750 } 751 li.classList.add('is-timedeal'); 752 try { mark(li); } catch (e) {} /* ë±ì§ + % ì¬ê³ì° */ 753 }); 754 } 755 function resurrectPlpCards() { 756 if (resurrectDone || !window.fetch) return; 757 var cate = plpCateNo(); 758 var lis = document.querySelectorAll('.prdList li[id^="anchorBoxId"]'); 759 if (!cate || !lis.length) return; 760 resurrectDone = true; 761 window.fetch('/product/event_items.html?cate_no=' + cate + '&_ts=' + Date.now(), { credentials: 'same-origin', cache: 'reload' }) 762 .then(function (r) { return r.text(); }) 763 .then(function (html) { 764 var doc = new DOMParser().parseFromString(html, 'text/html'); 765 var els = doc.querySelectorAll('.ev-item'); 766 for (var i = 0; i < els.length; i++) { 767 var no = (els[i].id || '').replace(/^evItem_/, ''); 768 if (!no) continue; 769 var deal = 0; 770 var rows = els[i].querySelectorAll('.ev-spec li'); 771 for (var r = 0; r < rows.length; r++) { 772 var txt = rows[r].textContent || ''; 773 if (txt.indexOf('í ì¸í매ê°') === -1) continue; 774 var m = txt.match(/([\d,]{2,})\s*ì/); 775 deal = m ? (parseInt(m[1].replace(/,/g, ''), 10) || 0) : 0; 776 break; 777 } 778 if (!deal) continue; 779 var li = document.getElementById('anchorBoxId_' + no); 780 if (!li) continue; 781 /* ì´ë¯¸ ë ë§í¬ì ì´ ìë ì¹´ëë 기존 íì´íë¼ì¸ 몫 */ 782 if (li.querySelector('.sale_countdown, .wp-timer') || li.classList.contains('is-timedeal') || li.classList.contains('ts-td-ended')) continue; 783 try { resurrectCard(li, deal); } catch (e) {} 784 } 785 }) 786 .catch(function () {}); 787 } 788 789 function run() { 790 /* ìì¸ íì´ë¨¸ë¥¼ **먼ì ** ì²ë¦¬íë¤ â ì¹´ë 루íìì ìì¸ê° ëë©´ ë¤ê° íµì§¸ë¡ ë§í기 ë문 791 (ì¤ì¸¡: PDP ì ê´ë ¨ìí ëª©ë¡ ë문ì gateDetailTimer ê° ì¤íëì§ ììë¤). */ 792 try { gateDetailTimer(); } catch (e) {} 793 var lis = document.querySelectorAll('.prdList li[id^="anchorBoxId"]'); 794 for (var i = 0; i < lis.length; i++) { 795 try { mark(lis[i]); } catch (e) {} 796 try { gateCardTimer(lis[i]); } catch (e) {} 797 } 798 try { resurrectPlpCards(); } catch (e) {} 799 } 800 801 /* âì¹´ì´í¸ë¤ì´ì´ 주ì ë기 **ì ì** 미리 ë§ëë¤ â 주ì í ê°ì¶ë©´ ë¼ìë°ê° ë²ì©ì¸ë¤ 802 (ë°ì£¼ì² "ê¹ë¹¡ê±°ë¦¬ë©´ì ëì¤ë¤ê° ë ¸ì¶ ìí¨"). `.period` ë ìë² HTML ì ì´ë¯¸ ìì´ì 803 defer ì¤í¬ë¦½í¸ ì¤í ìì ì´ë©´ íì ì´ ê°ë¥íë¤. ì§í ì¤ì¼ë¡ ë°íì§ë©´ setTimerHidden ì´ ê±·ëë¤. */ 804 try { 805 if (document.querySelector('.xans-product-detail') && preStartFrom(document) === true) { 806 document.documentElement.classList.add('ts-td-pre-doc'); 807 } 808 } catch (e) {} 809 810 if (document.readyState !== 'loading') run(); 811 else document.addEventListener('DOMContentLoaded', run); 812 window.addEventListener('load', run); 813 814 /* 30ì´ë§ë¤ ìì¸ íì´ë¨¸ë¥¼ ë¤ì íì íë¤(ììÂ·ì¢ ë£ ê²½ê³¼, ìºì·ìê³ ì´ê¸ë¨ í¡ì). 815 â ï¸**ì본 ì¤ë ì·ì´ ìì¼ë©´ ê·¸ê²ì ì´ë¤** â ë¡ì»¬ 문ìë ìºì본ì´ë¼ ìê°ì 믿ì ì ìë¤. 816 (ìì ì ë¡ì»¬ `preStartFrom(document)` ë§ ë´ì, ì본 íì ì¼ë¡ ì¨ê¸´ íì´ë¨¸ë¥¼ 30ì´ ë¤ì 817 ì¤ì¤ë¡ ë¤ì ì¼ë²ë ¸ë¤.) */ 818 /* â ï¸ì본 ì¤ë ì·ë ë³µê¶ì´ë¤(ì¡°í 8í ì¤ 1íë ìºì본 â ì¤ì¸¡). ì¤ë ì· íë를 ì ë´íì§ ìê³ 819 45ì´ë§ë¤ ë¤ì ì¡°íí´ **ì°ì 2í ê°ì íì ì¼ ëë§** ìí를 ë°ê¾¼ë¤(ìí 15í). */ 820 var pdpVerify = null; /* { last, streak } */ 821 var pdpVerifyN = 0; 822 window.setInterval(function () { 823 if (document.visibilityState === 'hidden') return; /* [F4] ì ë³´ë íìì ëë¹íì§ ìëë¤ */ 824 var el = document.querySelector('.xans-product-detail .sale_countdown_detail'); 825 if (!el && !window.__tsDealOff && !window.__tsDealLive) return; 826 if (++pdpVerifyN > 15 || !window.fetch) return; 827 var pno = (location.search.match(/product_no=(\d+)/) || [])[1] || 828 (location.pathname.match(/\/(\d+)\/(?:category|display)/) || [])[1]; 829 if (!pno) return; 830 window.fetch(PROBE_URL + pno + '&_td=' + Date.now(), { credentials: 'same-origin', cache: 'reload' }) 831 .then(function (r) { return r.text(); }) 832 .then(function (html) { 833 var doc = new DOMParser().parseFromString(html, 'text/html'); 834 var v = verdictFrom(doc); 835 if (v === null) return; 836 pdpVerify = (pdpVerify && pdpVerify.last === v) ? { last: v, streak: pdpVerify.streak + 1 } : { last: v, streak: 1 }; 837 if (pdpVerify.streak < 2) return; 838 var cd = document.querySelector('.xans-product-detail .sale_countdown_detail'); 839 if (v === 'gone') { markDetailEnded(); return; } 840 if (!cd) { if (v === 'run') setDealLive(endMsFrom(doc), dealPriceFromDoc(doc)); return; } 841 if (v === 'pre') { setTimerHidden(cd, true); scheduleRelease(cd, startMsFrom(doc)); } 842 else { 843 cd.classList.remove('ts-td-over'); 844 setTimerHidden(cd, false); 845 scheduleEnd(cd, endMsFrom(doc), markDetailEnded); 846 var lp = dealPriceFromDoc(doc); 847 if (lp) setDealLive(endMsFrom(doc), lp); /* [S6] ê°ê²©Â·ì¢ ë£ìê° ì¬ë기í */ 848 if (endMsFrom(doc)) shadowDetailTimer(endMsFrom(doc)); /* [468] */ 849 } 850 }) 851 .catch(function () {}); 852 }, 45000); 853 854 /* ââ ë¤ìê²° ê²ì¦ 루í (2026-09-01) âââââââââââââââââââââââââââââââââââââââ 855 â ï¸ì본 ì¡°í ìì²´ê° ë³µê¶ì´ë¤ â ê°ì ìì²ì 8ì°ë°ë¡ ìë©´ 7ë²ì ì ì , 1ë²ì ë ìì 856 ìºìë³¸ì´ ì¨ë¤(ì¤ì¸¡). í¤ëë¡ë êµ¬ë³ ë¶ê°(ë ë¤ x-cache HIT · date ì ì ). 857 ê·¸ëì 첫 ì¡°í í ë²ì íì ì ì구 ìºìíë©´, ì´ ëìê² ì 문ì를 ë°ì íì´ì§ë 858 **ììí í린 ìíë¡ êµ³ëë¤**(ë°ì£¼ì²: ì§í ìí¨ì¼ë¡ ë°ê¿¨ëë°ë ê³ì ë ¸ì¶). 859 â 60ì´ë§ë¤ ë¤ì ì¡°ííê³ , **ì°ì 2í ê°ì íì ì¼ ëë§** íì ìí를 ë°ê¾¼ë¤. 860 ììì¸ ìºìë³¸ì´ ë ë² ì°ì 걸릴 íë¥ ì ë®ê³ , ì ì í ìëµ
860ì ê¸ë°© 2ì°ìì´ ëë¤. 861 ìí 15í(â15ë¶) â ê·¸ ìì ì£ì§ ìºìë ìë ´íë¤(ì¤ì¸¡ ìµë 20ë¶ ë´). */ 862 var verify = {}; /* key â { last: 'gone'|'pre'|'run', streak: n } */ 863 function applyCardVerdict(key, v, doc) { 864 var all = document.querySelectorAll('li[id^="anchorBoxId"]'); 865 for (var i = 0; i < all.length; i++) { 866 var a = all[i].querySelector('a[href*="/product/"]'); 867 var m = a && (a.getAttribute('href') || '').match(/\/(\d+)\/(?:category|display)/); 868 if (!m || m[1] !== key) continue; 869 var el = all[i].querySelector('.sale_countdown, .wp-timer'); 870 if (v === 'gone') { markEnded(all[i]); continue; } 871 if (!el) continue; 872 if (v === 'pre') { setTimerHidden(el, true); scheduleRelease(el, startMsFrom(doc)); } 873 else { 874 unmarkEnded(all[i]); setTimerHidden(el, false); 875 try { syncCardDealPrice(all[i], dealPriceFromDoc(doc)); } catch (e) {} /* [S6] */ 876 scheduleEnd(el, endMsFrom(doc), (function (h) { return function () { markEnded(h); }; })(all[i])); 877 } 878 } 879 } 880 var verifyN = 0; 881 /* [F4] ìí(15í)ì "íì´ì§ ë¡ë í 15ë¶"ì´ ìëë¼ "ë§ì§ë§ í ë³µê· í 15ë¶" â 882 ì¤ë ì´ì´ë íë ì¬ì©ìê° ëìì¤ë©´ ìê°ì¹ì ê° ì´ìëë¤(TODO-462 ê²ì¦ í¨í´). */ 883 document.addEventListener('visibilitychange', function () { 884 if (document.visibilityState === 'visible') { pdpVerifyN = 0; verifyN = 0; resurrectDone = false; try { resurrectPlpCards(); } catch (e) {} } 885 }); 886 window.setInterval(function () { 887 if (document.visibilityState === 'hidden') return; 888 if (++verifyN > 15) return; 889 var seen = {}; 890 var lis = document.querySelectorAll('li[id^="anchorBoxId"]'); 891 for (var i = 0; i < lis.length; i++) { 892 var li = lis[i]; 893 /* ê²ì¦ ëì: ë íì ì´ ì(ì)ë ì¹´ë ì ë¶ â ë³´ì´ë ê²ë, ì¨ê¸´ ê²ë, ì¢ ë£ ì²ë¦¬í ê²ë */ 894 if (!li.classList.contains('is-timedeal') && !li.classList.contains('ts-td-ended')) continue; 895 var a = li.querySelector('a[href*="/product/"]'); 896 var m = a && (a.getAttribute('href') || '').match(/\/(\d+)\/(?:category|display)/); 897 if (!m || seen[m[1]]) continue; 898 seen[m[1]] = 1; 899 (function (key) { 900 window.fetch(PROBE_URL + key + '&_td=' + Date.now(), { credentials: 'same-origin', cache: 'reload' }) 901 .then(function (r) { return r.text(); }) 902 .then(function (html) { 903 var doc = new DOMParser().parseFromString(html, 'text/html'); 904 var v = verdictFrom(doc); 905 if (v === null) return; 906 var st = verify[key]; 907 verify[key] = (st && st.last === v) ? { last: v, streak: st.streak + 1 } : { last: v, streak: 1 }; 908 if (verify[key].streak >= 2) applyCardVerdict(key, v, doc); 909 }) 910 .catch(function () {}); 911 })(m[1]); 912 } 913 }, 60000); 914 915 /* wp-timer ë ë¤ì´í°ë¸ ì¤í¬ë¦½í¸ê° async 주ì â ìµë 10ì´ í´ë§ í ì¢ ë£ */ 916 var n = 0; 917 var iv = window.setInterval(function () { 918 run(); 919 if (++n >= 25) window.clearInterval(iv); 920 }, 400); 921 922 /* [ë보기] ì§ì° ë¡ë ëì */ 923 document.addEventListener('click', function (e) { 924 var t = e.target; 925 if (t && t.closest && t.closest('.btnMore, .ec-base-paginate a, .xans-product-listmore, .more')) { 926 window.setTimeout(run, 700); 927 window.setTimeout(run, 1500); /* ë©ì¸ ì§ì´(product_listmore) AJAX ì§ì° ëë¹ 2ì°¨ ì¬ì¤í */ 928 } 929 }); 930 931 /* [TODO-461] ì´ë²¤í¸ ê¸ ìí 그리ë(ts-event-post.js)ê° ê°ì ì본 íì ì ì°ëë¡ ìµì ê³µê°. 932 íì ì¡°ì(mark/markEnded ë±)ì Cafe24 ì§ì´ DOM ì ì©ì´ë¼ ê³µê°íì§ ìëë¤. */ 933 window.TSTimedeal = { verdictFrom: verdictFrom, startMsFrom: startMsFrom, endMsFrom: endMsFrom, settleVerdict: settleVerdict }; 934})();
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.