Tip of the day
Hunting activities that require inputs get bonuses from using FINE versions of them! Check the interface for what they give!

MediaWiki:Common.js

From Walkscape Walkthrough
Revision as of 13:30, 13 August 2026 by Bonez565 (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. */
/* VARIABLES ***********************************************************************************************************************/
var currentPageUrl = window.location.href;
var currentPageEditUrl = mw.util.getUrl(null, {
	action: 'edit'
});
var currentPageName = mw.util.getUrl(null, null).replace('/wiki/', '');
var currentPageNamespaceID = mw.config.get('wgNamespaceNumber');
//variables needed after page load
var buttons, contents, allLinks;
//variables needed for the infobutton
var infobutton, infopanel;
/* *********************************************************************************************************************************/
// Matomo
var _paq = window._paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
/*
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
  var u="https://matomo.tools.walkscape.app/";
  _paq.push(['setTrackerUrl', u+'matomo.php']);
  _paq.push(['setSiteId', '5']);
  var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
  g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})();
*/
/* sticky edit button */
// display the button only if #mw-content is present, if we are not in the edit mode, and if we're not in the Special: or Community: namespace
/*
if (document.body.contains(document.getElementById("mw-content")) && !currentPageUrl.includes("action=") && currentPageNamespaceID != -1 && currentPageNamespaceID != 3004)  {
document.getElementById("mw-content").insertAdjacentHTML('afterbegin', '<a href="https://wiki-temp.walkscape.app/' + currentPageEditUrl + '"><div id="custom-editbutton"><svg width="40" height="40" viewBox="-12 -10 50 50"><path d="M 20 2 L 26 8 L 8 26 L 2 26 L 2 20 Z M 16 6 L 22 12"></path></svg></div></a>');
}
*/
///////////////////////////////////////// ADDING THE INFO BUTTON
var infotitle = currentPageName + '/doc';
// add the info button ONLY when we use the edit mode now
if (document.body.contains(document.getElementById("mw-content")) && (currentPageUrl.includes("action=edit") || currentPageUrl.includes("action=submit"))) {
	mw.loader.using('mediawiki.api', function() {
		var api = new mw.Api();
		api.get({
			action: "query",
			titles: [infotitle],
		}).then(function(ret) {
			$.each(ret.query.pages, function() {
				if (this.missing !== "") {
					pageExists();
				}
			});
		});

		function pageExists() {
			api.get({
				action: 'parse',
				page: infotitle,
				contentmodel: 'wikitext'
			}).done(function(data) {
				InsertInfoPanel(data.parse.text['*']);
			});
		}
	});
}

function InsertInfoPanel(text) {
	//check which namespace we're in and adapt the text to it
	var infopanelTitle = 'Page';
	if (currentPageNamespaceID == 10) { //Template
		infopanelTitle = 'Template';
	} else if (currentPageNamespaceID == 828) { //Module
		infopanelTitle = 'Module';
	}
	// insert the panel and button
	document.getElementById("mw-content").insertAdjacentHTML('afterbegin', '<div id="custom-infobutton"></div><div id="custom-infopanel" style="display: none"><div id="custom-infopanel-title">' + infopanelTitle + ' Info</div><div id="custom-infopanel-content">' + text + '</div></div>');
	//set up containers
	infopanel = document.getElementById("custom-infopanel");
	infobutton = document.getElementById("custom-infobutton");
	//add an event listener to the button
	infobutton.addEventListener("click", infobuttonClicked);
}

function infobuttonClicked() {
	if (infopanel.style.display == 'none') {
		infopanel.style.display = 'block';
	} else {
		infopanel.style.display = 'none';
	}
}
/* rename the "DISCUSSION" talk page button to "DOCUMENTATION" */
//if there is such a button and we're in the Template: namespace
if (document.body.contains(document.getElementById("ca-talk")) && currentPageNamespaceID == 10) {
	document.getElementById("ca-talk").innerHTML = '<svg class="cosmos-button-icon" width="28" height="28" viewBox="-2 -2 20 20"><path d="M 4 2 Q 4 0 6 0 L 14 0 Q 16 0 16 2 L 8 2 Q 8 0 6 0 Q 4 0 4 2 L 4 12 Q 4 14 2 14 Q 0 14 0 12 L 2 12 L 0 12 Q 0 14 2 14 L 12 14 Q 14 14 14 12 L 14 4"></path></svg><span class="cosmos-button-text">Documentation</span>';
}
/* call specific functions when the page loads */
// old browsers or already loaded
if (document.readyState != "loading") AfterPageLoad();
// modern browsers
else if (document.addEventListener) document.addEventListener("DOMContentLoaded", AfterPageLoad);
/* FUNCTIONS **********************************************************************************************************************/
function AfterPageLoad() {
	StartTabs();
}
/* Tabs */
function StartTabs() {
	buttons = document.getElementsByClassName("tab-button");
	contents = document.getElementsByClassName("tab-content");
	if (buttons.length > 0) {
		clickfunction(buttons[0]);
		for (var i = 0; i < buttons.length; i++) {
			//console.log("Added Event Listener!");
			buttons[i].addEventListener("click", clickfunction);
		}
	}
}

function clickfunction(thing) {
	if (thing.id == null) {
		thing = this;
	}
	//buttons
	for (var i = 0; i < buttons.length; i++) {
		if (buttons[i].id == thing.id) {
			buttons[i].classList.remove("tab-disabled");
			buttons[i].classList.add("tab-active");
		} else {
			buttons[i].classList.remove("tab-active");
			buttons[i].classList.add("tab-disabled");
		}
	}
	//contents
	for (var i = 0; i < contents.length; i++) {
		if (contents[i].id == thing.id) {
			contents[i].style.display = 'block'
		} else {
			contents[i].style.display = 'none'
		}
	}
}

var resizeScheduled = false;

function scheduleRecalc(fn) {
  if (resizeScheduled) return;
  resizeScheduled = true;
  requestAnimationFrame(function () {
    resizeScheduled = false;
    fn();
  });
}

mw.hook('wikipage.content').add(function ($content) {
  $content.find('.tabberresize').each(function () {
    var $wrap = $(this);
    var wrapEl = this;
    var tabCount = $wrap.find('.tabber__tab').length;
	wrapEl.dataset.tabCount = String(tabCount);

    function setWidthImportant(px) {
      wrapEl.style.setProperty('width', px + 'px', 'important');
    }

    function recalc() {
      if (window.matchMedia('(max-width: 850px)').matches) {
        wrapEl.style.removeProperty('width');
        $wrap.css({ width: '100%', float: 'none', display: 'block' });
        return;
      }

      $wrap.css({
        float: 'right',
        display: 'inline-block',
        maxWidth: '100%'
      });

      // 1) Widest tab label
      var maxTab = 0;
      $wrap.find('.tabber__tab').each(function () {
        maxTab = Math.max(maxTab, Math.ceil(this.offsetWidth));
      });
      if (!maxTab) maxTab = 90;

      wrapEl.style.setProperty('--tab-w', maxTab + 'px');

      // 2) Widest article (prefer visible)
      var $section = $wrap.find('section.tabber__section').first();
      var $articles = $section.find('article');

      var $candidates = $articles.filter(':visible');
      if (!$candidates.length) {
        $candidates = $articles.filter('[aria-hidden="false"]');
      }
      if (!$candidates.length) {
        $candidates = $articles;
      }

      var maxArticleW = 0;
      $candidates.each(function () {
        maxArticleW = Math.max(
          maxArticleW,
          Math.ceil(Math.max(this.scrollWidth, this.offsetWidth))
        );
      });

      var target = Math.max(maxArticleW, maxTab * 3 + 12);
      setWidthImportant(target);
    }

    // Initial
    recalc();

    // Window resize
    $(window).on('resize', function () {
	  scheduleRecalc(recalc);
	});

    // React to tab changes / dynamic content
    if (window.ResizeObserver) {
      var ro = new ResizeObserver(recalc);
      $wrap.find('section.tabber__section article').each(function () {
        ro.observe(this);
      });
    }
  });
});

// Pet Sprite Animation
(function () {

	function startWalker(el) {
	  if (el.dataset.walkerApplied === '1') return;
	
      var speed =
        parseFloat(getComputedStyle(el).getPropertyValue('--walker-speed')) ||
        parseFloat(el.getAttribute('data-speed')) ||
        2;
	  var scale = parseFloat(getComputedStyle(el).getPropertyValue('--scale')) || 1;
	  var frame = parseFloat(getComputedStyle(el).getPropertyValue('--frame')) || 32;
	
	  var spriteWidth = frame * scale;
	  var maxX = Math.max(0, window.innerWidth - spriteWidth);
	
	  // Random starting direction: 1 = right, -1 = left
	  var dir = Math.random() < 0.5 ? 1 : -1;
	
	  // Random starting position anywhere across the screen
	  var x = Math.random() * maxX;
	
	  // Apply initial state immediately
	  el.style.setProperty('--walker-x', x + 'px');
	  el.style.setProperty('--walker-face', dir);
	
	  function tick() {
	    maxX = Math.max(0, window.innerWidth - spriteWidth);
	
	    x += speed * dir;
	
	    if (x >= maxX) {
	      x = maxX;
	      dir = -1;
	    } else if (x <= 0) {
	      x = 0;
	      dir = 1;
	    }
	
	    el.style.setProperty('--walker-x', x + 'px');
	    el.style.setProperty('--walker-face', dir);
	
	    requestAnimationFrame(tick);
	  }
	
	  el.dataset.walkerApplied = '1';
	  requestAnimationFrame(tick);
	}

  function initSprite(el) {
    if (el.dataset.spriteApplied === '1') return;

    var url = el.getAttribute('data-sprite');
    if (!url) return;

    var img = new Image();
    img.onload = function () {
      var w = img.naturalWidth;
      var h = img.naturalHeight;

      if (!w || !h || w < h) return;

      var frames = Math.floor(w / h);
      if (frames < 1) frames = 1;
      
      // Apply derived values
      el.style.backgroundImage = 'url("' + url.replace(/"/g, '\\"') + '")';
      el.style.setProperty('--frame', h + 'px');
      el.style.setProperty('--frames', frames);
      el.style.setProperty('--sheetW', w + 'px');

      el.dataset.spriteApplied = '1';

      if (el.classList.contains('ws-dev-walker')) {
        startWalker(el);
      }
    };

    img.src = url;
  }

  function applySprites(root) {
    (root || document).querySelectorAll('.ws-sprite[data-sprite]').forEach(initSprite);
  }

  // Initial load
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', function () { applySprites(document); });
  } else {
    applySprites(document);
  }

  // MediaWiki dynamic content hook
  if (window.mw && mw.hook) {
    mw.hook('wikipage.content').add(function ($content) {
      applySprites($content && $content[0] ? $content[0] : document);
    });
  }

})();

// User log spam filtering
mw.hook('wikipage.content').add(function ($content) {
    var $changeslist = $content.find('.mw-changeslist');
    if (!$changeslist.length) {
        return;
    }

    // Avoid duplicate processing if hook runs multiple times
    if ($changeslist.find('.mw-changeslist-newuser-group').length) {
        return;
    }

    $changeslist.each(function () {
        var $container = $(this);
        var $dayHeaders = $container.children('h4');

        $dayHeaders.each(function () {
            var $header = $(this);
            var $sectionNodes = $header.nextUntil('h4');
            var $entries = $sectionNodes.find('.mw-changeslist-src-mw-newuserlog');

            if (!$entries.length) {
                return;
            }

            var count = $entries.length;

            $entries.addClass('mw-changeslist-newuser-hidden');

            var $groupRow = $(
                '<li class="mw-changeslist-newuser-group">' +
                    '<span class="mw-changeslist-newuser-label"></span>' +
                '</li>'
            );

            $groupRow.find('.mw-changeslist-newuser-label').text('New Users (' + count + ')');

            // Insert before the first matching entry in this day section
            $entries.first().before($groupRow);

            $groupRow.on('click', function () {
                var isOpen = $groupRow.hasClass('is-open');
                $groupRow.toggleClass('is-open', !isOpen);
                $entries.toggleClass('is-open', !isOpen);
            });
        });
    });
});

// Move and control the custom WSWB language selector.
$(function () {
	const selector = document.querySelector(
		".wswb-language-selector"
	);

	if (!selector) {
		return;
	}

	const subpages = document.querySelector(".subpages");

	if (subpages) {
		subpages.replaceWith(selector);
	}

	const inlineLanguages = selector.querySelector(
		".wswb-language-selector__inline"
	);
	const toggle = selector.querySelector(
		".wswb-language-selector__toggle"
	);
	const menu = selector.querySelector(
		".wswb-language-selector__menu"
	);
	const toggleSeparator = selector.querySelector(
		".wswb-language-selector__toggle-separator"
	);

	if (!inlineLanguages || !toggle || !toggleSeparator || !menu) {
		return;
	}

	// Preserve the original language order even when options
	// move between the main bar and dropdown.
	const languageOptions = Array.from(
		inlineLanguages.querySelectorAll(
			".wswb-language-selector__option"
		)
	);
	
	const movableOptions = languageOptions.filter(
		function (option) {
			return !option.classList.contains(
				"wswb-language-selector__pinned"
			);
		}
	);
	
	function selectorOverflows() {
		return (
			selector.scrollWidth >
			selector.clientWidth + 1
		);
	}
	
	function arrangeLanguages() {
		setOpen(false);
	
		// Restore every language to its original order.
		languageOptions.forEach(function (option) {
			inlineLanguages.appendChild(option);
		});
	
		setToggleVisible(false);
	
		if (!selectorOverflows()) {
			return;
		}
	
		setToggleVisible(true);
	
		// Move only non-pinned languages, starting
		// from the right side of the row.
		for (
			let index = movableOptions.length - 1;
			index >= 0 && selectorOverflows();
			index -= 1
		) {
			const option = movableOptions[index];
	
			menu.insertBefore(
				option,
				menu.firstChild
			);
		}
	
		setToggleVisible(
			menu.children.length > 0
		);
	}

	function setOpen(open) {
		// Do not open an empty dropdown.
		if (
			open &&
			menu.children.length === 0
		) {
			open = false;
		}

		toggle.setAttribute(
			"aria-expanded",
			String(open)
		);
		menu.setAttribute(
			"aria-hidden",
			String(!open)
		);
		menu.classList.toggle("is-open", open);
	}

	function setToggleVisible(visible) {
		toggle.classList.toggle(
			"is-hidden",
			!visible
		);
		toggle.setAttribute(
			"aria-hidden",
			String(!visible)
		);
	
		toggleSeparator.classList.toggle(
			"is-hidden",
			!visible
		);
	
		if (!visible) {
			setOpen(false);
		}
	}

	toggle.addEventListener("click", function () {
		const open =
			toggle.getAttribute(
				"aria-expanded"
			) === "true";

		setOpen(!open);
	});

	toggle.addEventListener(
		"keydown",
		function (event) {
			if (
				event.key === "Enter" ||
				event.key === " "
			) {
				event.preventDefault();

				const open =
					toggle.getAttribute(
						"aria-expanded"
					) === "true";

				setOpen(!open);
			}
		}
	);

	// Escape closes the dropdown from anywhere on the page.
	document.addEventListener(
		"keydown",
		function (event) {
			if (
				event.key !== "Escape" &&
				event.key !== "Esc"
			) {
				return;
			}

			const open =
				toggle.getAttribute(
					"aria-expanded"
				) === "true";

			if (open) {
				setOpen(false);
				toggle.focus();
			}
		},
		true
	);

	// Clicking outside the selector closes the dropdown.
	document.addEventListener(
		"pointerdown",
		function (event) {
			if (!selector.contains(event.target)) {
				setOpen(false);
			}
		},
		true
	);

	// Avoid running the layout repeatedly during resizing.
	let resizeFrame = null;

	function scheduleArrangement() {
		if (resizeFrame !== null) {
			window.cancelAnimationFrame(
				resizeFrame
			);
		}

		resizeFrame =
			window.requestAnimationFrame(
				function () {
					resizeFrame = null;
					arrangeLanguages();
				}
			);
	}

	window.addEventListener(
		"resize",
		scheduleArrangement
	);

	// Also respond when the wiki content column changes size
	// without a full window resize.
	if (
		window.ResizeObserver &&
		selector.parentElement
	) {
		const resizeObserver =
			new ResizeObserver(
				scheduleArrangement
			);

		resizeObserver.observe(
			selector.parentElement
		);
	}

	setOpen(false);
	scheduleArrangement();

	// Recheck after web fonts finish loading because they can
	// slightly change the width of language names.
	if (document.fonts) {
		document.fonts.ready.then(
			scheduleArrangement
		);
	}
});