MediaWiki:Vector.js: Difference between revisions

From Geometry Dash Expanded Wiki
Jump to navigation Jump to search
Correct Vault and Vault of Secrets theme colours
Preserve sidebar colour spans and icons when translating navigation labels
 
(14 intermediate revisions by the same user not shown)
Line 224: Line 224:
         account.className = 'gd-header-menu gd-account-menu';
         account.className = 'gd-header-menu gd-account-menu';
         var accountLabel = document.createElement('summary');
         var accountLabel = document.createElement('summary');
         accountLabel.innerHTML = iconMarkup('user');
         accountLabel.setAttribute('aria-label', 'Account menu');
         var accountName = document.createElement('span');
        accountLabel.title = 'Account menu';
         accountName.textContent = mw.config.get('wgUserName') || 'Account';
        var accountGroup = document.createElement('div');
         accountLabel.appendChild(accountName);
        accountGroup.className = 'gd-account-group';
         var accountName = document.createElement('a');
         accountName.className = 'gd-account-talk-link';
        var userName = mw.config.get('wgUserName');
        accountName.href = mw.util.getUrl(userName ? 'User:' + userName : 'Special:UserLogin');
        accountName.innerHTML = iconMarkup('user');
        var nameText = document.createElement('span');
        nameText.textContent = userName || 'Account';
         accountName.appendChild(nameText);
        accountName.title = userName ? 'Your user page' : 'Log in';
        accountGroup.appendChild(accountName);
         account.appendChild(accountLabel);
         account.appendChild(accountLabel);
        var duplicateUserPage = links.querySelector('#pt-userpage');
        if (duplicateUserPage) duplicateUserPage.remove();
         links.classList.add('gd-account-links');
         links.classList.add('gd-account-links');
         account.appendChild(links);
         account.appendChild(links);
         controls.appendChild(account);
        accountGroup.appendChild(account);
         controls.appendChild(accountGroup);
        var barLogo = document.createElement('a');
        barLogo.className = 'gd-header-bar-logo';
        barLogo.href = mw.util.getUrl(mw.config.get('wgMainPageTitle') || 'Main Page');
        barLogo.title = mw.config.get('wgSiteName') || 'Geometry Dash Expanded Wiki';
        barLogo.setAttribute('aria-label', barLogo.title + ' main page');
        var logoImage = document.createElement('img');
        logoImage.src = 'https://geometrydashwiki.com/images/d/d4/Logo.jpg';
        logoImage.alt = ''; logoImage.width = 32; logoImage.height = 32;
        barLogo.appendChild(logoImage);
        personal.appendChild(barLogo);
         personal.appendChild(controls);
         personal.appendChild(controls);
         personal.classList.add('gd-header-ready');
         personal.classList.add('gd-header-ready');
Line 244: Line 267:
     });
     });
}());
}());
/* Expanded multilingual navigation: shared accounts, files and Recent Changes. */
(function () {
    'use strict';
    mw.loader.using(['mediawiki.api', 'mediawiki.util']).then(function () {
        $(function () {
            var controls = document.querySelector('.gd-header-controls');
            if (!controls || document.getElementById('gd-language-menu')) return;
            var page = (mw.config.get('wgPageName') || 'Main_Page').replace(/_/g, ' ');
            var match = /^(Spa|Rus|Pol)\/(.+)$/.exec(page);
            var pathCode = /^\/(eng|spa|rus|pol)(?:\/|$)/.exec(location.pathname);
            var articleCode = match ? match[1].toLowerCase() : 'eng';
            var cookie = /(?:^|;\s*)gdwiki-language=(eng|spa|rus|pol)(?:;|$)/.exec(document.cookie);
            var code = cookie ? cookie[1] : (mw.config.get('wgExpandedActiveLanguage') || (pathCode ? pathCode[1] : articleCode));
            var base = match ? match[2] : page;
            var spanish = code === 'spa';
            var isArticle = mw.config.get('wgNamespaceNumber') === 0;
            document.documentElement.setAttribute('data-gd-language', code);
            var definitions = [
                {code:'eng', name:'English', lang:'en', flag:'/images/4/49/Flag_gb.svg'},
                {code:'spa', name:'Español', lang:'es', flag:'/images/2/2d/Flag_es.svg'}
            ];
            var menu = document.createElement('details');
            menu.id = 'gd-language-menu'; menu.className = 'gd-header-menu gd-language-menu';
            var summary = document.createElement('summary');
            summary.setAttribute('aria-label', spanish ? 'Cambiar idioma' : 'Change language');
            summary.title = summary.getAttribute('aria-label');
            var current = definitions[spanish ? 1 : 0];
            var image = document.createElement('img'); image.src=current.flag; image.alt=''; image.width=24; image.height=16;
            summary.appendChild(image);
            var label=document.createElement('span'); label.textContent=current.name; summary.appendChild(label);
            menu.appendChild(summary);
            var panel=document.createElement('div'); panel.className='gd-header-dropdown gd-language-options';
            panel.setAttribute('aria-label', spanish ? 'Idiomas' : 'Languages');
            menu.appendChild(panel);
            var personal = document.getElementById('p-personal');
            personal.appendChild(menu);
            var api=new mw.Api();
            function route(title, lang) {
                if (!mw.config.get('wgExpandedLanguageRoutes')) return mw.util.getUrl(title);
                var m=/^(Spa|Rus|Pol)\/(.+)$/.exec(title);
                var language=m ? m[1].toLowerCase() : 'eng';
                var name=m ? m[2] : title;
                if (name.indexOf(':')!==-1 && !m) return mw.util.getUrl(title);
                return '/'+language+'/'+encodeURIComponent(name.replace(/ /g,'_')).replace(/%2F/g,'/');
            }
            function build(mapping) {
                var entry=mapping[base] || {};
                Object.keys(mapping).some(function (key) {
                    if (mapping[key][articleCode]===page) {base=key;entry=mapping[key];return true;}
                    return false;
                });
                var titles=definitions.map(function (d) {
                    return isArticle ? (entry[d.code] || (d.code==='eng' ? base : 'Spa/'+base)) : page;
                });
                api.get({action:'query',titles:titles.join('|'),prop:'info',formatversion:2}).then(function (data) {
                    var existing={};
                    (data.query.pages || []).forEach(function (p) {existing[p.title]=!p.missing && !p.invalid;});
                    definitions.forEach(function (d,i) {
                        var available=existing[titles[i]], target=available || !isArticle ? titles[i] : titles[0];
                        var link=document.createElement('a');link.lang=d.lang;link.hreflang=d.lang;
                        var flag=document.createElement('img');flag.src=d.flag;flag.alt='';flag.width=24;flag.height=16;link.appendChild(flag);
                        var text=document.createElement('span');text.textContent=d.name;link.appendChild(text);
                        if(d.code===code)link.setAttribute('aria-current','page');
                        link.href=route(target,d.lang);
                        link.addEventListener('click',function () {
                            document.cookie='gdwiki-language='+d.code+'; Path=/; Max-Age=31536000; SameSite=Lax; Secure';
                            try {
                                localStorage.setItem('gdwiki-language',d.code);
                                if(isArticle && !available)sessionStorage.setItem('gdwiki-fallback',JSON.stringify({language:d.code,page:base}));
                            } catch(error) {}
                        });
                        panel.appendChild(link);
                    });
                    if(isArticle && !existing[titles[1]]) {
                        var create=document.createElement('a');create.className='gd-language-create';
                        create.textContent=spanish ? 'Crear traducción al español' : 'Create Spanish translation';
                        if(mw.config.get('wgExpandedLanguageEditorSafe')) {
                            var editParams={action:'edit',preload:titles[0],summary:'Start Español translation from [['+titles[0]+']]'};
                            create.href=route(titles[1],'es')+'?'+new URLSearchParams(editParams).toString();
                        } else {create.setAttribute('aria-disabled','true');create.title='Translation setup awaiting server update';}
                        panel.appendChild(create);
                    }
                    var home=document.createElement('a');home.className='gd-language-home';home.textContent=spanish ? 'Inicio' : 'Home';home.href=route('Main Page','en');panel.appendChild(home);
                    var guide=document.createElement('a');guide.textContent=spanish ? 'Guía de traducción' : 'Translation guide';guide.href=mw.util.getUrl('Help:Translations');panel.appendChild(guide);
                }, function () {panel.textContent=spanish ? 'No se pudieron cargar los idiomas. Recarga la página.' : 'Languages could not load. Reload the page.';});
            }
            api.get({action:'query',titles:'MediaWiki:Expanded-language-pages.json',prop:'revisions',rvprop:'content',rvslots:'main',formatversion:2}).then(function (data) {
                try {build(JSON.parse(data.query.pages[0].revisions[0].slots.main.content));} catch (error) {build({});}
            },function () {build({});});
            document.addEventListener('click',function (event) {if (!menu.contains(event.target)) menu.open=false;});
            document.addEventListener('keydown',function (event) {if (event.key==='Escape') menu.open=false;});
            if (spanish) {
                var interfaceLabels={"Navigation": "Navegación", "Main page": "Página principal", "Recent changes": "Cambios recientes", "New files": "Archivos nuevos", "Random page": "Página aleatoria", "New here? Get started": "¿Eres nuevo? Empieza aquí", ">> Site policy": ">> Normas del sitio", ">> Staff": ">> Administración", "Help using MediaWiki": "Ayuda sobre MediaWiki", "GD Base Content": "Contenido base de GD", "Games": "Juegos", "Main levels": "Niveles principales", "Gameplay": "Jugabilidad", "Rewards": "Recompensas", "Rooms (vaults etc.)": "Salas (bóvedas, etc.)", "Level editing": "Editor de niveles", "Account features": "Funciones de la cuenta", "Updates": "Actualizaciones", "GD Community Content": "Contenido de la comunidad de GD", "Demon List levels": "Niveles de la Demon List", "Gauntlet levels": "Niveles de gauntlets", "Map Pack levels": "Niveles de paquetes de mapas", "Classic levels": "Niveles clásicos", "Platformer levels": "Niveles de plataformas", "Players": "Jugadores", "Community activities": "Actividades de la comunidad", "Wiki Resources": "Recursos de la wiki", "Propose new articles": "Proponer artículos nuevos", "Submit edits for review": "Enviar cambios para revisión", "Admin Dashboard": "Panel de administración", "Images": "Imágenes", "Videos": "Vídeos", "Audio": "Audio", "PDFs": "PDF", "Templates": "Plantillas", "Sandbox": "Zona de pruebas", "Discuss the wiki": "Debatir sobre la wiki", "Guestbook": "Libro de visitas", "Tools": "Herramientas", "What links here": "Lo que enlaza aquí", "Related changes": "Cambios relacionados", "Upload file": "Subir archivo", "Printable version": "Versión para imprimir", "Permanent link": "Enlace permanente", "Page information": "Información de la página", "Account": "Cuenta", "Preferences": "Preferencias", "Your user page": "Tu página de usuario", "Log in": "Iniciar sesión", "Account menu": "Menú de cuenta", "Appearance": "Apariencia"};
                document.querySelectorAll('#mw-panel h3, #mw-panel h3 span, #mw-panel a, .gd-account-links a, .gd-account-talk-link span').forEach(function (element) {
                    var key=element.textContent.trim();
                    if (interfaceLabels[key]) {
                        // Translate text nodes without removing colour spans, links or icons.
                        var walker=document.createTreeWalker(element,NodeFilter.SHOW_TEXT), node;
                        while ((node=walker.nextNode())) {
                            var original=node.nodeValue.trim();
                            if (interfaceLabels[original]) node.nodeValue=node.nodeValue.replace(original,interfaceLabels[original]);
                        }
                    }
                });
                document.querySelectorAll('#p-personal [title], #p-personal [aria-label]').forEach(function (element) {
                    ['title','aria-label'].forEach(function (attr) {var key=element.getAttribute(attr);if(interfaceLabels[key])element.setAttribute(attr,interfaceLabels[key]);});
                });
                var appearance=controls.querySelector('.gd-header-menu summary');
                if (appearance) {appearance.textContent='Apariencia';appearance.title='Apariencia';appearance.setAttribute('aria-label','Apariencia');}
                var account=controls.querySelector('.gd-account-menu summary');
                if (account) {account.title='Menú de cuenta';account.setAttribute('aria-label','Menú de cuenta');}
                var titles={'Blue':'Azul','Purple':'Morado','Green':'Verde','Red':'Rojo','Dark':'Oscuro','Blackout':'Negro','Vault':'La bóveda','Vault of Secrets':'La bóveda de los secretos','Chamber of Time':'La cámara del tiempo'};
                controls.querySelectorAll('.gd-theme-option').forEach(function (button) {if(titles[button.textContent])button.textContent=titles[button.textContent];});
            }
            // Optional translated assets use the same existing theme filters.
            var logos=mw.config.get('wgExpandedLanguageLogos') || {};
            logos.spa=Object.assign({"header": "https://geometrydashwiki.com/images/4/4a/Logo-spa.jpg", "banner": "https://geometrydashwiki.com/images/a/a7/Site-logo-spa.png"},logos.spa || {});
            if (logos[code]) {
                if (logos[code].header) {
                    var header=document.querySelector('.gd-header-bar-logo img');if(header)header.src=logos[code].header;
                }
                if (logos[code].banner) document.documentElement.style.setProperty('--wiki-logo-image','url("'+logos[code].banner.replace(/["\\]/g,'')+'")');
            }
        });
    });
}());
/* Keep language parameters and script endpoints out of visible navigation URLs. */
(function () {
    'use strict';
    function clean(raw) {
        var url;
        try {url=new URL(raw,location.href);} catch(error) {return raw;}
        if (url.origin!==location.origin) return raw;
        url.searchParams.delete('uselang');
        if (/\/index\.php$/.test(url.pathname) && !url.searchParams.has('title') && url.searchParams.has('search')) {url.pathname='/wiki/Special:Search';}
        if (/\/index\.php$/.test(url.pathname) && url.searchParams.has('title')) {
            var title=url.searchParams.get('title');url.searchParams.delete('title');
            var match=/^(Spa|Rus|Pol)\/(.+)$/.exec(title.replace(/_/g,' '));
            var ns=title.indexOf(':')!==-1;
            var prefix=match ? '/'+match[1].toLowerCase()+'/' : (ns ? '/wiki/' : '/eng/');
            var name=match ? match[2] : title;
            url.pathname=prefix+encodeURIComponent(name.replace(/ /g,'_')).replace(/%2F/g,'/').replace(/%3A/g,':');
        }
        return url.pathname+url.search+url.hash;
    }
    // The current request has already chosen its interface language.
    var address=new URL(location.href);
    var cleanAddress=clean(location.href);
    if (cleanAddress!==address.pathname+address.search+address.hash) history.replaceState(null,'',cleanAddress);
    function links() {
        document.querySelectorAll('a[href]').forEach(function (link) {
            var href=link.getAttribute('href');
            if (href && !/^(?:#|javascript:|mailto:)/.test(href)) {
                var replacement=clean(href);if(replacement!==href)link.setAttribute('href',replacement);
            }
        });
    }
    $(function () {
        links();
        var pending=false;
        new MutationObserver(function () {
            if(pending)return;pending=true;
            requestAnimationFrame(function () {pending=false;links();});
        }).observe(document.body,{childList:true,subtree:true});
    });
    mw.hook('wikipage.content').add(links);
    // Also handles asynchronously built language and account menus.
    document.addEventListener('click',function(event) {
        var link=event.target.closest && event.target.closest('a[href]');
        if(link)link.setAttribute('href',clean(link.getAttribute('href')));
    },true);
}());
/* Article-language tabs and links follow the persistent site language. */
(function () {
    'use strict';
    mw.loader.using(['mediawiki.api','mediawiki.util']).then(function () {
        $(function () {
            var cookie=/(?:^|;\s*)gdwiki-language=(eng|spa|rus|pol)(?:;|$)/.exec(document.cookie);
            var mode=cookie ? cookie[1] : (mw.config.get('wgExpandedActiveLanguage') || mw.config.get('wgExpandedLanguage') || 'eng');
            var names={eng:'English',spa:'Español',rus:'Русский',pol:'Polski'};
            var notices={eng:'This article is not available in English. Showing the original article.',spa:'Este artículo todavía no está disponible en español. Se muestra la versión en inglés.',rus:'Эта статья пока недоступна на русском языке. Показана английская версия.',pol:'Ten artykuł nie jest jeszcze dostępny po polsku. Wyświetlono wersję angielską.'};
            try {
                var pending=JSON.parse(sessionStorage.getItem('gdwiki-fallback') || 'null');
                sessionStorage.removeItem('gdwiki-fallback');
                if(!pending && mw.config.get('wgExpandedLanguageFallback'))pending={language:mw.config.get('wgExpandedLanguageFallback')};
                if(pending && notices[pending.language])mw.notify(notices[pending.language],{tag:'gd-language-fallback',autoHideSeconds:10});
            } catch(error) {}
            function rememberFallback(language) {
                try {sessionStorage.setItem('gdwiki-fallback',JSON.stringify({language:language}));} catch(error) {}
            }
            function normal(title) {title=title.replace(/_/g,' ').trim();return title.charAt(0).toUpperCase()+title.slice(1);}
            function bare(title) {return title.replace(/^(?:Spa|Rus|Pol)\//,'');}
            function route(title) {
                var m=/^(Spa|Rus|Pol)\/(.+)$/.exec(title);
                return '/'+(m ? m[1].toLowerCase() : 'eng')+'/'+encodeURIComponent((m ? m[2] : title).replace(/ /g,'_')).replace(/%2F/g,'/');
            }
            var api=new mw.Api();
            api.get({action:'query',titles:'MediaWiki:Expanded-language-pages.json',prop:'revisions',rvprop:'content',rvslots:'main',formatversion:2}).then(function (data) {
                var map;
                try {map=JSON.parse(data.query.pages[0].revisions[0].slots.main.content);} catch(error) {map={};}
                var aliases={};
                Object.keys(map).forEach(function (root) {
                    if(!map[root] || typeof map[root]!=='object')return;
                    [root].concat(Object.keys(map[root]).map(function (key) {return map[root][key];})).forEach(function (title) {
                        if(typeof title!=='string')return;
                        [normal(title),normal(bare(title))].forEach(function (alias) {
                            if(!aliases[alias])aliases[alias]=[];
                            if(aliases[alias].indexOf(root)===-1)aliases[alias].push(root);
                        });
                    });
                });
                function group(title) {
                    var roots=aliases[normal(title)] || [];
                    if(roots.length===1)return map[roots[0]];
                    if(roots.length>1)return null; // Never guess between unrelated concepts.
                    var english=bare(normal(title));return {eng:english,spa:'Spa/'+english,rus:'Rus/'+english,pol:'Pol/'+english};
                }
                var links=[],checks={},current=(mw.config.get('wgPageName') || '').replace(/_/g,' ');
                document.querySelectorAll('#mw-content-text a[href], #mw-panel a[href], .gd-header-bar-logo, .gd-language-home').forEach(function (link) {
                    var url;try {url=new URL(link.href);}catch(error){return;}
                    if(url.origin!==location.origin)return;
                    if(link.getAttribute('href').charAt(0)==='#')return;
                    var path=/^\/(?:eng|spa|rus|pol|wiki)\/(.+)$/.exec(url.pathname);
                    if(!path && url.pathname!=='/')return;
                    var title=path ? decodeURIComponent(path[1]).replace(/_/g,' ') : (mw.config.get('wgMainPageTitle') || 'Main Page');
                    if(/^\/(spa|rus|pol)\//.test(url.pathname))title=url.pathname.split('/')[1].charAt(0).toUpperCase()+url.pathname.split('/')[1].slice(1)+'/'+title;
                    if(title.indexOf(':')!==-1)return;
                    var action=url.searchParams.get('action');
                    var redlink=url.searchParams.get('redlink')==='1';
                    if((action && action!=='view' && !redlink) || url.searchParams.has('veaction') || url.searchParams.has('oldid') || url.searchParams.has('diff'))return;
                    if(normal(title)===normal(current) && url.hash)return;
                    var versions=group(title);if(!versions)return;
                    Object.keys(versions).forEach(function (lang) {checks[versions[lang]]=true;});
                    links.push({element:link,url:url,title:title,versions:versions});
                });
                var currentVersions=group(current);
                if(currentVersions)Object.keys(currentVersions).forEach(function (lang) {checks[currentVersions[lang]]=true;});
                var titles=Object.keys(checks),batches=[];
                for(var i=0;i<titles.length;i+=40)batches.push(titles.slice(i,i+40));
                Promise.all(batches.map(function (batch) {return api.get({action:'query',titles:batch.join('|'),prop:'info',formatversion:2});})).then(function (results) {
                    var exists={};results.forEach(function (result) {(result.query.pages || []).forEach(function (p) {exists[normal(p.title)]=!p.missing && !p.invalid;});});
                    links.forEach(function (item) {
                        var preferred=item.versions[mode],english=item.versions.eng;
                        var available=preferred && exists[normal(preferred)];
                        var target=available ? preferred : english;
                        if(!target || !exists[normal(target)])return;
                        item.url.searchParams.delete('title');item.url.searchParams.delete('uselang');item.url.searchParams.delete('redlink');if(item.url.searchParams.get('action')==='edit')item.url.searchParams.delete('action');
                        item.element.href=route(target)+(item.url.searchParams.size ? '?'+item.url.searchParams.toString() : '')+item.url.hash;
                        item.element.classList.remove('new');
                        if(!available && mode!=='eng')item.element.addEventListener('click',function () {rememberFallback(mode);});
                        // Prefixes are storage details, not part of the displayed article name.
                        if(item.element.textContent.trim()===item.title)item.element.textContent=bare(item.title);
                    });
                    if(!currentVersions || mw.config.get('wgNamespaceNumber')!==0 || mw.config.get('wgAction')!=='view')return;
                    var languages=Object.keys(names).filter(function (lang) {return currentVersions[lang] && exists[normal(currentVersions[lang])];});
                    if(languages.length<2 || document.getElementById('gd-article-languages'))return;
                    var nav=document.createElement('nav');nav.id='gd-article-languages';nav.className='gd-article-languages';nav.setAttribute('aria-label',mode==='spa' ? 'Idiomas del artículo' : 'Article languages');
                    languages.forEach(function (lang) {
                        var link=document.createElement('a');link.textContent=names[lang];link.href=route(currentVersions[lang]);link.setAttribute('data-gd-language-tab','');
                        if(normal(currentVersions[lang])===normal(current))link.setAttribute('aria-current','page');
                        nav.appendChild(link);
                    });
                    var heading=document.getElementById('firstHeading');if(heading){document.body.classList.add('gd-has-language-tabs');heading.appendChild(nav);}
                },function () { /* Preserve original working links if availability cannot be checked. */ });
            });
        });
    });
}());
/* Infobox labels: reader language on shared pages, article language on articles. */
(function () {
'use strict';
var labels={"Born": {"spa": "Nacimiento", "rus": "Дата рождения", "pol": "Data urodzenia"}, "Died": {"spa": "Fallecimiento", "rus": "Дата смерти", "pol": "Data śmierci"}, "Other names": {"spa": "Otros nombres", "rus": "Другие имена", "pol": "Inne nazwy"}, "Country": {"spa": "País", "rus": "Страна", "pol": "Kraj"}, "Mod status": {"spa": "Estado de moderador", "rus": "Статус модератора", "pol": "Status moderatora"}, "Uploaded levels": {"spa": "Niveles publicados", "rus": "Опубликованные уровни", "pol": "Opublikowane poziomy"}, "Rated levels": {"spa": "Niveles calificados", "rus": "Оценённые уровни", "pol": "Ocenione poziomy"}, "Creator points": {"spa": "Puntos de creador", "rus": "Очки создателя", "pol": "Punkty twórcy"}, "GD stats": {"spa": "Estadísticas de GD", "rus": "Статистика GD", "pol": "Statystyki GD"}, "Social media": {"spa": "Redes sociales", "rus": "Социальные сети", "pol": "Media społecznościowe"}, "Other": {"spa": "Otros", "rus": "Другое", "pol": "Inne"}, "Please search": {"spa": "Buscar", "rus": "Найти", "pol": "Wyszukaj"}, "Information": {"spa": "Información", "rus": "Информация", "pol": "Informacje"}, "Statistics": {"spa": "Estadísticas", "rus": "Статистика", "pol": "Statystyki"}, "Total jumps": {"spa": "Saltos totales", "rus": "Всего прыжков", "pol": "Łączna liczba skoków"}, "Total attempts": {"spa": "Intentos totales", "rus": "Всего попыток", "pol": "Łączna liczba prób"}, "Main levels": {"spa": "Niveles principales", "rus": "Основные уровни", "pol": "Główne poziomy"}, "Online levels": {"spa": "Niveles en línea", "rus": "Онлайн-уровни", "pol": "Poziomy online"}, "Daily levels": {"spa": "Niveles diarios", "rus": "Ежедневные уровни", "pol": "Poziomy dzienne"}, "Gauntlets": {"spa": "Gauntlets", "rus": "Испытания", "pol": "Gauntlety"}, "Map packs": {"spa": "Paquetes de mapas", "rus": "Наборы уровней", "pol": "Pakiety map"}, "Liked / disliked": {"spa": "Me gusta / no me gusta", "rus": "Лайки / дизлайки", "pol": "Polubione / nielubiane"}, "Chests opened": {"spa": "Cofres abiertos", "rus": "Открытые сундуки", "pol": "Otwarte skrzynie"}, "Players destroyed": {"spa": "Jugadores destruidos", "rus": "Уничтоженные игроки", "pol": "Zniszczeni gracze"}, "Leaderboard": {"spa": "Clasificación", "rus": "Таблица лидеров", "pol": "Ranking"}, "Last updated": {"spa": "Última actualización", "rus": "Последнее обновление", "pol": "Ostatnia aktualizacja"}};
function translate(root) {
var page=mw.config.get('wgPageName') || '',match=/^(Spa|Rus|Pol)\//.exec(page),cookie=/(?:^|;\s*)gdwiki-language=(eng|spa|rus|pol)(?:;|$)/.exec(document.cookie);
var lang=mw.config.get('wgNamespaceNumber')===0 ? (match ? match[1].toLowerCase() : 'eng') : (cookie ? cookie[1] : (mw.config.get('wgExpandedActiveLanguage') || 'eng'));
root.querySelectorAll('[data-gd-infobox-label]').forEach(function (el) {var key=el.getAttribute('data-gd-infobox-label');el.textContent=(labels[key] && labels[key][lang]) || key;});
root.querySelectorAll('[data-gd-stats-name]').forEach(function(el){var name=el.getAttribute('data-gd-stats-name');el.textContent=lang==='spa' ? 'Estadísticas de '+name : lang==='rus' ? 'Статистика '+name : lang==='pol' ? 'Statystyki '+name : name+"’s stats";});
}
$(function(){translate(document);mw.hook('wikipage.content').add(function(content){translate(content[0] || document);});});
})();

Latest revision as of 21:09, 14 October 2026

/* All JavaScript here will be loaded for users of the Vector skin */

/***************************/
/* Interface Modification **/
/***************************/

/* JavaScript Load Class (REQUIRED BY DEFAULT VECTOR.CSS) */
$(function () {
	document.body.classList.add('has-vector-mobile-menu');
});

/* Adapt standard Vector's structure for the imported stylesheet. */
$(function () {
    if (!document.body.classList.contains('skin-vector-legacy')) return;

    var content = document.getElementById('content');
    var navigation = document.getElementById('mw-navigation');
    if (!content || !navigation) return;

    if (!content.parentElement.classList.contains('content-wrapper')) {
        var wrapper = document.createElement('div');
        wrapper.className = 'content-wrapper';
        content.before(wrapper);
        wrapper.append(navigation, content);
    }

    if (!content.querySelector('.content-body')) {
        $(content).wrapInner('<div class="content-body"></div>');
    }
});

/* Search Toggle Button */
$(function () {
	var buttonClass = 'button-toggle button-toggle-search';
	var expandedClass = 'search--expanded';
	let searchButton = document.createElement('button');
	let sidebar = document.getElementById('mw-navigation');
	searchButton.className = buttonClass;
	searchButton.addEventListener('click', function () {
		searchButton.classList.toggle(expandedClass);
		sidebar.classList.toggle(expandedClass);
	});
	sidebar.prepend(searchButton);
});


/* Mobile Sidebar Toggle Button */
$(function () {
	var buttonClass = 'button-toggle button-toggle-sidebar-mobile';
	var expandedClass = 'sidebar-mobile--expanded';
	let mobileSidebarButton = document.createElement('button');
	let sidebar = document.getElementById('mw-navigation');
	mobileSidebarButton.className = buttonClass;
	mobileSidebarButton.addEventListener('click', function () {
		mobileSidebarButton.classList.toggle(expandedClass);
		sidebar.classList.toggle(expandedClass);
	});
	sidebar.prepend(mobileSidebarButton);
});


/* Sidebar Toggle Button */
$(function () {
	var buttonClass = 'button-toggle button-toggle-sidebar';
	var expandedClass = 'sidebar--collapsed';
	let sidebarButton = document.createElement('button');
	let sidebar = document.getElementById('mw-navigation');
	sidebarButton.className = buttonClass;
	sidebarButton.addEventListener('click', function () {
		sidebarButton.classList.toggle(expandedClass);
		sidebar.classList.toggle(expandedClass);
	});
	sidebar.prepend(sidebarButton);
});


/* Sidebar Box Content Collaspible Toggles */
$(function() {
    // configure sections (by header string) to initially collapse for all users by default
    var initiallyCollapsedIDs = []; /* e.g. ['Character_Classes', 'Items', 'External_Links'] */

    // add the p- onto ids for ease of use, if not present
    initiallyCollapsedIDs.forEach(function(id, index) {
        if(!id.startsWith('p-')) {initiallyCollapsedIDs[index] = 'p-' + id;}
    });
	var $portals = $("#mw-panel .vector-menu-portal");
	var setup = function() {
		$portals.each(function(index, el) {
			if(window.innerWidth < 721) {return;}
			var $el = $(el);
			var $id = $el.attr("id");
			if(!$id) {return;}
			// check if this portal should be collapsed - portal is set to be initially collapsed and user has not indicated wanting it open || user has indicated wanting this portal collapsed
			if(
				(initiallyCollapsedIDs.includes($id) && localStorage.getItem('sidebar_c_'+$id) != "n") || (localStorage.getItem('sidebar_c_'+$id) === "y")
			) {$el.addClass('collapsed').find('.vector-menu-content').slideUp(0);}
		});
	};
	setup();
	$(window).on('resize', setup);
	$portals.on("click", "h3", function(event) {
		if(window.innerWidth < 721) {return;}
		var $el = $(this).parent();
		var $id = $el.attr("id");
		if(!$id) {return;}
		$el.toggleClass('collapsed');
		if($el.hasClass('collapsed')) { // more consistent between class and slide status
			localStorage.setItem('sidebar_c_'+$id, "y");
			$el.find('.vector-menu-content').slideUp('fast');
		}
		else {
			localStorage.setItem('sidebar_c_'+$id, "n");
			$el.find('.vector-menu-content').slideDown('fast');
		}
	});
});


/* Header Dropdown Menu Purge Cache Link */
$(function() {
	if (mw.config.get('wgNamespaceNumber') === -1 ) {return;} // disable on special pages
	var url = new URL(window.location.href);
	url.searchParams.set('action', 'purge');
	var button = mw.util.addPortletLink('p-cactions', url.href, 'Purge cache', 'ca-gadget-purgecache', 'Purge the server cache for this page', '1');
	button.addEventListener('click', (function(event) {
		event.preventDefault();
		var api = new mw.Api();
		api.post({
			action: 'purge',
			titles: mw.config.get('wgPageName'),
			forcerecursivelinkupdate: true
		}).then(function() {
			window.location.reload(true);
		}).fail(function(code) {
			mw.notify('Page purge unsuccessful. Error code: $1'.replace('$1', code));
		});
	}));
	console.log('purge loaded');
});

/* Independent GD Wiki header: themes and existing account links. */
(function () {
    'use strict';
    var themes = [
        ['blue', 'Geometry Dash'], ['green', 'Vault'],
        ['purple', 'Vault of Secrets'], ['red', 'Chamber of Time'],
        ['dark', 'Dark'], ['blackout', 'Blackout']
    ];
    var storageKey = 'gdwiki-theme';
    function applyTheme(key) {
        if (!themes.some(function (theme) { return theme[0] === key; })) key = 'blue';
        var root = document.documentElement;
        themes.forEach(function (theme) { root.classList.remove('theme-' + theme[0]); });
        root.classList.remove('view-light');
        root.classList.add('view-dark', 'theme-' + key);
        return key;
    }
    var selected = 'blue';
    try { selected = localStorage.getItem(storageKey) || selected; } catch (error) {}
    selected = applyTheme(selected);
    $(function () {
        if (!document.body.classList.contains('skin-vector-legacy')) return;
        var personal = document.getElementById('p-personal');
        if (!personal || personal.querySelector('.gd-header-controls')) return;
        var links = personal.querySelector('ul');
        if (!links) return;
        var controls = document.createElement('div');
        controls.className = 'gd-header-controls';
        var appearance = document.createElement('details');
        appearance.className = 'gd-header-menu';
        var appearanceLabel = document.createElement('summary');
        appearanceLabel.textContent = 'Appearance';
        appearance.appendChild(appearanceLabel);
        var themePanel = document.createElement('div');
        themePanel.className = 'gd-header-dropdown';
        themePanel.setAttribute('role', 'group');
        themePanel.setAttribute('aria-label', 'Theme');
        themes.forEach(function (theme) {
            var button = document.createElement('button');
            button.type = 'button';
            button.className = 'gd-theme-option';
            button.textContent = theme[1];
            button.setAttribute('aria-pressed', String(theme[0] === selected));
            button.addEventListener('click', function () {
                selected = applyTheme(theme[0]);
                try { localStorage.setItem(storageKey, selected); } catch (error) {}
                themePanel.querySelectorAll('button').forEach(function (item) {
                    item.setAttribute('aria-pressed', String(item === button));
                });
                appearance.open = false;
            });
            themePanel.appendChild(button);
        });
        appearance.appendChild(themePanel);
        controls.appendChild(appearance);
        var icons = {
            gear: '<path d="m10 2 .5 2a8 8 0 0 1 3 0l.5-2 3 1 0 2a8 8 0 0 1 2 2l2 0 1 3-2 .5a8 8 0 0 1 0 3l2 .5-1 3-2 0a8 8 0 0 1-2 2l0 2-3 1-.5-2a8 8 0 0 1-3 0L10 22l-3-1 0-2a8 8 0 0 1-2-2l-2 0-1-3 2-.5a8 8 0 0 1 0-3L2 10l1-3 2 0a8 8 0 0 1 2-2l0-2z"/><circle cx="12" cy="12" r="3" fill="#03052f"/>',
            watch: '<path d="M3 3h18v15h-6l-2 3h-2l-2-3H3zm2 2v11h5l2 3 2-3h5V5z"/>',
            user: '<circle cx="12" cy="7" r="4"/><path d="M3 22v-2a9 9 0 0 1 18 0v2z"/>'
        };
        function iconMarkup(name) {
            return '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">' + icons[name] + '</svg>';
        }
        function iconLink(id, name, label) {
            var original = document.querySelector('#' + id + ' a');
            if (!original) return;
            var link = original.cloneNode(false);
            link.className = 'gd-header-icon';
            link.title = label;
            link.setAttribute('aria-label', label);
            link.innerHTML = iconMarkup(name);
            controls.appendChild(link);
        }
        iconLink('pt-preferences', 'gear', 'Preferences');
        // Use Echo's actual widgets so alerts and notices retain their behavior.
        ['pt-notifications-alert', 'pt-notifications-notice'].forEach(function (id) {
            var notification = document.getElementById(id);
            if (notification) {
                notification.classList.add('gd-header-notification');
                controls.appendChild(notification);
            }
        });
        var account = document.createElement('details');
        account.className = 'gd-header-menu gd-account-menu';
        var accountLabel = document.createElement('summary');
        accountLabel.setAttribute('aria-label', 'Account menu');
        accountLabel.title = 'Account menu';
        var accountGroup = document.createElement('div');
        accountGroup.className = 'gd-account-group';
        var accountName = document.createElement('a');
        accountName.className = 'gd-account-talk-link';
        var userName = mw.config.get('wgUserName');
        accountName.href = mw.util.getUrl(userName ? 'User:' + userName : 'Special:UserLogin');
        accountName.innerHTML = iconMarkup('user');
        var nameText = document.createElement('span');
        nameText.textContent = userName || 'Account';
        accountName.appendChild(nameText);
        accountName.title = userName ? 'Your user page' : 'Log in';
        accountGroup.appendChild(accountName);
        account.appendChild(accountLabel);
        var duplicateUserPage = links.querySelector('#pt-userpage');
        if (duplicateUserPage) duplicateUserPage.remove();
        links.classList.add('gd-account-links');
        account.appendChild(links);
        accountGroup.appendChild(account);
        controls.appendChild(accountGroup);
        var barLogo = document.createElement('a');
        barLogo.className = 'gd-header-bar-logo';
        barLogo.href = mw.util.getUrl(mw.config.get('wgMainPageTitle') || 'Main Page');
        barLogo.title = mw.config.get('wgSiteName') || 'Geometry Dash Expanded Wiki';
        barLogo.setAttribute('aria-label', barLogo.title + ' main page');
        var logoImage = document.createElement('img');
        logoImage.src = 'https://geometrydashwiki.com/images/d/d4/Logo.jpg';
        logoImage.alt = ''; logoImage.width = 32; logoImage.height = 32;
        barLogo.appendChild(logoImage);
        personal.appendChild(barLogo);
        personal.appendChild(controls);
        personal.classList.add('gd-header-ready');
        document.addEventListener('click', function (event) {
            [appearance, account].forEach(function (menu) {
                if (!menu.contains(event.target)) menu.open = false;
            });
        });
        document.addEventListener('keydown', function (event) {
            if (event.key === 'Escape') { appearance.open = false; account.open = false; }
        });
    });
}());
/* Expanded multilingual navigation: shared accounts, files and Recent Changes. */
(function () {
    'use strict';
    mw.loader.using(['mediawiki.api', 'mediawiki.util']).then(function () {
        $(function () {
            var controls = document.querySelector('.gd-header-controls');
            if (!controls || document.getElementById('gd-language-menu')) return;
            var page = (mw.config.get('wgPageName') || 'Main_Page').replace(/_/g, ' ');
            var match = /^(Spa|Rus|Pol)\/(.+)$/.exec(page);
            var pathCode = /^\/(eng|spa|rus|pol)(?:\/|$)/.exec(location.pathname);
            var articleCode = match ? match[1].toLowerCase() : 'eng';
            var cookie = /(?:^|;\s*)gdwiki-language=(eng|spa|rus|pol)(?:;|$)/.exec(document.cookie);
            var code = cookie ? cookie[1] : (mw.config.get('wgExpandedActiveLanguage') || (pathCode ? pathCode[1] : articleCode));
            var base = match ? match[2] : page;
            var spanish = code === 'spa';
            var isArticle = mw.config.get('wgNamespaceNumber') === 0;
            document.documentElement.setAttribute('data-gd-language', code);
            var definitions = [
                {code:'eng', name:'English', lang:'en', flag:'/images/4/49/Flag_gb.svg'},
                {code:'spa', name:'Español', lang:'es', flag:'/images/2/2d/Flag_es.svg'}
            ];
            var menu = document.createElement('details');
            menu.id = 'gd-language-menu'; menu.className = 'gd-header-menu gd-language-menu';
            var summary = document.createElement('summary');
            summary.setAttribute('aria-label', spanish ? 'Cambiar idioma' : 'Change language');
            summary.title = summary.getAttribute('aria-label');
            var current = definitions[spanish ? 1 : 0];
            var image = document.createElement('img'); image.src=current.flag; image.alt=''; image.width=24; image.height=16;
            summary.appendChild(image);
            var label=document.createElement('span'); label.textContent=current.name; summary.appendChild(label);
            menu.appendChild(summary);
            var panel=document.createElement('div'); panel.className='gd-header-dropdown gd-language-options';
            panel.setAttribute('aria-label', spanish ? 'Idiomas' : 'Languages');
            menu.appendChild(panel);
            var personal = document.getElementById('p-personal');
            personal.appendChild(menu);
            var api=new mw.Api();
            function route(title, lang) {
                if (!mw.config.get('wgExpandedLanguageRoutes')) return mw.util.getUrl(title);
                var m=/^(Spa|Rus|Pol)\/(.+)$/.exec(title);
                var language=m ? m[1].toLowerCase() : 'eng';
                var name=m ? m[2] : title;
                if (name.indexOf(':')!==-1 && !m) return mw.util.getUrl(title);
                return '/'+language+'/'+encodeURIComponent(name.replace(/ /g,'_')).replace(/%2F/g,'/');
            }
            function build(mapping) {
                var entry=mapping[base] || {};
                Object.keys(mapping).some(function (key) {
                    if (mapping[key][articleCode]===page) {base=key;entry=mapping[key];return true;}
                    return false;
                });
                var titles=definitions.map(function (d) {
                    return isArticle ? (entry[d.code] || (d.code==='eng' ? base : 'Spa/'+base)) : page;
                });
                api.get({action:'query',titles:titles.join('|'),prop:'info',formatversion:2}).then(function (data) {
                    var existing={};
                    (data.query.pages || []).forEach(function (p) {existing[p.title]=!p.missing && !p.invalid;});
                    definitions.forEach(function (d,i) {
                        var available=existing[titles[i]], target=available || !isArticle ? titles[i] : titles[0];
                        var link=document.createElement('a');link.lang=d.lang;link.hreflang=d.lang;
                        var flag=document.createElement('img');flag.src=d.flag;flag.alt='';flag.width=24;flag.height=16;link.appendChild(flag);
                        var text=document.createElement('span');text.textContent=d.name;link.appendChild(text);
                        if(d.code===code)link.setAttribute('aria-current','page');
                        link.href=route(target,d.lang);
                        link.addEventListener('click',function () {
                            document.cookie='gdwiki-language='+d.code+'; Path=/; Max-Age=31536000; SameSite=Lax; Secure';
                            try {
                                localStorage.setItem('gdwiki-language',d.code);
                                if(isArticle && !available)sessionStorage.setItem('gdwiki-fallback',JSON.stringify({language:d.code,page:base}));
                            } catch(error) {}
                        });
                        panel.appendChild(link);
                    });
                    if(isArticle && !existing[titles[1]]) {
                        var create=document.createElement('a');create.className='gd-language-create';
                        create.textContent=spanish ? 'Crear traducción al español' : 'Create Spanish translation';
                        if(mw.config.get('wgExpandedLanguageEditorSafe')) {
                            var editParams={action:'edit',preload:titles[0],summary:'Start Español translation from [['+titles[0]+']]'};
                            create.href=route(titles[1],'es')+'?'+new URLSearchParams(editParams).toString();
                        } else {create.setAttribute('aria-disabled','true');create.title='Translation setup awaiting server update';}
                        panel.appendChild(create);
                    }
                    var home=document.createElement('a');home.className='gd-language-home';home.textContent=spanish ? 'Inicio' : 'Home';home.href=route('Main Page','en');panel.appendChild(home);
                    var guide=document.createElement('a');guide.textContent=spanish ? 'Guía de traducción' : 'Translation guide';guide.href=mw.util.getUrl('Help:Translations');panel.appendChild(guide);
                }, function () {panel.textContent=spanish ? 'No se pudieron cargar los idiomas. Recarga la página.' : 'Languages could not load. Reload the page.';});
            }
            api.get({action:'query',titles:'MediaWiki:Expanded-language-pages.json',prop:'revisions',rvprop:'content',rvslots:'main',formatversion:2}).then(function (data) {
                try {build(JSON.parse(data.query.pages[0].revisions[0].slots.main.content));} catch (error) {build({});}
            },function () {build({});});
            document.addEventListener('click',function (event) {if (!menu.contains(event.target)) menu.open=false;});
            document.addEventListener('keydown',function (event) {if (event.key==='Escape') menu.open=false;});
            if (spanish) {
                var interfaceLabels={"Navigation": "Navegación", "Main page": "Página principal", "Recent changes": "Cambios recientes", "New files": "Archivos nuevos", "Random page": "Página aleatoria", "New here? Get started": "¿Eres nuevo? Empieza aquí", ">> Site policy": ">> Normas del sitio", ">> Staff": ">> Administración", "Help using MediaWiki": "Ayuda sobre MediaWiki", "GD Base Content": "Contenido base de GD", "Games": "Juegos", "Main levels": "Niveles principales", "Gameplay": "Jugabilidad", "Rewards": "Recompensas", "Rooms (vaults etc.)": "Salas (bóvedas, etc.)", "Level editing": "Editor de niveles", "Account features": "Funciones de la cuenta", "Updates": "Actualizaciones", "GD Community Content": "Contenido de la comunidad de GD", "Demon List levels": "Niveles de la Demon List", "Gauntlet levels": "Niveles de gauntlets", "Map Pack levels": "Niveles de paquetes de mapas", "Classic levels": "Niveles clásicos", "Platformer levels": "Niveles de plataformas", "Players": "Jugadores", "Community activities": "Actividades de la comunidad", "Wiki Resources": "Recursos de la wiki", "Propose new articles": "Proponer artículos nuevos", "Submit edits for review": "Enviar cambios para revisión", "Admin Dashboard": "Panel de administración", "Images": "Imágenes", "Videos": "Vídeos", "Audio": "Audio", "PDFs": "PDF", "Templates": "Plantillas", "Sandbox": "Zona de pruebas", "Discuss the wiki": "Debatir sobre la wiki", "Guestbook": "Libro de visitas", "Tools": "Herramientas", "What links here": "Lo que enlaza aquí", "Related changes": "Cambios relacionados", "Upload file": "Subir archivo", "Printable version": "Versión para imprimir", "Permanent link": "Enlace permanente", "Page information": "Información de la página", "Account": "Cuenta", "Preferences": "Preferencias", "Your user page": "Tu página de usuario", "Log in": "Iniciar sesión", "Account menu": "Menú de cuenta", "Appearance": "Apariencia"};
                document.querySelectorAll('#mw-panel h3, #mw-panel h3 span, #mw-panel a, .gd-account-links a, .gd-account-talk-link span').forEach(function (element) {
                    var key=element.textContent.trim();
                    if (interfaceLabels[key]) {
                        // Translate text nodes without removing colour spans, links or icons.
                        var walker=document.createTreeWalker(element,NodeFilter.SHOW_TEXT), node;
                        while ((node=walker.nextNode())) {
                            var original=node.nodeValue.trim();
                            if (interfaceLabels[original]) node.nodeValue=node.nodeValue.replace(original,interfaceLabels[original]);
                        }
                    }
                });
                document.querySelectorAll('#p-personal [title], #p-personal [aria-label]').forEach(function (element) {
                    ['title','aria-label'].forEach(function (attr) {var key=element.getAttribute(attr);if(interfaceLabels[key])element.setAttribute(attr,interfaceLabels[key]);});
                });
                var appearance=controls.querySelector('.gd-header-menu summary');
                if (appearance) {appearance.textContent='Apariencia';appearance.title='Apariencia';appearance.setAttribute('aria-label','Apariencia');}
                var account=controls.querySelector('.gd-account-menu summary');
                if (account) {account.title='Menú de cuenta';account.setAttribute('aria-label','Menú de cuenta');}
                var titles={'Blue':'Azul','Purple':'Morado','Green':'Verde','Red':'Rojo','Dark':'Oscuro','Blackout':'Negro','Vault':'La bóveda','Vault of Secrets':'La bóveda de los secretos','Chamber of Time':'La cámara del tiempo'};
                controls.querySelectorAll('.gd-theme-option').forEach(function (button) {if(titles[button.textContent])button.textContent=titles[button.textContent];});
            }
            // Optional translated assets use the same existing theme filters.
            var logos=mw.config.get('wgExpandedLanguageLogos') || {};
            logos.spa=Object.assign({"header": "https://geometrydashwiki.com/images/4/4a/Logo-spa.jpg", "banner": "https://geometrydashwiki.com/images/a/a7/Site-logo-spa.png"},logos.spa || {});
            if (logos[code]) {
                if (logos[code].header) {
                    var header=document.querySelector('.gd-header-bar-logo img');if(header)header.src=logos[code].header;
                }
                if (logos[code].banner) document.documentElement.style.setProperty('--wiki-logo-image','url("'+logos[code].banner.replace(/["\\]/g,'')+'")');
            }
        });
    });
}());
/* Keep language parameters and script endpoints out of visible navigation URLs. */
(function () {
    'use strict';
    function clean(raw) {
        var url;
        try {url=new URL(raw,location.href);} catch(error) {return raw;}
        if (url.origin!==location.origin) return raw;
        url.searchParams.delete('uselang');
        if (/\/index\.php$/.test(url.pathname) && !url.searchParams.has('title') && url.searchParams.has('search')) {url.pathname='/wiki/Special:Search';}
        if (/\/index\.php$/.test(url.pathname) && url.searchParams.has('title')) {
            var title=url.searchParams.get('title');url.searchParams.delete('title');
            var match=/^(Spa|Rus|Pol)\/(.+)$/.exec(title.replace(/_/g,' '));
            var ns=title.indexOf(':')!==-1;
            var prefix=match ? '/'+match[1].toLowerCase()+'/' : (ns ? '/wiki/' : '/eng/');
            var name=match ? match[2] : title;
            url.pathname=prefix+encodeURIComponent(name.replace(/ /g,'_')).replace(/%2F/g,'/').replace(/%3A/g,':');
        }
        return url.pathname+url.search+url.hash;
    }
    // The current request has already chosen its interface language.
    var address=new URL(location.href);
    var cleanAddress=clean(location.href);
    if (cleanAddress!==address.pathname+address.search+address.hash) history.replaceState(null,'',cleanAddress);
    function links() {
        document.querySelectorAll('a[href]').forEach(function (link) {
            var href=link.getAttribute('href');
            if (href && !/^(?:#|javascript:|mailto:)/.test(href)) {
                var replacement=clean(href);if(replacement!==href)link.setAttribute('href',replacement);
            }
        });
    }
    $(function () {
        links();
        var pending=false;
        new MutationObserver(function () {
            if(pending)return;pending=true;
            requestAnimationFrame(function () {pending=false;links();});
        }).observe(document.body,{childList:true,subtree:true});
    });
    mw.hook('wikipage.content').add(links);
    // Also handles asynchronously built language and account menus.
    document.addEventListener('click',function(event) {
        var link=event.target.closest && event.target.closest('a[href]');
        if(link)link.setAttribute('href',clean(link.getAttribute('href')));
    },true);
}());
/* Article-language tabs and links follow the persistent site language. */
(function () {
    'use strict';
    mw.loader.using(['mediawiki.api','mediawiki.util']).then(function () {
        $(function () {
            var cookie=/(?:^|;\s*)gdwiki-language=(eng|spa|rus|pol)(?:;|$)/.exec(document.cookie);
            var mode=cookie ? cookie[1] : (mw.config.get('wgExpandedActiveLanguage') || mw.config.get('wgExpandedLanguage') || 'eng');
            var names={eng:'English',spa:'Español',rus:'Русский',pol:'Polski'};
            var notices={eng:'This article is not available in English. Showing the original article.',spa:'Este artículo todavía no está disponible en español. Se muestra la versión en inglés.',rus:'Эта статья пока недоступна на русском языке. Показана английская версия.',pol:'Ten artykuł nie jest jeszcze dostępny po polsku. Wyświetlono wersję angielską.'};
            try {
                var pending=JSON.parse(sessionStorage.getItem('gdwiki-fallback') || 'null');
                sessionStorage.removeItem('gdwiki-fallback');
                if(!pending && mw.config.get('wgExpandedLanguageFallback'))pending={language:mw.config.get('wgExpandedLanguageFallback')};
                if(pending && notices[pending.language])mw.notify(notices[pending.language],{tag:'gd-language-fallback',autoHideSeconds:10});
            } catch(error) {}
            function rememberFallback(language) {
                try {sessionStorage.setItem('gdwiki-fallback',JSON.stringify({language:language}));} catch(error) {}
            }
            function normal(title) {title=title.replace(/_/g,' ').trim();return title.charAt(0).toUpperCase()+title.slice(1);}
            function bare(title) {return title.replace(/^(?:Spa|Rus|Pol)\//,'');}
            function route(title) {
                var m=/^(Spa|Rus|Pol)\/(.+)$/.exec(title);
                return '/'+(m ? m[1].toLowerCase() : 'eng')+'/'+encodeURIComponent((m ? m[2] : title).replace(/ /g,'_')).replace(/%2F/g,'/');
            }
            var api=new mw.Api();
            api.get({action:'query',titles:'MediaWiki:Expanded-language-pages.json',prop:'revisions',rvprop:'content',rvslots:'main',formatversion:2}).then(function (data) {
                var map;
                try {map=JSON.parse(data.query.pages[0].revisions[0].slots.main.content);} catch(error) {map={};}
                var aliases={};
                Object.keys(map).forEach(function (root) {
                    if(!map[root] || typeof map[root]!=='object')return;
                    [root].concat(Object.keys(map[root]).map(function (key) {return map[root][key];})).forEach(function (title) {
                        if(typeof title!=='string')return;
                        [normal(title),normal(bare(title))].forEach(function (alias) {
                            if(!aliases[alias])aliases[alias]=[];
                            if(aliases[alias].indexOf(root)===-1)aliases[alias].push(root);
                        });
                    });
                });
                function group(title) {
                    var roots=aliases[normal(title)] || [];
                    if(roots.length===1)return map[roots[0]];
                    if(roots.length>1)return null; // Never guess between unrelated concepts.
                    var english=bare(normal(title));return {eng:english,spa:'Spa/'+english,rus:'Rus/'+english,pol:'Pol/'+english};
                }
                var links=[],checks={},current=(mw.config.get('wgPageName') || '').replace(/_/g,' ');
                document.querySelectorAll('#mw-content-text a[href], #mw-panel a[href], .gd-header-bar-logo, .gd-language-home').forEach(function (link) {
                    var url;try {url=new URL(link.href);}catch(error){return;}
                    if(url.origin!==location.origin)return;
                    if(link.getAttribute('href').charAt(0)==='#')return;
                    var path=/^\/(?:eng|spa|rus|pol|wiki)\/(.+)$/.exec(url.pathname);
                    if(!path && url.pathname!=='/')return;
                    var title=path ? decodeURIComponent(path[1]).replace(/_/g,' ') : (mw.config.get('wgMainPageTitle') || 'Main Page');
                    if(/^\/(spa|rus|pol)\//.test(url.pathname))title=url.pathname.split('/')[1].charAt(0).toUpperCase()+url.pathname.split('/')[1].slice(1)+'/'+title;
                    if(title.indexOf(':')!==-1)return;
                    var action=url.searchParams.get('action');
                    var redlink=url.searchParams.get('redlink')==='1';
                    if((action && action!=='view' && !redlink) || url.searchParams.has('veaction') || url.searchParams.has('oldid') || url.searchParams.has('diff'))return;
                    if(normal(title)===normal(current) && url.hash)return;
                    var versions=group(title);if(!versions)return;
                    Object.keys(versions).forEach(function (lang) {checks[versions[lang]]=true;});
                    links.push({element:link,url:url,title:title,versions:versions});
                });
                var currentVersions=group(current);
                if(currentVersions)Object.keys(currentVersions).forEach(function (lang) {checks[currentVersions[lang]]=true;});
                var titles=Object.keys(checks),batches=[];
                for(var i=0;i<titles.length;i+=40)batches.push(titles.slice(i,i+40));
                Promise.all(batches.map(function (batch) {return api.get({action:'query',titles:batch.join('|'),prop:'info',formatversion:2});})).then(function (results) {
                    var exists={};results.forEach(function (result) {(result.query.pages || []).forEach(function (p) {exists[normal(p.title)]=!p.missing && !p.invalid;});});
                    links.forEach(function (item) {
                        var preferred=item.versions[mode],english=item.versions.eng;
                        var available=preferred && exists[normal(preferred)];
                        var target=available ? preferred : english;
                        if(!target || !exists[normal(target)])return;
                        item.url.searchParams.delete('title');item.url.searchParams.delete('uselang');item.url.searchParams.delete('redlink');if(item.url.searchParams.get('action')==='edit')item.url.searchParams.delete('action');
                        item.element.href=route(target)+(item.url.searchParams.size ? '?'+item.url.searchParams.toString() : '')+item.url.hash;
                        item.element.classList.remove('new');
                        if(!available && mode!=='eng')item.element.addEventListener('click',function () {rememberFallback(mode);});
                        // Prefixes are storage details, not part of the displayed article name.
                        if(item.element.textContent.trim()===item.title)item.element.textContent=bare(item.title);
                    });
                    if(!currentVersions || mw.config.get('wgNamespaceNumber')!==0 || mw.config.get('wgAction')!=='view')return;
                    var languages=Object.keys(names).filter(function (lang) {return currentVersions[lang] && exists[normal(currentVersions[lang])];});
                    if(languages.length<2 || document.getElementById('gd-article-languages'))return;
                    var nav=document.createElement('nav');nav.id='gd-article-languages';nav.className='gd-article-languages';nav.setAttribute('aria-label',mode==='spa' ? 'Idiomas del artículo' : 'Article languages');
                    languages.forEach(function (lang) {
                        var link=document.createElement('a');link.textContent=names[lang];link.href=route(currentVersions[lang]);link.setAttribute('data-gd-language-tab','');
                        if(normal(currentVersions[lang])===normal(current))link.setAttribute('aria-current','page');
                        nav.appendChild(link);
                    });
                    var heading=document.getElementById('firstHeading');if(heading){document.body.classList.add('gd-has-language-tabs');heading.appendChild(nav);}
                },function () { /* Preserve original working links if availability cannot be checked. */ });
            });
        });
    });
}());
/* Infobox labels: reader language on shared pages, article language on articles. */
(function () {
'use strict';
var labels={"Born": {"spa": "Nacimiento", "rus": "Дата рождения", "pol": "Data urodzenia"}, "Died": {"spa": "Fallecimiento", "rus": "Дата смерти", "pol": "Data śmierci"}, "Other names": {"spa": "Otros nombres", "rus": "Другие имена", "pol": "Inne nazwy"}, "Country": {"spa": "País", "rus": "Страна", "pol": "Kraj"}, "Mod status": {"spa": "Estado de moderador", "rus": "Статус модератора", "pol": "Status moderatora"}, "Uploaded levels": {"spa": "Niveles publicados", "rus": "Опубликованные уровни", "pol": "Opublikowane poziomy"}, "Rated levels": {"spa": "Niveles calificados", "rus": "Оценённые уровни", "pol": "Ocenione poziomy"}, "Creator points": {"spa": "Puntos de creador", "rus": "Очки создателя", "pol": "Punkty twórcy"}, "GD stats": {"spa": "Estadísticas de GD", "rus": "Статистика GD", "pol": "Statystyki GD"}, "Social media": {"spa": "Redes sociales", "rus": "Социальные сети", "pol": "Media społecznościowe"}, "Other": {"spa": "Otros", "rus": "Другое", "pol": "Inne"}, "Please search": {"spa": "Buscar", "rus": "Найти", "pol": "Wyszukaj"}, "Information": {"spa": "Información", "rus": "Информация", "pol": "Informacje"}, "Statistics": {"spa": "Estadísticas", "rus": "Статистика", "pol": "Statystyki"}, "Total jumps": {"spa": "Saltos totales", "rus": "Всего прыжков", "pol": "Łączna liczba skoków"}, "Total attempts": {"spa": "Intentos totales", "rus": "Всего попыток", "pol": "Łączna liczba prób"}, "Main levels": {"spa": "Niveles principales", "rus": "Основные уровни", "pol": "Główne poziomy"}, "Online levels": {"spa": "Niveles en línea", "rus": "Онлайн-уровни", "pol": "Poziomy online"}, "Daily levels": {"spa": "Niveles diarios", "rus": "Ежедневные уровни", "pol": "Poziomy dzienne"}, "Gauntlets": {"spa": "Gauntlets", "rus": "Испытания", "pol": "Gauntlety"}, "Map packs": {"spa": "Paquetes de mapas", "rus": "Наборы уровней", "pol": "Pakiety map"}, "Liked / disliked": {"spa": "Me gusta / no me gusta", "rus": "Лайки / дизлайки", "pol": "Polubione / nielubiane"}, "Chests opened": {"spa": "Cofres abiertos", "rus": "Открытые сундуки", "pol": "Otwarte skrzynie"}, "Players destroyed": {"spa": "Jugadores destruidos", "rus": "Уничтоженные игроки", "pol": "Zniszczeni gracze"}, "Leaderboard": {"spa": "Clasificación", "rus": "Таблица лидеров", "pol": "Ranking"}, "Last updated": {"spa": "Última actualización", "rus": "Последнее обновление", "pol": "Ostatnia aktualizacja"}};
function translate(root) {
 var page=mw.config.get('wgPageName') || '',match=/^(Spa|Rus|Pol)\//.exec(page),cookie=/(?:^|;\s*)gdwiki-language=(eng|spa|rus|pol)(?:;|$)/.exec(document.cookie);
 var lang=mw.config.get('wgNamespaceNumber')===0 ? (match ? match[1].toLowerCase() : 'eng') : (cookie ? cookie[1] : (mw.config.get('wgExpandedActiveLanguage') || 'eng'));
 root.querySelectorAll('[data-gd-infobox-label]').forEach(function (el) {var key=el.getAttribute('data-gd-infobox-label');el.textContent=(labels[key] && labels[key][lang]) || key;});
 root.querySelectorAll('[data-gd-stats-name]').forEach(function(el){var name=el.getAttribute('data-gd-stats-name');el.textContent=lang==='spa' ? 'Estadísticas de '+name : lang==='rus' ? 'Статистика '+name : lang==='pol' ? 'Statystyki '+name : name+"’s stats";});
}
$(function(){translate(document);mw.hook('wikipage.content').add(function(content){translate(content[0] || document);});});
})();