Module:T-Campaign: Difference between revisions

// via Wikitext Extension for VSCode
Tag: Reverted
// via Wikitext Extension for VSCode
 
(41 intermediate revisions by the same user not shown)
Line 1: Line 1:
-- T-Campaign.lua
-- Module:T-Campaign.lua
-- Generic campaign template that dynamically loads campaign data from JSON files
-- Generic campaign template that dynamically loads campaign data from JSON files
-- Usage: {{#invoke:T-Campaign|render|campaign_name=ASP2025}}
-- Usage: {{#invoke:T-Campaign|render|campaign_name=NAME}}


local p = {}
local p = {}
Line 44: Line 44:


template.config.blocks = template.config.blocks or {}
template.config.blocks = template.config.blocks or {}
-- Helper function: Check for "not applicable" values
local function isNotApplicable(value)
    if not value or type(value) ~= "string" then
        return false
    end
    local lowerVal = value:lower():match("^%s*(.-)%s*$")
    return lowerVal == "n/a" or lowerVal == "na" or lowerVal == "none" or lowerVal == "no" or lowerVal == "false"
end


-- Helper function: Tokenize semicolon-separated strings for instructions
-- Helper function: Tokenize semicolon-separated strings for instructions
Line 89: Line 98:
     -- Use JSON config or fallback to default instruction text
     -- Use JSON config or fallback to default instruction text
     local headerText = (campaignData.instructions and campaignData.instructions.header_text)  
     local headerText = (campaignData.instructions and campaignData.instructions.header_text)  
         or "'''READ CAREFULLY'''. These are temporary instructions that will appear only until all parameters outlined here have been filled. Choose 'Edit source' at any time and edit the code below if it already exists. It can also be added manually to any page:"
         or "'''READ CAREFULLY'''. These are temporary instructions that will appear only until all parameters outlined here have been filled with data or have 'N/A' in them if the field is not applicable. Choose 'Edit source' at any time and edit the code below if it already exists. It can also be added manually to any page:"
      
      
     local parameterIntro = (campaignData.instructions and campaignData.instructions.parameter_intro)
     local parameterIntro = (campaignData.instructions and campaignData.instructions.parameter_intro)
Line 163: Line 172:
         local banner = args._campaign_data.banner
         local banner = args._campaign_data.banner
         local bannerContent = banner.content or ""
         local bannerContent = banner.content or ""
         local cssClass = banner.css_class or "campaign-banner"
         local titleText = template.config.constants.title or "Campaign"
       
        -- Combine generic notice-box class with specific campaign class
        local cssClass = "notice-box"
        if banner.css_class and banner.css_class ~= "" then
            cssClass = cssClass .. " " .. banner.css_class
        end
          
          
         if bannerContent == "" then
         if bannerContent == "" then
Line 170: Line 185:
         end
         end
          
          
         local placeholderValues = {
         -- Use the centralized NoticeFactory to create the notice
            CAMPAIGN_NAME = args._campaign_data.defaults.title or "Campaign"
         local noticeOptions = {
        }
             type = "campaign-js",
       
        bannerContent = WikitextProcessor.processContentForFrontend(bannerContent, placeholderValues, context)
       
         local noticeData = {
             type = "campaign",
             position = "top",
             position = "top",
             content = bannerContent,
             content = bannerContent,
            title = titleText,
             cssClass = cssClass
             cssClass = cssClass
         }
         }
          
          
         local success, result = pcall(function()
         return WikitextProcessor.createNoticeForJS(noticeOptions) .. ErrorHandling.formatCombinedOutput(context)
            return string.format(
                '<div style="display:none" class="notice-data" data-notice-type="%s" data-notice-position="%s" data-notice-content="%s" data-notice-css="%s"></div>',
                mw.text.encode(noticeData.type),
                mw.text.encode(noticeData.position),
                mw.text.encode(noticeData.content),
                mw.text.encode(noticeData.cssClass)
            )
        end)
       
        if success then
            return result .. ErrorHandling.formatCombinedOutput(context)
        else
            ErrorHandling.addError(context, 'campaignBanner', 'Data attribute creation failed', tostring(result), false)
            return ErrorHandling.formatCombinedOutput(context)
        end
     end
     end
}
}
Line 259: Line 255:
-- Generic field processor that handles different data types
-- Generic field processor that handles different data types
local function processFieldValue(value, fieldType)
local function processFieldValue(value, fieldType)
    if isNotApplicable(value) then
        return nil
    end
     if type(value) == "table" then
     if type(value) == "table" then
         if #value > 0 then
         if #value > 0 then
Line 282: Line 282:
         for item in value:gmatch("[^;]+") do
         for item in value:gmatch("[^;]+") do
             local trimmed = item:match("^%s*(.-)%s*$") -- trim whitespace
             local trimmed = item:match("^%s*(.-)%s*$") -- trim whitespace
             if trimmed and trimmed ~= "" then
             if trimmed and trimmed ~= "" and not isNotApplicable(trimmed) then
                 table.insert(items, '<span class="campaign-token">' .. trimmed .. '</span>')
                 table.insert(items, '<span class="campaign-token">' .. trimmed .. '</span>')
             end
             end
Line 289: Line 289:
             return table.concat(items, ' ')
             return table.concat(items, ' ')
         else
         else
             return tostring(value)
             return nil -- Return nil if all items were "not applicable"
         end
         end
     else
     else
Line 369: Line 369:
     -- Always show campaign content fields (they'll show placeholder text when empty)
     -- Always show campaign content fields (they'll show placeholder text when empty)
     for _, fieldDef in ipairs(campaignData.field_definitions) do
     for _, fieldDef in ipairs(campaignData.field_definitions) do
         table.insert(fields, {
         -- CRITICAL: Skip 'title' as it is not a content field
            key = fieldDef.key,
        if fieldDef.key ~= "title" then
            label = fieldDef.label,
            table.insert(fields, {
            type = fieldDef.type
                key = fieldDef.key,
        })
                label = fieldDef.label,
                type = fieldDef.type
            })
        end
     end
     end
      
      
Line 393: Line 396:
     end
     end
      
      
     -- Add campaign-specific category
     -- Add campaign-specific category, defaulting to template_id
     template.config.categories.base = {campaignName}
    local category_value = campaignData.category or campaignData.template_id
     template.config.categories.base = {category_value}
      
      
     return args
     return args