Участник:Урахара/logoswitcher.js

Материал из Циклопедии
Перейти к навигации Перейти к поиску

Замечание: Возможно, после публикации вам придётся очистить кэш своего браузера, чтобы увидеть изменения.

  • Firefox / Safari: Удерживая клавишу Shift, нажмите на панели инструментов Обновить либо нажмите Ctrl+F5 или Ctrl+R (⌘+R на Mac)
  • Google Chrome: Нажмите Ctrl+Shift+R (⌘+Shift+R на Mac)
  • Internet Explorer / Edge: Удерживая Ctrl, нажмите Обновить либо нажмите Ctrl+F5
  • Opera: Нажмите Ctrl+F5.
/*
 **************************************************************
 *            ГАДЖЕТ ДИНАМИЧЕСКОЙ ЗАМЕНЫ ЛОГОТИПА             *
 * С масштабированием для всех скинов Циклопедии на март 2026 *
 *           Автор: Урахара, лицензия: CC BY-SA 4.0           *
 *        Рабочей базой служил движок Mediawiki 1.39.1        *
 **************************************************************
 */
(function() {
    'use strict';
    
    if (typeof mw === 'undefined' || !mw.util) {
        return;
    }
    
    var config = mw.config.get(['skin']);
    var currentSkin = config.skin;
    
    var LOGO_URLS = {
        ru: 'https://dg.cyclowiki.org/images/5/53/Newcyclo-ru.svg',
        not: 'https://dg.cyclowiki.org/images/4/42/Newcyclo-not.svg'
    };
    
    var RU_SKINS = ['vector', 'anisa', 'citizen'];
    
    /**
     * Конфигурация для разных скинов
     */
    var SKIN_CONFIG = {
        vector: {
            selector: '.mw-wiki-logo',
            extraStyles: {
                backgroundSize: 'contain',
                backgroundRepeat: 'no-repeat',
                backgroundPosition: 'center'
            },
            clearStyles: ['backgroundImage']
        },
        // Рабочее решение для Citizen
        citizen: {
            selector: '.citizen-header-logo a',
            useMask: true,
            extraStyles: {
                maskSize: 'contain',
                maskRepeat: 'no-repeat',
                maskPosition: 'center',
                WebkitMaskSize: 'contain',
                WebkitMaskRepeat: 'no-repeat',
                WebkitMaskPosition: 'center',
                backgroundColor: 'transparent'
            },
            clearStyles: ['maskImage', 'WebkitMaskImage', 'backgroundImage']
        },
        anisa: {
            selector: '.site-logo a',
            extraStyles: {
                backgroundSize: 'contain',
                backgroundRepeat: 'no-repeat',
                backgroundPosition: 'center'
            }
        },
        // Timeless-настройки с -2px
        timeless: {
            selector: '#p-logo-text a',
            extraStyles: {
                // Логотип 32x32 слева
                backgroundImage: '',
                backgroundSize: '32px 32px',
                backgroundRepeat: 'no-repeat',
                backgroundPosition: 'left center',
                // Отступ для текста
                paddingLeft: '42px',
                // Размеры контейнера
                display: 'inline-block',
                minWidth: '180px',
                height: '32px',
                lineHeight: '32px',
                margin: '0',
                marginTop: '-2px',
                // Стили текста
                fontSize: '22px',
                fontWeight: 'bold',
                fontFamily: '"Linux Libertine", "Georgia", "Times", serif',
                color: '#333',
                textDecoration: 'none',
                verticalAlign: 'top'
            },
            clearStyles: ['backgroundImage']
        },
        // Minerva: логотип слева от надписи
        minerva: {
            selector: '.branding-box a',
            extraStyles: {
                // Логотип 24x24 слева
                backgroundImage: '',
                backgroundSize: '24px 24px',
                backgroundRepeat: 'no-repeat',
                backgroundPosition: 'left center',
                // Отступ для текста
                paddingLeft: '32px',
                // Размеры и стили с flex-выравниванием
                display: 'flex',
                alignItems: 'center',
                minWidth: '120px',
                height: '32px',
                margin: '0',
                fontSize: '16px',
                fontWeight: 'bold',
                color: '#333',
                textDecoration: 'none',
                lineHeight: 'normal'
            },
            clearStyles: ['backgroundImage']
        },
        default: {
            selector: '.mw-wiki-logo',
            extraStyles: {
                backgroundSize: 'contain',
                backgroundRepeat: 'no-repeat',
                backgroundPosition: 'center'
            }
        }
    };
    
    function getSkinConfig(skin) {
        return SKIN_CONFIG[skin] || SKIN_CONFIG.default;
    }
    
    /**
     * Очищает старые стили логотипа
     */
    function clearOldLogo(logoElement, skinConfig) {
        if (!logoElement) return;
        
        // Сбрасываем конкретные стили
        if (skinConfig.clearStyles) {
            skinConfig.clearStyles.forEach(function(styleProp) {
                logoElement.style[styleProp] = '';
            });
        }
        
        // Для Citizen сбрасываем mask-image полностью
        if (skinConfig.useMask) {
            logoElement.style.mask = '';
            logoElement.style.WebkitMask = '';
        }
        
        // Удаляем внутренние картинки если нужно
        if (skinConfig.removeImage) {
            var imgs = logoElement.querySelectorAll('img');
            imgs.forEach(function(img) {
                img.style.display = 'none';
            });
        }
        
        // На всякий случай сбрасываем background
        logoElement.style.background = 'transparent';
        logoElement.style.backgroundColor = 'transparent';
    }
    
    /**
     * Замена логотипа с сохранением пропорций
     */
    function replaceLogo(logoUrl) {
        var skinConfig = getSkinConfig(currentSkin);
        var logoElement = document.querySelector(skinConfig.selector);
        
        if (logoElement) {
            // Сначала очищаем старый логотип
            clearOldLogo(logoElement, skinConfig);
            
            if (skinConfig.useMask) {
                // Для Citizen используем mask-image
                logoElement.style.maskImage = 'url("' + logoUrl + '")';
                logoElement.style.WebkitMaskImage = 'url("' + logoUrl + '")';
            } else {
                // Для остальных используем background-image
                logoElement.style.backgroundImage = 'url("' + logoUrl + '")';
            }
            
            Object.keys(skinConfig.extraStyles).forEach(function(prop) {
                if (prop !== 'backgroundImage') {
                    logoElement.style[prop] = skinConfig.extraStyles[prop];
                }
            });
            
            // Для Timeless оставляем текст
            if (currentSkin === 'timeless') {
                if (!logoElement.textContent.trim()) {
                    logoElement.textContent = 'ЦИКЛОПЕДИЯ';
                }
                
                var parent = logoElement.closest('#p-logo-text');
                if (parent) {
                    parent.style.margin = '0';
                    parent.style.padding = '0';
                    parent.style.height = '32px';
                    parent.style.marginTop = '-2px';
                    parent.style.overflow = 'visible';
                }
            }
            
            // Для Minerva убеждаемся что текст есть
            if (currentSkin === 'minerva') {
                if (!logoElement.textContent.trim()) {
                    logoElement.textContent = 'ЦИКЛОПЕДИЯ';
                }
            }
            
            return true;
        }
        
        var fallbackSelectors = [
            '#p-logo a',
            '.mw-logo',
            '.mw-logo-container',
            '.header-logo a',
            '.mw-wiki-logo'
        ];
        
        for (var i = 0; i < fallbackSelectors.length; i++) {
            var fallbackElement = document.querySelector(fallbackSelectors[i]);
            if (fallbackElement) {
                // Очищаем
                fallbackElement.style.backgroundImage = '';
                fallbackElement.style.maskImage = '';
                fallbackElement.style.WebkitMaskImage = '';
                fallbackElement.style.backgroundImage = 'url("' + logoUrl + '")';
                fallbackElement.style.backgroundSize = 'contain';
                fallbackElement.style.backgroundRepeat = 'no-repeat';
                fallbackElement.style.backgroundPosition = 'center';
                
                // Прячем картинки внутри
                var innerImg = fallbackElement.querySelector('img');
                if (innerImg) {
                    innerImg.style.display = 'none';
                }
                return true;
            }
        }
        
        return false;
    }
    
    function watchForLogo(logoUrl) {
        var observer = new MutationObserver(function() {
            if (replaceLogo(logoUrl)) {
                observer.disconnect();
            }
        });
        
        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
        
        setTimeout(function() {
            observer.disconnect();
        }, 5000);
    }
    
    function escapeCssUrl(url) {
        return url.replace(/[\\"']/g, '\\$&').replace(/[()]/g, '\\$&');
    }
    
    function isValidHttpUrl(url) {
        try {
            var urlObject = new URL(url);
            return urlObject.protocol === 'http:' || urlObject.protocol === 'https:';
        } catch (_) {
            return false;
        }
    }
    
    mw.hook('userjs.dynamicLogo').add(function(customConfig) {
        try {
            if (customConfig) {
                if (customConfig.urls) {
                    Object.keys(customConfig.urls).forEach(function(key) {
                        var url = customConfig.urls[key];
                        if (isValidHttpUrl(url)) {
                            LOGO_URLS[key] = url;
                        }
                    });
                }
                if (Array.isArray(customConfig.skins)) {
                    RU_SKINS = customConfig.skins;
                }
            }
            
            var targetUrl = RU_SKINS.includes(currentSkin) ? LOGO_URLS.ru : LOGO_URLS.not;
            var escapedUrl = escapeCssUrl(targetUrl);
            
            mw.util.addCSS(
                '.mw-wiki-logo { background-image: url("' + escapedUrl + '") !important; background-size: contain !important; background-repeat: no-repeat !important; background-position: center !important; }'
            );
            
            // рабочее CSS для Citizen
            if (currentSkin === 'citizen') {
                mw.util.addCSS(
                    '.citizen-header-logo a { mask-image: url("' + escapedUrl + '") !important; -webkit-mask-image: url("' + escapedUrl + '") !important; mask-size: contain !important; -webkit-mask-size: contain !important; mask-repeat: no-repeat !important; -webkit-mask-repeat: no-repeat !important; mask-position: center !important; -webkit-mask-position: center !important; background-color: currentColor !important; background-image: none !important; }'
                );
            }
            
            // Timeless с -2px
            if (currentSkin === 'timeless') {
                mw.util.addCSS(
                    '#p-logo-text { ' +
                    'height: 32px !important; ' +
                    'margin: 0 !important; ' +
                    'padding: 0 !important; ' +
                    'margin-top: -2px !important; ' +
                    'overflow: visible !important; ' +
                    '} ' +
                    
                    '#p-logo-text a { ' +
                    'background-image: url("' + escapedUrl + '") !important; ' +
                    'background-size: 32px 32px !important; ' +
                    'background-repeat: no-repeat !important; ' +
                    'background-position: left center !important; ' +
                    'padding-left: 42px !important; ' +
                    'display: inline-block !important; ' +
                    'min-width: 180px !important; ' +
                    'height: 32px !important; ' +
                    'line-height: 32px !important; ' +
                    'margin: 0 !important; ' +
                    'margin-top: -2px !important; ' +
                    'font-size: 22px !important; ' +
                    'font-weight: bold !important; ' +
                    'font-family: "Linux Libertine", "Georgia", "Times", serif !important; ' +
                    'color: #333 !important; ' +
                    'text-decoration: none !important; ' +
                    'vertical-align: top !important; ' +
                    '} '
                );
            }
            
            // Minerva: логотип 24x24 слева от текста
            if (currentSkin === 'minerva') {
                mw.util.addCSS(
                    '.branding-box a { ' +
                    'background-image: url("' + escapedUrl + '") !important; ' +
                    'background-size: 24px 24px !important; ' +
                    'background-repeat: no-repeat !important; ' +
                    'background-position: left center !important; ' +
                    'padding-left: 32px !important; ' +
                    'display: flex !important; ' +
                    'align-items: center !important; ' +
                    'min-width: 120px !important; ' +
                    'height: 32px !important; ' +
                    'font-size: 16px !important; ' +
                    'font-weight: bold !important; ' +
                    'color: #333 !important; ' +
                    'text-decoration: none !important; ' +
                    'line-height: normal !important; ' +
                    '} '
                );
            }
            
            if (!replaceLogo(targetUrl)) {
                watchForLogo(targetUrl);
            } else {
                // таймер для Citizen
                if (currentSkin === 'citizen') {
                    setTimeout(function() {
                        replaceLogo(targetUrl);
                    }, 200);
                }
                if (currentSkin === 'timeless') {
                    setTimeout(function() {
                        replaceLogo(targetUrl);
                    }, 300);
                }
                // Для Minerva тоже таймер на всякий случай
                if (currentSkin === 'minerva') {
                    setTimeout(function() {
                        replaceLogo(targetUrl);
                    }, 300);
                }
            }
            
        } catch (error) {}
    }).fire();
})();