<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://marovi.ai/index.php?action=history&amp;feed=atom&amp;title=MediaWiki%3ACommon.js</id>
	<title>MediaWiki:Common.js - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://marovi.ai/index.php?action=history&amp;feed=atom&amp;title=MediaWiki%3ACommon.js"/>
	<link rel="alternate" type="text/html" href="https://marovi.ai/index.php?title=MediaWiki:Common.js&amp;action=history"/>
	<updated>2026-04-24T15:35:50Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.39.1</generator>
	<entry>
		<id>https://marovi.ai/index.php?title=MediaWiki:Common.js&amp;diff=2033&amp;oldid=prev</id>
		<title>DeployBot: [deploy-bot] Add MathJax 3 client-side loader for source-mode LaTeX rendering</title>
		<link rel="alternate" type="text/html" href="https://marovi.ai/index.php?title=MediaWiki:Common.js&amp;diff=2033&amp;oldid=prev"/>
		<updated>2026-04-24T06:10:52Z</updated>

		<summary type="html">&lt;p&gt;[deploy-bot] Add MathJax 3 client-side loader for source-mode LaTeX rendering&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;/* ============================================================&lt;br /&gt;
   Marovi — Custom Reading Experience Scripts&lt;br /&gt;
   Applied via MediaWiki:Common.js&lt;br /&gt;
   ============================================================ */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &amp;#039;use strict&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
    /* --- Glossary Term Popups ---------------------------------- */&lt;br /&gt;
&lt;br /&gt;
    var popup = null;&lt;br /&gt;
    var hideTimer = null;&lt;br /&gt;
&lt;br /&gt;
    function createPopup() {&lt;br /&gt;
        if (popup) return popup;&lt;br /&gt;
        popup = document.createElement(&amp;#039;div&amp;#039;);&lt;br /&gt;
        popup.className = &amp;#039;marovi-term-popup&amp;#039;;&lt;br /&gt;
        popup.style.display = &amp;#039;none&amp;#039;;&lt;br /&gt;
        document.body.appendChild(popup);&lt;br /&gt;
&lt;br /&gt;
        popup.addEventListener(&amp;#039;mouseenter&amp;#039;, function () {&lt;br /&gt;
            clearTimeout(hideTimer);&lt;br /&gt;
        });&lt;br /&gt;
        popup.addEventListener(&amp;#039;mouseleave&amp;#039;, function () {&lt;br /&gt;
            hidePopup();&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        return popup;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function showPopup(term, event) {&lt;br /&gt;
        var el = createPopup();&lt;br /&gt;
        var definition = term.getAttribute(&amp;#039;data-definition&amp;#039;);&lt;br /&gt;
        var article = term.getAttribute(&amp;#039;data-article&amp;#039;);&lt;br /&gt;
        var termName = term.getAttribute(&amp;#039;data-term&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
        if (!definition) return;&lt;br /&gt;
&lt;br /&gt;
        var html = &amp;#039;&amp;#039;;&lt;br /&gt;
        if (termName) {&lt;br /&gt;
            html += &amp;#039;&amp;lt;div class=&amp;quot;marovi-term-popup-title&amp;quot;&amp;gt;&amp;#039; + escapeHtml(termName) + &amp;#039;&amp;lt;/div&amp;gt;&amp;#039;;&lt;br /&gt;
        }&lt;br /&gt;
        html += &amp;#039;&amp;lt;div class=&amp;quot;marovi-term-popup-definition&amp;quot;&amp;gt;&amp;#039; + escapeHtml(definition) + &amp;#039;&amp;lt;/div&amp;gt;&amp;#039;;&lt;br /&gt;
        if (article) {&lt;br /&gt;
            var articleUrl = mw.util.getUrl(article);&lt;br /&gt;
            html += &amp;#039;&amp;lt;div class=&amp;quot;marovi-term-popup-link&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;&amp;#039; + articleUrl + &amp;#039;&amp;quot;&amp;gt;Read full article &amp;amp;rarr;&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;&amp;#039;;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        el.innerHTML = html;&lt;br /&gt;
        el.style.display = &amp;#039;block&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
        var rect = term.getBoundingClientRect();&lt;br /&gt;
        var scrollTop = window.pageYOffset || document.documentElement.scrollTop;&lt;br /&gt;
        var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;&lt;br /&gt;
&lt;br /&gt;
        el.style.top = (rect.bottom + scrollTop + 8) + &amp;#039;px&amp;#039;;&lt;br /&gt;
        el.style.left = Math.max(8, rect.left + scrollLeft - 20) + &amp;#039;px&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
        var popupRect = el.getBoundingClientRect();&lt;br /&gt;
        if (popupRect.right &amp;gt; window.innerWidth - 8) {&lt;br /&gt;
            el.style.left = (window.innerWidth - popupRect.width - 8) + &amp;#039;px&amp;#039;;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function hidePopup() {&lt;br /&gt;
        hideTimer = setTimeout(function () {&lt;br /&gt;
            if (popup) {&lt;br /&gt;
                popup.style.display = &amp;#039;none&amp;#039;;&lt;br /&gt;
            }&lt;br /&gt;
        }, 200);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function escapeHtml(text) {&lt;br /&gt;
        var div = document.createElement(&amp;#039;div&amp;#039;);&lt;br /&gt;
        div.appendChild(document.createTextNode(text));&lt;br /&gt;
        return div.innerHTML;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function initGlossary() {&lt;br /&gt;
        var terms = document.querySelectorAll(&amp;#039;.marovi-term[data-definition]&amp;#039;);&lt;br /&gt;
        terms.forEach(function (term) {&lt;br /&gt;
            term.addEventListener(&amp;#039;mouseenter&amp;#039;, function (e) {&lt;br /&gt;
                clearTimeout(hideTimer);&lt;br /&gt;
                showPopup(term, e);&lt;br /&gt;
            });&lt;br /&gt;
            term.addEventListener(&amp;#039;mouseleave&amp;#039;, function () {&lt;br /&gt;
                hidePopup();&lt;br /&gt;
            });&lt;br /&gt;
            term.addEventListener(&amp;#039;click&amp;#039;, function (e) {&lt;br /&gt;
                e.preventDefault();&lt;br /&gt;
                clearTimeout(hideTimer);&lt;br /&gt;
                showPopup(term, e);&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&amp;#039;keydown&amp;#039;, function (e) {&lt;br /&gt;
            if (e.key === &amp;#039;Escape&amp;#039; &amp;amp;&amp;amp; popup) {&lt;br /&gt;
                popup.style.display = &amp;#039;none&amp;#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        document.addEventListener(&amp;#039;click&amp;#039;, function (e) {&lt;br /&gt;
            if (popup &amp;amp;&amp;amp; !popup.contains(e.target) &amp;amp;&amp;amp; !e.target.classList.contains(&amp;#039;marovi-term&amp;#039;)) {&lt;br /&gt;
                popup.style.display = &amp;#039;none&amp;#039;;&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* --- Language Tabs ----------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
    function initLanguageTabs() {&lt;br /&gt;
        var title = mw.config.get(&amp;#039;wgTitle&amp;#039;);&lt;br /&gt;
        var pageTitle = mw.config.get(&amp;#039;wgPageName&amp;#039;);&lt;br /&gt;
        var namespaceName = mw.config.get(&amp;#039;wgCanonicalNamespace&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
        if (namespaceName !== &amp;#039;&amp;#039; &amp;amp;&amp;amp; namespaceName !== &amp;#039;Main&amp;#039;) return;&lt;br /&gt;
&lt;br /&gt;
        var parts = pageTitle.split(&amp;#039;/&amp;#039;);&lt;br /&gt;
        var basePage = parts[0];&lt;br /&gt;
        var currentLang = parts.length &amp;gt; 1 ? parts[parts.length - 1] : &amp;#039;en&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
        var languages = [&lt;br /&gt;
            { code: &amp;#039;en&amp;#039;, label: &amp;#039;EN&amp;#039;, page: basePage },&lt;br /&gt;
            { code: &amp;#039;es&amp;#039;, label: &amp;#039;ES&amp;#039;, page: basePage + &amp;#039;/es&amp;#039; },&lt;br /&gt;
            { code: &amp;#039;zh&amp;#039;, label: &amp;#039;中文&amp;#039;, page: basePage + &amp;#039;/zh&amp;#039; }&lt;br /&gt;
        ];&lt;br /&gt;
&lt;br /&gt;
        var pagesToCheck = languages&lt;br /&gt;
            .filter(function (l) { return l.code !== currentLang; })&lt;br /&gt;
            .map(function (l) { return l.page; });&lt;br /&gt;
&lt;br /&gt;
        if (pagesToCheck.length === 0) return;&lt;br /&gt;
&lt;br /&gt;
        new mw.Api().get({&lt;br /&gt;
            action: &amp;#039;query&amp;#039;,&lt;br /&gt;
            titles: pagesToCheck.join(&amp;#039;|&amp;#039;),&lt;br /&gt;
            formatversion: 2&lt;br /&gt;
        }).then(function (result) {&lt;br /&gt;
            var existingPages = {};&lt;br /&gt;
            if (result.query &amp;amp;&amp;amp; result.query.pages) {&lt;br /&gt;
                result.query.pages.forEach(function (page) {&lt;br /&gt;
                    if (!page.missing) {&lt;br /&gt;
                        existingPages[page.title.replace(/ /g, &amp;#039;_&amp;#039;)] = true;&lt;br /&gt;
                    }&lt;br /&gt;
                });&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            existingPages[basePage.replace(/ /g, &amp;#039;_&amp;#039;)] = true;&lt;br /&gt;
&lt;br /&gt;
            var availableLangs = languages.filter(function (l) {&lt;br /&gt;
                return existingPages[l.page.replace(/ /g, &amp;#039;_&amp;#039;)];&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            if (availableLangs.length &amp;lt; 2) return;&lt;br /&gt;
&lt;br /&gt;
            var container = document.createElement(&amp;#039;div&amp;#039;);&lt;br /&gt;
            container.className = &amp;#039;marovi-lang-tabs&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
            availableLangs.forEach(function (lang) {&lt;br /&gt;
                var tab = document.createElement(&amp;#039;a&amp;#039;);&lt;br /&gt;
                tab.className = &amp;#039;marovi-lang-tab&amp;#039;;&lt;br /&gt;
                tab.textContent = lang.label;&lt;br /&gt;
                tab.href = mw.util.getUrl(lang.page);&lt;br /&gt;
&lt;br /&gt;
                if (lang.code === currentLang) {&lt;br /&gt;
                    tab.classList.add(&amp;#039;marovi-lang-tab--active&amp;#039;);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                container.appendChild(tab);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            var heading = document.getElementById(&amp;#039;firstHeading&amp;#039;) || document.querySelector(&amp;#039;.mw-first-heading&amp;#039;);&lt;br /&gt;
            if (heading &amp;amp;&amp;amp; heading.parentNode) {&lt;br /&gt;
                heading.parentNode.insertBefore(container, heading.nextSibling);&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* --- CJK Body Class --------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
    function initCJKClass() {&lt;br /&gt;
        var pageTitle = mw.config.get(&amp;#039;wgPageName&amp;#039;);&lt;br /&gt;
        if (pageTitle.match(/\/zh$/)) {&lt;br /&gt;
            document.body.classList.add(&amp;#039;marovi-lang-zh&amp;#039;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* --- MathJax loader --------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
    // MediaWiki runs in $wgMathValidModes=[&amp;#039;source&amp;#039;], so &amp;lt;math&amp;gt; tags are&lt;br /&gt;
    // rendered as &amp;lt;span class=&amp;quot;mwe-math-fallback-source-{inline,block} tex&amp;quot;&amp;gt;&lt;br /&gt;
    // containing $...$ / $$...$$ LaTeX. MathJax 3 reparses those on the client.&lt;br /&gt;
    function initMathJax() {&lt;br /&gt;
        if (!document.querySelector(&lt;br /&gt;
            &amp;#039;.mwe-math-fallback-source-inline, .mwe-math-fallback-source-block&amp;#039;&lt;br /&gt;
        )) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        window.MathJax = {&lt;br /&gt;
            tex: {&lt;br /&gt;
                inlineMath: [[&amp;#039;$&amp;#039;, &amp;#039;$&amp;#039;], [&amp;#039;\\(&amp;#039;, &amp;#039;\\)&amp;#039;]],&lt;br /&gt;
                displayMath: [[&amp;#039;$$&amp;#039;, &amp;#039;$$&amp;#039;], [&amp;#039;\\[&amp;#039;, &amp;#039;\\]&amp;#039;]],&lt;br /&gt;
                processEscapes: true,&lt;br /&gt;
                tags: &amp;#039;none&amp;#039;&lt;br /&gt;
            },&lt;br /&gt;
            options: {&lt;br /&gt;
                skipHtmlTags: [&amp;#039;script&amp;#039;, &amp;#039;noscript&amp;#039;, &amp;#039;style&amp;#039;, &amp;#039;textarea&amp;#039;, &amp;#039;pre&amp;#039;, &amp;#039;code&amp;#039;],&lt;br /&gt;
                ignoreHtmlClass: &amp;#039;mw-parser-output-nomath|no-mathjax&amp;#039;,&lt;br /&gt;
                processHtmlClass: &amp;#039;mwe-math-fallback-source-inline|mwe-math-fallback-source-block|tex&amp;#039;&lt;br /&gt;
            }&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        var script = document.createElement(&amp;#039;script&amp;#039;);&lt;br /&gt;
        script.async = true;&lt;br /&gt;
        script.src = &amp;#039;https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js&amp;#039;;&lt;br /&gt;
        document.head.appendChild(script);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* --- Init ------------------------------------------------- */&lt;br /&gt;
&lt;br /&gt;
    $(function () {&lt;br /&gt;
        initGlossary();&lt;br /&gt;
        initCJKClass();&lt;br /&gt;
        initMathJax();&lt;br /&gt;
        mw.loader.using(&amp;#039;mediawiki.api&amp;#039;).then(initLanguageTabs);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
}());&lt;/div&gt;</summary>
		<author><name>DeployBot</name></author>
	</entry>
</feed>