MediaWiki:Common.js: различия между версиями

мНет описания правки
Метка: ручная отмена
мНет описания правки
Строка 282: Строка 282:
// Функция для увеличения яркости цвета
// Функция для увеличения яркости цвета
function brightenColor(color, factor) {
function brightenColor(color, factor) {
    function getBrightness(r, g, b) {
function getBrightness(r, g, b) {
        return 0.2126 * r + 0.7152 * g + 0.0722 * b;
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
    }
}


    function isGray(r, g, b) {
function isGray(r, g, b) {
        var maxDiff = 20; // Максимальное допустимое отклонение между RGB для серого
var maxDiff = 20; // Максимальное допустимое отклонение между RGB для серого
        return Math.abs(r - g) < maxDiff && Math.abs(g - b) < maxDiff && Math.abs(r - b) < maxDiff;
return Math.abs(r - g) < maxDiff && Math.abs(g - b) < maxDiff && Math.abs(r - b) < maxDiff;
    }
}


    var rgbValues = color.match(/\d+(\.\d+)?/g);
var rgbValues = color.match(/\d+(\.\d+)?/g);
    var r = parseInt(rgbValues[0], 10);
var r = parseInt(rgbValues[0], 10);
    var g = parseInt(rgbValues[1], 10);
var g = parseInt(rgbValues[1], 10);
    var b = parseInt(rgbValues[2], 10);
var b = parseInt(rgbValues[2], 10);
    var a = rgbValues.length === 4 ? parseFloat(rgbValues[3]) : 1;
var a = rgbValues.length === 4 ? parseFloat(rgbValues[3]) : 1;


    var brightness = getBrightness(r, g, b);
var brightness = getBrightness(r, g, b);


    if (factor === undefined) {
if (factor === undefined) {
        if (brightness <= 180) {
if (brightness <= 180) {
            factor = 4;
factor = 4;
        } else {
} else {
            factor = 0;
factor = 0;
        }
}
    }
}


    // Если цвет серый, уменьшаем фактор
// Если цвет серый, уменьшаем фактор
    if (isGray(r, g, b)) {
if (isGray(r, g, b)) {
        factor = Math.max(1, factor * 0.85);
factor = Math.max(1, factor * 0.85);
    }
}


    // Добавляем фактор вместо умножения
// Добавляем фактор вместо умножения
    r = Math.min(255, r + factor);
r = Math.min(255, r + factor);
    g = Math.min(255, g + factor);
g = Math.min(255, g + factor);
    b = Math.min(255, b + factor);
b = Math.min(255, b + factor);


    return a < 1 ? 'rgba(' + r + ', ' + g + ', ' + b + ', ' + a + ')' : 'rgb(' + r + ', ' + g + ', ' + b + ')';
return a < 1 ? 'rgba(' + r + ', ' + g + ', ' + b + ', ' + a + ')' : 'rgb(' + r + ', ' + g + ', ' + b + ')';
}
}


Строка 336: Строка 336:
return row.parentElement === tbody && !row.querySelector('table');
return row.parentElement === tbody && !row.querySelector('table');
});
});
// Пропускаем первую строку, если нет <thead> и нет класса 'no-header-table'
// Пропускаем первую строку, если нет <thead> и нет класса 'no-header-table'
var topLevelRows = (!thead && !noHeader) ? rows.slice(1) : rows;
var topLevelRows = (!thead && !noHeader) ? rows.slice(1) : rows;
var hasInvalidRowspan = false;
var hasInvalidRowspan = false;
var hasTooManyRowspan = false;
var hasTooManyRowspan = false;
// Проверка на ошибки в rowspan
// Проверка на ошибки в rowspan
Array.prototype.forEach.call(topLevelRows, function(row) {
Array.prototype.forEach.call(topLevelRows, function(row) {
Строка 347: Строка 349:
var cellCount = cells.length;
var cellCount = cells.length;
var rowspanCount = cells.filter(function(cell) {
var rowspanCount = cells.filter(function(cell) {
return cell.hasAttribute('rowspan') && cell.getAttribute('rowspan') !== '1';
return cell.hasAttribute('rowspan') && cell.getAttribute('rowspan') !== '1'; // Игнорируем rowspan="1"
}).length;
}).length;
// Проверка на слишком большое количество rowspan или неправильное расположение rowspan
// Проверка на слишком большое количество rowspan или неправильное расположение rowspan
if (rowspanCount > 2 || (cellCount <= 3 && rowspanCount > 1)) {
if (rowspanCount > 2 || (cellCount <= 3 && rowspanCount > 1)) {
Строка 354: Строка 357:
return;
return;
}
}
// Проверяем, что ячейки с rowspan находятся по краям строки
var hasValidRowspanEdge = cells.some(function(cell, index) {
var hasValidRowspanEdge = cells.some(function(cell, index) {
return cell.hasAttribute('rowspan') && cell.getAttribute('rowspan') !== '1' && (index === 0 ||
return cell.hasAttribute('rowspan') && cell.getAttribute('rowspan') !== '1' && (index === 0 || index === cells.length - 1);
index === cells.length - 1);
});
});
// Если ячейки с rowspan находятся не по краям
if (!hasValidRowspanEdge && cells.some(function(cell, index) {
if (!hasValidRowspanEdge && cells.some(function(cell, index) {
return cell.hasAttribute('rowspan') && cell.getAttribute('rowspan') !== '1' && index > 0 && index <
return cell.hasAttribute('rowspan') && cell.getAttribute('rowspan') !== '1' && index > 0 && index < cells.length - 1;
cells.length - 1;
})) {
})) {
hasInvalidRowspan = true;
hasInvalidRowspan = true;
}
}
});
});
// Если есть ошибки в rowspan, выходим
// Если есть ошибки в rowspan, выходим
if (hasTooManyRowspan || hasInvalidRowspan) return;
if (hasTooManyRowspan || hasInvalidRowspan) return;
// Обработка наведения на строки и ячейки
// Обработка наведения на строки и ячейки
Array.prototype.forEach.call(topLevelRows, function(row, rowIndex) {
Array.prototype.forEach.call(topLevelRows, function(row, rowIndex) {
Строка 377: Строка 384:
};
};
});
});
// Наведение на строку (tr)
// Наведение на строку (tr)
row.addEventListener('mouseover', function() {
row.addEventListener('mouseover', function() {
Строка 384: Строка 392:
highlightRow(row, rowIndex, false);
highlightRow(row, rowIndex, false);
});
});
// Наведение на ячейки с rowspan
// Наведение на ячейки с rowspan
Array.prototype.forEach.call(cells, function(cell, cellIndex) {
Array.prototype.forEach.call(cells, function(cell, cellIndex) {
// Обрабатываем только ячейки с rowspan > 1
if (cell.hasAttribute('rowspan') && parseInt(cell.getAttribute('rowspan')) > 1) {
if (cell.hasAttribute('rowspan') && parseInt(cell.getAttribute('rowspan')) > 1) {
var rowspan = parseInt(cell.getAttribute('rowspan'));
var rowspan = parseInt(cell.getAttribute('rowspan'));
// Обработка rowspan ячейки
// Обработка rowspan ячейки
cell.addEventListener('mouseover', function() {
cell.addEventListener('mouseover', function() {
Строка 394: Строка 405:
highlightRowspanArea(rowIndex, cellIndex, rowspan, true);
highlightRowspanArea(rowIndex, cellIndex, rowspan, true);
});
});
cell.addEventListener('mouseout', function() {
cell.addEventListener('mouseout', function() {
// Восстанавливаем состояние строки при уходе курсора
// Восстанавливаем состояние строки при уходе курсора
Строка 401: Строка 413:
}
}
});
});
// Функция подсветки строки (только текущее tr)
// Функция подсветки строки (только текущее tr)
function highlightRow(row, rowIndex, highlight) {
function highlightRow(row, rowIndex, highlight) {
Строка 406: Строка 419:
var rowCells = Array.prototype.slice.call(row.querySelectorAll('td, th'));
var rowCells = Array.prototype.slice.call(row.querySelectorAll('td, th'));
Array.prototype.forEach.call(rowCells, function(cell, cellIndex) {
Array.prototype.forEach.call(rowCells, function(cell, cellIndex) {
// Подсвечиваем только ячейки, не имеющие атрибут rowSpan
// Подсвечиваем только ячейки, не имеющие атрибут rowSpan или с rowspan="1"
if (!cell.hasAttribute('rowspan')) {
if (!cell.hasAttribute('rowspan') || parseInt(cell.getAttribute('rowspan')) === 1) {
var cellStyle = getComputedStyle(cell);
var cellStyle = getComputedStyle(cell);
cell.style.setProperty('background-color', highlight ? brightenColor(cellStyle.backgroundColor) :
cell.style.setProperty('background-color', highlight ? brightenColor(cellStyle.backgroundColor) :
originalStyles[cellIndex].backgroundColor, 'important');
originalStyles[cellIndex].backgroundColor, 'important');
cell.style.setProperty('color', highlight ? brightenColor(cellStyle.color) : originalStyles[
cell.style.setProperty('color', highlight ? brightenColor(cellStyle.color) : originalStyles[cellIndex].color, 'important');
cellIndex].color, 'important');
}
}
});
});
}
}
// Функция подсветки для ячеек с rowspan (подсвечивает все строки, которые охватывает ячейка)
// Функция подсветки для ячеек с rowspan (подсвечивает все строки, которые охватывает ячейка)
function highlightRowspanArea(rowIndex, cellIndex, rowspan, highlight) {
function highlightRowspanArea(rowIndex, cellIndex, rowspan, highlight) {
Строка 423: Строка 436:
var targetCells = Array.prototype.slice.call(targetRow.querySelectorAll('td, th'));
var targetCells = Array.prototype.slice.call(targetRow.querySelectorAll('td, th'));
// Обработка ячейки в каждой строке, затронутой rowspan
// Обработка ячейки в каждой строке, затронутой rowspan
Array.prototype.forEach.call(targetCells, function(targetCell, targetCellIndex) {
Array.prototype.forEach.call(targetCells, function(targetCell) {
var targetCellStyle = getComputedStyle(targetCell);
var targetCellStyle = getComputedStyle(targetCell);
// Сохраняем оригинальные стили для каждой ячейки, если подсветка включена
// Сохраняем оригинальные стили для каждой ячейки, если подсветка включена
Строка 445: Строка 458:
// Функции для добавления кастомных заголовков в TOC
// Функции для добавления кастомных заголовков в TOC
function addHeadingsWithTOC() {
function addHeadingsWithTOC() {
    mw.hook('wikipage.content').add(function($content) {
mw.hook('wikipage.content').add(function($content) {
        var $toc = $('#toc ul'); // Находим TOC
var $toc = $('#toc ul'); // Находим TOC
        $toc.empty();
$toc.empty();
        var $headings = $content.find('h1, h2, h3, h4, h5, h6, .custom-heading');
var $headings = $content.find('h1, h2, h3, h4, h5, h6, .custom-heading');
        var tocCounters = [];
var tocCounters = [];
        var $currentList = $toc; // Текущий список для вставки элементов
var $currentList = $toc; // Текущий список для вставки элементов
        var levelStack = []; // Стек для отслеживания уровней заголовков
var levelStack = []; // Стек для отслеживания уровней заголовков
        var maxLevel = 7; // Изначально максимальный уровень не определён
var maxLevel = 7; // Изначально максимальный уровень не определён


        // Первый проход для нахождения минимального уровня заголовков
// Первый проход для нахождения минимального уровня заголовков
        $headings.each(function() {
$headings.each(function() {
            var $heading = $(this);
var $heading = $(this);
            var level;
var level;
            if ($heading.hasClass('custom-heading')) {
if ($heading.hasClass('custom-heading')) {
                level = 1; // Для кастомных заголовков
level = 1; // Для кастомных заголовков
            } else {
} else {
                var tagName = $heading.prop('tagName').toLowerCase();
var tagName = $heading.prop('tagName').toLowerCase();
                level = parseInt(tagName.charAt(1), 10); // Определяем уровень h1-h6
level = parseInt(tagName.charAt(1), 10); // Определяем уровень h1-h6
            }
}
            if (level < maxLevel) {
if (level < maxLevel) {
                maxLevel = level; // Находим минимальный уровень заголовков
maxLevel = level; // Находим минимальный уровень заголовков
            }
}
        });
});


        function updateCounters(level) {
function updateCounters(level) {
            if (level > tocCounters.length) {
if (level > tocCounters.length) {
                tocCounters.push(0);
tocCounters.push(0);
            } else if (level < tocCounters.length) {
} else if (level < tocCounters.length) {
                tocCounters = tocCounters.slice(0, level);
tocCounters = tocCounters.slice(0, level);
            }
}
            tocCounters[level - 1]++;
tocCounters[level - 1]++;
        }
}


        function getSectionNumber() {
function getSectionNumber() {
            return tocCounters.join('.');
return tocCounters.join('.');
        }
}


        function createNestedList($parent) {
function createNestedList($parent) {
            var $nestedList = $('<ul>');
var $nestedList = $('<ul>');
            $parent.append($nestedList);
$parent.append($nestedList);
            return $nestedList;
return $nestedList;
        }
}


        function closeNestedLists(targetLevel) {
function closeNestedLists(targetLevel) {
            while (levelStack.length > 0 && levelStack[levelStack.length - 1] >= targetLevel) {
while (levelStack.length > 0 && levelStack[levelStack.length - 1] >= targetLevel) {
                $currentList = $currentList.parent().closest('ul');
$currentList = $currentList.parent().closest('ul');
                levelStack.pop();
levelStack.pop();
            }
}
        }
}


        $headings.each(function() {
$headings.each(function() {
            var $heading = $(this);
var $heading = $(this);
            var level;
var level;
            var $headlineSpan = $heading.find('span.mw-headline');
var $headlineSpan = $heading.find('span.mw-headline');


            if ($heading.hasClass('custom-heading')) {
if ($heading.hasClass('custom-heading')) {
                level = 1;
level = 1;
                var customId = $heading.attr('id') || 'custom-heading-' + getSectionNumber();
var customId = $heading.attr('id') || 'custom-heading-' + getSectionNumber();
                $heading.attr('id', customId);
$heading.attr('id', customId);
            } else if ($headlineSpan.length > 0) {
} else if ($headlineSpan.length > 0) {
                var tagName = $heading.prop('tagName').toLowerCase();
var tagName = $heading.prop('tagName').toLowerCase();
                level = parseInt(tagName.charAt(1), 10);
level = parseInt(tagName.charAt(1), 10);
                var existingId = $headlineSpan.attr('id');
var existingId = $headlineSpan.attr('id');


                if (!existingId) {
if (!existingId) {
                    var sectionId = 'heading-' + getSectionNumber();
var sectionId = 'heading-' + getSectionNumber();
                    $headlineSpan.attr('id', sectionId);
$headlineSpan.attr('id', sectionId);
                }
}
            } else {
} else {
                return; // Пропускаем элементы без заголовков
return; // Пропускаем элементы без заголовков
            }
}


            updateCounters(level);
updateCounters(level);


            var headingText = $headlineSpan.text().trim() || $heading.text().trim();
var headingText = $headlineSpan.text().trim() || $heading.text().trim();


            if (headingText.length > 0) {
if (headingText.length > 0) {
                // Закрываем вложенные списки, если текущий уровень меньше
// Закрываем вложенные списки, если текущий уровень меньше
                closeNestedLists(level);
closeNestedLists(level);


                var tocItem = $('<li>').addClass('toclevel-' + (level - maxLevel)).append(
var tocItem = $('<li>').addClass('toclevel-' + (level - maxLevel)).append(
                    $('<a>').attr('href', '#' + ($headlineSpan.attr('id') || customId)).append(
$('<a>').attr('href', '#' + ($headlineSpan.attr('id') || customId)).append(
                        $('<span>').addClass('tocnumber').text(getSectionNumber()),
$('<span>').addClass('tocnumber').text(getSectionNumber()),
                        $('<span>').addClass('toctext').text(headingText)
$('<span>').addClass('toctext').text(headingText)
                    )
)
                );
);


                // Если текущий уровень равен максимальному (высший уровень), добавляем его в основной список
// Если текущий уровень равен максимальному (высший уровень), добавляем его в основной список
                if (level === maxLevel) {
if (level === maxLevel) {
                    $toc.append(tocItem); // Главный список
$toc.append(tocItem); // Главный список
                    $currentList = $toc; // Сбрасываем на основной список
$currentList = $toc; // Сбрасываем на основной список
                } else {
} else {
                    // Если уровень ниже максимального, создаем вложенный список
// Если уровень ниже максимального, создаем вложенный список
                    if (level > levelStack[levelStack.length - 1]) {
if (level > levelStack[levelStack.length - 1]) {
                        var $nestedList = createNestedList($currentList);
var $nestedList = createNestedList($currentList);
                        $currentList = $nestedList;
$currentList = $nestedList;
                    }
}
                    $currentList.append(tocItem);
$currentList.append(tocItem);
                }
}


                // Добавляем уровень в стек для дальнейшего отслеживания
// Добавляем уровень в стек для дальнейшего отслеживания
                levelStack.push(level);
levelStack.push(level);
            }
}
        });
});
    });
});
}
}
// Функция для логики меню создаваемым модулем CategoryMenu
// Функция для логики меню создаваемым модулем CategoryMenu
function initCategorySwitcher() {
function initCategorySwitcher() {
    var categories = document.querySelectorAll('.categories div');
var categories = document.querySelectorAll('.categories div');
    var menus = document.querySelectorAll('.menu');
var menus = document.querySelectorAll('.menu');
    var contentDivs = document.querySelectorAll('.content div');
var contentDivs = document.querySelectorAll('.content div');
    var menuItems = document.querySelectorAll('.menu div');
var menuItems = document.querySelectorAll('.menu div');


    function clearActiveContent() {
function clearActiveContent() {
        for (var i = 0; i < contentDivs.length; i++) {
for (var i = 0; i < contentDivs.length; i++) {
            contentDivs[i].classList.remove('active');
contentDivs[i].classList.remove('active');
        }
}
    }
}


    function clearActiveMenu() {
function clearActiveMenu() {
        for (var i = 0; i < menus.length; i++) {
for (var i = 0; i < menus.length; i++) {
            menus[i].classList.remove('active');
menus[i].classList.remove('active');
        }
}
    }
}


    function clearActiveMenuItems() {
function clearActiveMenuItems() {
        for (var i = 0; i < menuItems.length; i++) {
for (var i = 0; i < menuItems.length; i++) {
            menuItems[i].classList.remove('active');
menuItems[i].classList.remove('active');
        }
}
    }
}


    function switchCategory(categoryClass) {
function switchCategory(categoryClass) {
        clearActiveMenu();
clearActiveMenu();
        clearActiveContent();
clearActiveContent();
        var selectedMenu = document.querySelector('.' + categoryClass + '-menu');
var selectedMenu = document.querySelector('.' + categoryClass + '-menu');
        if (selectedMenu) {
if (selectedMenu) {
            selectedMenu.classList.add('active');
selectedMenu.classList.add('active');
            var firstParagraph = selectedMenu.querySelector('div');
var firstParagraph = selectedMenu.querySelector('div');
            if (firstParagraph) {
if (firstParagraph) {
                switchContent(firstParagraph);
switchContent(firstParagraph);
            }
}
        }
}
    }
}


    function switchContent(menuItem) {
function switchContent(menuItem) {
        clearActiveMenuItems();
clearActiveMenuItems();
        clearActiveContent();
clearActiveContent();
        var contentClass = menuItem.className + '-content';
var contentClass = menuItem.className + '-content';
        var content = document.querySelector('.' + contentClass);
var content = document.querySelector('.' + contentClass);
        if (content) {
if (content) {
            content.classList.add('active');
content.classList.add('active');
            menuItem.classList.add('active');
menuItem.classList.add('active');
        }
}
    }
}


    for (var i = 0; i < categories.length; i++) {
for (var i = 0; i < categories.length; i++) {
        categories[i].addEventListener('click', function() {
categories[i].addEventListener('click', function() {
            var categoryClass = this.classList[0];
var categoryClass = this.classList[0];
            switchCategory(categoryClass);
switchCategory(categoryClass);
        });
});
    }
}


    for (var i = 0; i < menuItems.length; i++) {
for (var i = 0; i < menuItems.length; i++) {
        menuItems[i].addEventListener('click', function() {
menuItems[i].addEventListener('click', function() {
            switchContent(this);
switchContent(this);
        });
});
    }
}


    // Открытие первой категории и первого пункта
// Открытие первой категории и первого пункта
    var firstCategory = categories.length > 0 ? categories[0].classList[0] : null;
var firstCategory = categories.length > 0 ? categories[0].classList[0] : null;
    if (firstCategory) {
if (firstCategory) {
        switchCategory(firstCategory);
switchCategory(firstCategory);
    }
}
}
}
const currentPageTitle = document.title;
const currentPageTitle = document.title;
Строка 708: Строка 721:
};
};
}
}
    var categoriesExist = document.querySelectorAll('.categories');
var categoriesExist = document.querySelectorAll('.categories');
    if (categoriesExist.length > 0) {
if (categoriesExist.length > 0) {
        initCategorySwitcher();  
initCategorySwitcher();  
    }
}
});
});
/*WikiEditor/Викификатор*/
/*WikiEditor/Викификатор*/