User:Iniquity/translateEditor.js

// WikiEditor Tranlate Integration
// Integrates WikiEditor and CodeMirror into [[mw:Help:Extension:Translate]]
// Author: [[User:Iniquity]]

(function() {
    'use strict';
    
    // Wait for page load
    $(document).ready(function() {
        // Fast initialization
        initTranslateWikiEditor();
        
        // Track DOM changes for new forms
        observeNewForms();
    });
    
    function initTranslateWikiEditor() {
        // Find all translatewiki.net translation fields
        var $translationTextareas = $('textarea.tux-textarea-translation');
        
        if (!$translationTextareas.length) {
            // Fast retry
            setTimeout(initTranslateWikiEditor, 100);
            return;
        }
        
        // Initialize only visible fields that haven't been initialized yet
        $translationTextareas.each(function() {
            var $textarea = $(this);
            
            // Check that textarea is visible and not initialized
            if ($textarea.is(':visible') && !$textarea.data('wecm-tux-initialized')) {
                initializeForm($textarea);
            }
        });
    }
    

    
    function initializeForm($textarea) {
        // Check if this textarea is already initialized
        if ($textarea.data('wecm-tux-initialized')) {
            return;
        }
        
        // Set ID for compatibility (if not already set)
        if (!$textarea.attr('id')) {
            $textarea.attr('id', 'wpTextbox1-' + Date.now());
        }
        
        // Load resources and setup editor
        loadResourcesAndSetup($textarea);
        
        // Mark textarea as initialized
        $textarea.data('wecm-tux-initialized', true);
    }
    
    function loadResourcesAndSetup($textarea) {
        // Check MediaWiki API availability
        if (typeof mw === 'undefined' || !mw.loader) {
            return;
        }
        
        // Load WikiEditor and CodeMirror
        mw.loader.using([
            'ext.wikiEditor',
            'ext.CodeMirror.v6.WikiEditor',
            'ext.CodeMirror.v6.mode.mediawiki'
        ]).then(function(require) {
            if (typeof mw.addWikiEditor === 'function') {
                try {
                    mw.addWikiEditor($textarea);
                    $textarea.wikiEditor({
                        toolbar: {
                            gadgets: {
                                type: 'group',
                                label: 'Гаджеты'
                            },
                            format: {},
                            insert: {},
                            advanced: {}
                        }
                    });
                    
                    // Attempt CodeMirror initialization (optional)
                    try {
                        const CodeMirrorWikiEditor = require('ext.CodeMirror.v6.WikiEditor');
                        const mediawikiLang = require('ext.CodeMirror.v6.mode.mediawiki');
                        
                        if (typeof CodeMirrorWikiEditor === 'function' && typeof mediawikiLang === 'function') {
                            // Additional textarea checks before CodeMirror initialization
                            if ($textarea[0] && 
                                $textarea[0].tagName === 'TEXTAREA' && 
                                $textarea[0].value !== null && 
                                $textarea[0].name !== null &&
                                $textarea[0].id !== null) {
                                
                                // Save original properties for compatibility
                                var originalTextarea = $textarea[0];
                                var originalReadOnly = originalTextarea.readOnly;
                                var originalDisabled = originalTextarea.disabled;
                                
                                const cmWe = new CodeMirrorWikiEditor($textarea[0], mediawikiLang());
                                
                                // Check that initialization was successful
                                if (!cmWe || typeof cmWe.initialize !== 'function') {
                                    return;
                                }
                                
                                // Set mode manually if not set
                                if (!cmWe.mode) {
                                    cmWe.mode = 'mediawiki';
                                }
                                
                                // Additional checks before initialization
                                if (!cmWe.$textarea) {
                                    cmWe.$textarea = $textarea;
                                }
                                
                                if (!cmWe.context) {
                                    // Create minimal context
                                    cmWe.context = {
                                        $ui: $textarea.closest('.wikiEditor-ui'),
                                        modules: {
                                            toolbar: {
                                                $toolbar: $textarea.closest('.wikiEditor-ui').find('.toolbar')
                                            }
                                        }
                                    };
                                }
                                
                                try {
                                    cmWe.initialize();
                                } catch (initError) {
                                    return;
                                }
                                
                                // Check that view is created
                                if (!cmWe.view || !cmWe.view.dom) {
                                    return;
                                }
                                
                                // Restore properties for compatibility
                                Object.defineProperty(cmWe.view.dom, 'readOnly', {
                                    get: function() { return originalReadOnly; },
                                    set: function(value) { originalReadOnly = value; }
                                });
                                
                                Object.defineProperty(cmWe.view.dom, 'disabled', {
                                    get: function() { return originalDisabled; },
                                    set: function(value) { originalDisabled = value; }
                                });
                                
                                Object.defineProperty(cmWe.view.dom, 'tagName', {
                                    get: function() { return 'TEXTAREA'; }
                                });
                                
                                Object.defineProperty(cmWe.view.dom, 'value', {
                                    get: function() { return cmWe.view.state.doc.toString(); },
                                    set: function(value) { 
                                        cmWe.view.dispatch({
                                            changes: { from: 0, to: cmWe.view.state.doc.length, insert: value }
                                        });
                                    }
                                });
                                
                                // Save reference to editor
                                $textarea.data('codeMirrorEditor', cmWe);

                                // Add auto-resize functionality for CodeMirror
                                setupAutoResize(cmWe, $textarea);

                                // Add Ctrl+Enter (Cmd+Enter) save shortcut on .cm-content with capture:true
                                var cmContent = $(cmWe.view.dom).find('.cm-content')[0];
                                if (cmContent && !$textarea.data('wecm-tux-capture-keydown')) {
                                    $textarea.data('wecm-tux-capture-keydown', true);
                                    cmContent.addEventListener('keydown', function(e) {
                                        const isCmdModifierPressed = $.client.profile().platform === 'mac' ? e.metaKey : e.ctrlKey;
                                        if (isCmdModifierPressed && !e.shiftKey && !e.altKey && e.keyCode === 13) {
                                            e.preventDefault();
                                            e.stopPropagation();
                                            var $btn = $('.tux-editor-save-button').filter(function() {
                                                var $el = $(this);
                                                return $el.is(':visible') && !$el.prop('disabled');
                                            });
                                            console.log('[edit-here] All candidate save buttons:', $('.tux-editor-save-button').toArray());
                                            if ($btn.length) {
                                                $btn.click();
                                                console.log('[edit-here] Save button clicked from cm-content capture');
                                            } else {
                                                console.log('[edit-here] Save button not found from cm-content capture');
                                            }
                                            return false;
                                        }
                                    }, true);
                                }

                                // Register custom keymap for Ctrl+Enter in CodeMirror (works even if event does not bubble)
                                mw.loader.using('ext.CodeMirror.v6.lib').then(function(lib) {
                                    if (cmWe && cmWe.view && typeof cmWe.view.applyExtension === 'function' && !$textarea.data('wecm-tux-keymap-registered')) {
                                        $textarea.data('wecm-tux-keymap-registered', true);
                                        var saveKeymap = lib.keymap.of([
                                            {
                                                key: "Ctrl-Enter",
                                                run: function() {
                                                    var $btn = $('button[value="save"], input[value="save"], .save-button');
                                                    if ($btn.length) {
                                                        $btn.click();
                                                        console.log('[edit-here] Save button clicked from keymap');
                                                    } else {
                                                        console.log('[edit-here] Save button not found from keymap');
                                                    }
                                                    return true;
                                                }
                                            }
                                        ]);
                                        cmWe.view.applyExtension(saveKeymap);
                                    }
                                });

                                // -- Fallback: MutationObserver for CodeMirror content changes --
                                if (cmWe && cmWe.view && cmWe.view.dom && !$textarea.data('wecm-tux-mutation-observer')) {
                                    $textarea.data('wecm-tux-mutation-observer', true);
                                    var cmContent = $(cmWe.view.dom).find('.cm-content')[0];
                                    var cmEditor = $(cmWe.view.dom).closest('.cm-editor')[0] || $(cmWe.view.dom).find('.cm-editor')[0];
                                    if (cmContent) {
                                        var lastText = cmWe.view.state.doc.toString();
                                        var syncTimeout = null;
                                        var observer = new MutationObserver(function(mutationsList, observer) {
                                            clearTimeout(syncTimeout);
                                            syncTimeout = setTimeout(function() {
                                                var newText = cmWe.view.state.doc.toString();
                                                if (newText !== lastText) {
                                                    lastText = newText;
                                                    $textarea.css('display', 'block').css('visibility', 'visible');
                                                    // Set direction and language from .cm-editor
                                                    if (cmEditor) {
                                                        var dir = cmEditor.getAttribute('dir') || 'ltr';
                                                        var lang = cmEditor.getAttribute('lang') || 'en';
                                                        $textarea.attr('dir', dir);
                                                        $textarea.attr('lang', lang);
                                                        $(cmEditor).find('.cm-content').attr('dir', dir).attr('lang', lang);
                                                    }
                                                    var ta = $textarea[0];
                                                    ta.dispatchEvent(new Event('input', { bubbles: true }));
                                                    ta.dispatchEvent(new Event('change', { bubbles: true }));
                                                    // Do not change value, focus or blur!
                                                }
                                            }, 50);
                                        });
                                        observer.observe(cmContent, { characterData: true, subtree: true, childList: true });
                                        $textarea.data('wecm-tux-mutation-observer-instance', observer);
                                    }
                                }

                            } else {
                                // Textarea not ready for CodeMirror
                            }
                        }
                    } catch (cmError) {
                        // CodeMirror unavailable, continue without it
                    }
                    
                    // Load wikificator and add to toolbar
                    loadWikificatorAndSetup($textarea);
                    
                    // Add keyboard shortcuts
                    addKeyboardShortcuts($textarea);
                    
                    // Add syntax button handler
                    addSyntaxButtonHandler($textarea);
                    
                    // Remove margin from all group-format on page after initialization
                    setTimeout(function() {
                        $('.wikiEditor-ui .group-format').each(function() {
                            this.style.setProperty('margin-left', '0', 'important');
                        });
                    }, 100);
                    
                } catch (e) {
                    // Error initializing WikiEditor
                }
            }
            
        }).catch(function(error) {
            // Failed to load WikiEditor, CodeMirror
        });
    }
    
    function setupAutoResize(cmWe, $textarea) {
        // Function to automatically resize CodeMirror editor based on content
        function autoResize() {
            if (!cmWe || !cmWe.view || !cmWe.view.dom) {
                return;
            }
            
            // Get the CodeMirror editor element
            var $cmEditor = $(cmWe.view.dom).closest('.cm-editor');
            if (!$cmEditor.length) {
                return;
            }
            
            // Get current content and calculate lines
            var content = cmWe.view.state.doc.toString();
            var lines = content.split('\n');
            var lineCount = lines.length;
            
            // Calculate minimum and maximum heights
            var minHeight = 100; // Minimum height in pixels
            var maxHeight = 600; // Maximum height in pixels
            var lineHeight = 20; // Approximate line height in pixels
            var padding = 40; // Padding for editor
            
            // Calculate additional height for long lines that wrap
            var editorWidth = $cmEditor.width() || 600; // Get current editor width
            var charWidth = 8; // Approximate character width in pixels
            var widthPadding = 20; // Account for padding and scrollbars
            var charsPerLine = Math.floor((editorWidth - widthPadding) / charWidth);
            
            var totalWrappedLines = 0;
            for (var i = 0; i < lines.length; i++) {
                var line = lines[i];
                
                // Calculate actual line width considering different character types
                var lineWidth = 0;
                for (var j = 0; j < line.length; j++) {
                    var char = line[j];
                    // Adjust width for different character types
                    if (char.charCodeAt(0) > 127) {
                        // Non-ASCII characters (like Cyrillic) are wider
                        lineWidth += charWidth * 1.2;
                    } else if (char === ' ' || char === '\t') {
                        // Spaces and tabs
                        lineWidth += charWidth * 0.5;
                    } else {
                        // Regular ASCII characters
                        lineWidth += charWidth;
                    }
                }
                
                // Check if line needs wrapping
                if (lineWidth > editorWidth - widthPadding) {
                    // Calculate how many lines this long line will wrap to
                    var wrappedLines = Math.ceil(lineWidth / (editorWidth - widthPadding));
                    totalWrappedLines += (wrappedLines - 1); // Subtract 1 because we already count the original line
                }
            }
            
            // Add extra height for wrapped lines
            var wrappedHeight = totalWrappedLines * lineHeight;
            var finalHeight = Math.max(minHeight, Math.min(maxHeight, lineCount * lineHeight + wrappedHeight + padding));
            
            // Apply new height to CodeMirror editor
            $cmEditor.css({
                'height': finalHeight + 'px',
                'min-height': minHeight + 'px',
                'max-height': maxHeight + 'px',
                'overflow-y': finalHeight >= maxHeight ? 'auto' : 'hidden'
            });
            
            // Also update the textarea height for compatibility
            $textarea.css({
                'height': finalHeight + 'px',
                'min-height': minHeight + 'px',
                'max-height': maxHeight + 'px'
            });
            
            // Force CodeMirror to update its layout
            if (cmWe.view.requestMeasure) {
                cmWe.view.requestMeasure();
            }
        }
        
        // Initial resize
        setTimeout(autoResize, 100);
        
        // Listen for content changes using CodeMirror's update event
        if (cmWe.view && cmWe.view.state) {
            try {
                // Try to use CodeMirror's built-in update listener
                mw.loader.using('@codemirror/view').then(function(viewModule) {
                    if (cmWe.view && cmWe.view.state) {
                        // Add update listener
                        var updateListener = viewModule.EditorView.updateListener.of(function(update) {
                            if (update.docChanged) {
                                setTimeout(autoResize, 10);
                            }
                        });
                        
                        // Apply the listener
                        cmWe.view.dispatch({
                            effects: updateListener
                        });
                    }
                }).catch(function() {
                    // Fallback to MutationObserver if CodeMirror view module not available
                    setupMutationObserver();
                });
            } catch (e) {
                // Fallback to MutationObserver
                setupMutationObserver();
            }
        } else {
            // Fallback to MutationObserver
            setupMutationObserver();
        }
        
        function setupMutationObserver() {
            var $cmContent = $(cmWe.view.dom).find('.cm-content');
            if ($cmContent.length) {
                var observer = new MutationObserver(function() {
                    setTimeout(autoResize, 10);
                });
                observer.observe($cmContent[0], { 
                    childList: true, 
                    subtree: true, 
                    characterData: true 
                });
                $textarea.data('wecm-tux-resize-observer', observer);
            }
        }
        
        // Also listen for window resize events
        $(window).off('resize.wecm-tux-resize').on('resize.wecm-tux-resize', function() {
            setTimeout(autoResize, 100);
        });
        
        // Listen for input events on the CodeMirror editor for faster response
        var $cmEditor = $(cmWe.view.dom).closest('.cm-editor');
        if ($cmEditor.length) {
            $cmEditor.off('input.wecm-tux-resize keyup.wecm-tux-resize').on('input.wecm-tux-resize keyup.wecm-tux-resize', function() {
                setTimeout(autoResize, 50);
            });
        }
    }
    
    function loadWikificatorAndSetup($textarea) {
        // Load wikificator directly from ru.wikipedia.org
        loadWikificatorFallback($textarea);
    }
    
    function loadWikificatorFallback($textarea) {
        // Fallback: load via $.getScript
        $.getScript('//ru.wikipedia.org/w/index.php?title=MediaWiki:Gadget-wikificator.js&action=raw&ctype=text/javascript')
            .done(function() {
                addWikificatorToToolbar($textarea);
            })
            .fail(function(jqXHR, textStatus, errorThrown) {
                // Wikificator not loaded
            });
    }
    
    function addWikificatorToToolbar($textarea) {
        // Wait for toolbar readiness (like in edit-here-config.js)
        var $wikiEditorUI = $textarea.closest('.wikiEditor-ui');
        var toolbarReady = $wikiEditorUI.length && $wikiEditorUI.find('.toolbar').length;
        
        if (toolbarReady) {
            try {
                var gadgetsTools = {
                    wikificator: {
                        label: 'Викификатор — автоматический обработчик текста (Ctrl+Alt+W)',
                        type: 'button',
                        icon: 'https://upload.wikimedia.org/wikipedia/commons/0/06/Wikify-toolbutton.png',
                        action: {
                            type: 'callback',
                            execute: function() {
                                if (typeof window.Wikify === 'function') {
                                    window.Wikify($textarea[0]);
                                } else {
                                    // Wikify not found
                                }
                            }
                        }
                    }
                };
                
                $textarea.wikiEditor('addToToolbar', {
                    section: 'main',
                    groups: {
                        gadgets: {
                            tools: gadgetsTools
                        }
                    }
                });
                
                // Move gadgets group to the beginning of toolbar
                $wikiEditorUI.find('.group-gadgets').insertBefore($wikiEditorUI.find('.section-main .group-format'));
                
                // Remove temporary margin from group-format
                $wikiEditorUI.find('.group-format').each(function() {
                    this.style.setProperty('margin-left', '0', 'important');
                });
                
                // Remove CSS rule from styles
                $('style').each(function() {
                    var $style = $(this);
                    var cssText = $style.text();
                    if (cssText.includes('.wikiEditor-ui .group-format') && cssText.includes('margin-left: 34px !important')) {
                        var newCssText = cssText.replace(/\.wikiEditor-ui \.group-format\s*\{\s*margin-left:\s*34px\s*!important;\s*\}/g, '');
                        $style.text(newCssText);
                    }
                });
                
                // Remove margin from all group-format on page
                $('.wikiEditor-ui .group-format').each(function() {
                    this.style.setProperty('margin-left', '0', 'important');
                });
                
            } catch (e) {
                // Error integrating Wikificator
            }
        } else {
            // Retry after 500ms
            setTimeout(function() {
                addWikificatorToToolbar($textarea);
            }, 500);
        }
    }
    
    function addKeyboardShortcuts($textarea) {
        // Remove previous handlers
        $textarea.off('keydown.wecm-tux');
        // Add to textarea (in case focus is there)
        $textarea.on('keydown.wecm-tux', handleShortcut);

        // Add to CodeMirror content if present
        var cmWe = $textarea.data('codeMirrorEditor');
        if (cmWe && cmWe.view && cmWe.view.dom) {
            var $cmContent = $(cmWe.view.dom).find('.cm-content');
            $cmContent.off('keydown.wecm-tux');
            $cmContent.on('keydown.wecm-tux', handleShortcut);
        }

        function handleShortcut(e) {
            const isCmdModifierPressed = $.client.profile().platform === 'mac' ? e.metaKey : e.ctrlKey;

            // Ctrl+Enter for save
            if (isCmdModifierPressed && !e.shiftKey && !e.altKey && e.keyCode === 13) {
                e.preventDefault();
                e.stopPropagation();
                $('button[value="save"], input[value="save"], .save-button').click();
                return false;
            }
            // Ctrl+Alt+W for wikificator
            if (isCmdModifierPressed && !e.shiftKey && e.altKey && e.keyCode === 87) {
                e.preventDefault();
                e.stopPropagation();
                if (typeof window.Wikify === 'function') {
                    window.Wikify($textarea[0]);
                }
                return false;
            }
            // ALT+SHIFT+D for skip
            if (!isCmdModifierPressed && e.shiftKey && e.altKey && e.keyCode === 68) {
                e.preventDefault();
                e.stopPropagation();
                $('.tux-editor-skip-button').click();
                return false;
            }
            // ALT+SHIFT+B for edit summary
            if (!isCmdModifierPressed && e.shiftKey && e.altKey && e.keyCode === 66) {
                e.preventDefault();
                e.stopPropagation();
                $('.tux-input-editsummary').focus();
                return false;
            }
        }
    }
    

    
    function runWikificator(textareaElement) {
        if (typeof window.Wikify === 'function') {
            window.Wikify(textareaElement);
            showNotification('Wikificator started', 'success');
        } else {
            showNotification('Wikificator unavailable', 'error');
        }
    }
    
    
    // Add CSS styles for proper WikiEditor and CodeMirror display
    function addStyles() {
        var styles = `
            /* Force show toolbar and WikiEditor tabs even for readonly/inactive CodeMirror */
            .wikiEditor-ui.ext-codemirror-readonly .wikiEditor-section-secondary,
            .wikiEditor-ui:not(.ext-codemirror-mediawiki) .wikiEditor-section-secondary,
            .wikiEditor-ui.ext-codemirror-readonly .tabs,
            .wikiEditor-ui:not(.ext-codemirror-mediawiki) .tabs,
            .wikiEditor-ui.ext-codemirror-readonly .sections,
            .wikiEditor-ui:not(.ext-codemirror-mediawiki) .sections {
                display: block !important;
            }

            .wikiEditor-ui:not(.ext-codemirror-mediawiki) .group:not(.group-codemirror):not(.group-codemirror-format):not(.group-codemirror-preferences):not(.group-codemirror-search),
            .wikiEditor-ui.ext-codemirror-readonly .group:not(.group-codemirror):not(.group-codemirror-format):not(.group-codemirror-preferences):not(.group-codemirror-search) {
                display: flex;
            }

            /* Proper cursor for text fields */
            .wikiEditor-ui textarea,
            .wikiEditor-ui .wikiEditor-ui-text textarea,
            .wikiEditor-ui .wikiEditor-ui-text .wikiEditor-ui-text textarea {
                cursor: text !important;
            }

            /* Cursor for CodeMirror */
            .wikiEditor-ui .cm-editor {
                cursor: text !important;
                transition: height 0.2s ease-in-out;
            }

            /* Auto-resize styles for CodeMirror */
            .wikiEditor-ui .cm-editor.cm-focused {
                outline: none !important;
            }

            .wikiEditor-ui .cm-editor .cm-scroller {
                overflow-x: auto !important;
            }

            .wikiEditor-ui .cm-editor .cm-content {
                white-space: pre-wrap !important;
                word-wrap: break-word !important;
                word-break: break-word !important;
                overflow-wrap: break-word !important;
            }

            /* Cursor for buttons and controls */
            .wikiEditor-ui .tool,
            .wikiEditor-ui .toolbar .tool,
            .wikiEditor-ui button,
            .wikiEditor-ui input[type="button"],
            .wikiEditor-ui input[type="submit"] {
                cursor: pointer !important;
            }

            /* Reserve space for wikificator button */
            .wikiEditor-ui .group-gadgets {
                min-width: 34px !important;
            }

            /* Temporarily move group-format */
            .wikiEditor-ui .group-format {
                margin-left: 34px !important;
            }
        `;
        
        var $style = $('<style>').text(styles);
        $('head').append($style);
    }
    
    function cleanupPreviousEditors() {
        // Clean up previous CodeMirror editors and observers
        $('textarea.tux-textarea-translation').each(function() {
            var $textarea = $(this);
            
            // Clean up resize observer
            var resizeObserver = $textarea.data('wecm-tux-resize-observer');
            if (resizeObserver && typeof resizeObserver.disconnect === 'function') {
                resizeObserver.disconnect();
                $textarea.removeData('wecm-tux-resize-observer');
            }
            
            // Clean up mutation observer
            var mutationObserver = $textarea.data('wecm-tux-mutation-observer-instance');
            if (mutationObserver && typeof mutationObserver.disconnect === 'function') {
                mutationObserver.disconnect();
                $textarea.removeData('wecm-tux-mutation-observer-instance');
            }
            
            // Remove event handlers
            $textarea.off('keydown.wecm-tux');
            $(window).off('resize.wecm-tux-resize');
            
            // Remove CodeMirror editor event handlers
            var cmWe = $textarea.data('codeMirrorEditor');
            if (cmWe && cmWe.view && cmWe.view.dom) {
                var $cmEditor = $(cmWe.view.dom).closest('.cm-editor');
                if ($cmEditor.length) {
                    $cmEditor.off('input.wecm-tux-resize keyup.wecm-tux-resize');
                }
            }
            
            // Reset textarea styles
            $textarea.css({
                'height': '',
                'min-height': '',
                'max-height': ''
            });
            
            // Remove CodeMirror editor reference
            $textarea.removeData('codeMirrorEditor');
            $textarea.removeData('wecm-tux-initialized');
        });
    }
    
    function observeNewForms() {
        // Fast tracking of clicks on links for new form initialization
        $(document).on('click', 'a[href*="action=translate"], .tux-editor-link', function() {
            // Clean up previous editors before switching
            cleanupPreviousEditors();
            
            // Add margin when switching forms
            addMarginToGroupFormat();
            
            setTimeout(function() {
                initTranslateWikiEditor();
            }, 100);
        });
        
        // More frequent check for new forms (every 500ms)
        setInterval(function() {
            initTranslateWikiEditor();
        }, 500);
    }
    
    function addMarginToGroupFormat() {
        // Add margin to all group-format on page
        $('.wikiEditor-ui .group-format').each(function() {
            this.style.setProperty('margin-left', '34px', 'important');
        });
        
        // Add CSS rule back
        var $existingStyle = $('style').filter(function() {
            return $(this).text().includes('wecm-tux-wikieditor');
        }).first();
        
        if ($existingStyle.length) {
            var cssText = $existingStyle.text();
            if (!cssText.includes('.wikiEditor-ui .group-format') || !cssText.includes('margin-left: 34px !important')) {
                var newRule = '\n            /* Temporarily move group-format */\n            .wikiEditor-ui .group-format {\n                margin-left: 34px !important;\n            }';
                $existingStyle.text(cssText + newRule);
            }
        }
    }
    

    
    // Add styles on initialization
    addStyles();
    
    // Global Ctrl+Enter handler for save (works even if CodeMirror eats the event)
    $(document).off('keydown.wecm-tux-global').on('keydown.wecm-tux-global', function(e) {
        const isCmdModifierPressed = $.client.profile().platform === 'mac' ? e.metaKey : e.ctrlKey;
        if (isCmdModifierPressed && !e.shiftKey && !e.altKey && e.keyCode === 13) {
            console.log('[edit-here] Global Ctrl+Enter handler fired');
            e.preventDefault();
            e.stopPropagation();
            var $btn = $('button[value="save"], input[value="save"], .save-button');
            console.log('[edit-here] Save button:', $btn[0], 'disabled:', $btn.prop('disabled'), 'opacity:', $btn.css('opacity'), 'class:', $btn.attr('class'));
            if ($btn.length) {
                $btn.click();
                console.log('[edit-here] Save button clicked');
            } else {
                console.log('[edit-here] Save button not found');
            }
            return false;
        }
    });
    
})();