Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

MediaWiki:Common.js: Difference between revisions

MediaWiki interface page
No edit summary
No edit summary
Line 80: Line 80:
       if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); window.location.href = link.href; }
       if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); window.location.href = link.href; }
     });
     });
  });
  /* Make gallery cards clickable */
  document.querySelectorAll('.gallerybox').forEach(function (box) {
    var link = box.querySelector('a[href]');
    if (!link) return;
    box.style.cursor = 'pointer';
    box.addEventListener('click', function () { window.location.href = link.href; });
   });
   });



Revision as of 16:14, 6 March 2026

/* CrabCodex — Minimal global JS. No external libs. Optional UX enhancements. */
(function () {
  'use strict';

  /* Smooth scroll for same-page anchors */
  document.querySelectorAll('a[href^="#"]').forEach(function (a) {
    var id = a.getAttribute('href').slice(1);
    if (!id) return;
    var target = document.getElementById(id);
    if (target && a.getAttribute('href') !== '#') {
      a.addEventListener('click', function (e) {
        if (target) {
          e.preventDefault();
          target.scrollIntoView({ behavior: 'smooth', block: 'start' });
        }
      });
    }
  });

  /* TOC: collapsible on small screens, optional sticky + active link */
  var toc = document.querySelector('.toc') || document.querySelector('#toc') || document.querySelector('.vector-toc');
  if (toc) {
    var titleEl = toc.querySelector('.toctitle') || toc.querySelector('div:first-child') || toc.firstElementChild;
    if (titleEl && window.matchMedia('(max-width: 767px)').matches) {
      var wrapper = document.createElement('div');
      wrapper.className = 'cc-toc-mobile';
      toc.parentNode.insertBefore(wrapper, toc);
      wrapper.appendChild(toc);
      var btn = document.createElement('button');
      btn.type = 'button';
      btn.className = 'cc-toc-toggle';
      btn.setAttribute('aria-expanded', 'false');
      btn.textContent = titleEl.textContent || 'Contents';
      btn.style.cssText = 'width:100%;padding:12px 16px;text-align:left;font-weight:700;background:var(--cc-bg-elevated);border:1px solid var(--cc-border);border-radius:8px;cursor:pointer;color:inherit;';
      toc.style.display = 'none';
      wrapper.insertBefore(btn, toc);
      btn.addEventListener('click', function () {
        var open = toc.style.display !== 'none';
        toc.style.display = open ? 'none' : 'block';
        btn.setAttribute('aria-expanded', open ? 'false' : 'true');
      });
    }
    if (window.matchMedia('(min-width: 1024px)').matches) {
      toc.classList.add('sticky');
    }
  }

  /* Optional: highlight TOC link for current section (on scroll) */
  var tocLinks = document.querySelectorAll('.toc a[href^="#"], #toc a[href^="#"], .vector-toc a[href^="#"]');
  if (tocLinks.length && 'IntersectionObserver' in window) {
    var headings = [];
    tocLinks.forEach(function (link) {
      var id = (link.getAttribute('href') || '').slice(1);
      var el = document.getElementById(id);
      if (el) headings.push({ id: id, el: el, link: link });
    });
    var observer = new IntersectionObserver(
      function (entries) {
        entries.forEach(function (entry) {
          if (!entry.isIntersecting) return;
          var id = entry.target.id;
          tocLinks.forEach(function (l) { l.classList.remove('cc-toc-active'); });
          var active = document.querySelector('.toc a[href="#' + id + '"], #toc a[href="#' + id + '"]');
          if (active) active.classList.add('cc-toc-active');
        });
      },
      { rootMargin: '-80px 0px -60% 0px', threshold: 0 }
    );
    headings.forEach(function (h) { observer.observe(h.el); });
  }
  /* Make cards clickable by using first link inside */
  document.querySelectorAll('.cc-card, .cc-strategy-card').forEach(function (card) {
    if (card.tagName.toLowerCase() === 'a') return;
    var link = card.querySelector('a[href]');
    if (!link) return;
    card.setAttribute('role', 'link');
    card.tabIndex = 0;
    card.addEventListener('click', function () { window.location.href = link.href; });
    card.addEventListener('keydown', function (e) {
      if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); window.location.href = link.href; }
    });
  });

  /* Make gallery cards clickable */
  document.querySelectorAll('.gallerybox').forEach(function (box) {
    var link = box.querySelector('a[href]');
    if (!link) return;
    box.style.cursor = 'pointer';
    box.addEventListener('click', function () { window.location.href = link.href; });
  });

  /* SEO + Social meta */
  var head = document.head;
  function setMeta(name, content, prop) {
    var sel = prop ? 'meta[property="' + name + '"]' : 'meta[name="' + name + '"]';
    var el = document.querySelector(sel);
    if (!el) {
      el = document.createElement('meta');
      if (prop) el.setAttribute('property', name);
      else el.setAttribute('name', name);
      head.appendChild(el);
    }
    el.setAttribute('content', content);
  }
  setMeta('description', 'CrabCodex — the community wiki for Everything is Crab. Evolutions, bestiary, genetics, POIs, mushrooms, and strategy guides.', false);
  setMeta('og:title', 'CrabCodex — Everything is Crab Wiki', true);
  setMeta('og:description', 'Evolutions, bestiary, genetics, POIs, mushrooms, and strategy guides for Everything is Crab.', true);
  setMeta('og:image', '/wiki/Special:FilePath/og_image.png', true);
  setMeta('twitter:card', 'summary_large_image', false);
  setMeta('twitter:image', '/wiki/Special:FilePath/og_image.png', false);

  function setLink(rel, href, type) {
    var el = document.querySelector('link[rel="' + rel + '"]');
    if (!el) {
      el = document.createElement('link');
      el.setAttribute('rel', rel);
      head.appendChild(el);
    }
    el.setAttribute('href', href);
    if (type) el.setAttribute('type', type);
  }
  setLink('icon', '/favicon.ico', 'image/x-icon');
  setLink('apple-touch-icon', '/apple-touch-icon.png');
  setLink('manifest', '/site.webmanifest');

  /* Site footer */
  var footer = document.getElementById('mw-footer') || document.querySelector('footer');
  if (footer && !document.querySelector('.cc-site-footer')) {
    var wrap = document.createElement('div');
    wrap.className = 'cc-site-footer';
    wrap.innerHTML = [
      '<img src="/wiki/Special:FilePath/logo_crabcodex.png" alt="CrabCodex" style="height:22px;vertical-align:middle;margin-right:8px;">',
      '<strong>CrabCodex</strong> — the community guide to <em>Everything is Crab</em>.',
      '<br><span class="cc-footer-tagline">Evolve. Explore. Share.</span>',
      '<br><a href="/wiki/CrabCodex:About">About</a> · <a href="/wiki/CrabCodex:Privacy_policy">Privacy</a> · <a href="/wiki/CrabCodex:General_disclaimer">Disclaimer</a>',
      '<br><a href="https://discord.gg/suWDjZZb9t" rel="nofollow"><img src="/wiki/Special:FilePath/discord_icon.png" alt="Discord" style="height:16px;vertical-align:middle;margin-right:6px;">CrabCodex Discord</a> · <a href="https://store.steampowered.com/app/3526710/Everything_is_Crab_The_Animal_Evolution_Roguelite" rel="nofollow">Steam</a>'
    ].join('');
    footer.appendChild(wrap);
  }
})();