MediaWiki:Common.js

From AnarchyMU Wiki
Revision as of 10:58, 20 March 2026 by Admin (talk | contribs)

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.
/* Any JavaScript here will be loaded for all users on every page load. */
// Ensures class card images use the intended foreground image if data-src is present.
(function () {
  function applyDataSrc() {
    var images = document.querySelectorAll('.mw-card-image img[data-src]');
    for (var i = 0; i < images.length; i++) {
      var img = images[i];
      var dataSrc = img.getAttribute('data-src');
      if (dataSrc && img.getAttribute('src') !== dataSrc) {
        img.setAttribute('src', dataSrc);
      }
    }
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', applyDataSrc);
  } else {
    applyDataSrc();
  }
})();

/* Update 047: robust nested Stage dropdown - v7 with precise click zones */
(function () {
  function textOf(el) {
    return (el && el.textContent ? el.textContent : '').replace(/\s+/g, ' ').trim();
  }

  function norm(s) {
    return (s || '').replace(/\s+/g, ' ').trim().toLowerCase();
  }

  function urlOf(link) {
    if (!link) return '';
    var href = link.getAttribute('href') || '';
    var title = link.getAttribute('title') || '';
    var parts = href.split('/');
    var page = parts[parts.length - 1] || '';
    return page || title;
  }

  function isStageLabel(label) {
    return /^stage\s+[1-4]$/i.test(label);
  }

  function getStageNumber(label) {
    var m = label.match(/^stage\s+([1-4])$/i);
    return m ? m[1] : null;
  }

  function isMiniLabel(label) {
    return /^mini\s+stage\s+\d+$/i.test(label);
  }

  function isMiniLabelForStage(url, label, stageNum) {
    if (!isMiniLabel(label)) return false;

    if (stageNum === '1') {
      return !/^Stage_\d+_Mini_Stage/.test(url);
    } else {
      var pattern = new RegExp('^Stage_' + stageNum + '_Mini_Stage');
      return pattern.test(url);
    }
  }

  function directLink(li) {
    if (!li || !li.childNodes) return null;
    var i;
    for (i = 0; i < li.childNodes.length; i++) {
      var n = li.childNodes[i];
      if (n && n.nodeType === 1 && n.tagName && n.tagName.toLowerCase() === 'a') {
        return n;
      }
    }
    return null;
  }

  function childLis(container) {
    if (!container || !container.children) return [];
    var out = [];
    var i;
    for (i = 0; i < container.children.length; i++) {
      var c = container.children[i];
      if (c && c.tagName && c.tagName.toLowerCase() === 'li') {
        out.push(c);
      }
    }
    return out;
  }

  function scoreContainer(container) {
    var lis = childLis(container);
    if (!lis.length) return 0;

    var stageCount = 0;
    var miniCount = 0;
    var overviewCount = 0;
    var i;

    for (i = 0; i < lis.length; i++) {
      var label = norm(textOf(directLink(lis[i])));
      if (/^stage\s+[1-4]$/i.test(label)) stageCount++;
      if (/^mini\s+stage\s+\d+$/i.test(label)) miniCount++;
      if (label === 'overview') overviewCount++;
    }

    if (stageCount >= 4 && miniCount >= 8) {
      return (stageCount * 100) + miniCount + (overviewCount ? 10 : 0);
    }
    return 0;
  }

  function findStagesListContainer() {
    var candidates = document.querySelectorAll('ul, ol');
    var best = null;
    var bestScore = 0;
    var i;

    for (i = 0; i < candidates.length; i++) {
      var score = scoreContainer(candidates[i]);
      if (score > bestScore) {
        bestScore = score;
        best = candidates[i];
      }
    }

    return best;
  }

  function makeToggle(stageLi, toggleSpan, stageNum) {
    return function (ev) {
      // Prevent event from bubbling up to parent LI or window
      ev.preventDefault();
      ev.stopPropagation();
      ev.stopImmediatePropagation();

      var open = stageLi.classList.toggle('stages-open');
      toggleSpan.textContent = open ? '▾' : '▸';
      console.log('[UPDATE-047] Stage ' + stageNum + ' toggle: ' + (open ? 'OPENED' : 'CLOSED'));
      return false;
    };
  }

  function applyNestedStages() {
    var list = findStagesListContainer();
    if (!list || list.dataset.stagesNestedV7Applied === '1') {
      return;
    }

    var items = childLis(list);
    if (!items.length) return;

    var rebuilt = [];
    var currentStageLi = null;
    var currentMiniUl = null;
    var currentStageNum = null;
    var i;

    for (i = 0; i < items.length; i++) {
      var li = items[i];
      var link = directLink(li);
      if (!link) {
        rebuilt.push(li.cloneNode(true));
        continue;
      }

      var label = textOf(link);
      var labelNorm = norm(label);
      var url = urlOf(link);

      if (isStageLabel(labelNorm)) {
        var stageNum = getStageNumber(labelNorm);
        currentStageNum = stageNum;

        currentStageLi = li.cloneNode(true);
        currentStageLi.className = (currentStageLi.className ? currentStageLi.className + ' ' : '') + 'stages-inner-parent stages-inner-stage-' + stageNum;
        currentStageLi.setAttribute('data-stage-num', stageNum);

        var stageLink = directLink(currentStageLi);
        if (stageLink) {
          stageLink.style.fontWeight = 'bold';
          stageLink.href = '#';

          // Create toggle span - very narrow and precise
          var toggleSpan = document.createElement('span');
          toggleSpan.className = 'stages-inner-toggle-icon';
          toggleSpan.setAttribute('data-stage-toggle', stageNum);
          toggleSpan.textContent = '▸';
          toggleSpan.style.display = 'inline-block';
          toggleSpan.style.width = '16px';
          toggleSpan.style.height = '16px';
          toggleSpan.style.marginRight = '4px';
          toggleSpan.style.color = '#f3b549';
          toggleSpan.style.cursor = 'pointer';
          toggleSpan.style.fontWeight = 'bold';
          toggleSpan.style.textAlign = 'center';
          toggleSpan.style.userSelect = 'none';

          var toggleHandler = makeToggle(currentStageLi, toggleSpan, stageNum);

          // Add click listener only to toggle span
          toggleSpan.addEventListener('click', toggleHandler, true);

          // Add click listener to link to also toggle
          stageLink.addEventListener('click', toggleHandler, true);

          stageLink.parentNode.insertBefore(toggleSpan, stageLink);
        }

        currentMiniUl = document.createElement('ul');
        currentMiniUl.className = 'stages-inner-submenu';
        currentMiniUl.setAttribute('data-stage-minis', stageNum);

        currentStageLi.appendChild(currentMiniUl);
        rebuilt.push(currentStageLi);
        continue;
      }

      if (isMiniLabel(labelNorm)) {
        if (currentMiniUl && currentStageNum) {
          var matches = isMiniLabelForStage(url, label, currentStageNum);
          if (matches) {
            currentMiniUl.appendChild(li.cloneNode(true));
            continue;
          }
        }
      }

      currentStageLi = null;
      currentMiniUl = null;
      currentStageNum = null;
      rebuilt.push(li.cloneNode(true));
    }

    while (list.firstChild) {
      list.removeChild(list.firstChild);
    }

    for (i = 0; i < rebuilt.length; i++) {
      list.appendChild(rebuilt[i]);
    }

    list.dataset.stagesNestedV7Applied = '1';
    console.log('[UPDATE-047] Applied nested stages v7. Rebuilt ' + rebuilt.length + ' items.');
  }

  function boot() {
    console.log('[UPDATE-047] Boot sequence starting v7...');
    applyNestedStages();
    window.setTimeout(function () {
      applyNestedStages();
    }, 350);
    window.setTimeout(function () {
      applyNestedStages();
    }, 900);
    window.setTimeout(function () {
      applyNestedStages();
    }, 1800);
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', boot);
  } else {
    boot();
  }
})();