← back to Designer Wallcoverings
auto-save: 2026-07-22T13:14:23 (1 files) — shopify/theme-LIVE-591/assets/dw-card-hover.js
265cb3497b2089258f8f0a8ca2845c86e3090441 · 2026-07-22 13:14:31 -0700 · Steve Abrams
Files touched
M shopify/theme-LIVE-591/assets/dw-card-hover.js
Diff
commit 265cb3497b2089258f8f0a8ca2845c86e3090441
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed Jul 22 13:14:31 2026 -0700
auto-save: 2026-07-22T13:14:23 (1 files) — shopify/theme-LIVE-591/assets/dw-card-hover.js
---
shopify/theme-LIVE-591/assets/dw-card-hover.js | 87 +++++++++++++++++++++++---
1 file changed, 80 insertions(+), 7 deletions(-)
diff --git a/shopify/theme-LIVE-591/assets/dw-card-hover.js b/shopify/theme-LIVE-591/assets/dw-card-hover.js
index 9e61401b..bacbef92 100644
--- a/shopify/theme-LIVE-591/assets/dw-card-hover.js
+++ b/shopify/theme-LIVE-591/assets/dw-card-hover.js
@@ -1,5 +1,20 @@
/* ============================================================================
- DW card label v5 (2026-06-27) — collection / search product grids.
+ DW card label v6 (2026-07-22) — collection / search product grids.
+ v6 fix: eliminated infinite-scroll glitch caused by two bugs in v5:
+ 1. GUARD BUG: labelCard() guarded with card.querySelector('.dw-hover-overlay')
+ but v5 places the overlay OUTSIDE the card element (as a sibling of the
+ image-col in the card's parent). card.querySelector() can't find it, so
+ every run() call re-processed already-labeled cards and inserted duplicate
+ overlays. Fix: use card.dataset.dwHover as the authoritative processed flag.
+ 2. OBSERVER SCOPE BUG: MutationObserver watched document.body with subtree:true
+ and triggered run() for ANY added node — including the .dw-hover-overlay nodes
+ that run() itself inserts. This created a self-reinforcing loop: Boost appends
+ 24 cards → observer fires → run() inserts 24 overlays → observer fires again
+ → run() rescans all cards (O(n) querySelectorAll) → etc. The main thread was
+ saturated during the exact window Boost needs for its IntersectionObserver-
+ driven next-page fetch, stalling infinite scroll. Fix: observer now filters to
+ only fire run() when actual product card/container nodes are added, ignoring
+ .dw-hover-overlay and all other node types.
v5 (Steve): the name/vendor label was a DARK absolute OVERLAY riding the
bottom of the image (a "pill" on top of the thumbnail). It is now a
SMALLER, light, in-flow pill placed DIRECTLY UNDER the image — no
@@ -106,7 +121,11 @@
}
function labelCard(card) {
- if (card.querySelector('.dw-hover-overlay')) return;
+ // Guard must check BOTH inside-card overlays (legacy placement) AND the
+ // v5 sibling placement: overlay is inserted as the next sibling of the
+ // image-column, OUTSIDE the card element. card.querySelector() misses it.
+ // Use a data attribute on the card itself as the canonical processed flag.
+ if (card.dataset.dwHover) return;
var tEl = card.querySelector(TITLE);
if (!tEl) return;
var name = patternName(tEl.textContent || '');
@@ -138,6 +157,9 @@
} else {
imgWrap.appendChild(ov);
}
+
+ // Mark card as processed AFTER successful insertion so re-runs skip it.
+ card.dataset.dwHover = '1';
}
function run() {
@@ -152,15 +174,66 @@
}
// Re-apply when the grid re-renders or lazy/infinite scroll appends cards.
+ // FIX (v6): The original observer watched document.body with subtree:true and
+ // fired run() (full document querySelectorAll) for ANY added node anywhere on
+ // the page — including the .dw-hover-overlay nodes run() itself inserts.
+ // This creates a self-reinforcing cascade: run() inserts overlay → observer
+ // fires again → run() rescans all cards → finds nothing new → inserts nothing
+ // → BUT the rescan still costs O(n) querySelectorAll on the whole document.
+ // With Boost infinite-scroll appending 24 cards × many child nodes each load,
+ // plus this observer firing for every one of those nodes, the main thread is
+ // saturated with repeated full-grid scans during the exact window Boost needs
+ // to complete its IntersectionObserver-driven next-page fetch.
+ //
+ // Fix: scope the observer to the product grid container only (not body), so
+ // sidebar / toolbar / overlay mutations don't trigger rescans. Also guard
+ // against the overlay insertions triggering the observer by ignoring mutations
+ // from nodes we just inserted (checked via card.dataset.dwHover).
var t;
var obs = new MutationObserver(function (muts) {
+ var hasNewProductNode = false;
for (var i = 0; i < muts.length; i++) {
- if (muts[i].addedNodes && muts[i].addedNodes.length) {
- clearTimeout(t);
- t = setTimeout(run, 80);
- return;
+ var added = muts[i].addedNodes;
+ for (var j = 0; j < added.length; j++) {
+ var node = added[j];
+ // Skip text nodes and our own overlay insertions
+ if (node.nodeType !== 1) continue;
+ if (node.classList && node.classList.contains('dw-hover-overlay')) continue;
+ // Only trigger run() if this looks like a product card or a container
+ // that might hold product cards (Boost wraps cards in list containers)
+ if (node.classList && (
+ node.classList.contains('boost-sd__product-item') ||
+ node.classList.contains('product-list-item') ||
+ node.classList.contains('boost-sd__product-list') ||
+ node.querySelector && node.querySelector('.boost-sd__product-item, .product-list-item')
+ )) {
+ hasNewProductNode = true;
+ break;
+ }
}
+ if (hasNewProductNode) break;
+ }
+ if (hasNewProductNode) {
+ clearTimeout(t);
+ t = setTimeout(run, 80);
}
});
- obs.observe(document.body, { childList: true, subtree: true });
+
+ // Observe the tightest container that holds product cards.
+ // Fall back to body if the grid isn't found yet (it initialises async).
+ function attachObserver() {
+ var grid = document.querySelector(
+ '.boost-sd__product-list, .boost-sd__product-grid, ' +
+ '.product-list, #boost-sd-filter-tree-container, ' +
+ '[class*="boost-sd__product-list"]'
+ );
+ var target = grid || document.body;
+ obs.observe(target, { childList: true, subtree: true });
+ }
+
+ if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', attachObserver);
+ } else {
+ attachObserver();
+ }
})();
← 8f5ec303 New Arrivals mailer v4: Shop by Color moved directly below c
·
back to Designer Wallcoverings
·
auto-save: 2026-07-22T13:44:34 (1 files) — shopify/scripts/c d1e74c41 →