Jump to content

Module:T-Person: Difference between revisions

// via Wikitext Extension for VSCode
 
// via Wikitext Extension for VSCode
 
(42 intermediate revisions by the same user not shown)
Line 1: Line 1:
-- Module:T-Person
-- Module:T-Person
-- Blueprint migration of Person template (Phase 1)
-- Makes use of ICANNWiki's "Template Blueprint Framework" to render the "Person" template


local p = {}
local p = {}


-- ==================== Required modules ====================
-- ==================== Required modules ====================
local Blueprint       = require('Module:LuaTemplateBlueprint')
local Blueprint = require('Module:LuaTemplateBlueprint')
local TemplateHelpers  = require('Module:TemplateHelpers')
local ErrorHandling = require('Module:ErrorHandling')
local ErrorHandling   = require('Module:ErrorHandling')
local LinkParser = require('Module:LinkParser')
local ConfigRepository = require('Module:ConfigRepository')
local Achievements = require('Module:AchievementSystem')
local LinkParser       = require('Module:LinkParser')
 
-- Blueprint default: Module-level cache for lazy-loaded modules
local moduleCache = {}
 
-- Blueprint default: Lazy module loader
local function lazyRequire(moduleName)
    return function()
        if not moduleCache[moduleName] then
            moduleCache[moduleName] = require(moduleName)
        end
        return moduleCache[moduleName]
    end
end
 
-- Blueprint default: Modules to lazy load
local CanonicalForms            = lazyRequire('Module:CanonicalForms')
local CountryData              = lazyRequire('Module:CountryData')
local SemanticCategoryHelpers  = lazyRequire('Module:SemanticCategoryHelpers')
local LanguageNormalization    = lazyRequire('Module:NormalizationLanguage')
local socialFooter              = lazyRequire('Module:SocialMedia')
local Achievements              = lazyRequire('Module:AchievementSystem')


-- ==================== Helper Functions ====================
-- ==================== Helper Functions ====================
local errorContext = ErrorHandling.createContext('T-Person')
-- Blueprint default: Create error context for the module
 
local errorContext = ErrorHandling.createContext("T-Person")
local function extractSemanticValue(fieldValue, fieldName)
    return TemplateHelpers.extractSemanticValue(fieldValue, fieldName, errorContext)
end


-- ================================================================================
-- ================================================================================


-- IMPORTANT! TEMPLATE BLUEPRINT FRAMEWORK INSTRUCTIONS
-- IMPORTANT! TEMPLATE BLUEPRINT FRAMEWORK INSTRUCTIONS
-- CONTROL OF TEMPLATE FEATURES: THIS LIST SPECIFIES IN AN EXPLICIT MANNER WHAT FEATURES ARE TO BE CALLED/RENDERED BY THE TEMPLATE.
local template = Blueprint.registerTemplate('Person', {
local template = Blueprint.registerTemplate('Person', {
     features = {
     features = {
         title             = true,
         title = true,
         logo               = false,
        achievementHeader = true,
         fields             = true,
        portraitCarousel = true,
         socialMedia       = true,
         logo = true,
         fields = true,
        achievementBadges = true,
         socialMedia = true,
         semanticProperties = true,
         semanticProperties = true,
         categories         = true,
         categories = true,
         errorReporting     = true,
         errorReporting = true,
     }
     }
})
})
Line 57: Line 36:
Blueprint.initializeConfig(template)
Blueprint.initializeConfig(template)


-- CONTROL THE VISUAL ORDER OF BLOCKS
-- CONTROL THE VISUAL ORDER THAT EACH ASPECT IS RENDERED IN
template.config.blockSequence = {
template.config.blockSequence = {
     'title',
     'title',
     'achievementHeader',
     'achievementHeader',
     'portraitCarousel',
     'portraitCarousel',
    'logo',
     'fields',
     'fields',
    'achievementsSectionHeader',
     'achievementBadges',
     'achievementBadges',
     'socialMedia'
     'socialMedia',
    'semanticProperties',
    'categories',
    'errors'
}
}


-- ================================================================================
-- ================================================================================


-- Block: Title
-- TEMPLATE-SPECIFIC CALLS AND CODE
local function renderTitleBlock(args, frame)
 
     local pageId = mw.title.getCurrentTitle().id
-- BLOCK: ACHIEVEMENTS SECTION HEADER
     local cls, name = Achievements().getTitleClass(pageId, frame)
local function renderAchievementsHeader(template, args)
    local aid = ''
    -- Get the current page ID from the arguments pre-filled by the 'setPageIdField' preprocessor
    if cls and cls ~= '' then
     local pageId = args.ID
         aid = cls:gsub('^achievement%-', '')
     if not pageId or pageId == '' then
         return ''
     end
     end
    return TemplateHelpers.renderTitleBlock(
        args,
        'template-title template-title-person person-template',
        'Person',
        {
            achievementSupport = true,
            achievementClass  = cls or '',
            achievementId      = aid,
            achievementName    = name or ''
        }
    )
end


-- Block: Achievement header
    -- Get badge achievements using the centralized function
local function renderAchievementHeaderBlock(args, frame)
     local badgeAchievements = Achievements.getBadgeAchievements(pageId, template.current_frame)
     local pageId = mw.title.getCurrentTitle().id
 
    local css, display, aid = Achievements().getTitleAchievement(pageId, frame)
     -- Only render the header if there are badges to display
     if css ~= '' and display ~= '' and aid ~= '' then
    if #badgeAchievements > 0 then
         return string.format(
        local TemplateStructure = require('Module:TemplateStructure')
            '|-\n! colspan="2" class="achievement-header %s" data-achievement-id="%s" data-achievement-name="%s" | %s',
         return TemplateStructure.renderDividerBlock("Achievements")
            aid, aid, display, display
        )
     end
     end
     return ''
     return ''
end
end
template.config.blocks = template.config.blocks or {}
template.config.blocks.achievementsSectionHeader = {
    render = function(template, args)
        return renderAchievementsHeader(template, args)
    end
}


-- Block: Portrait carousel
-- ELEMENT: ACHIEVEMENT HEADER
local function renderPortraitCarousel(args)
if template.features.achievementHeader then
     if not args.portrait or args.portrait == '' then
    local ElementAchievementHeader = ErrorHandling.safeRequire(errorContext,
         return ''
        'Module:ElementAchievementHeader', false)
     if ElementAchievementHeader then
        Blueprint.registerElement(ElementAchievementHeader.elementName, ElementAchievementHeader)
         Blueprint.addElementToTemplate(template, 'achievementHeader')
     end
     end
     local images = SemanticCategoryHelpers().splitMultiValueString(
end
         args.portrait,
 
        SemanticCategoryHelpers().SEMICOLON_PATTERN
-- ELEMENT: ACHIEVEMENT BADGES
    )
if template.features.achievementBadges then
     if #images == 0 then
     local ElementAchievementBadges = ErrorHandling.safeRequire(errorContext,
         return ''
         'Module:ElementAchievementBadges', false)
    elseif #images == 1 then
     if ElementAchievementBadges then
         return string.format(
         Blueprint.registerElement(ElementAchievementBadges.elementName, ElementAchievementBadges)
            '|-\n| colspan="2" class="person-portrait" | [[Image:%s|220px|center]]',
         Blueprint.addElementToTemplate(template, 'achievementBadges')
            images[1]
        )
     end
     end
    local out = '|-\n| colspan="2" class="person-portrait-carousel" |'
    out = out .. '<div class="carousel-container">'
    out = out .. '<div class="carousel-nav carousel-prev">&#9664;</div>'
    out = out .. '<div class="carousel-images">'
    for i, img in ipairs(images) do
        local vis  = (i == 1) and 'carousel-visible' or 'carousel-hidden'
        local pos  = ''
        if #images == 2 then
            pos = (i == 1) and 'carousel-orbital-1' or 'carousel-orbital-2'
        else
            if i == 2 then pos = 'carousel-right' end
            if i == #images then pos = 'carousel-left' end
        end
        out = out .. string.format(
            '<div class="carousel-item %s %s" data-index="%d">[[Image:%s|220px|center]]</div>',
            vis, pos, i, img
        )
    end
    out = out .. '</div>'
    out = out .. '<div class="carousel-nav carousel-next">&#9654;</div>'
    out = out .. '</div>'
    return out
end
end


-- Block: Fields
-- ELEMENT: PORTRAIT CAROUSEL
local function renderFieldsBlock(args, frame)
if template.features.portraitCarousel then
    local processors = {
    local ElementPortraitCarousel = ErrorHandling.safeRequire(errorContext,  
        community = function(val)
         'Module:ElementPortraitCarousel', false)
            return select(1, CanonicalForms().normalize(val, template.config.mappings.community)) or val
    if ElementPortraitCarousel then
        end,
        Blueprint.registerElement(ElementPortraitCarousel.elementName, ElementPortraitCarousel)
        languages = function(val)
       
            return LanguageNormalization().formatLanguages(val)
         -- Add the element with a custom wrapper that creates a separate table row
        end,
         Blueprint.addElementToTemplate(template, 'portraitCarousel', {
         country  = TemplateHelpers.normalizeCountries,
             wrapperTemplate = '|-\n| colspan="2" class="person-portrait-row" |%s'
        website  = TemplateHelpers.normalizeWebsites,
         })
        soi      = function(val)
     end
            local formatted = string.format('[%s Here]', val)
            return {
                isCompleteHtml = true,
                html          = string.format(TemplateHelpers.FIELD_FORMAT, 'SOI', formatted)
            }
         end,
         userbox  = function(val)
            local pid = mw.title.getCurrentTitle().id
            local ok, box = pcall(function()
                return Achievements().renderAchievementBox(pid, frame)
            end)
             if ok and box and box ~= '' then
                return box
            end
            return val
         end
    }
     return TemplateHelpers.renderFieldsBlock(args, template.config.fields, processors)
end
end


-- Block: Achievement badges
-- PROCESSORS
local function renderAchievementBadgesBlock(args, frame)
template.config.processors = {
    local pid = mw.title.getCurrentTitle().id
     -- SOI field processor
    local ok, achmod = pcall(Achievements)
     soi = function(value)
     local parts = { '|-\n| colspan="2" |' }
         if value and value ~= "" then
    if not ok then
             return string.format("[%s Here]", value)
        table.insert(parts, '<div class="achievement-badges"></div>')
        return table.concat(parts)
     end
    local types = achmod.loadTypes(frame)
    local defs  = {}
    for _, t in ipairs(types) do defs[t.id] = t end
    local badges = {}
    for _, a in ipairs(achmod.getUserAchievements(pid)) do
        local td = defs[a.type]
         if td and td.type == 'badge' then
             table.insert(badges, { id = a.type, name = td.name or a.type })
         end
         end
    end
        return value
     if #badges > 0 then
     end,
        table.insert(parts, '<div class="achievement-badges">')
      
        for _, b in ipairs(badges) do
}
            table.insert(parts, string.format(
                '<div class="achievement-badge %s" data-achievement-id="%s" data-achievement-name="%s" title="%s"></div>',
                b.id, b.id, b.name, b.name
            ))
        end
        table.insert(parts, '</div>')
    else
        table.insert(parts, '<div class="achievement-badges"></div>')
    end
     return table.concat(parts)
end


-- Register blocks with Blueprint
-- ================================================================================
Blueprint.addBlock(template, 'title', renderTitleBlock)
Blueprint.addBlock(template, 'achievementHeader', renderAchievementHeaderBlock)
Blueprint.addBlock(template, 'portraitCarousel', renderPortraitCarousel)
Blueprint.addBlock(template, 'fields', renderFieldsBlock)
Blueprint.addBlock(template, 'achievementBadges', renderAchievementBadgesBlock)
Blueprint.addBlock(template, 'socialMedia', socialFooter().render)


-- ==================== Preprocessors ====================
-- ==================== Preprocessors ====================
Blueprint.addPreprocessor(template, 'setPageIdField')
-- Basic preprocessors
Blueprint.addPreprocessor(template, 'setPageIdField')  -- Blueprint default
Blueprint.addPreprocessor(template, 'deriveRegionFromCountry')


-- ==================== Main Render Function ====================
-- ==================== Main Render Function ====================
-- Blueprint default: Render
function p.render(frame)
function p.render(frame)
     return ErrorHandling.protect(
     return ErrorHandling.protect(
         errorContext,
         errorContext,
         'render',
         "render",
         function()
         function()
             return template.render(frame)
             return template.render(frame)
         end,
         end,
         ErrorHandling.getMessage('TEMPLATE_RENDER_ERROR'),
         ErrorHandling.getMessage("TEMPLATE_RENDER_ERROR"),
         frame
         frame
     )
     )

Latest revision as of 18:56, 8 July 2025

Documentation for this module may be created at Module:T-Person/doc

-- Module:T-Person
-- Makes use of ICANNWiki's "Template Blueprint Framework" to render the "Person" template

local p = {}

-- ==================== Required modules ====================
local Blueprint = require('Module:LuaTemplateBlueprint')
local ErrorHandling = require('Module:ErrorHandling')
local LinkParser = require('Module:LinkParser')
local Achievements = require('Module:AchievementSystem')

-- ==================== Helper Functions ====================
-- Blueprint default: Create error context for the module
local errorContext = ErrorHandling.createContext("T-Person")

-- ================================================================================

-- IMPORTANT! TEMPLATE BLUEPRINT FRAMEWORK INSTRUCTIONS
-- CONTROL OF TEMPLATE FEATURES: THIS LIST SPECIFIES IN AN EXPLICIT MANNER WHAT FEATURES ARE TO BE CALLED/RENDERED BY THE TEMPLATE.
local template = Blueprint.registerTemplate('Person', {
    features = {
        title = true,
        achievementHeader = true,
        portraitCarousel = true,
        logo = true,
        fields = true,
        achievementBadges = true,
        socialMedia = true,
        semanticProperties = true,
        categories = true,
        errorReporting = true,
    }
})

-- Blueprint default: Initialize standard configuration
Blueprint.initializeConfig(template)

-- CONTROL THE VISUAL ORDER THAT EACH ASPECT IS RENDERED IN
template.config.blockSequence = {
    'title',
    'achievementHeader',
    'portraitCarousel',
    'logo',
    'fields',
    'achievementsSectionHeader',
    'achievementBadges',
    'socialMedia',
    'semanticProperties',
    'categories',
    'errors'
}

-- ================================================================================

-- TEMPLATE-SPECIFIC CALLS AND CODE

-- BLOCK: ACHIEVEMENTS SECTION HEADER
local function renderAchievementsHeader(template, args)
    -- Get the current page ID from the arguments pre-filled by the 'setPageIdField' preprocessor
    local pageId = args.ID
    if not pageId or pageId == '' then
        return ''
    end

    -- Get badge achievements using the centralized function
    local badgeAchievements = Achievements.getBadgeAchievements(pageId, template.current_frame)

    -- Only render the header if there are badges to display
    if #badgeAchievements > 0 then
        local TemplateStructure = require('Module:TemplateStructure')
        return TemplateStructure.renderDividerBlock("Achievements")
    end

    return ''
end
template.config.blocks = template.config.blocks or {}
template.config.blocks.achievementsSectionHeader = {
    render = function(template, args)
        return renderAchievementsHeader(template, args)
    end
}

-- ELEMENT: ACHIEVEMENT HEADER
if template.features.achievementHeader then
    local ElementAchievementHeader = ErrorHandling.safeRequire(errorContext, 
        'Module:ElementAchievementHeader', false)
    if ElementAchievementHeader then
        Blueprint.registerElement(ElementAchievementHeader.elementName, ElementAchievementHeader)
        Blueprint.addElementToTemplate(template, 'achievementHeader')
    end
end

-- ELEMENT: ACHIEVEMENT BADGES
if template.features.achievementBadges then
    local ElementAchievementBadges = ErrorHandling.safeRequire(errorContext, 
        'Module:ElementAchievementBadges', false)
    if ElementAchievementBadges then
        Blueprint.registerElement(ElementAchievementBadges.elementName, ElementAchievementBadges)
        Blueprint.addElementToTemplate(template, 'achievementBadges')
    end
end

-- ELEMENT: PORTRAIT CAROUSEL
if template.features.portraitCarousel then
    local ElementPortraitCarousel = ErrorHandling.safeRequire(errorContext, 
        'Module:ElementPortraitCarousel', false)
    if ElementPortraitCarousel then
        Blueprint.registerElement(ElementPortraitCarousel.elementName, ElementPortraitCarousel)
        
        -- Add the element with a custom wrapper that creates a separate table row
        Blueprint.addElementToTemplate(template, 'portraitCarousel', {
            wrapperTemplate = '|-\n| colspan="2" class="person-portrait-row" |%s'
        })
    end
end

-- PROCESSORS
template.config.processors = {
    -- SOI field processor
    soi = function(value)
        if value and value ~= "" then
            return string.format("[%s Here]", value)
        end
        return value
    end,
    
}

-- ================================================================================

-- ==================== Preprocessors ====================
-- Basic preprocessors
Blueprint.addPreprocessor(template, 'setPageIdField')  -- Blueprint default
Blueprint.addPreprocessor(template, 'deriveRegionFromCountry')

-- ==================== Main Render Function ====================
-- Blueprint default: Render
function p.render(frame)
    return ErrorHandling.protect(
        errorContext,
        "render",
        function()
            return template.render(frame)
        end,
        ErrorHandling.getMessage("TEMPLATE_RENDER_ERROR"),
        frame
    )
end

return p