<!-- 07.26c16v2 Product Image in Cart Page -->
<style>
  .cart-row-img { transition: opacity .2s ease; }
  .cart-row-img:not([data-cart-img-done]) {
    opacity: 0;
    animation: cartImgFailsafe .2s 3s forwards;
  }
  @keyframes cartImgFailsafe { to { opacity: 1; } }
</style>

<script>
window.CartImageConfig = {
  imageFormat: '?format=300w',
  cachePrefix: 'cartimg:v1:',
  cacheTTL: 600000,
  debounceDelay: 50
};
</script>

<script>
(function () {
  var cfg = window.CartImageConfig || {};
  var IMAGE_FORMAT = cfg.imageFormat || '?format=300w';
  var CACHE_PREFIX = cfg.cachePrefix || 'cartimg:v1:';
  var CACHE_TTL = cfg.cacheTTL || 600000;
  var DEBOUNCE = cfg.debounceDelay || 50;
  var productCache = {};
  var timer = null;

  function slug(s) { return String(s).toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, ''); }

  function reveal(el) { el.dataset.cartImgDone = '1'; }

  function cacheGet(key) {
    try {
      var raw = sessionStorage.getItem(CACHE_PREFIX + key);
      if (!raw) return null;
      var o = JSON.parse(raw);
      if (!o || Date.now() - o.t > CACHE_TTL) { sessionStorage.removeItem(CACHE_PREFIX + key); return null; }
      return o.v;
    } catch (e) { return null; }
  }

  function cacheSet(key, val) {
    try { sessionStorage.setItem(CACHE_PREFIX + key, JSON.stringify({ t: Date.now(), v: val })); } catch (e) {}
  }

  function getProductData(key) {
    if (productCache[key]) return productCache[key];
    productCache[key] = fetch(key + '?format=json&noredirect', { headers: { 'Accept': 'application/json' } })
      .then(function (r) { return r.json(); })
      .then(function (j) { return j.item || null; })
      .catch(function () { return null; });
    return productCache[key];
  }

  function findRow(imgEl) {
    var el = imgEl;
    for (var i = 0; i < 8 && el; i++) {
      if (el.querySelector && el.querySelector('a[href*="/p/"]')) return el;
      el = el.parentElement;
    }
    return null;
  }

  function variantText(row) {
    var vEl = row.querySelector('.cart-row-variants');
    return vEl ? (vEl.textContent || '').trim() : '';
  }

  function parseVariantText(txt) {
    if (!txt) return null;
    var attrs = {};
    txt.split(/[\n\u2022|]/).forEach(function (part) {
      var idx = part.indexOf(':');
      if (idx > -1) attrs[slug(part.slice(0, idx))] = slug(part.slice(idx + 1));
      else if (part.trim()) attrs['_' + Object.keys(attrs).length] = slug(part);
    });
    return Object.keys(attrs).length ? attrs : null;
  }

  function assetBase(im) { return (im && im.assetUrl) ? im.assetUrl.split('?')[0] : null; }

  function pickAsset(item, wantAttrs) {
    var gallery = item.items || [];
    var mainBase = item.assetUrl ? item.assetUrl.split('?')[0] : null;
    if (!wantAttrs) return mainBase;
    var wantVals = Object.keys(wantAttrs).map(function (k) { return wantAttrs[k]; });
    for (var i = 0; i < gallery.length; i++) {
      var base = assetBase(gallery[i]);
      if (!base) continue;
      var fn = slug(base.split('/').pop());
      if (wantVals.every(function (v) { return v && fn.indexOf(v) > -1; })) return base;
    }
    var variants = item.variants || [];
    for (var k = 0; k < variants.length; k++) {
      var va = variants[k].attributes || {};
      var vSlugs = Object.keys(va).map(function (kk) { return slug(va[kk]); });
      if (wantVals.every(function (v) { return vSlugs.indexOf(v) > -1; })) {
        if (variants[k].image && variants[k].image.assetUrl) return variants[k].image.assetUrl.split('?')[0];
        if (gallery[k]) return assetBase(gallery[k]);
      }
    }
    return mainBase;
  }

  function applyImage(imgDiv, base) {
    var cur = imgDiv.getAttribute('style') || '';
    var m = cur.match(/url\(["']?([^"')]+)/);
    var curBase = m ? m[1].split('?')[0] : '';
    if (curBase === base) { reveal(imgDiv); return; }
    var fmt = (m && /[?&]format=[^&]+/.test(m[1]))
      ? m[1].match(/[?&]format=[^&]+/)[0].replace('&', '?')
      : IMAGE_FORMAT;
    var url = base + fmt;
    var pre = new Image();
    pre.onload = function () { imgDiv.style.backgroundImage = 'url("' + url + '")'; reveal(imgDiv); };
    pre.onerror = function () { reveal(imgDiv); };
    pre.src = url;
  }

  function fixCart() {
    document.querySelectorAll('.cart-row-img').forEach(function (imgDiv) {
      if (imgDiv.dataset.cartImgInit) return;
      imgDiv.dataset.cartImgInit = '1';
      var row = findRow(imgDiv);
      var link = row && row.querySelector('a[href*="/p/"]');
      if (!link) { reveal(imgDiv); return; }
      var href = link.getAttribute('href').split('?')[0];
      var vTxt = variantText(row);
      var key = href + '|' + vTxt;
      var cached = cacheGet(key);
      if (cached) { applyImage(imgDiv, cached); return; }
      var wantAttrs = parseVariantText(vTxt);
      getProductData(href).then(function (item) {
        if (!item) { reveal(imgDiv); return; }
        var newBase = pickAsset(item, wantAttrs);
        if (!newBase) { reveal(imgDiv); return; }
        cacheSet(key, newBase);
        applyImage(imgDiv, newBase);
      });
    });
  }

  function schedule() { clearTimeout(timer); timer = setTimeout(fixCart, DEBOUNCE); }

  fixCart();
  new MutationObserver(schedule).observe(document.documentElement, { childList: true, subtree: true });
})();
</script>

 

Buy me a coffee