// ==UserScript==
// @name Википедия - Кнопка перенаправления
// @description Добавляет кнопку создания перенаправления в визуальный редактор
// @namespace https://ru.wikipedia.org/
// @include https://ru.wikipedia.org/*
// @version 0.8 - Работает, но выглядит некрасиво
// @grant none
// ==/UserScript==
(function() {
'use strict';
console.log('[Redirect] Скрипт инициализирован');
// Добавляем CSS для стилизации кнопки
const addCSS = (css) => {
const style = document.createElement('style');
style.textContent = css;
document.head.appendChild(style);
};
addCSS(`
.custom-redirect-tool .oo-ui-buttonElement-button {
padding: 0.4em 0.6em; /* Регулируем отступы */
border-radius: 3px; /* Закругляем углы */
font-weight: bold; /* Делаем текст жирным */
}
`);
const initRedirectButton = () => {
// Проверяем готовность VE
if (!window.ve || !ve.init?.target?.getSurface()) {
console.log('[Redirect] VE не готов');
return;
}
// Проверяем, если кнопка уже была добавлена
if (document.querySelector('.custom-redirect-tool')) {
console.log('[Redirect] Кнопка уже существует');
return;
}
console.log('[Redirect] Ищем место для кнопки...');
// Список возможных мест для вставки кнопки в порядке приоритета
const potentialTargets = [
// Новый интерфейс VE - панели инструментов вставки
{ selector: '.ve-ui-toolbar-group-insert', type: 'insertGroup' },
// Выпадающее меню вставки (русский/английский)
{ selector: '.oo-ui-toolGroup[aria-label="Вставка"] .oo-ui-toolGroup-tools', type: 'insertDropdown' },
{ selector: '.oo-ui-toolGroup[aria-label="Insert"] .oo-ui-toolGroup-tools', type: 'insertDropdown' },
// Группа "Дополнительно" (русский/английский)
{ selector: '.oo-ui-toolGroup[aria-label="Дополнительно"] .oo-ui-toolGroup-tools', type: 'moreDropdown' },
{ selector: '.oo-ui-toolGroup[aria-label="More"] .oo-ui-toolGroup-tools', type: 'moreDropdown' },
// Резервные варианты
{ selector: '.ve-ui-toolbar-actions', type: 'actions' },
{ selector: '.oo-ui-toolbar-tools', type: 'toolbarTools' },
// Любая доступная группа инструментов
{ selector: '.oo-ui-toolGroup-tools', type: 'anyToolGroup' }
];
let targetElement = null;
let targetType = '';
// Перебираем возможные места вставки
for (const target of potentialTargets) {
const element = document.querySelector(target.selector);
if (element) {
console.log(`[Redirect] Найдено подходящее место: ${target.type}`);
targetElement = element;
targetType = target.type;
break;
}
}
// Если не нашли, выводим доступные элементы и пробуем создать собственную панель
if (!targetElement) {
console.warn('[Redirect] Не найдено подходящее место для кнопки');
// Диагностика - выводим все доступные группы
const allGroups = document.querySelectorAll('.oo-ui-toolGroup');
console.log('[Redirect] Доступные группы:',
Array.from(allGroups).map(el => ({
ariaLabel: el.getAttribute('aria-label'),
className: el.className
}))
);
// Пробуем найти любой подходящий контейнер
const toolbar = document.querySelector('.oo-ui-toolbar-tools') ||
document.querySelector('.ve-ui-toolbar');
if (toolbar) {
targetElement = toolbar;
targetType = 'customToolbar';
console.log('[Redirect] Используем запасной вариант для вставки');
} else {
return;
}
}
try {
// Создаём кнопку
const button = new OO.ui.ButtonWidget({
icon: 'articleRedirect',
label: 'Редирект', // Добавляем надпись
title: 'Добавить редирект',
classes: ['custom-redirect-tool'],
flags: ['progressive']
});
// Создаём обёртку в зависимости от типа цели
let wrapper;
if (targetType.includes('Dropdown') || targetType === 'anyToolGroup') {
// Для выпадающих меню создаем обертку как инструмент
wrapper = document.createElement('div');
wrapper.className = 'oo-ui-tool oo-ui-widget oo-ui-iconElement oo-ui-tool-name-redirect';
wrapper.appendChild(button.$element[0]);
} else {
// Для других мест просто используем элемент кнопки
wrapper = button.$element[0];
}
// Вставляем кнопку
if (targetType === 'insertGroup' || targetType === 'actions') {
// Для групп вставки и действий добавляем в конец
targetElement.appendChild(wrapper);
} else {
// Для остальных добавляем в начало
targetElement.prepend(wrapper);
}
console.log(`[Redirect] Кнопка добавлена в ${targetType}`);
// Исправленный обработчик клика с правильным методом вставки
button.on('click', () => {
const target = prompt('Введите название целевой статьи:', '');
if (target) {
try {
const surface = ve.init.target.getSurface();
const fragment = surface.getModel().getFragment();
var redirectContent = [
{
type: 'mwRedirect',
attributes: {title: target}
}
];
// Используем метод insertContent на фрагменте документа
fragment.collapseToStart().insertContent(redirectContent);
} catch(e) {
console.error('[Redirect] Ошибка вставки:', e);
alert('Ошибка: ' + e.message);
}
}
});
} catch(e) {
console.error('[Redirect] Ошибка создания кнопки:', e);
}
};
// Основной хук с улучшенным отслеживанием
mw.hook('ve.activationComplete').add(() => {
console.log('[Redirect] VE активирован');
// Запускаем с задержкой для полной загрузки интерфейса
setTimeout(() => {
initRedirectButton();
// Наблюдатель для динамического обновления интерфейса
const editor = document.querySelector('.ve-init-target') || document.querySelector('.ve-ui-surface');
if (editor) {
console.log('[Redirect] Настроен наблюдатель за изменениями в редакторе');
const observer = new MutationObserver((mutations) => {
// Проверяем только если кнопка еще не добавлена
if (!document.querySelector('.custom-redirect-tool')) {
initRedirectButton();
}
});
observer.observe(editor, { childList: true, subtree: true });
}
}, 5000);
});
})();