1class o{constructor(){this.cache=new Map,this.maxSize=50,this.defaultTimeout=3e5}static getInstance(){return o.instance||(o.instance=new o),o.instance}get(t,s=this.defaultTimeout){const e=this.cache.get(t);return e?Date.now()-e.timestamp>s?(this.cache.delete(t),null):e.html:null}set(t,s){if(this.cache.set(t,{html:s,timestamp:Date.now()}),this.cache.size>this.maxSize){const e=Array.from(this.cache.entries()).sort(([,a],[,c])=>a.timestamp-c.timestamp)[0][0];this.cache.delete(e)}}clear(){this.cache.clear()}size(){return this.cache.size}}class n extends HTMLElement{constructor(){super(),this.isLoading=!1,this.defaultConfig={cacheTimeout:3e5,preloadOnHover:!0,updateHistory:!1,loadingClass:"swatch-loading",activeClass:"swatch-active",errorClass:"swatch-error"},this.globalCache=o.getInstance(),this.config={...this.defaultConfig},this.handleSwatchClick=this.handleSwatchClick.bind(this),this.handleSwatchHover=this.handleSwatchHover.bind(this)}static get observedAttributes(){return["cache-timeout","preload-on-hover","update-history","loading-class","active-class","error-class"]}connectedCallback(){this.initializeConfig(),this.attachEventListeners()}disconnectedCallback(){this.removeEventListeners(),this.abortController&&this.abortController.abort(),this.debounceTimer&&window.clearTimeout(this.debounceTimer)}attributeChangedCallback(t,s,e){if(s!==e)switch(t){case"cache-timeout":this.config.cacheTimeout=parseInt(e)||this.defaultConfig.cacheTimeout;break;case"preload-on-hover":this.config.preloadOnHover=e!=="false";break;case"update-history":this.config.updateHistory=e==="true";break;case"loading-class":this.config.loadingClass=e||this.defaultConfig.loadingClass;break;case"active-class":this.config.activeClass=e||this.defaultConfig.activeClass;break;case"error-class":this.config.errorClass=e||this.defaultConfig.errorClass;break}}initializeConfig(){const t=this.attributes;for(let s=0;s<t.length;s++){const e=t[s];this.attributeChangedCallback(e.name,"",e.value)}}attachEventListeners(){this.addEventListener("click",this.handleSwatchClick),this.config.preloadOnHover&&this.addEventListener("mouseenter",this.handleSwatchHover,!0)}removeEventListeners(){this.removeEventListener("click",this.handleSwatchClick),this.removeEventListener("mouseenter",this.handleSwatchHover,!0)}async handleSwatchClick(t){var r;const s=t.target,e=s.closest(".swatch-link, [data-swatch-url]"),a=((r=s.closest("product-form"))==null?void 0:r.getAttribute("data-is-pdp"))==="true";if(!e)return;const c=e.getAttribute("data-swatch-url");if(a&&c){window.location.replace(c);return}if(t.preventDefault(),t.stopPropagation(),!this.isLoading)try{const i=this.extractSwatchData(e);if(!i.url)throw new Error("No swatch URL found");await this.loadProductVariant(i,e)}catch(i){console.error("Swatch click failed:",i),this.handleError(i)}}async handleSwatchHover(t){const e=t.target.closest(".swatch-link, [data-swatch-url]");if(!e)return;const a=this.extractSwatchData(e);a.url&&(this.debounceTimer&&window.clearTimeout(this.debounceTimer),this.debounceTimer=window.setTimeout(()=>{this.preloadProduct(a.url,a.template)},300))}extractSwatchData(t){return{url:t.dataset.swatchUrl||t.href||"",template:t.dataset.productTemplate||"swatch-product"}}async loadProductVariant(t,s){const e=this.getProductCard();if(!e)throw new Error("Product card not found");try{this.setLoadingState(!0),this.clearError();const a=await this.fetchProductHtml(t.url,t.template);this.replaceProductContent(e,a),this.updateActiveStates(s),this.config.updateHistory&&this.updateBrowserHistory(t.url),this.dispatchSwatchEvent("swatch:changed",{swatchData:t,productCard:e,swatchLink:s})}catch(a){throw this.handleError(a),a}finally{this.setLoadingState(!1)}}async fetchProductHtml(t,s){const e=this.getCacheKey(`${t}__${s||"default"}`),a=this.globalCache.get(e,this.config.cacheTimeout);if(a)return a;this.abortController&&this.abortController.abort(),this.abortController=new AbortController;const c=this.buildFetchUrl(t,s),r=await fetch(c,{method:"GET",headers:{"Content-Type":"text/html","X-Requested-With":"XMLHttpRequest",Accept:"text/html"},signal:this.abortController.signal});if(!r.ok)throw new Error(`HTTP error! status: ${r.status}`);const i=await r.text();return this.globalCache.set(e,i),i}buildFetchUrl(t,s){const e=new URL(t,window.location.origin);return e.searchParams.has("view")||s!=null&&e.searchParams.set("view",s),e.toString()}async preloadProduct(t,s){const e=this.getCacheKey(`${t}__${s||"default"}`);if(!(this.globalCache.get(e,this.config.cacheTimeout)||this.isLoading))try{await this.fetchProductHtml(t,s)}catch(a){console.debug("Preload failed for:",t,a)}}replaceProductContent(t,s){const e=document.createElement("div");e.innerHTML=s;const a=e.querySelector('[data-selector="product-card"]');if(!a)throw new Error("Invalid product HTML structure - missing product card selector");const c=["data-product-id","data-selector"];
1c.forEach(r=>{const i=t.getAttribute(r);i&&a.setAttribute(r,i)}),t.innerHTML=a.innerHTML,Array.from(a.attributes).forEach(r=>{r.name.startsWith("data-")&&!c.includes(r.name)&&t.setAttribute(r.name,r.value)}),this.initializeNestedComponents(t)}initializeNestedComponents(t){this.removeEventListeners(),this.attachEventListeners(),t.dispatchEvent(new CustomEvent("product:content-updated",{bubbles:!0,detail:{container:t}}))}updateActiveStates(t){this.querySelectorAll(".swatch-item, .swatch-link").forEach(e=>{e.classList.remove(this.config.activeClass)});const s=t.closest(".swatch-item")||t;s&&s.classList.add(this.config.activeClass)}setLoadingState(t){this.isLoading=t;const s=this.getProductCard();s&&s.classList.toggle(this.config.loadingClass,t),this.classList.toggle(this.config.loadingClass,t),this.querySelectorAll(".swatch-link, [data-swatch-url]").forEach(a=>{t?(a.style.pointerEvents="none",a.setAttribute("aria-disabled","true")):(a.style.pointerEvents="",a.removeAttribute("aria-disabled"))})}handleError(t){console.error("Product swatch error:",t);const s=this.getProductCard();s&&s.classList.add(this.config.errorClass),this.classList.add(this.config.errorClass),this.dispatchSwatchEvent("swatch:error",{error:t}),setTimeout(()=>{s&&s.classList.remove(this.config.errorClass),this.classList.remove(this.config.errorClass)},3e3)}clearError(){const t=this.getProductCard();t&&t.classList.remove(this.config.errorClass),this.classList.remove(this.config.errorClass)}updateBrowserHistory(t){window.history&&window.history.replaceState&&window.history.replaceState({swatchUrl:t},"",t)}getProductCard(){return this.closest('[data-selector="product-card"]')||this.querySelector('[data-selector="product-card"]')}getCacheKey(t){return`swatch_${t}`}dispatchSwatchEvent(t,s){this.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:s}))}async loadVariant(t){const s={url:t},e=document.createElement("div");await this.loadProductVariant(s,e)}clearCache(){this.globalCache.clear()}getCacheSize(){return this.globalCache.size()}}customElements.define("product-swatch",n);
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.