refactor(web): remove legacy card hover system (~230 lines of dead code)

This commit is contained in:
matt 2025-10-28 17:35:47 -07:00
parent 6a94b982cb
commit ed381dfdce

View file

@ -6,10 +6,6 @@
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests" />
<title>MTG Deckbuilder</title>
<script src="https://unpkg.com/htmx.org@1.9.12" onerror="var s=document.createElement('script');s.src='/static/vendor/htmx-1.9.12.min.js';document.head.appendChild(s);"></script>
<script>
// Ensure legacy hover system never initializes (set before its script executes)
window.__disableLegacyCardHover = true;
</script>
<script>
(function(){
// Pre-CSS theme bootstrapping to avoid flash/mismatch on first paint
@ -244,34 +240,7 @@
setInterval(pollStatus, 10000);
pollStatus();
function ensureCard() {
// Legacy large image hover kept for fallback; disabled in favor of unified hover-card-panel
if (window.__disableLegacyCardHover) return document.getElementById('card-hover') || document.createElement('div');
var pop = document.getElementById('card-hover');
if (!pop) {
pop = document.createElement('div');
pop.id = 'card-hover';
pop.className = 'card-hover';
var inner = document.createElement('div');
inner.className = 'card-hover-inner';
var img = document.createElement('img');
img.alt = 'Card preview';
var img2 = document.createElement('img');
img2.alt = 'Card preview'; img2.style.display = 'none';
var meta = document.createElement('div');
meta.className = 'card-meta';
var dual = document.createElement('div');
dual.className = 'dual';
dual.appendChild(img);
dual.appendChild(img2);
inner.appendChild(dual);
inner.appendChild(meta);
pop.appendChild(inner);
document.body.appendChild(pop);
}
return pop;
}
var cardPop = ensureCard();
// Card image URL builder with synergy annotation stripping
var PREVIEW_VERSIONS = ['normal','large'];
function normalizeCardName(raw){
if(!raw) return raw;
@ -340,132 +309,10 @@
});
}
function positionCard(e) {
var x = e.clientX + 16, y = e.clientY + 16;
cardPop.style.display = 'block';
cardPop.style.left = x + 'px';
cardPop.style.top = y + 'px';
var rect = cardPop.getBoundingClientRect();
var vw = window.innerWidth || document.documentElement.clientWidth;
var vh = window.innerHeight || document.documentElement.clientHeight;
if (x + rect.width + 8 > vw) cardPop.style.left = (e.clientX - rect.width - 16) + 'px';
if (y + rect.height + 8 > vh) cardPop.style.top = (e.clientY - rect.height - 16) + 'px';
}
function attachCardHover() {
if (window.__disableLegacyCardHover) return; // short-circuit legacy system
document.querySelectorAll('[data-card-name]').forEach(function(el) {
if (el.__cardHoverBound) return; // avoid duplicate bindings
el.__cardHoverBound = true;
el.addEventListener('mouseenter', function(e) {
var img = cardPop.querySelector('.card-hover-inner img');
var img2 = cardPop.querySelector('.card-hover-inner .dual img:nth-child(2)');
if (img2) img2.style.display = 'none';
var dualNode = cardPop.querySelector('.card-hover-inner .dual');
if (img2) { img2.style.display = 'none'; }
if (dualNode) { dualNode.classList.remove('combo','two-faced'); }
var meta = cardPop.querySelector('.card-meta');
var name = el.getAttribute('data-card-name') || '';
var vi = 0; // always start at 'normal' on hover
img.src = buildCardUrl(name, PREVIEW_VERSIONS[vi], false, 'front');
// Bind a one-off error handler per enter to try fallbacks
var triedNoCache = false;
function onErr(){
if (vi < PREVIEW_VERSIONS.length - 1){ vi += 1; img.src = buildCardUrl(name, PREVIEW_VERSIONS[vi], false, 'front'); }
else if (!triedNoCache){ triedNoCache = true; img.src = buildCardUrl(name, PREVIEW_VERSIONS[vi], true, 'front'); }
else { img.removeEventListener('error', onErr); }
}
img.addEventListener('error', onErr, { once:false });
img.addEventListener('load', function onOk(){ img.removeEventListener('load', onOk); img.removeEventListener('error', onErr); });
// Attempt to load back face (double-faced / transform). If it fails, we silently hide.
if (img2) {
img2.style.display = 'none';
var backTriedNoCache = false;
var backIdx = 0;
function backErr(){
if (backIdx < PREVIEW_VERSIONS.length - 1){
backIdx += 1; img2.src = buildCardUrl(name, PREVIEW_VERSIONS[backIdx], false, 'back');
} else if (!backTriedNoCache){
backTriedNoCache = true; img2.src = buildCardUrl(name, PREVIEW_VERSIONS[backIdx], true, 'back');
} else {
img2.removeEventListener('error', backErr); img2.style.display='none';
}
}
function backOk(){ img2.removeEventListener('error', backErr); img2.removeEventListener('load', backOk); if (dualNode) dualNode.classList.add('two-faced'); img2.style.display=''; }
img2.addEventListener('error', backErr, { once:false });
img2.addEventListener('load', backOk, { once:false });
img2.src = buildCardUrl(name, PREVIEW_VERSIONS[0], false, 'back');
}
var role = el.getAttribute('data-role') || '';
var rawTags = el.getAttribute('data-tags') || '';
var overlapsRaw = el.getAttribute('data-overlaps') || '';
// Clean and split tags into an array; remove brackets and quotes
var tags = rawTags
.replace(/[\[\]\u2018\u2019'\u201C\u201D"]/g,'')
.split(/\s*,\s*/)
.filter(function(t){ return t && t.trim(); });
var overlaps = overlapsRaw.split(/\s*,\s*/).filter(function(t){ return t; });
var overlapSet = new Set(overlaps);
var highlightOverlapsInList = overlaps.length === 0;
if (role || (tags && tags.length)) {
var html = '';
if (role) {
html += '<div class="line"><span class="label">Role</span>' + role.replace(/</g,'&lt;') + '</div>';
}
if (tags && tags.length) {
html += '<div class="line"><span class="label themes-label">Themes</span><ul class="themes-list">' + tags.map(function(t){ var safe=t.replace(/</g,'&lt;'); var isOverlap = overlapSet.has(t); return '<li' + ((highlightOverlapsInList && isOverlap) ? ' class="overlap"' : '') + '>' + safe + '</li>'; }).join('') + '</ul></div>';
if (overlaps.length){
html += '<div class="line" style="margin-top:4px;"><span class="label" title="Themes shared with preview selection">Overlaps</span>' + overlaps.map(function(o){ return '<span class="ov-chip">'+o.replace(/</g,'&lt;')+'</span>'; }).join(' ') + '</div>';
}
}
meta.innerHTML = html;
meta.style.display = '';
} else {
meta.style.display = 'none';
meta.innerHTML = '';
}
positionCard(e);
});
el.addEventListener('mousemove', positionCard);
el.addEventListener('mouseleave', function() { cardPop.style.display = 'none'; });
});
// Dual-card hover for combo rows
document.querySelectorAll('[data-combo-names]').forEach(function(el){
if (el.__comboHoverBound) return; el.__comboHoverBound = true;
el.addEventListener('mouseenter', function(e){
var namesAttr = el.getAttribute('data-combo-names') || '';
var parts = namesAttr.split('||');
var a = (parts[0]||'').trim(); var b = (parts[1]||'').trim();
if (!a || !b) return;
var img = cardPop.querySelector('.card-hover-inner img');
var img2 = cardPop.querySelector('.card-hover-inner .dual img:nth-child(2)');
var meta = cardPop.querySelector('.card-meta');
if (img2) img2.style.display = '';
var vi1 = 0, vi2 = 0; var triedNoCache1 = false, triedNoCache2 = false;
img.src = buildCardUrl(a, PREVIEW_VERSIONS[vi1], false);
img.src = buildCardUrl(a, PREVIEW_VERSIONS[vi1], false, 'front');
img2.src = buildCardUrl(b, PREVIEW_VERSIONS[vi2], false, 'front');
var dualNode = cardPop.querySelector('.card-hover-inner .dual');
if (dualNode){ dualNode.classList.add('combo'); dualNode.classList.remove('two-faced'); }
function err1(){ if (vi1 < PREVIEW_VERSIONS.length - 1){ vi1 += 1; img.src = buildCardUrl(a, PREVIEW_VERSIONS[vi1], false);} else if (!triedNoCache1){ triedNoCache1 = true; img.src = buildCardUrl(a, PREVIEW_VERSIONS[vi1], true);} else { img.removeEventListener('error', err1);} }
function err2(){ if (vi2 < PREVIEW_VERSIONS.length - 1){ vi2 += 1; img2.src = buildCardUrl(b, PREVIEW_VERSIONS[vi2], false);} else if (!triedNoCache2){ triedNoCache2 = true; img2.src = buildCardUrl(b, PREVIEW_VERSIONS[vi2], true);} else { img2.removeEventListener('error', err2);} }
img.addEventListener('error', err1, { once:false });
img2.addEventListener('error', err2, { once:false });
img.addEventListener('load', function on1(){ img.removeEventListener('load', on1); img.removeEventListener('error', err1); });
img2.addEventListener('load', function on2(){ img2.removeEventListener('load', on2); img2.removeEventListener('error', err2); });
meta.style.display = 'none'; meta.innerHTML = '';
positionCard(e);
});
el.addEventListener('mousemove', positionCard);
el.addEventListener('mouseleave', function(){ cardPop.style.display='none'; });
});
}
// Expose re-init functions globally for dynamic content
window.attachCardHover = attachCardHover;
window.bindAllCardImageRetries = bindAllCardImageRetries;
attachCardHover();
bindAllCardImageRetries();
document.addEventListener('htmx:afterSwap', function() { attachCardHover(); bindAllCardImageRetries(); });
// Expose image retry binding globally for dynamic content
window.bindAllCardImageRetries = bindAllCardImageRetries;
bindAllCardImageRetries();
document.addEventListener('htmx:afterSwap', bindAllCardImageRetries);
})();
</script>
<script>
@ -765,8 +612,6 @@
<script>
// Global delegated hover card panel initializer (ensures functionality after HTMX swaps)
(function(){
// Disable legacy multi-element hover in favor of single unified panel
window.__disableLegacyCardHover = true;
// Global delegated curated-only & reasons controls (works after HTMX swaps and inline render)
function findPreviewRoot(el){ return el.closest('.preview-modal-content.theme-preview-expanded') || el.closest('.preview-modal-content'); }
function applyCuratedFor(root){