Module:T-CountryHub: Difference between revisions

// via Wikitext Extension for VSCode
Maintenance update // via Wikitext Extension for VSCode
 
(33 intermediate revisions by the same user not shown)
Line 21: Line 21:
local CountryData  = safeRequire('Module:CountryData')
local CountryData  = safeRequire('Module:CountryData')
local TemplateHelpers = safeRequire('Module:TemplateHelpers')
local TemplateHelpers = safeRequire('Module:TemplateHelpers')
local LinkParser = safeRequire('Module:LinkParser')
local NormalizationText = safeRequire('Module:NormalizationText')
local NormalizationText = safeRequire('Module:NormalizationText')
local NormalizationDiacritic = safeRequire('Module:NormalizationDiacritic')
local NormalizationDiacritic = safeRequire('Module:NormalizationDiacritic')
local MasonryLayout = safeRequire('Module:MasonryLayout')
local mw            = mw
local mw            = mw
local html          = mw.html
local html          = mw.html
Line 81: Line 83:
     return renderTable(data, columns)
     return renderTable(data, columns)
end
end
-- -- generateProcessedBrowseLink: Constructs and preprocesses a MediaWiki link for browsing data, with {{fullurl:...}} correctly expanded by MediaWiki before the link is rendered.
-- local function generateProcessedBrowseLink(template, browseType, browseQueryParam, linkTextPattern, country)
--    -- Explicitly URL-encode the country name for use in the URL query parameter
--    local encodedCountry = mw.uri.encode(country, 'QUERY') -- 'QUERY' mode is for query string values
--    local browseLinkString = string.format(
--        '[{{fullurl:Special:BrowseData/%s|%s=%s}} %s →]',
--        browseType,
--        browseQueryParam,
--        encodedCountry,  -- Use the encoded country name for the URL part
--        string.format(linkTextPattern, country) -- Use the original country name for the display text
--    )
   
--    if template.current_frame and template.current_frame.preprocess then
--        local ok, result = pcall(function() return template.current_frame:preprocess(browseLinkString) end)
--        if ok then
--            return result
--        else
--            return browseLinkString -- Fallback on preprocess error
--        end
--    end
--    return browseLinkString -- Fallback if no frame or preprocess
-- end


local errorContext = ErrorHandling.createContext("T-CountryHub")
local errorContext = ErrorHandling.createContext("T-CountryHub")
Line 122: Line 100:
         organizations = true,
         organizations = true,
         people = true,
         people = true,
         laws = false,
         laws = true,
         documents = false,
         documents = false,
         geoTlds = true,
         geoTlds = true,
Line 143: Line 121:
template.config.blockSequence = {
template.config.blockSequence = {
     'wrapperOpen',
     'wrapperOpen',
     'infoBox',
     'featureBanner',
    'intro',
     'overview',
     'overview',
     'dataColumns',
     'intelligentMasonry',
     'wrapperClose',
     'wrapperClose',
     'categories',
     'categories',
     'errors'
     'errors'
}
-- MASONRY LAYOUT CONFIGURATION
local cardDefinitions = {
    {blockId = 'intro', feature = 'intro', title = 'Welcome'},
    {blockId = 'organizations', feature = 'organizations', title = 'Organizations'},
    {blockId = 'people', feature = 'people', title = 'People'},
    {blockId = 'geoTlds', feature = 'geoTlds', title = 'GeoTLDs'},
    {blockId = 'meetings', feature = 'meetings', title = 'Internet Governance Events'},
    {blockId = 'nra', feature = 'nra', title = 'National Authorities'},
    {blockId = 'laws', feature = 'laws', title = 'Laws and Regulations'},
    {blockId = 'documents', feature = 'documents', title = 'Key Documents'},
    {blockId = 'resources', feature = 'resources', title = 'Resources'},
    {blockId = 'infoBox', feature = 'infoBox', title = 'Country Info'}
}
local masonryOptions = {
    columns = 3,
    mobileColumns = 1,
    containerClass = 'country-hub-masonry-container',
    columnClass = 'country-hub-masonry-column',
    cardClass = 'country-hub-masonry-card',
    -- Note: We cannot detect mobile server-side in MediaWiki
    -- The MasonryLayout will output both desktop and mobile HTML
    -- CSS media queries will handle the actual display
    mobileMode = false -- Always use desktop mode in Lua, CSS handles responsive
}
}


Line 176: Line 179:
          
          
         return '<div class="country-hub-wrapper">' -- .. flagImageWikitext -- Appended flag
         return '<div class="country-hub-wrapper">' -- .. flagImageWikitext -- Appended flag
    end
}
-- Feature Preview Banner
template.config.blocks.featureBanner = {
    feature = 'fullPage',
    render = function(template, args)
        return '<div class="country-hub-feature-banner">' ..
              '<strong>Country Hubs</strong> have been enabled as a feature preview and are still under testing.' ..
              ' Contribute more knowledge to our database so that they can keep growing!' ..
              '</div>'
     end
     end
}
}
Line 204: Line 218:
         local regionData = askCached('infoBox:region:' .. args.has_country, regionParams)
         local regionData = askCached('infoBox:region:' .. args.has_country, regionParams)
         local regionText = regionData[1] and regionData[1]['Has ICANN region'] or ''
         local regionText = regionData[1] and regionData[1]['Has ICANN region'] or ''
         regionText = NormalizationText.processWikiLink(regionText, 'strip')
         regionText = LinkParser.processWikiLink(regionText, 'strip')
          
          
         -- Check for an ISOC chapter in the country using fuzzy matching
         -- Check for an ISOC chapter in the country using fuzzy matching
Line 257: Line 271:
         if not foundMatch then
         if not foundMatch then
             ISOCText = string.format('[[Internet Society %s Chapter]]', args.has_country)
             ISOCText = string.format('[[Internet Society %s Chapter]]', args.has_country)
        end
       
        -- Check for a Youth IGF initiative in the country
        local youthParams = {
            string.format('[[Category:Youth IGF %s]]', args.has_country),
            limit = 1
        }
        local youthData = askCached('infoBox:youth:' .. args.has_country, youthParams)
        local youthText
        if youthData[1] and youthData[1]['result'] and youthData[1]['result'] ~= '' then
            youthText = youthData[1]['result']
        else
            youthText = string.format('[[Youth IGF %s]]', args.has_country)
         end
         end
          
          
Line 318: Line 319:
             :tag('th'):wikitext('ISOC chapter'):done()
             :tag('th'):wikitext('ISOC chapter'):done()
             :tag('td'):wikitext(ISOCText):done()
             :tag('td'):wikitext(ISOCText):done()
            :done()
       
        -- Youth IGF row
        infoBox:tag('tr')
            :tag('th'):wikitext('Youth IGF'):done()
            :tag('td'):wikitext(youthText):done()
             :done()
             :done()
          
          
Line 372: Line 367:
         local params = {
         local params = {
             string.format('[[Has country::%s]] [[Has entity type::Organization]]', args.has_country),
             string.format('[[Has country::%s]] [[Has entity type::Organization]]', args.has_country),
             limit    = 50
             limit    = 20
         }
         }
         local data = askCached('organizations:' .. args.has_country, params)
         local data = askCached('organizations:' .. args.has_country, params)
        -- Store the raw count for masonry layout
        template._rawDataCounts = template._rawDataCounts or {}
        template._rawDataCounts.organizations = #data
        -- Only render if we have data
        if #data == 0 then
            return ''
        end
         return renderTable(data, {'Organizations'})
         return renderTable(data, {'Organizations'})
     end
     end
Line 389: Line 391:
         }
         }
         local data = askCached('people:' .. args.has_country, params)
         local data = askCached('people:' .. args.has_country, params)
        -- Store the raw count for masonry layout
        template._rawDataCounts = template._rawDataCounts or {}
        template._rawDataCounts.people = #data
        -- Only render if we have data
        if #data == 0 then
            return ''
        end
         return renderTable(data, {'People'})
         return renderTable(data, {'People'})
     end,
     end,
Line 398: Line 407:
     render = function(template, args)
     render = function(template, args)
         local params = {
         local params = {
             string.format('[[Has country::%s]]', args.has_country),
             string.format('[[Has country::%s]] [[Has entity type::Norm]]', args.has_country),
            '[[Category:Laws]]',
             limit    = 20
            mainlabel = 'Law', sort = 'Has date', order = 'desc',
             limit    = 50
         }
         }
         return renderSection('laws:' .. args.has_country, params, {'Laws and Regulations'})
         local data = askCached('laws:' .. args.has_country, params)
        -- Store the raw count for masonry layout
        template._rawDataCounts = template._rawDataCounts or {}
        template._rawDataCounts.laws = #data
        -- Only render if we have data
        if #data == 0 then
            return ''
        end
        return renderTable(data, {'Laws and Regulations'})
     end,
     end,
}
}
Line 415: Line 430:
             '[[Category:Document]]',
             '[[Category:Document]]',
             mainlabel = 'Document', sort = 'Has date', order = 'desc',
             mainlabel = 'Document', sort = 'Has date', order = 'desc',
             limit    = 50
             limit    = 20
         }
         }
         return renderSection('documents:' .. args.has_country, params, {'Key Documents'})
         return renderSection('documents:' .. args.has_country, params, {'Key Documents'})
Line 427: Line 442:
         local params = {
         local params = {
             string.format('[[Has country::%s]] [[Has entity type::TLD]] [[Has TLD subtype::geoTLD]]', args.has_country),
             string.format('[[Has country::%s]] [[Has entity type::TLD]] [[Has TLD subtype::geoTLD]]', args.has_country),
             limit    = 50
             limit    = 20
         }
         }
         return renderSection('geoTlds:' .. args.has_country, params, {'GeoTLDs'})
         local data = askCached('geoTlds:' .. args.has_country, params)
        -- Store the raw count for masonry layout
        template._rawDataCounts = template._rawDataCounts or {}
        template._rawDataCounts.geoTlds = #data
        -- Only render if we have data
        if #data == 0 then
            return ''
        end
        return renderTable(data, {'GeoTLDs'})
     end,
     end,
}
}
Line 440: Line 463:
             string.format('[[Has country::%s]]', args.has_country),  
             string.format('[[Has country::%s]]', args.has_country),  
             '[[Has entity type::Event]]',  
             '[[Has entity type::Event]]',  
             limit    = 50
             limit    = 20
         }
         }
         return renderSection('events:' .. args.has_country, params, {'Internet Governance Events'})
         local data = askCached('events:' .. args.has_country, params)
        -- Store the raw count for masonry layout
        template._rawDataCounts = template._rawDataCounts or {}
        template._rawDataCounts.meetings = #data
        -- Only render if we have data
        if #data == 0 then
            return ''
        end
        return renderTable(data, {'Internet Governance Events'})
     end,
     end,
}
}
Line 452: Line 483:
         local params = {
         local params = {
             string.format('[[Has country::%s]] [[Has entity type::Organization]] [[Has organization type::Government agency]]', args.has_country),
             string.format('[[Has country::%s]] [[Has entity type::Organization]] [[Has organization type::Government agency]]', args.has_country),
             limit    = 10
             limit    = 20
         }
         }
         return renderSection('nra:' .. args.has_country, params, {'National Authorities'})
         local data = askCached('nra:' .. args.has_country, params)
        -- Store the raw count for masonry layout
        template._rawDataCounts = template._rawDataCounts or {}
        template._rawDataCounts.nra = #data
        -- Only render if we have data
        if #data == 0 then
            return ''
        end
        return renderTable(data, {'National Authorities'})
     end,
     end,
}
}


-- -- REVIEW: CONNECTED COUNTRIES
-- -- REVIEW: CONNECTED COUNTRIES (COLONIES)


-- ANCHOR: RESOURCES
-- ANCHOR: RESOURCES
Line 468: Line 507:
             '[[Category:Resource]]',
             '[[Category:Resource]]',
             mainlabel = 'Resource',
             mainlabel = 'Resource',
             limit    = 10
             limit    = 20
         }
         }
         return renderSection('resources:' .. args.has_country, params, {'Resources'})
         return renderSection('resources:' .. args.has_country, params, {'Resources'})
Line 474: Line 513:
}
}


-- Data columns "super block"
-- Data wrapper blocks
template.config.blocks.dataColumns = {
template.config.blocks.dataWrapperOpen = {
    feature = 'fullPage',
    render  = function() return '<div class="country-hub-data-container">' end
}
template.config.blocks.dataWrapperClose = {
     feature = 'fullPage',
     feature = 'fullPage',
     render = function(template, args)
     render = function() return '</div>' end
        local dataBlocks = {}
        local dataBlockNames = {
            'organizations', 'people', 'laws', 'documents',
            'geoTlds', 'meetings', 'nra', 'resources'
        }
 
        for _, blockName in ipairs(dataBlockNames) do
            -- We need to check if the feature for the block is enabled before rendering
            if template.features[blockName] then
                local blockContent = template:renderBlock(blockName, args)
                if blockContent and blockContent ~= '' then
                    table.insert(dataBlocks, blockContent)
                end
            end
        end
 
        if #dataBlocks == 0 then
            return ''
        end
 
        local columns = {'', '', ''}
        for i, blockContent in ipairs(dataBlocks) do
            local colIndex = (i - 1) % 3 + 1
            columns[colIndex] = columns[colIndex] .. blockContent
        end
 
        local dataContainer = html.create('div'):addClass('country-hub-data-container')
        for _, colContent in ipairs(columns) do
            if colContent ~= '' then
                dataContainer:tag('div'):addClass('country-hub-column'):wikitext(colContent):done()
            end
        end
       
        return tostring(dataContainer)
    end
}
}


Line 519: Line 527:
     feature = 'countryWrapper',
     feature = 'countryWrapper',
     render  = function() return '</div>' end
     render  = function() return '</div>' end
}
-- INTELLIGENT MASONRY LAYOUT INTEGRATION
-- Single block that handles all masonry logic at render-time (Blueprint pattern)
template.config.blocks.intelligentMasonry = {
    feature = 'fullPage',
    render = function(template, args)
        return MasonryLayout.renderIntelligentLayout(template, args, {
            cardDefinitions = cardDefinitions,
            options = masonryOptions,
            blockRenderers = {
                intro = template.config.blocks.intro,
                organizations = template.config.blocks.organizations,
                people = template.config.blocks.people,
                geoTlds = template.config.blocks.geoTlds,
                meetings = template.config.blocks.meetings,
                nra = template.config.blocks.nra,
                laws = template.config.blocks.laws,
                documents = template.config.blocks.documents,
                resources = template.config.blocks.resources,
                infoBox = template.config.blocks.infoBox
            }
        })
    end
}
}


Line 553: Line 585:
     return ErrorHandling.protect(
     return ErrorHandling.protect(
         errorContext, "render",
         errorContext, "render",
         function() return template:render(frame) end,
         function() return template.render(frame) end,
         ErrorHandling.getMessage("TEMPLATE_RENDER_ERROR"),
         ErrorHandling.getMessage("TEMPLATE_RENDER_ERROR"),
         frame
         frame