Module:TemplateHelpers: Difference between revisions
Appearance
// via Wikitext Extension for VSCode Tag: Reverted |
// via Wikitext Extension for VSCode Tag: Reverted |
||
| Line 257: | Line 257: | ||
description = "Template module" | description = "Template module" | ||
} | } | ||
-- Handle mappings | |||
config.mappings = config.mappings or {} | config.mappings = config.mappings or {} | ||
-- For backward compatibility, copy mappings to top-level | |||
if config.mappings.type then | |||
config.typeMapping = config.mappings.type | |||
end | |||
if config.mappings.subtype then | |||
config.subtypeMapping = config.mappings.subtype | |||
end | |||
if config.mappings.community then | |||
config.communityMapping = config.mappings.community | |||
end | |||
config.fields = config.fields or {} | config.fields = config.fields or {} | ||
config.semantics = config.semantics or { | config.semantics = config.semantics or { | ||
Revision as of 00:20, 6 April 2025
Documentation for this module may be created at Module:TemplateHelpers/doc
-- Module:TemplateHelpers
-- Common helper functions for template modules to promote code reuse and consistency. This module provides utilities for string processing, field handling, normalization, and standardized block rendering to be used across multiple template types.
local p = {}
-- Dependencies
local linkParser = require('Module:LinkParser')
local MultiCountryDisplay = require('Module:MultiCountryDisplay')
local dateNormalization = require('Module:DateNormalization')
local CanonicalForms = require('Module:CanonicalForms')
--------------------------------------------------------------------------------
-- String Processing Functions
--------------------------------------------------------------------------------
-- Trims leading and trailing whitespace from a string
function p.trim(s)
return (s:gsub("^%s+", ""):gsub("%s+$", ""))
end
-- Splits a semicolon-delimited string into a table of trimmed non-empty values
function p.splitSemicolonValues(value)
if not value or value == "" then return {} end
local items = {}
for item in string.gmatch(value, "[^;]+") do
local trimmed = item:match("^%s*(.-)%s*$")
if trimmed and trimmed ~= "" then
table.insert(items, trimmed)
end
end
return items
end
-- Joins a table of values with the specified delimiter
function p.joinValues(values, delimiter)
delimiter = delimiter or "; "
if not values or #values == 0 then return "" end
return table.concat(values, delimiter)
end
--------------------------------------------------------------------------------
-- Field Processing Functions
--------------------------------------------------------------------------------
-- Retrieves a field value from args using either multiple possible keys or a single key
function p.getFieldValue(args, field)
if field.keys then
for _, key in ipairs(field.keys) do
if args[key] and args[key] ~= "" then
return key, args[key]
end
end
return nil, nil
end
return field.key, (args[field.key] and args[field.key] ~= "") and args[field.key] or nil
end
-- Processes multiple values with a given processor function
function p.processMultipleValues(values, processor)
if not values or values == "" then return {} end
local items = p.splitSemicolonValues(values)
local results = {}
for _, item in ipairs(items) do
local processed = processor(item)
if processed and processed ~= "" then
table.insert(results, processed)
end
end
return results
end
--------------------------------------------------------------------------------
-- Normalization Wrappers
--------------------------------------------------------------------------------
-- Formats website URLs as either a single link or an HTML unordered list of links
function p.normalizeWebsites(value)
if not value or value == "" then return "" end
local websites = p.splitSemicolonValues(value)
if #websites > 1 then
local listItems = {}
for _, site in ipairs(websites) do
local formattedLink = string.format("[%s %s]", site, linkParser.strip(site))
table.insert(listItems, string.format("<li>%s</li>", formattedLink))
end
return string.format("<ul class=\"template-list template-list-website\" style=\"margin:0; padding-left:1em;\">%s</ul>", table.concat(listItems, ""))
elseif #websites == 1 then
return string.format("[%s %s]", websites[1], linkParser.strip(websites[1]))
end
return ""
end
-- Wrapper around MultiCountryDisplay for consistent country formatting
function p.normalizeCountries(value)
if not value or value == "" then return "" end
return MultiCountryDisplay.formatCountries(value)
end
-- Wrapper around DateNormalization for consistent date formatting
function p.normalizeDates(value)
if not value or value == "" then return "" end
return tostring(dateNormalization.formatDate(value))
end
--------------------------------------------------------------------------------
-- Block Generation Helpers
--------------------------------------------------------------------------------
-- Generates a standard title block with configurable class and text
function p.renderTitleBlock(args, titleClass, titleText)
titleClass = titleClass or "template-title"
return string.format('|-\n! colspan="2" class="%s" | %s', titleClass, titleText)
end
-- Renders a standard fields block based on field definitions and processors
function p.renderFieldsBlock(args, fields, processors)
processors = processors or {}
local out = {}
for _, field in ipairs(fields) do
local key, value = p.getFieldValue(args, field)
if value then
-- Apply processor if available for this field
if key and processors[key] and type(processors[key]) == "function" then
value = processors[key](value, args)
end
-- Skip insertion if processor returned nil or false
if value ~= nil and value ~= false then
table.insert(out, string.format("|-\n| '''%s''':\n| %s", field.label, value))
end
end
end
return table.concat(out, "\n")
end
-- Renders a standard divider block with optional label
function p.renderDividerBlock(label)
if label and label ~= "" then
return string.format('|-\n| colspan="2" class="template-divider" |\n|-\n| colspan="2" class="icannwiki-centered" | <span class="icannwiki-bold">%s</span>', label)
else
return '|-\n| colspan="2" class="template-divider" |'
end
end
--------------------------------------------------------------------------------
-- Category Utilities
--------------------------------------------------------------------------------
-- Builds a category string from a table of category names
function p.buildCategories(categories)
if not categories or #categories == 0 then return "" end
local formatted = {}
for _, cat in ipairs(categories) do
-- Check if the category already has the [[ ]] wrapper
if not string.match(cat, "^%[%[Category:") then
table.insert(formatted, string.format("[[Category:%s]]", cat))
else
table.insert(formatted, cat)
end
end
return table.concat(formatted, "\n")
end
-- Adds categories based on a canonical mapping
function p.addMappingCategories(value, mapping)
if not value or value == "" or not mapping then return {} end
local categories = {}
local canonical = select(1, CanonicalForms.normalize(value, mapping))
if canonical then
for _, group in ipairs(mapping) do
if group.canonical == canonical and group.category then
table.insert(categories, group.category)
break
end
end
end
return categories
end
--------------------------------------------------------------------------------
-- Semantic Property Utilities
--------------------------------------------------------------------------------
-- Generates semantic properties based on a configuration and arguments
function p.generateSemanticProperties(args, semanticConfig)
if not semanticConfig or not semanticConfig.properties then
return ""
end
local output = ""
-- Process basic property mappings
for property, fieldKey in pairs(semanticConfig.properties) do
if args[fieldKey] and args[fieldKey] ~= "" then
local value = args[fieldKey]
-- Apply transformation if available
if semanticConfig.transforms and semanticConfig.transforms[property] then
value = semanticConfig.transforms[property](value)
end
-- Add the property
if mw.smw then
local propSet = {}
propSet[property] = value
mw.smw.set(propSet)
else
output = output .. "\n" ..
'<div style="display:none;">\n {{#set: ' .. property .. '=' ..
value .. ' }}\n</div>'
end
end
end
-- Process multi-value properties if configured
if semanticConfig.multiValueProperties then
for property, config in pairs(semanticConfig.multiValueProperties) do
local fieldKey = config.field
local delimiter = config.delimiter or ";"
local transform = config.transform
if args[fieldKey] and args[fieldKey] ~= "" then
local values = p.splitSemicolonValues(args[fieldKey])
for _, value in ipairs(values) do
if transform then
value = transform(value)
end
if value and value ~= "" then
if mw.smw then
local propSet = {}
propSet[property] = value
mw.smw.set(propSet)
else
output = output .. "\n" ..
'<div style="display:none;">\n {{#set: ' .. property .. '=' ..
value .. ' }}\n</div>'
end
end
end
end
end
end
return output
end
-- Creates a standard config structure for templates
function p.createStandardConfig(config)
-- Ensure all standard sections exist
config = config or {}
config.meta = config.meta or {
description = "Template module"
}
-- Handle mappings
config.mappings = config.mappings or {}
-- For backward compatibility, copy mappings to top-level
if config.mappings.type then
config.typeMapping = config.mappings.type
end
if config.mappings.subtype then
config.subtypeMapping = config.mappings.subtype
end
if config.mappings.community then
config.communityMapping = config.mappings.community
end
config.fields = config.fields or {}
config.semantics = config.semantics or {
properties = {},
multiValueProperties = {}
}
config.constants = config.constants or {}
config.patterns = config.patterns or {}
return config
end
return p