Участник:Vavilexxx/enhanceWikitextEditor.js

Материал из Википедии — свободной энциклопедии
// <nowiki>
/**
 * За основу взят Enhance Wikitext Editor - Serhio Magpie
 */

$(function() {
    // Конфигурация редактора
    const config = {
        contentModel: mw.config.get('wgPageContentModel'),
        codeEditorLanguage: mw.config.get('wgCodeEditorCurrentLanguage')
    };

    // Инициализация глобального объекта
    const EnhanceWikitextEditor = window.EnhanceWikitextEditor || {};
    
    // Настройки по умолчанию
    const defaultConfig = {
        name: 'EnhanceWikitextEditor',
        allow: ['wikitext'],
        toggleEditOptions: true,
        minHeight: '100vh' // Минимальная высота окна
    };

    // Объединение настроек
    EnhanceWikitextEditor.config = { ...defaultConfig, ...EnhanceWikitextEditor.config };

    // Кэширование DOM-элементов
    const nodes = {
        textbox: $('#wpTextbox1'),
        toolbar: $('#wikiEditor-ui-toolbar'),
        toolbarMain: $('#wikiEditor-section-main'),
        wpPreviewLive: $('#wpPreviewLive'),
        wpDiffLive: $('#wpDiffLive'),
        editOptions: $('#editform .editOptions'),
        summary: $('#wpSummary'),
        sandboxPage: $('#wpTemplateSandboxPage .oo-ui-inputWidget-input'),
        codeMirrorButton: $('#mw-editbutton-codemirror .oo-ui-buttonElement-button'),
        aceEditorButton: $('#editform .wikiEditor-ui-toolbar .group-codeeditor-main .oo-ui-toggleButtonWidget .oo-ui-buttonElement-button')
    };

    // Оптимизированная функция масштабирования текстового поля
    function resizeTextbox() {
        const handlers = [
            nodes.codeMirrorButton,
            nodes.aceEditorButton,
            nodes.textbox
        ];

        handlers.forEach(element => {
            element.on('click keyup', handleResize);
        });

        function handleResize() {
            const scrollTop = $(window).scrollTop();
            const minHeight = calculateMinHeight();
            
            nodes.textbox
                .css('min-height', minHeight)
                .css('height', 'auto')
                .css('height', Math.max(
                    nodes.textbox.prop('scrollHeight'),
                    minHeight
                ) + 'px');
            
            setEditor();
            $(window).scrollTop(scrollTop);
        }

        handleResize();
    }

    // Функция расчёта минимальной высоты
    function calculateMinHeight() {
        const windowHeight = window.innerHeight;
        const toolbarHeight = nodes.toolbar.outerHeight() || 0;
        const editOptionsHeight = nodes.editOptions.outerHeight() || 0;
        
        return windowHeight - toolbarHeight - editOptionsHeight;
    }

    // Оптимизированная функция настройки панели редактирования
    function setupEditOptions() {
        if (!EnhanceWikitextEditor.config.toggleEditOptions) return;

        const options = nodes.editOptions
            .addClass('enhanceWikitextEditor--editOptions')
            .on('mouseenter', updateOptionsHeight);

        ['focus', 'blur'].forEach(event => {
            nodes.summary.on(event, toggleOptions);
            nodes.sandboxPage.on(event, toggleOptions);
        });

        function updateOptionsHeight() {
            const css = mw.util.addCSS(`
                :root {
                    --edit-options-height: ${options.prop('scrollHeight') - 
                        options.outerHeight() + options.height()}px;
                }
            `);
            css.cssRules[0].style.setProperty('--edit-options-height', 
                options.prop('scrollHeight') + 'px');
        }

        function toggleOptions() {
            options.toggleClass('visible');
        }
    }

    // Оптимизированная функция настройки редакторов
    function setupEditors() {
        const editors = {
            codeMirror: () => {
                if (typeof CodeMirror !== 'undefined') {
                    CodeMirror.defaults.viewportMargin = Infinity;
                }
            },
            ace: () => {
                if (typeof ace !== 'undefined') {
                    const editor = ace.edit(nodes.ace.get(0));
                    editor.setOptions({ maxLines: Infinity });
                }
            }
        };

        return {
            init: () => {
                Object.values(editors).forEach(editor => editor());
            }
        };
    }

    // Оптимизированная функция инициализации
    function init() {
        const css = mw.util.addCSS(`
            :root {
                --edit-options-hidden-height: 12px;
                --edit-options-visible-height: 300px;
                --min-textbox-height: ${calculateMinHeight()}px;
            }
            
            .wikiEditor-ui .wikiEditor-ui-top {
                position: sticky;
                top: 0;
                z-index: 20;
            }
            
            .wikiEditor-ui .wikiEditor-ui-text {
                min-height: var(--min-textbox-height);
                height: auto !important;
            }
            
            .enhanceWikitextEditor--editOptions {
                height: var(--edit-options-hidden-height);
                position: sticky;
                bottom: 0;
                z-index: 19;
                overflow: hidden;
                transition: height 0.25s ease-in-out;
            }
            
            .enhanceWikitextEditor--editOptions.visible {
                height: var(--edit-options-visible-height);
            }
        `);

        resizeTextbox();
        setupEditOptions();
        setupEditors().init();
    }

    // Оптимизированная функция проверки поддержки редакторов
    function checkEditorSupport() {
        const checkCodeMirror = () => 
            EnhanceWikitextEditor.config.allow.includes(config.contentModel) &&
            !['error', 'missing'].includes(mw.loader.getState('ext.CodeMirror'));

        const checkAce = () =>
            config.codeEditorLanguage &&
            !['error', 'missing'].includes(mw.loader.getState('ext.codeEditor.ace'));

        return {
            codeMirror: checkCodeMirror(),
            ace: checkAce()
        };
    }

    // Запуск инициализации
    const { codeMirror, ace } = checkEditorSupport();
    if (codeMirror) {
        init();
        mw.loader.using(['ext.wikiEditor']).then(setupEditors().init);
    } else if (ace) {
        init();
        mw.loader.using(['ext.codeEditor', 'ext.codeEditor.ace'])
            .then(setupEditors().init);
    }
});
// </nowiki>