Jump to content

User:Polygnotus/Scripts/ReplyButtonsv4.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
(function() {
    if (mw.config.get('wgDiscussionToolsFeaturesEnabled')) {
        mw.loader.using(['ext.discussionTools.ReplyWidget', 'mediawiki.api'], () => {
            // Improved configuration loading with caching
            async function loadToolsConfig() {
                const username = mw.config.get('wgUserName');
                if (!username) return [];

                const api = new mw.Api();
                try {
                    const result = await api.get({
                        action: 'query',
                        prop: 'revisions',
                        titles: `User:${username}/ReplyButtonsJSON`,
                        rvslots: '*',
                        rvprop: 'content',
                        formatversion: '2',
                        uselang: 'content', // Enable caching
                        smaxage: '86400',   // Cache for 1 day
                        maxage: '86400'     // Cache for 1 day
                    });

                    if (result.query.pages[0].missing) {
                        return [];
                    }

                    const content = result.query.pages[0].revisions[0].slots.main.content;
                    return JSON.parse(content);
                } catch (error) {
                    console.error('Error loading reply buttons configuration:', error);
                    return [];
                }
            }

            // Helper function to create tools from config
            function createToolFromConfig(config) {
                // Add error handling for icon URLs
                if (config.icon?.startsWith('http')) {
                    try {
                        addCustomIconCSS(config.name, config.icon);
                    } catch (error) {
                        console.warn(`Failed to add custom icon for ${config.name}:`, error);
                        config.icon = 'help'; // Fallback icon
                    }
                }

                // Create command with improved error handling
                const CommandClass = function() {
                    ve.ui.Command.call(this, config.name);
                };
                OO.inheritClass(CommandClass, ve.ui.Command);
                
                CommandClass.prototype.execute = function() {
                    try {
                        const target = ve.init.target;
                        if (!target) {
                            console.warn('Visual editor target not found');
                            return false;
                        }

                        const surface = target.getSurface();
                        const surfaceModel = surface.getModel();
                        
                        const content = typeof config.insertContent === 'function' 
                            ? config.insertContent()
                            : config.insertText.replace(/'\s*\+\s*'/g, '');
                            
                        surfaceModel.getFragment()
                            .collapseToEnd()
                            .insertContent(content)
                            .collapseToEnd()
                            .select();
                            
                        return true;
                    } catch (error) {
                        console.error(`Error executing command ${config.name}:`, error);
                        return false;
                    }
                };
                
                ve.ui.commandRegistry.register(new CommandClass());
                
                // Create tool with improved validation
                const ToolClass = function() {
                    ve.ui.Tool.apply(this, arguments);
                };
                OO.inheritClass(ToolClass, ve.ui.Tool);
                
                ToolClass.static.name = config.name;
                ToolClass.static.title = config.title || config.name;
                ToolClass.static.commandName = config.name;
                ToolClass.static.icon = config.icon?.startsWith('http') 
                    ? 'custom-' + config.name 
                    : (config.icon || 'help');

                ve.ui.toolFactory.register(ToolClass);
                
                // Add to toolbar groups with improved module detection
                const replyWidget = mw.loader.moduleRegistry['ext.discussionTools.ReplyWidget']
                    ?.packageExports?.['dt-ve/CommentTarget.js'];
                    
                const newTopicWidget = mw.loader.moduleRegistry['ext.discussionTools.NewTopic']
                    ?.packageExports?.['dt-ve/NewTopicTarget.js'];
                
                if (replyWidget?.static?.toolbarGroups) {
                    const toolbarGroup = replyWidget.static.toolbarGroups[3];
                    if (toolbarGroup && Array.isArray(toolbarGroup.include)) {
                        toolbarGroup.include.push(config.name);
                    }
                }
                
                if (newTopicWidget?.static?.toolbarGroups) {
                    let customGroup = newTopicWidget.static.toolbarGroups.find(g => g.name === 'custom');
                    if (!customGroup) {
                        customGroup = {
                            name: 'custom',
                            include: [],
                            demote: ['custom']
                        };
                        newTopicWidget.static.toolbarGroups.push(customGroup);
                    }
                    if (Array.isArray(customGroup.include)) {
                        customGroup.include.push(config.name);
                    }
                }
            }

            // Function to add custom CSS with error handling
            function addCustomIconCSS(name, iconUrl) {
                const styleId = `custom-icon-${name}`;
                if (!document.getElementById(styleId)) {
                    const style = document.createElement('style');
                    style.id = styleId;
                    style.textContent = `
                        .oo-ui-icon-custom-${name} {
                            background-image: url(${iconUrl}) !important;
                            background-size: contain !important;
                            background-position: center !important;
                            background-repeat: no-repeat !important;
                        }
                    `;
                    document.head.appendChild(style);
                }
            }

            // Initialize tools with improved error handling
            loadToolsConfig().then(tools => {
                if (Array.isArray(tools) && tools.length > 0) {
                    tools.forEach(config => {
                        try {
                            createToolFromConfig(config);
                        } catch (error) {
                            console.error(`Failed to create tool from config:`, config, error);
                        }
                    });
                }
            }).catch(error => {
                console.error('Failed to load tools configuration:', error);
            });
        });
    }
})();