MediaWiki:Common.js
Увага: Після публікування слід очистити кеш браузера, щоб побачити зміни.
- Firefox / Safari: тримайте Shift, коли натискаєте Оновити, або натисніть Ctrl-F5 чи Ctrl-Shift-R (⌘-R на Apple Mac)
- Google Chrome: натисніть Ctrl-Shift-R (⌘-Shift-R на Apple Mac)
- Internet Explorer / Edge: тримайте Ctrl, коли натискаєте Оновити, або натисніть Ctrl-F5
- Opera: натисніть Ctrl-F5
// ==================================================
// RANDOM ARTICLES
// ==================================================
$(document).ready(function() {
var apiUrl = mw.config.get('wgScriptPath') + '/api.php';
$.getJSON(apiUrl, {
action: 'query',
format: 'json',
list: 'random',
rnnamespace: '0',
rnlimit: '5',
prop: 'extracts',
exchars: '250',
exlimit: 'max',
explaintext: true
}, function(data) {
var html = '';
$.each(data.query.random, function(i, article) {
html += '<div class="random-article-preview">';
html += '<h2><a href="/wiki/' + encodeURIComponent(article.title) + '">' + article.title + '</a></h2>';
html += '<p>' + article.extract + '</p>';
html += '</div>';
});
$('#random-articles-container').html(html);
});
});
// ==================================================
// L-BOX NAVIGATION
// ==================================================
$(function() {
var items = $('.l-box-item');
var sections = [];
items.each(function() {
var target = $(this).data('target');
if (target === 'top') {
sections.push({item: $(this), target: null, offset: 0});
} else {
var el = document.getElementById(target);
if (el) {
sections.push({item: $(this), target: $(el), offset: $(el).offset().top});
}
}
});
items.on('click', function() {
var target = $(this).data('target');
var scrollTo = 0;
if (target === 'top') {
scrollTo = 0;
} else {
var el = document.getElementById(target);
if (el) {
scrollTo = $(el).offset().top - 100;
}
}
$('html, body').animate({scrollTop: scrollTo}, 300);
});
$(window).on('scroll', function() {
var scrollPos = $(window).scrollTop() + 120;
var current = null;
for (var i = 0; i < sections.length; i++) {
var checkPos = sections[i].target ? sections[i].target.offset().top : 0;
if (checkPos <= scrollPos) {
current = sections[i].item;
}
}
items.removeClass('active');
if (current) {
current.addClass('active');
}
});
$(window).trigger('scroll');
});
// ==================================================
// PROFILE ICONS
// ==================================================
$(document).ready(function() {
$('.profile-icon').each(function() {
var icon = $(this);
var url = icon.attr('data-url');
if (url && url.trim() !== '') {
icon.css('cursor', 'pointer');
icon.on('click', function() {
window.open(url, '_blank');
});
} else {
icon.css({
'opacity': '0.3',
'filter': 'grayscale(100%)',
'-webkit-filter': 'grayscale(100%)',
'cursor': 'default'
});
}
});
});
// ==================================================
// ДИНАМІЧНІ ПОСИЛАННЯ НА ГОЛОВНІЙ
// ==================================================
$(document).ready(function() {
// Тільки на головній сторінці
if ($('body').hasClass('page-Головна_сторінка')) {
// Списки посилань для кожного блоку
var block1Links = [
{ title: 'Фінал Року', url: '/index.php/Фінал_Року' }
];
var block2Links = [
{ title: 'Перша статистика', url: '/index.php/Перша_статистика' },
{ title: 'Період', url: '/index.php/Період' },
{ title: 'Друга статистика', url: '/index.php/Статистика' }
];
var block3Links = [
{ title: 'Mafia Closed Cup I', url: '/index.php/Mafia_Closed_Cup_I' },
{ title: 'Mafia Closed Cup I Online', url: '/index.php/Mafia_Closed_Cup_I_Online' },
{ title: 'My Closest Circle I', url: '/index.php/My_Closest_Circle_I' }
];
// Функція випадкового вибору
function getRandomItem(arr) {
return arr[Math.floor(Math.random() * arr.length)];
}
// Знаходимо блоки і замінюємо посилання
var $blocks = $('.home__block-image-block p');
if ($blocks.length >= 3) {
var link1 = getRandomItem(block1Links);
var link2 = getRandomItem(block2Links);
var link3 = getRandomItem(block3Links);
$blocks.eq(0).html('<a href="' + link1.url + '">' + link1.title + '</a>');
$blocks.eq(1).html('<a href="' + link2.url + '">' + link2.title + '</a>');
$blocks.eq(2).html('<a href="' + link3.url + '">' + link3.title + '</a>');
}
}
});
// ==================================================
// PLAYER TABS WITH LAZY LOADING
// ==================================================
$(function() {
var $tabs = $('.player-tab');
var $contents = $('.player-tab-content');
var $lbox = $('.l-box');
var $rbox = $('.r-box');
if ($tabs.length === 0) return;
// Функція перевірки мобільної версії
function isMobile() {
return $(window).width() <= 768;
}
$tabs.on('click', function() {
var $tab = $(this);
var tabId = $tab.data('tab');
var $content = $('#tab-' + tabId);
// Перемикаємо активні класи
$tabs.removeClass('active');
$tab.addClass('active');
$contents.removeClass('active');
$content.addClass('active');
// Ховаємо/показуємо l-box залежно від табу (на десктопі)
if (tabId === 'games') {
$lbox.fadeOut(200);
} else {
$lbox.fadeIn(200);
}
// Ховаємо/показуємо r-box на МОБІЛЬНИХ при переході на "games"
if (isMobile()) {
if (tabId === 'games') {
$rbox.slideUp(200);
} else {
$rbox.slideDown(200);
}
}
// Lazy load для ігор
if (tabId === 'games' && !$content.data('loaded')) {
var playerName = $content.data('player');
if (playerName) {
// Показуємо loader
$content.html('<div class="tab-loader">Завантаження...</div>');
$.ajax({
url: mw.config.get('wgScriptPath') + '/api.php',
data: {
action: 'expandtemplates',
format: 'json',
text: '{{#invoke:FetchData|player_games|player=' + playerName + '}}',
prop: 'wikitext'
},
dataType: 'json',
success: function(response) {
if (response.expandtemplates && response.expandtemplates.wikitext) {
$.ajax({
url: mw.config.get('wgScriptPath') + '/api.php',
data: {
action: 'parse',
format: 'json',
text: response.expandtemplates.wikitext,
contentmodel: 'wikitext',
disablelimitreport: true
},
dataType: 'json',
success: function(parseResponse) {
if (parseResponse.parse && parseResponse.parse.text) {
$content.html(parseResponse.parse.text['*']);
$content.data('loaded', true);
$content.find('table.sortable').tablesorter();
}
},
error: function() {
$content.html('<p style="color: #ff7777; text-align: center;">Помилка завантаження. Спробуйте оновити сторінку.</p>');
}
});
}
},
error: function() {
$content.html('<p style="color: #ff7777; text-align: center;">Помилка завантаження. Спробуйте оновити сторінку.</p>');
}
});
}
}
});
// При зміні розміру вікна - показуємо r-box на десктопі
$(window).on('resize', function() {
if (!isMobile()) {
$rbox.show();
}
});
});
// ==================================================
// МОБІЛЬНИЙ ПОШУК
// ==================================================
$(function() {
if ($(window).width() > 768) return;
// Перевіряємо чи вже створено
if ($('.mobile-search-btn').length > 0) return;
var $searchBtn = $('<div class="mobile-search-btn">' +
'<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2">' +
'<circle cx="11" cy="11" r="8"/>' +
'<path d="m21 21-4.35-4.35"/>' +
'</svg>' +
'</div>');
var $overlay = $('<div class="mobile-search-overlay">' +
'<input type="text" placeholder="Пошук..." autocomplete="off">' +
'<div class="mobile-search-close">×</div>' +
'</div>');
$('.minerva-header .branding-box').after($searchBtn);
$('body').append($overlay);
var $input = $overlay.find('input');
var $close = $overlay.find('.mobile-search-close');
$searchBtn.on('click', function(e) {
e.preventDefault();
e.stopPropagation();
$overlay.addClass('active');
setTimeout(function() { $input.focus(); }, 100);
});
$close.on('click', function() {
$overlay.removeClass('active');
$input.val('');
});
$input.on('keydown', function(e) {
if (e.keyCode === 13) {
var query = $input.val().trim();
if (query) {
window.location.href = '/index.php?title=Спеціальна:Пошук&search=' + encodeURIComponent(query);
}
}
if (e.keyCode === 27) {
$overlay.removeClass('active');
$input.val('');
}
});
$overlay.on('click', function(e) {
if (e.target === this) {
$overlay.removeClass('active');
$input.val('');
}
});
});
// ==================================================
// БЛОКУВАННЯ MINERVA SEARCH OVERLAY (ДЕСКТОП)
// ==================================================
$(function() {
// Тільки для десктопа
if ($(window).width() <= 768) return;
var $searchInput = $('#searchInput');
if ($searchInput.length === 0) return;
// Затримка щоб DOM завантажився
setTimeout(function() {
// Змінюємо placeholder
$searchInput.attr('placeholder', 'Пошук...');
// Клонуємо input щоб прибрати всі event listeners
var $newInput = $searchInput.clone(false);
$searchInput.replaceWith($newInput);
$searchInput = $newInput;
// Прибираємо readonly і класи тригера
$searchInput.prop('readonly', false);
$searchInput.removeAttr('readonly');
$searchInput.removeClass('skin-minerva-search-trigger');
// При фокусі - блокуємо overlay
$searchInput.on('focus click', function(e) {
e.stopPropagation();
// Прибираємо overlay класи з body
$('body').removeClass('overlay-enabled search-enabled');
// Видаляємо overlay елементи
$('.overlay, .search-overlay').hide();
// Прибираємо hash
if (window.location.hash === '#/search') {
history.replaceState(null, null, window.location.pathname);
}
});
// При Enter - перехід на сторінку пошуку
$searchInput.on('keydown', function(e) {
if (e.which === 13 || e.keyCode === 13) {
e.preventDefault();
var query = $(this).val().trim();
if (query) {
window.location.href = '/index.php?title=Спеціальна:Пошук&search=' + encodeURIComponent(query);
}
return false;
}
});
}, 100);
// Блокуємо hashchange на #/search
$(window).on('hashchange', function(e) {
if (window.location.hash === '#/search') {
e.preventDefault();
history.replaceState(null, null, window.location.pathname);
$('body').removeClass('overlay-enabled search-enabled');
$('.overlay, .search-overlay').hide();
}
});
// Перевіряємо hash при завантаженні
if (window.location.hash === '#/search') {
history.replaceState(null, null, window.location.pathname);
}
});
// ==================================================
// BANNER SEARCH (LIQUIPEDIA STYLE)
// ==================================================
$(function() {
var $container = $('#bannerSearchContainer');
if ($container.length === 0) return;
// Створюємо елементи через JS
var $input = $('<input>', {
type: 'text',
id: 'bannerSearchInput',
placeholder: 'Пошук MCC...'
});
var $btn = $('<button>', {
id: 'bannerSearchBtn',
text: 'Пошук'
});
$container.append($input).append($btn);
// Функція пошуку
function doSearch() {
var query = $input.val().trim();
if (query) {
window.location.href = '/index.php?title=Спеціальна:Пошук&search=' + encodeURIComponent(query);
}
}
$btn.on('click', doSearch);
$input.on('keydown', function(e) {
if (e.keyCode === 13) {
e.preventDefault();
doSearch();
}
});
});
// ==================================================
// MCC DESIGN SYSTEM v2 — append to Common.js
// ==================================================
// --------------------------------------------------
// 1. АНІМАЦІЯ РЯДКІВ ПРИ СОРТУВАННІ ТАБЛИЦЬ
// Хукається на jQuery tablesorter sortEnd
// --------------------------------------------------
$(function () {
// Чекаємо поки tablesorter ініціалізується
$(document).on('sortEnd', 'table.wikitable', function () {
var $table = $(this);
// Спочатку прибираємо анімацію
$table.addClass('mcc-sorting').removeClass('mcc-sorted');
// Після мікро-затримки запускаємо знову
setTimeout(function () {
$table.removeClass('mcc-sorting').addClass('mcc-sorted');
// Прибираємо клас після завершення останньої анімації
setTimeout(function () {
$table.removeClass('mcc-sorted');
}, 600);
}, 20);
});
});
// --------------------------------------------------
// 2. ГОРИЗОНТАЛЬНИЙ СКРОЛ + ГРАДІЄНТ-ПІДКАЗКА
// Обгортає широкі таблиці в .mcc-scroll-outer
// --------------------------------------------------
$(function () {
// Класи таблиць, які треба загорнути
var WIDE_SELECTORS = [
'.wikitable.wide-table', // існуючий клас
'.mcc-wide', // новий клас для розмітки
// Запис ігор — таблиця з класом full-width або в секції Запис ігор
'.wikitable.full-width'
].join(', ');
function wrapScrollable($table) {
// Не загортаємо двічі
if ($table.closest('.mcc-scroll-inner').length) return;
var $outer = $('<div class="mcc-scroll-outer"></div>');
var $inner = $('<div class="mcc-scroll-inner"></div>');
$table.wrap($inner);
$table.closest('.mcc-scroll-inner').wrap($outer);
var $scrollEl = $table.closest('.mcc-scroll-inner');
var $outerEl = $scrollEl.closest('.mcc-scroll-outer');
function checkFade() {
var atEnd = $scrollEl[0].scrollLeft + $scrollEl[0].clientWidth >= $scrollEl[0].scrollWidth - 4;
$outerEl.toggleClass('mcc-no-fade', atEnd);
}
$scrollEl.on('scroll', checkFade);
checkFade();
}
// Широкі таблиці (існуючі класи)
$(WIDE_SELECTORS).each(function () {
wrapScrollable($(this));
});
// Таблиця "Запис ігор" — знаходимо по кількості колонок (> 8)
$('.wikitable').each(function () {
var $t = $(this);
if ($t.closest('.mcc-scroll-inner').length) return; // вже загорнута
var cols = $t.find('thead tr:first th').length;
if (cols > 8) {
$t.addClass('mcc-wide-table');
wrapScrollable($t);
}
});
});
// --------------------------------------------------
// 3. ПІДСВІЧУВАННЯ ВІНРЕЙТУ В ТАБЛИЦЯХ
// Автоматично додає клас .wr-hi / .wr-lo до клітинок %
// --------------------------------------------------
$(function () {
$('.wikitable tbody tr').each(function () {
var $cells = $(this).find('td');
$cells.each(function () {
var text = $(this).text().trim();
// Якщо клітинка містить відсоток
if (/^\d+(\.\d+)?%$/.test(text)) {
var val = parseFloat(text);
if (val >= 55) {
$(this).addClass('wr-hi');
} else if (val <= 33) {
$(this).addClass('wr-lo');
}
}
});
});
});
// --------------------------------------------------
// 4. PROFILE ICONS — inactive якщо немає URL
// (доповнює існуючий код, не замінює)
// --------------------------------------------------
$(function () {
$('.profile-icon').each(function () {
var $icon = $(this);
var url = $icon.attr('data-url') || '';
if (!url.trim()) {
$icon.addClass('inactive');
}
});
});
// ==================================================
// L-BOX NAVIGATION — замінює існуючий блок у Common.js
// ==================================================
$(function () {
var $lbox = $('.l-box');
if ($lbox.length === 0) return;
var $items = $lbox.find('.l-box-item');
// ── Будуємо карту секцій ──
// Перераховуємо при кожному activate щоб врахувати
// динамічний контент (таби, lazy load)
function buildSectionMap() {
var map = [];
$items.each(function () {
var target = $(this).data('target');
if (target === 'top') {
map.push({ $item: $(this), top: 0 });
} else {
// MediaWiki генерує id для h2 — пробіли замінює на _
var $el = $('#' + target);
if ($el.length) {
map.push({ $item: $(this), top: $el.offset().top });
}
}
});
// Сортуємо за позицією (на всяк випадок)
map.sort(function (a, b) { return a.top - b.top; });
return map;
}
// ── Оновлення активного пункту ──
function updateActive(map) {
var scrollY = $(window).scrollTop() + 110; // offset для header
var current = null;
for (var i = 0; i < map.length; i++) {
if (map[i].top <= scrollY) {
current = map[i].$item;
}
}
$items.removeClass('active');
if (current) current.addClass('active');
}
// ── Клік — скрол до секції ──
$items.on('click', function () {
var target = $(this).data('target');
if (target === 'top') {
$('html, body').animate({ scrollTop: 0 }, 280);
} else {
var $el = $('#' + target);
if ($el.length) {
var offset = $el.offset().top - 75;
$('html, body').animate({ scrollTop: offset }, 280);
}
}
});
// ── Ініціалізація та підписка на scroll ──
var sectionMap = buildSectionMap();
// Перебудовуємо після можливого lazy-load (таби)
$(document).on('mcc:content-loaded', function () {
sectionMap = buildSectionMap();
updateActive(sectionMap);
});
var ticking = false;
$(window).on('scroll', function () {
if (!ticking) {
window.requestAnimationFrame(function () {
updateActive(sectionMap);
ticking = false;
});
ticking = true;
}
});
// Перший виклик
updateActive(sectionMap);
// Перебудовуємо після resize (позиції можуть змінитись)
$(window).on('resize', function () {
sectionMap = buildSectionMap();
updateActive(sectionMap);
});
});