Участник:No4ni/addRedirButtonToVE.js

// ==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);
    });
})();
Prefix: a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9

Portal di Ensiklopedia Dunia

Kembali kehalaman sebelumnya