Участник:Урахара/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();
})();