MediaWiki:Common.js: Difference between revisions

From Fate/Starry Night Wiki
Jump to navigation Jump to search
No edit summary
Tag: Reverted
No edit summary
Tag: Manual revert
Line 8: Line 8:
   if (!toc) return;
   if (!toc) return;
    
    
 
  // Horizontal pin helper
  function pinHorizontalPosition() {
    const rect = toc.getBoundingClientRect();
    toc.style.setProperty('--toc-left', rect.left + 'px');
    toc.style.left = rect.left + 'px';
    toc.style.width = rect.width + 'px';
  }


   // Avoid duplicating if MW re-renders content
   // Avoid duplicating if MW re-renders content

Revision as of 13:53, 10 February 2026

/* Any JavaScript here will be loaded for all users on every page load. */

/*
  TOC - floating
 */
 mw.hook('wikipage.content').add(function () {
  const toc = document.getElementById('toc');
  if (!toc) return;
  
  // Horizontal pin helper
  function pinHorizontalPosition() {
    const rect = toc.getBoundingClientRect();
    toc.style.setProperty('--toc-left', rect.left + 'px');
    toc.style.left = rect.left + 'px';
    toc.style.width = rect.width + 'px';
  }

  // Avoid duplicating if MW re-renders content
  if (toc.querySelector('.toc-fold-btn')) return;

  // Insert fold button
  const btn = document.createElement('button');
  btn.type = 'button';
  btn.className = 'toc-fold-btn';
  btn.setAttribute('aria-expanded', 'true');
  btn.setAttribute('title', 'Hide table of contents');
  btn.textContent = '⟨⟨'; // folded indicator; we’ll flip it dynamically
  toc.prepend(btn);

  const STORAGE_KEY = 'mw_toc_folded';

  function setFolded(folded) {
    toc.classList.toggle('toc-folded', folded);
    btn.setAttribute('aria-expanded', String(!folded));
    btn.setAttribute('title', folded ? 'Show table of contents' : 'Hide table of contents');
    btn.textContent = folded ? '⟩⟩' : '⟨⟨';
    try { localStorage.setItem(STORAGE_KEY, folded ? '1' : '0'); } catch (e) {}
  }

  // Restore folded state
  let folded = false;
  try { folded = localStorage.getItem(STORAGE_KEY) === '1'; } catch (e) {}
  setFolded(folded);

  btn.addEventListener('click', function (e) {
    e.preventDefault();
    folded = !toc.classList.contains('toc-folded');
    setFolded(folded);
  });
  
  // Don't float if not using desktop
  if (window.innerWidth < 1200) return;
  const tocTop = toc.getBoundingClientRect().top + window.scrollY;
  
  // Floating trigger: only float after scrolling past original position
  function onScroll() {
    if (window.scrollY > tocTop) {
      toc.classList.add('toc-floating');
    } else {
      toc.classList.remove('toc-floating');
      // optional: when not floating, don’t keep it folded-looking
      toc.classList.remove('toc-folded');
      btn.setAttribute('aria-expanded', 'true');
      btn.setAttribute('title', 'Hide table of contents');
      btn.textContent = '⟨⟨';
    }
  }

  window.addEventListener('scroll', onScroll, { passive: true });
  onScroll();
});

// Prevent overlap with footer
const footer = document.querySelector('#footer');
const footerTop = footer.getBoundingClientRect().top + window.scrollY;
if (window.scrollY + toc.offsetHeight + 100 > footerTop) {
  toc.style.opacity = '0';
} else {
  toc.style.opacity = '1';
}