Jump to content

MediaWiki:Gadget-PageCreator.js

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
// Page Creator
// SHARED CODEBASE
function fetchTemplateList(callback, errorCallback) {
    var api = new mw.Api();
    api.parse('{{#invoke:TemplateStarter|listTemplates}}')
        .done(function(html) {
            var tempDiv = document.createElement('div');
            tempDiv.innerHTML = html;
            var templateListText = tempDiv.textContent || tempDiv.innerText || '';
            var availableTemplates = templateListText.split(',').map(function(t) {
                return t.trim().split('\n')[0].trim();
            }).filter(function(t) {
                return t.length > 0 && t.match(/^[a-zA-Z][a-zA-Z0-9_\-\s\(\)]*$/);
            });
            callback(availableTemplates);
        })
        .fail(function(error) {
            if (errorCallback) errorCallback(error);
        });
}

function fetchTemplateContent(templateType, callback, errorCallback) {
    var api = new mw.Api();
    api.parse('{{#invoke:TemplateStarter|preload|' + templateType + '}}')
        .done(function(html) {
            var tempDiv = document.createElement('div');
            tempDiv.innerHTML = html;
            var templateContent = tempDiv.textContent || tempDiv.innerText || '';
            callback(templateContent);
        })
        .fail(function(error) {
            if (errorCallback) errorCallback(error);
        });
}

function cleanupUnfilledPlaceholders(templateContent, pageName, formData) {
    var processedContent = templateContent;
    if (!pageName || pageName.trim() === '') {
        throw new Error('Page name is required and cannot be empty');
    }
    processedContent = processedContent.replace(/\$PAGE_NAME\$/g, pageName);
    for (var key in formData) {
        if (key !== 'PAGE_NAME' && formData[key] && formData[key].trim() !== '') {
            var placeholder = '$' + key + '$';
            var escapedPlaceholder = placeholder.replace(/\$/g, '\\$');
            processedContent = processedContent.replace(new RegExp(escapedPlaceholder, 'g'), formData[key]);
        }
    }
    processedContent = processedContent.replace(/\$[A-Z_]+\$/g, '');
    processedContent = processedContent.replace(/\s+/g, ' ');
    processedContent = processedContent.replace(/is a\s+based/g, 'is based');
    processedContent = processedContent.replace(/is a\s+in/g, 'is in');
    processedContent = processedContent.replace(/\s+\./g, '.');
    processedContent = processedContent.trim();
    return processedContent;
}

// HERO PAGE CREATOR WIDGET
mw.loader.using(['mediawiki.api', 'mediawiki.util'], function() {
    $(function() {
        // Only run if the hero page creator container exists
        if ($('#hero-page-creator').length === 0) return;

        console.log('Initializing page creator widget');

        // Build the form HTML (containers exist, we populate them)
        var formHtml =
            '<input type="text" id="hero-page-name" class="searchboxInput" placeholder="Page name">' +
            '<select id="hero-template-type" class="searchboxInput" disabled>' +
                '<option value="">Loading...</option>' +
            '</select>' +
            '<button id="hero-create-btn" class="mw-ui-button mw-ui-progressive" disabled>Create</button>';
        
        $('#hero-page-creator .mw-inputbox-element').html(formHtml);

        // Fetch available templates using shared function
        fetchTemplateList(
            function(availableTemplates) {
                var $select = $('#hero-template-type');
                $select.empty().append('<option value="">Select a subject (template)</option>');
                availableTemplates.forEach(function(template) {
                    $select.append('<option value="' + template + '">' + template + '</option>');
                });
                $select.prop('disabled', false);
            },
            function() {
                $('#hero-template-type').empty().append('<option value="">Error</option>');
            }
        );

        // Enable/disable create button
        function updateHeroCreateButton() {
            var pageName = $('#hero-page-name').val().trim();
            var templateType = $('#hero-template-type').val();
            $('#hero-create-btn').prop('disabled', !pageName || !templateType);
        }

        $('#hero-page-name, #hero-template-type').on('input change', updateHeroCreateButton);

        // Handle create button click
        $('#hero-create-btn').on('click', function() {
            var pageName = $('#hero-page-name').val().trim();
            var templateType = $('#hero-template-type').val();

            if (!pageName || !templateType) return;

            $(this).prop('disabled', true).text('Creating...');

            fetchTemplateContent(templateType, function(templateContent) {
                try {
                    var formData = {};
                    templateContent = cleanupUnfilledPlaceholders(templateContent, pageName, formData);
                } catch (error) {
                    alert('Error: ' + error.message);
                    $('#hero-create-btn').prop('disabled', false).text('Create');
                    return;
                }

                var api = new mw.Api();
                var summary = templateType === 'None' ? 'Creating new page' : 'Creating new ' + templateType + ' page';
                api.create(pageName, { summary: summary }, templateContent)
                    .done(function() {
                        window.location.href = mw.util.getUrl(pageName, { veaction: 'edit' });
                    })
                    .fail(function(code) {
                        if (code === 'articleexists') {
                            if (confirm('Page already exists. Do you want to edit it?')) {
                                window.location.href = mw.util.getUrl(pageName, { action: 'edit' });
                            }
                        } else {
                            alert('Error creating page: ' + code);
                        }
                        $('#hero-create-btn').prop('disabled', false).text('Create');
                    });
            }, function() {
                alert('Error loading template content.');
                $('#hero-create-btn').prop('disabled', false).text('Create');
            });
        });
    });
});

// CREATE A PAGE METAPAGE
mw.loader.using(['mediawiki.api', 'mediawiki.util'], function() {
    $(function() {
        // Only run on pages that have the template creator container
        if ($('#template-creator-container').length === 0) return;
        
        console.log('Initializing TemplateStarter');
        
        // Build the initial HTML with loading state
        var formHtml =
            '<div class="template-creator-main-layout">' +
                '<div class="template-creator-form-container">' +
                    '<h3>Create New Page</h3>' +
                    '<div class="form-group">' +
                        '<label for="template-type">Template Type:</label>' +
                        '<select id="template-type" class="form-control" disabled>' +
                            '<option value="">Loading templates...</option>' +
                        '</select>' +
                    '</div>' +
                    '<div class="form-group">' +
                        '<label for="page-name">Page Name:</label>' +
                        '<input type="text" id="page-name" class="form-control" placeholder="Enter page name...">' +
                    '</div>' +
                    '<div id="dynamic-fields-container"></div>' +
                    '<button id="create-page-btn" class="mw-ui-button mw-ui-progressive" disabled>Create Page</button>' +
                '</div>' +
                '<div id="template-preview" class="template-creator-preview-container" style="display:none;">' +
                    '<h4>Preview:</h4>' +
                    '<pre id="template-preview-content"></pre>' +
                '</div>' +
            '</div>';
        
        // Insert the form
        $('#template-creator-container').html(formHtml);
        
        // Fetch available templates using shared function
        fetchTemplateList(
            function(availableTemplates) {
                var $select = $('#template-type');
                $select.empty().append('<option value="">Select a template...</option>');
                availableTemplates.forEach(function(template) {
                    $select.append('<option value="' + template + '">' + template + '</option>');
                });
                $select.prop('disabled', false);
                console.log('Loaded templates dynamically:', availableTemplates);
            },
            function(error) {
                console.error('Failed to load templates dynamically:', error);
                $('#template-type').empty().append('<option value="">Error loading templates</option>').prop('disabled', true);
            }
        );
        
        // Enable/disable create button based on form completion
        function updateCreateButton() {
            var templateType = $('#template-type').val();
            var pageName = $('#page-name').val().trim();
            $('#create-page-btn').prop('disabled', !templateType || !pageName);
        }
        
        // Update button state when inputs change
        $('#template-type, #page-name').on('change input', updateCreateButton);
        
        // Preview template when type is selected
        $('#template-type').on('change', function() {
            var templateType = $(this).val();
            if (!templateType) {
                $('#template-preview').hide();
                $('#dynamic-fields-container').empty();
                return;
            }
            
            // Load dynamic fields for this template type
            loadDynamicFields(templateType);
            updatePreview();
        });
        
        // Update preview when page name changes
        $('#page-name').on('input', function() {
            var templateType = $('#template-type').val();
            if (templateType) {
                updatePreview();
            }
        });
        
        // Function to update the preview with processed placeholders
        function updatePreview() {
            var templateType = $('#template-type').val();
            var pageName = $('#page-name').val().trim();
            
            if (!templateType) return;
            
            // Call the Lua module to get template structure
            var api = new mw.Api();
            api.parse('{{#invoke:TemplateStarter|preload|' + templateType + '}}')
                .done(function(html) {
                    // Extract text content from the parsed HTML
                    var tempDiv = document.createElement('div');
                    tempDiv.innerHTML = html;
                    var templateContent = tempDiv.textContent || tempDiv.innerText || '';
                    
                    // Collect form data and process placeholders
                    var formData = collectFormData();
                    templateContent = processPlaceholders(templateContent, pageName, formData);
                    
                    $('#template-preview-content').text(templateContent);
                    $('#template-preview').show();
                })
                .fail(function(error) {
                    console.error('Failed to preview template:', error);
                    $('#template-preview-content').text('Error loading template preview');
                    $('#template-preview').show();
                });
        }
        
        // Function to load dynamic fields for a template type
        function loadDynamicFields(templateType) {
            console.log('Loading dynamic fields for template:', templateType);
            
            var api = new mw.Api();
            api.parse('{{#invoke:TemplateStarter|getCreatorFieldDefinitionsJSON|' + templateType + '}}')
                .done(function(html) {
                    // Extract JSON content from the parsed HTML
                    var tempDiv = document.createElement('div');
                    tempDiv.innerHTML = html;
                    var jsonText = tempDiv.textContent || tempDiv.innerText || '';
                    
                    try {
                        var fieldDefinitions = JSON.parse(jsonText);
                        console.log('Field definitions loaded:', fieldDefinitions);
                        
                        // Generate form fields
                        generateDynamicFields(fieldDefinitions);
                    } catch (e) {
                        console.error('Failed to parse field definitions JSON:', e, jsonText);
                        $('#dynamic-fields-container').html('<p style="color: red;">Error loading field definitions</p>');
                    }
                })
                .fail(function(error) {
                    console.error('Failed to load field definitions:', error);
                    $('#dynamic-fields-container').html('<p style="color: red;">Error loading field definitions</p>');
                });
        }
        
        // Function to generate dynamic form fields
        function generateDynamicFields(fieldDefinitions) {
            var $container = $('#dynamic-fields-container');
            $container.empty();
            
            // Skip PAGE_NAME as it's handled separately
            for (var fieldKey in fieldDefinitions) {
                if (fieldKey === 'PAGE_NAME') continue;
                
                var fieldDef = fieldDefinitions[fieldKey];
                var $formGroup = $('<div class="form-group"></div>');
                
                // Create label
                var $label = $('<label></label>')
                    .attr('for', 'dynamic-field-' + fieldKey)
                    .text(fieldDef.label);
                
                // Create input
                var $input = $('<input type="text" class="form-control dynamic-field">')
                    .attr('id', 'dynamic-field-' + fieldKey)
                    .attr('data-field-key', fieldKey)
                    .attr('placeholder', fieldDef.placeholder);
                
                // Mark required fields
                if (fieldDef.required) {
                    $label.append(' <span style="color: red;">*</span>');
                    $input.attr('required', true);
                }
                
                $formGroup.append($label).append($input);
                $container.append($formGroup);
                
                // Add event listener for preview updates
                $input.on('input', function() {
                    var templateType = $('#template-type').val();
                    if (templateType) {
                        updatePreview();
                    }
                });
            }
            
            // Update create button state when dynamic fields change
            $container.on('input', '.dynamic-field', updateCreateButton);
            
            console.log('Dynamic fields generated');
        }
        
        // Function to collect form data from dynamic fields
        function collectFormData() {
            var formData = {};
            
            // Only collect dynamic field values (PAGE_NAME is handled separately)
            $('.dynamic-field').each(function() {
                var $field = $(this);
                var fieldKey = $field.data('field-key');
                var value = $field.val().trim();
                
                if (value) {
                    formData[fieldKey] = value;
                }
            });
            
            return formData;
        }
        
        // Function to process $VARIABLE$ placeholders
        function processPlaceholders(templateContent, pageName, formData) {
            var processedContent = templateContent;
            
            // Replace $PAGE_NAME$ with the actual page name
            if (pageName) {
                processedContent = processedContent.replace(/\$PAGE_NAME\$/g, pageName);
            }
            
            // Replace other placeholders with form data
            for (var key in formData) {
                if (key !== 'PAGE_NAME' && formData[key]) {
                    var placeholder = '$' + key + '$';
                    // Properly escape the $ characters for regex
                    var escapedPlaceholder = placeholder.replace(/\$/g, '\\$');
                    processedContent = processedContent.replace(new RegExp(escapedPlaceholder, 'g'), formData[key]);
                }
            }
            return processedContent;
        }

        // Handle create button click
        $('#create-page-btn').on('click', function() {
            var templateType = $('#template-type').val();
            var pageName = $('#page-name').val().trim();
            
            if (!templateType || !pageName) {
                alert('Please select a template type and enter a page name');
                return;
            }
            
            // Disable button to prevent double-clicks
            $(this).prop('disabled', true).text('Creating...');
            
            fetchTemplateContent(templateType, function(templateContent) {
                var formData = collectFormData();
                
                try {
                    var processedContent = cleanupUnfilledPlaceholders(templateContent, pageName, formData);
                } catch (error) {
                    alert('Error: ' + error.message);
                    $('#create-page-btn').prop('disabled', false).text('Create Page');
                    return;
                }
                
                var api = new mw.Api();
                var summary = templateType === 'None' ? 'Creating new page' : 'Creating new ' + templateType + ' page';
                api.create(pageName, { summary: summary }, processedContent)
                    .done(function() {
                        window.location.href = mw.util.getUrl(pageName, { veaction: 'edit' });
                    })
                    .fail(function(code, error) {
                        if (code === 'articleexists') {
                            if (confirm('Page already exists. Do you want to edit it and add the template?')) {
                                window.location.href = mw.util.getUrl(pageName, { veaction: 'edit' });
                            }
                        } else {
                            console.error('Failed to create page:', code, error);
                            alert('Error creating page: ' + (error && error.error ? error.error.info : code));
                        }
                        $('#create-page-btn').prop('disabled', false).text('Create Page');
                    });
            }, function(error) {
                console.error('Failed to get template:', error);
                alert('Error loading template. Please try again.');
                $('#create-page-btn').prop('disabled', false).text('Create Page');
            });
        });
        
        console.log('TemplateStarter initialized');
    });
});