Module:TemplateStarter: Difference between revisions

// via Wikitext Extension for VSCode
// via Wikitext Extension for VSCode
Line 6: Line 6:
-- Required modules
-- Required modules
local ConfigRepository = require('Module:ConfigRepository')
local ConfigRepository = require('Module:ConfigRepository')
local ErrorHandling = require('Module:ErrorHandling')
-- Cache for template lists to improve performance
local templateListCache = nil
local templateListCacheTime = 0
local CACHE_DURATION = 300 -- 5 minutes in seconds


-- Generate empty template wikitext from template type
-- Generate empty template wikitext from template type
function p.generateTemplate(templateType)
function p.generateTemplate(templateType)
     -- Get configuration for the template type
     -- Input validation and sanitization
     local config = ConfigRepository.getConfig(templateType)
    if not templateType or templateType == "" then
        return "Error: Template type is required"
     end
      
      
     -- Check if template exists
     -- Sanitize input - remove any potentially harmful characters
     if not config or not config.fields then
    templateType = mw.text.trim(tostring(templateType))
         return string.format("Error: Template type '%s' not found in ConfigRepository", templateType)
     if not templateType:match("^[%w_%-]+$") then
         return "Error: Invalid template type format"
     end
     end
      
      
     -- Start building the template
     -- Create error context for better error handling
     local lines = {"{{" .. templateType}
     local errorContext = ErrorHandling.createContext()
      
      
     -- Process each field
     -- Protected function to get configuration
     for _, field in ipairs(config.fields) do
     local function getTemplateConfig()
         -- Skip hidden fields
        local config = ConfigRepository.getConfig(templateType)
         if not field.hidden then
          
             -- Handle fields with multiple keys
         if not config then
            local fieldKey = field.key or (field.keys and field.keys[1])
             ErrorHandling.addError(errorContext, 'TemplateStarter.generateTemplate',
              
                string.format("Template type '%s' not found in ConfigRepository", templateType))
            if fieldKey then
             return nil
                table.insert(lines, string.format("|%s = ", fieldKey))
        end
             end
       
        if not config.fields then
            ErrorHandling.addError(errorContext, 'TemplateStarter.generateTemplate',
                string.format("Template type '%s' has no fields configuration", templateType))
             return nil
         end
         end
       
        return config
     end
     end
      
      
     -- Close the template
     -- Get configuration with error protection
     table.insert(lines, "}}")
     local success, config = ErrorHandling.protect(errorContext, getTemplateConfig)
    if not success or not config then
        return "Error: " .. (ErrorHandling.formatOutput(errorContext) or "Failed to load template configuration")
    end
      
      
     -- Join with newlines
     -- Pre-allocate lines table for better performance
    return table.concat(lines, "\n")
     local lines = {}
end
     lines[1] = "{{" .. templateType
 
     local lineCount = 1
-- Main function to be called from wiki
function p.main(frame)
     local args = frame.args
     local parent = frame:getParent()
     local pargs = parent and parent.args or {}
      
      
     -- Get parameters (check both direct and parent args)
     -- Process each field with error protection
    local articleName = args.articleName or pargs.articleName or args[1] or pargs[1]
    local function processFields()
    local templateType = args.templateType or pargs.templateType or args[2] or pargs[2]
        for _, field in ipairs(config.fields) do
   
            -- Skip hidden fields
    -- Validate inputs
            if not field.hidden then
    if not articleName or articleName == "" then
                -- Handle fields with multiple keys (prefer single key, fallback to first of multiple)
        return "Error: Article name is required"
                local fieldKey = field.key or (field.keys and field.keys[1])
               
                if fieldKey and fieldKey ~= "" then
                    lineCount = lineCount + 1
                    lines[lineCount] = string.format("|%s = ", fieldKey)
                end
            end
        end
     end
     end
      
      
     if not templateType or templateType == "" then
    -- Process fields with error protection
         return "Error: Template type is required"
    local fieldSuccess = ErrorHandling.protect(errorContext, processFields)
     if not fieldSuccess then
         ErrorHandling.addError(errorContext, 'TemplateStarter.generateTemplate',
            "Failed to process template fields")
     end
     end
      
      
     -- Generate the template content
     -- Close the template
     local content = p.generateTemplate(templateType)
     lineCount = lineCount + 1
    lines[lineCount] = "}}"
      
      
     -- For testing, return the generated content in a pre block
     -- Join with newlines (more efficient than multiple concatenations)
     return string.format('<pre>Page: %s\n\n%s</pre>', articleName, content)
     return table.concat(lines, "\n")
end
end


-- Generate a form with copy-paste content
-- Main function to be called from wiki (for testing/preview)
function p.createLink(frame)
function p.main(frame)
     local args = frame.args
     local errorContext = ErrorHandling.createContext()
    local parent = frame:getParent()
    local pargs = parent and parent.args or {}
      
      
     -- Get parameters
     -- Protected function to process arguments
    local articleName = args.articleName or pargs.articleName or args[1] or pargs[1]
    local function processArgs()
    local templateType = args.templateType or pargs.templateType or args[2] or pargs[2]
        local args = frame.args
   
        local parent = frame:getParent()
    -- Validate inputs
        local pargs = parent and parent.args or {}
    if not articleName or articleName == "" then
       
        return "Error: Article name is required"
        -- Get parameters (check both direct and parent args)
        local articleName = args.articleName or pargs.articleName or args[1] or pargs[1]
        local templateType = args.templateType or pargs.templateType or args[2] or pargs[2]
       
        -- Validate inputs
        if not articleName or mw.text.trim(tostring(articleName)) == "" then
            ErrorHandling.addError(errorContext, 'TemplateStarter.main', "Article name is required")
            return nil
        end
       
        if not templateType or mw.text.trim(tostring(templateType)) == "" then
            ErrorHandling.addError(errorContext, 'TemplateStarter.main', "Template type is required")
            return nil
        end
       
        return {
            articleName = mw.text.trim(tostring(articleName)),
            templateType = mw.text.trim(tostring(templateType))
        }
     end
     end
      
      
     if not templateType or templateType == "" then
    -- Process arguments with error protection
         return "Error: Template type is required"
    local success, params = ErrorHandling.protect(errorContext, processArgs)
     if not success or not params then
         return "Error: " .. (ErrorHandling.formatOutput(errorContext) or "Invalid parameters")
     end
     end
      
      
     -- Generate the template content
     -- Generate the template content
     local content = p.generateTemplate(templateType)
     local content = p.generateTemplate(params.templateType)
      
      
     -- Check if content is an error
     -- For testing, return the generated content in a pre block
    if content:match("^Error:") then
     return string.format('<pre>Page: %s\n\n%s</pre>',  
        return content
         mw.text.nowiki(params.articleName),  
    end
         mw.text.nowiki(content))
   
    -- Create edit URL (without preload since that doesn't work via URL)
    local editUrl = mw.uri.fullUrl(articleName, {
        action = 'edit',
        summary = 'Creating new ' .. templateType .. ' page'
    })
   
    -- Generate a unique ID for the textarea
    local textareaId = "template-content-" .. mw.hash.hashValue('md5', articleName .. templateType)
   
    -- Return a form with the content and a button
     return string.format(
        '<div class="template-starter-create" style="border: 1px solid #a2a9b1; padding: 15px; margin: 10px 0; background: #f8f9fa;">' ..
        '<h4 style="margin-top: 0;">Create: %s</h4>' ..
        '<p>Template type: <b>%s</b></p>' ..
        '<div style="margin: 10px 0;">' ..
        '<label for="%s" style="display: block; margin-bottom: 5px;"><b>Step 1:</b> Copy this template code:</label>' ..
        '<textarea id="%s" readonly style="width: 100%%; height: 200px; font-family: monospace; font-size: 12px;">%s</textarea>' ..
        '</div>' ..
        '<p><b>Step 2:</b> Click the button below to create the page, then paste the template code:</p>' ..
        '<span class="plainlinks">[%s <span class="mw-ui-button mw-ui-progressive">Create Page "%s"</span>]</span>' ..
        '</div>',
         mw.text.nowiki(articleName),
        templateType,
        textareaId,
        textareaId,
         mw.text.nowiki(content),
        tostring(editUrl),
        mw.text.nowiki(articleName)
    )
end
end


-- Generate a dynamic preload template
-- Generate a dynamic preload template (main function used by JavaScript)
function p.preload(frame)
function p.preload(frame)
     local args = frame.args
     local args = frame.args
     local templateType = args.templateType or args[1]
     local templateType = args.templateType or args[1]
      
      
     if not templateType then
     if not templateType or mw.text.trim(tostring(templateType)) == "" then
         return "<!-- No template type specified -->"
         return "<!-- No template type specified -->"
     end
     end
      
      
     return p.generateTemplate(templateType)
     return p.generateTemplate(mw.text.trim(tostring(templateType)))
end
end


-- Create an InputBox-style form
-- Get list of available templates with caching
function p.createForm(frame)
function p.getAvailableTemplates()
     local args = frame.args
     local currentTime = os.time()
     local templateType = args.templateType or args[1] or "Person"
   
    -- Check if cache is valid
    if templateListCache and (currentTime - templateListCacheTime) < CACHE_DURATION then
        return templateListCache
    end
   
    -- Create error context for template list generation
     local errorContext = ErrorHandling.createContext()
      
      
     -- Generate a unique ID for this form instance
     -- Protected function to get templates
     local formId = "templatestarter-" .. os.time()
     local function getTemplates()
        local templates = {}
       
        if not ConfigRepository.templates then
            ErrorHandling.addError(errorContext, 'TemplateStarter.getAvailableTemplates',
                "ConfigRepository.templates is not available")
            return {}
        end
       
        -- Pre-allocate table for better performance
        local templateCount = 0
        for _ in pairs(ConfigRepository.templates) do
            templateCount = templateCount + 1
        end
       
        local templates = {}
        local index = 1
        for templateName, _ in pairs(ConfigRepository.templates) do
            if templateName and templateName ~= "" then
                templates[index] = templateName
                index = index + 1
            end
        end
       
        table.sort(templates)
        return templates
    end
      
      
     return string.format([[
     -- Get templates with error protection
<div class="template-starter-form">
    local success, templates = ErrorHandling.protect(errorContext, getTemplates)
<inputbox>
    if not success then
type=create
        -- Fallback to basic list if there's an error
default=%s/
        templates = {"Person", "Organization", "Event", "TLD", "Process", "Norm", "LibraryInterview"}
buttonlabel=Create %s Page
placeholder=Enter page name...
width=40
preload=Template:TemplateStarter/%s
editintro=Template:TemplateStarter/EditIntro
</inputbox>
</div>
]], templateType, templateType, templateType)
end
 
-- Get list of available templates
function p.getAvailableTemplates()
    local templates = {}
    for templateName, _ in pairs(ConfigRepository.templates) do
        table.insert(templates, templateName)
     end
     end
     table.sort(templates)
      
    -- Update cache
    templateListCache = templates
    templateListCacheTime = currentTime
   
     return templates
     return templates
end
end
Line 172: Line 206:
function p.listTemplates(frame)
function p.listTemplates(frame)
     local templates = p.getAvailableTemplates()
     local templates = p.getAvailableTemplates()
    if #templates == 0 then
        return "No templates available"
    end
     return "Available templates: " .. table.concat(templates, ", ")
     return "Available templates: " .. table.concat(templates, ", ")
end
end


return p
return p