MediaWiki:Common.js

From SWCCG Wiki
Revision as of 00:37, 24 September 2026 by Admin (talk | contribs) (Common.js: clear #swccg-card-zoom src before load so Firefox never flashes previous card)
Jump to navigation Jump to search

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/* Logo stays in the sidebar. Search sits at the left of the header.
   Card list: 200px thumbs for load; hover shows a fixed popup of the full 745px GEMP image.
   Chrome/Edge ignore src changes while srcset is set, so we never swap the thumb src.
   CardLink / #swccg-card-zoom: clear src and hide until the new image loads so Firefox
   never flashes the previous card art. */
(function () {
  function originalFromImg(img) {
    var src = img.getAttribute('src') || img.src || '';
    var ss = img.getAttribute('srcset') || '';
    var m = src.match(/\/images\/thumb\/([^/]+\/[^/]+\/[^/?#]+)\/\d+px-/);
    if (m) {
      return '/images/' + m[1];
    }
    m = ss.match(/\/images\/thumb\/([^/]+\/[^/]+\/[^/?#]+)\//);
    if (m) {
      return '/images/' + m[1];
    }
    m = src.match(/\/images\/[^/]+\/[^/]+\/Premiere-[LD]-[^/?#]+/i);
    if (m) {
      return m[0];
    }
    return src.split(' ')[0];
  }

  function ensureZoomPop() {
    var pop = document.getElementById('swccg-card-zoom');
    if (!pop) {
      pop = document.createElement('img');
      pop.id = 'swccg-card-zoom';
      pop.alt = '';
      document.body.appendChild(pop);
    }
    return pop;
  }

  function placeZoom(pop, rect) {
    var w = 450;
    var h = 630;
    var left = rect.right + 10;
    if (left + w > window.innerWidth - 8) {
      left = Math.max(8, rect.left - w - 10);
    }
    var top = rect.top;
    if (top + h > window.innerHeight - 8) {
      top = Math.max(8, window.innerHeight - h - 8);
    }
    pop.style.left = left + 'px';
    pop.style.top = top + 'px';
  }

  /** Show full-size art without flashing the previously loaded card (Firefox). */
  function showZoom(pop, full, rect) {
    if (!full) {
      return;
    }
    placeZoom(pop, rect);
    var cur = pop.getAttribute('src') || '';
    if (cur === full && pop.complete && pop.naturalWidth > 0) {
      pop.classList.add('is-on');
      return;
    }
    pop.classList.remove('is-on');
    pop.removeAttribute('src');
    var gen = (parseInt(pop.getAttribute('data-zoom-gen') || '0', 10) || 0) + 1;
    pop.setAttribute('data-zoom-gen', String(gen));
    function reveal() {
      if (pop.getAttribute('data-zoom-gen') !== String(gen)) {
        return;
      }
      if (pop.naturalWidth > 0) {
        pop.classList.add('is-on');
      }
    }
    pop.onload = reveal;
    pop.onerror = function () {
      if (pop.getAttribute('data-zoom-gen') === String(gen)) {
        pop.classList.remove('is-on');
      }
    };
    pop.src = full;
    if (pop.complete) {
      reveal();
    }
  }

  function hideZoom(pop) {
    pop.classList.remove('is-on');
  }

  function bindCardLinks(root) {
    var pop = ensureZoomPop();
    var nodes = (root || document).querySelectorAll('span.swccg-card-link[data-card-image]');
    for (var i = 0; i < nodes.length; i++) {
      if (nodes[i].getAttribute('data-zoom-bound')) {
        continue;
      }
      nodes[i].setAttribute('data-zoom-bound', '1');
      (function (el) {
        el.addEventListener('mouseenter', function () {
          showZoom(pop, el.getAttribute('data-card-image'), el.getBoundingClientRect());
        });
        el.addEventListener('mouseleave', function () {
          hideZoom(pop);
        });
      })(nodes[i]);
    }
  }

  function bindZoom(root) {
    var pop = ensureZoomPop();
    var links = (root || document).querySelectorAll('table.card-thumbs a, .card-portrait a');
    for (var i = 0; i < links.length; i++) {
      if (links[i].getAttribute('data-zoom-bound')) {
        continue;
      }
      links[i].setAttribute('data-zoom-bound', '1');
      (function (a) {
        var img = a.querySelector('img');
        if (!img) {
          return;
        }
        a.addEventListener('mouseenter', function () {
          showZoom(pop, originalFromImg(img), img.getBoundingClientRect());
        });
        a.addEventListener('mouseleave', function () {
          hideZoom(pop);
        });
      })(links[i]);
    }
  }

  function moveSearch() {
    var search = document.getElementById('p-search');
    var head = document.getElementById('mw-head');
    if (search && head && search.parentNode !== head) {
      head.insertBefore(search, head.firstChild);
    }
  }

  function start() {
    moveSearch();
    bindZoom(document);
    bindCardLinks(document);
  }

  if (window.mw && mw.hook) {
    mw.hook('wikipage.content').add(function () {
      start();
    });
  }
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', start);
  } else {
    start();
  }
})();