MediaWiki:Vector.js: Difference between revisions

From Geometry Dash Expanded Wiki
Jump to navigation Jump to search
Link the header username to its user page and remove the duplicate account menu entry
Show translation creation links entirely in their target language
 
(14 intermediate revisions by the same user not shown)
Line 245: Line 245:
         accountGroup.appendChild(account);
         accountGroup.appendChild(account);
         controls.appendChild(accountGroup);
         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 257: 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', russian = code === 'rus';
            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'},
                {code:'rus', name:'Русский', lang:'ru', flag:'/images/d/d7/Flag_ru.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', russian ? 'Выбрать язык' : (spanish ? 'Cambiar idioma' : 'Change language'));
            summary.title = summary.getAttribute('aria-label');
            var current = definitions.filter(function(d){return d.code===code;})[0] || definitions[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', russian ? 'Языки' : (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 : d.code.charAt(0).toUpperCase()+d.code.slice(1)+'/'+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);
                    });
                    definitions.forEach(function(d,i){
                        if(!isArticle || d.code==='eng' || existing[titles[i]])return;
                        var create=document.createElement('a');create.className='gd-language-create';
                        create.textContent=({spa:'Crear traducción al español',rus:'Создать перевод на русский',pol:'Utwórz polskie tłumaczenie'})[d.code] || 'Create English translation';
                        create.lang=d.lang;
                        if(mw.config.get('wgExpandedLanguageEditorSafe')) {
                            var editParams={action:'edit',preload:titles[0],summary:'Start '+d.name+' translation from [['+titles[0]+']]'};
                            create.href=route(titles[i],d.lang)+'?'+new URLSearchParams(editParams).toString();
                        } else {create.setAttribute('aria-disabled','true');create.title=russian ? 'Ожидается обновление сервера' : 'Translation setup awaiting server update';}
                        panel.appendChild(create);
                    });
                    var home=document.createElement('a');home.className='gd-language-home';home.textContent=russian ? 'Главная' : (spanish ? 'Inicio' : 'Home');home.href=route('Main Page','en');panel.appendChild(home);
                    var guide=document.createElement('a');guide.textContent=russian ? 'Руководство по переводу' : (spanish ? 'Guía de traducción' : 'Translation guide');guide.href=mw.util.getUrl('Help:Translations');panel.appendChild(guide);
                }, function () {panel.textContent=russian ? 'Не удалось загрузить языки. Обновите страницу.' : (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 || russian) {
                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"};
                if(russian)interfaceLabels={"Navigation": "Навигация", "Main page": "Главная страница", "Recent changes": "Свежие правки", "New files": "Новые файлы", "Random page": "Случайная страница", "New here? Get started": "Впервые здесь? Начните здесь", ">> Site policy": ">> Правила сайта", ">> Staff": ">> Администрация", "Help using MediaWiki": "Справка MediaWiki", "GD Base Content": "Основной контент GD", "Games": "Игры", "Main levels": "Основные уровни", "Gameplay": "Игровой процесс", "Rewards": "Награды", "Rooms (vaults etc.)": "Локации и хранилища", "Level editing": "Редактор уровней", "Account features": "Возможности аккаунта", "Updates": "Обновления", "GD Community Content": "Контент сообщества GD", "Demon List levels": "Уровни Demon List", "Gauntlet levels": "Испытания", "Map Pack levels": "Наборы уровней", "Classic levels": "Классические уровни", "Platformer levels": "Платформеры", "Players": "Игроки", "Community activities": "События сообщества", "Wiki Resources": "Ресурсы вики", "Propose new articles": "Предложить статью", "Submit edits for review": "Отправить правки на проверку", "Admin Dashboard": "Панель администратора", "Images": "Изображения", "Videos": "Видео", "Audio": "Аудио", "PDFs": "PDF", "Templates": "Шаблоны", "Sandbox": "Песочница", "Discuss the wiki": "Обсуждение вики", "Guestbook": "Гостевая книга", "Tools": "Инструменты", "What links here": "Ссылки сюда", "Related changes": "Связанные правки", "Upload file": "Загрузить файл", "Printable version": "Версия для печати", "Permanent link": "Постоянная ссылка", "Page information": "Сведения о странице", "Account": "Учётная запись", "Preferences": "Настройки", "Your user page": "Ваша страница", "Log in": "Войти", "Account menu": "Меню учётной записи", "Appearance": "Оформление"};
                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=interfaceLabels.Appearance;appearance.title=interfaceLabels.Appearance;appearance.setAttribute('aria-label',interfaceLabels.Appearance);}
                var account=controls.querySelector('.gd-account-menu summary');
                if (account) {account.title=interfaceLabels['Account menu'];account.setAttribute('aria-label',interfaceLabels['Account menu']);}
                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'};
                if(russian)titles={"Blue": "Синий", "Purple": "Фиолетовый", "Green": "Зелёный", "Red": "Красный", "Dark": "Тёмная", "Blackout": "Чёрная", "Vault": "Хранилище", "Vault of Secrets": "Хранилище секретов", "Chamber of Time": "Комната времени"};
                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 03:28, 18 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', russian = code === 'rus';
            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'},
                {code:'rus', name:'Русский', lang:'ru', flag:'/images/d/d7/Flag_ru.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', russian ? 'Выбрать язык' : (spanish ? 'Cambiar idioma' : 'Change language'));
            summary.title = summary.getAttribute('aria-label');
            var current = definitions.filter(function(d){return d.code===code;})[0] || definitions[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', russian ? 'Языки' : (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 : d.code.charAt(0).toUpperCase()+d.code.slice(1)+'/'+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);
                    });
                    definitions.forEach(function(d,i){
                        if(!isArticle || d.code==='eng' || existing[titles[i]])return;
                        var create=document.createElement('a');create.className='gd-language-create';
                        create.textContent=({spa:'Crear traducción al español',rus:'Создать перевод на русский',pol:'Utwórz polskie tłumaczenie'})[d.code] || 'Create English translation';
                        create.lang=d.lang;
                        if(mw.config.get('wgExpandedLanguageEditorSafe')) {
                            var editParams={action:'edit',preload:titles[0],summary:'Start '+d.name+' translation from [['+titles[0]+']]'};
                            create.href=route(titles[i],d.lang)+'?'+new URLSearchParams(editParams).toString();
                        } else {create.setAttribute('aria-disabled','true');create.title=russian ? 'Ожидается обновление сервера' : 'Translation setup awaiting server update';}
                        panel.appendChild(create);
                    });
                    var home=document.createElement('a');home.className='gd-language-home';home.textContent=russian ? 'Главная' : (spanish ? 'Inicio' : 'Home');home.href=route('Main Page','en');panel.appendChild(home);
                    var guide=document.createElement('a');guide.textContent=russian ? 'Руководство по переводу' : (spanish ? 'Guía de traducción' : 'Translation guide');guide.href=mw.util.getUrl('Help:Translations');panel.appendChild(guide);
                }, function () {panel.textContent=russian ? 'Не удалось загрузить языки. Обновите страницу.' : (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 || russian) {
                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"};
                if(russian)interfaceLabels={"Navigation": "Навигация", "Main page": "Главная страница", "Recent changes": "Свежие правки", "New files": "Новые файлы", "Random page": "Случайная страница", "New here? Get started": "Впервые здесь? Начните здесь", ">> Site policy": ">> Правила сайта", ">> Staff": ">> Администрация", "Help using MediaWiki": "Справка MediaWiki", "GD Base Content": "Основной контент GD", "Games": "Игры", "Main levels": "Основные уровни", "Gameplay": "Игровой процесс", "Rewards": "Награды", "Rooms (vaults etc.)": "Локации и хранилища", "Level editing": "Редактор уровней", "Account features": "Возможности аккаунта", "Updates": "Обновления", "GD Community Content": "Контент сообщества GD", "Demon List levels": "Уровни Demon List", "Gauntlet levels": "Испытания", "Map Pack levels": "Наборы уровней", "Classic levels": "Классические уровни", "Platformer levels": "Платформеры", "Players": "Игроки", "Community activities": "События сообщества", "Wiki Resources": "Ресурсы вики", "Propose new articles": "Предложить статью", "Submit edits for review": "Отправить правки на проверку", "Admin Dashboard": "Панель администратора", "Images": "Изображения", "Videos": "Видео", "Audio": "Аудио", "PDFs": "PDF", "Templates": "Шаблоны", "Sandbox": "Песочница", "Discuss the wiki": "Обсуждение вики", "Guestbook": "Гостевая книга", "Tools": "Инструменты", "What links here": "Ссылки сюда", "Related changes": "Связанные правки", "Upload file": "Загрузить файл", "Printable version": "Версия для печати", "Permanent link": "Постоянная ссылка", "Page information": "Сведения о странице", "Account": "Учётная запись", "Preferences": "Настройки", "Your user page": "Ваша страница", "Log in": "Войти", "Account menu": "Меню учётной записи", "Appearance": "Оформление"};
                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=interfaceLabels.Appearance;appearance.title=interfaceLabels.Appearance;appearance.setAttribute('aria-label',interfaceLabels.Appearance);}
                var account=controls.querySelector('.gd-account-menu summary');
                if (account) {account.title=interfaceLabels['Account menu'];account.setAttribute('aria-label',interfaceLabels['Account menu']);}
                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'};
                if(russian)titles={"Blue": "Синий", "Purple": "Фиолетовый", "Green": "Зелёный", "Red": "Красный", "Dark": "Тёмная", "Blackout": "Чёрная", "Vault": "Хранилище", "Vault of Secrets": "Хранилище секретов", "Chamber of Time": "Комната времени"};
                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);});});
})();