Jump to content

MediaWiki:Common.js: Difference between revisions

From Doom Relics
No edit summary
Tag: Reverted
No edit summary
Tag: Reverted
Line 118: Line 118:
   if (sp !== 'FormEdit' && sp !== 'FormStart') return;
   if (sp !== 'FormEdit' && sp !== 'FormStart') return;


   // Track which image slot user is filling
   const IMG_SELECTOR = 'input[name^="Relic[img"]';
   let activeImgName = null;
   let activeId = null;
  let baseline = new Map();
  let timer = null;


   // When user focuses an img field, remember it
   function snapshot() {
  $content.on('focus click', 'input[name^="Relic[img"]', function () {
    baseline.clear();
    activeImgName = this.getAttribute('name'); // e.g. Relic[img3]
    $content.find(IMG_SELECTOR).each(function () {
  });
      baseline.set(this, this.value || '');
    });
  }


   // Convenience: clicking "Upload N" next to a field sets that field active
   function enforce() {
  $content.on('click', 'a', function () {
     if (!activeId) return;
    const txt = ($(this).text() || '').trim().toLowerCase();
     if (!txt.startsWith('upload')) return;


     const $row = $(this).closest('tr');
     $content.find(IMG_SELECTOR).each(function () {
    const $input = $row.find('input[name^="Relic[img"]').first();
      const el = this;
    if ($input.length) {
       const prev = baseline.get(el) ?? '';
       activeImgName = $input.attr('name');
       const now = el.value || '';
       $input.trigger('focus');
    }
  });


  // If we land on a File: page right after upload, show a one-click "Copy filename" bar.
      // Only allow the active input to change; lock all others
  // (User clicks, it copies filename; then they paste into the active img field.)
      if (el.id === activeId) {
  // This keeps things simple + reliable even on shared hosting.
        // Update baseline for active field only
  if (mw.config.get('wgCanonicalNamespace') === 6) { // File namespace
        baseline.set(el, now);
    const title = mw.config.get('wgTitle'); // filename without "File:"
       } else {
    const $bar = $('<div style="position:sticky;top:0;z-index:9999;padding:10px;margin:0 0 10px 0;border:1px solid rgba(255,120,0,.35);background:rgba(0,0,0,.65);border-radius:12px;">' +
        if (now !== prev) {
       '<b>Uploaded:</b> ' + title +
          el.value = prev;
      ' <button id="copy-file-title" style="margin-left:10px;">Copy filename</button>' +
        }
      '</div>');
       }
    $('#mw-content-text').prepend($bar);
 
    $('#copy-file-title').on('click', function () {
      navigator.clipboard.writeText(title);
      $(this).text('Copied!');
       setTimeout(() => $(this).text('Copy filename'), 1200);
     });
     });
   }
   }
  // When user clicks PF upload link, set the active input and lock others for 20 seconds
  $content.on('mousedown click', 'a.pf_uploadable', function () {
    activeId = this.getAttribute('data-inputid'); // e.g. input_8
    if (!activeId) return;
    snapshot();
    // Focus the correct field
    const target = document.getElementById(activeId);
    if (target) { target.focus(); target.click(); }
    // Start enforcement loop
    if (timer) clearInterval(timer);
    timer = setInterval(enforce, 150);
    // Stop after 20 seconds
    setTimeout(function () {
      if (timer) clearInterval(timer);
      timer = null;
      activeId = null;
    }, 20000);
  });
  // Also enforce on any input/change events
  $content.on('input change', IMG_SELECTOR, function () {
    enforce();
  });
});
});

Revision as of 15:13, 25 December 2025

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

// Vector 2022: pin main menu for logged-out users on desktop
if (!mw.config.get('wgUserName') && window.matchMedia('(min-width: 1120px)').matches) {
  const observer = new MutationObserver((_, obs) => {
    if (document.documentElement.classList.contains('vector-animations-ready')) {
      const pin = document.querySelector('[data-event-name="pinnable-header.vector-main-menu.pin"]');
      if (pin) pin.click();
      obs.disconnect();
    }
  });
  observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] });
}
// Remove "Main menu" headings/labels injected by Vector/Vector 2022 (works across variants)
(function () {
  function killMainMenuText(root = document) {
    // Look for common heading/label elements
    const candidates = root.querySelectorAll(
      '#vector-main-menu, #vector-main-menu-pinned-container, #mw-panel, nav.vector-main-menu, #vector-main-menu-dropdown'
    );

    candidates.forEach(container => {
      // Remove elements whose visible text is exactly "Main menu"
      container.querySelectorAll('*').forEach(el => {
        const txt = (el.textContent || '').trim();
        if (txt === 'Main menu') {
          el.style.display = 'none';
        }
        // Also catch the longer hint text variants
        if (txt.toLowerCase().includes('main menu has moved here')) {
          el.style.display = 'none';
        }
      });
    });
  }

  // Run now, on load, and after Vector finishes UI init
  killMainMenuText();
  window.addEventListener('load', () => killMainMenuText());

  const obs = new MutationObserver(() => killMainMenuText());
  obs.observe(document.documentElement, { childList: true, subtree: true });
})();
// DOOM ARCHIVES header: inject above your Doom Titles links (guaranteed)
(function () {
  const HEADER_CLASS = 'doom-archives-header';

  function styleHeader(header) {
    header.style.display = 'block';
    header.style.width = '100%';
    header.style.boxSizing = 'border-box';
    header.style.margin = '10px 0 10px';
    header.style.padding = '12px 14px';
    header.style.background = 'rgba(0,0,0,0.75)';
    header.style.border = '1px solid #3a0000';
    header.style.borderRadius = '12px';
    header.style.boxShadow = 'inset 0 0 20px rgba(180,0,0,0.30), 0 0 8px rgba(0,0,0,0.8)';
    header.style.color = '#f5c542';
    header.style.fontWeight = '900';
    header.style.letterSpacing = '0.22em';
    header.style.textTransform = 'uppercase';
    header.style.textAlign = 'center';
    header.style.fontFamily = "'Bebas Neue', Arial, sans-serif";
    header.style.textShadow = '0 0 3px rgba(245,197,66,0.35)';
    header.style.fontSize = '22px';
  }

  function findAnchor() {
    // Use a link you KNOW exists in your sidebar
    return (
      document.querySelector('a[href*="Category:Doom_(1993)"]') ||
      document.querySelector('a[href*="Category:Doom_II"]') ||
      document.querySelector('a[href*="Category:Doom_3"]') ||
      document.querySelector('a[href*="Category:Doom_Eternal"]')
    );
  }

  function ensureHeader() {
    const a = findAnchor();
    if (!a) return;

    // Find the menu content container that holds the link list
    const menuContent =
      a.closest('.vector-menu-content') ||
      a.closest('ul') ||
      a.parentElement;

    if (!menuContent) return;

    // Avoid duplicates
    if (menuContent.querySelector('.' + HEADER_CLASS)) return;

    const header = document.createElement('div');
    header.className = HEADER_CLASS;
    header.textContent = 'DOOM RELICS';
    styleHeader(header);

    // Insert header before the first list item / first link area
    menuContent.insertBefore(header, menuContent.firstChild);
  }

  function run() {
    ensureHeader();
    setTimeout(ensureHeader, 150);
    setTimeout(ensureHeader, 600);
    setTimeout(ensureHeader, 1200);
  }

  // Run now + keep alive if Vector re-renders
  run();
  window.addEventListener('load', run);

  const obs = new MutationObserver(() => ensureHeader());
  obs.observe(document.documentElement, { childList: true, subtree: true });
})();
mw.hook('wikipage.content').add(function ($content) {
  const sp = mw.config.get('wgCanonicalSpecialPageName');
  if (sp !== 'FormEdit' && sp !== 'FormStart') return;

  const IMG_SELECTOR = 'input[name^="Relic[img"]';
  let activeId = null;
  let baseline = new Map();
  let timer = null;

  function snapshot() {
    baseline.clear();
    $content.find(IMG_SELECTOR).each(function () {
      baseline.set(this, this.value || '');
    });
  }

  function enforce() {
    if (!activeId) return;

    $content.find(IMG_SELECTOR).each(function () {
      const el = this;
      const prev = baseline.get(el) ?? '';
      const now = el.value || '';

      // Only allow the active input to change; lock all others
      if (el.id === activeId) {
        // Update baseline for active field only
        baseline.set(el, now);
      } else {
        if (now !== prev) {
          el.value = prev;
        }
      }
    });
  }

  // When user clicks PF upload link, set the active input and lock others for 20 seconds
  $content.on('mousedown click', 'a.pf_uploadable', function () {
    activeId = this.getAttribute('data-inputid'); // e.g. input_8
    if (!activeId) return;

    snapshot();

    // Focus the correct field
    const target = document.getElementById(activeId);
    if (target) { target.focus(); target.click(); }

    // Start enforcement loop
    if (timer) clearInterval(timer);
    timer = setInterval(enforce, 150);

    // Stop after 20 seconds
    setTimeout(function () {
      if (timer) clearInterval(timer);
      timer = null;
      activeId = null;
    }, 20000);
  });

  // Also enforce on any input/change events
  $content.on('input change', IMG_SELECTOR, function () {
    enforce();
  });
});