Module:ListGeneration
Documentation for this module may be created at Module:ListGeneration/doc
-- Module:ListGeneration
-- A centralized and flexible module for generating various types of lists from delimited strings.
--
-- This module is designed to replace fragmented list generation logic across the wiki,
-- providing a single, powerful function to create multiple list formats.
--
-- Features:
-- * Handles semicolon-delimited strings automatically.
-- * Supports multiple list modes:
-- - 'bullet': Standard HTML unordered list (<ul>).
-- - 'bullet_custom': Unordered list with a custom Unicode character as the bullet.
-- - 'invisible': A bulleted list with the 'no-bullets' CSS class for an unstyled list.
-- - 'comma': A simple, comma-separated string of items.
-- * Allows for custom CSS classes on the list container.
-- * Provides an 'itemHook' for custom, per-item processing and formatting.
--
-- Usage:
-- local ListGeneration = require('Module:ListGeneration')
-- local options = {
-- mode = 'bullet',
-- listClass = 'my-custom-list',
-- itemHook = function(item) return '<b>' .. item .. '</b>' end
-- }
-- local htmlList = ListGeneration.createList('item1; item2; item3', options)
local p = {}
-- Dependencies
local NormalizationText = require('Module:NormalizationText')
-- Core list creation function
-- @param input string The semicolon-delimited string of list items.
-- @param options table A table of configuration options.
-- - mode (string): 'bullet' (default), 'bullet_custom', 'invisible', 'comma'.
-- - bulletChar (string): The character to use for custom bullets.
-- - listClass (string): A custom CSS class for the <ul> element.
-- - itemHook (function): A function to process each list item.
-- @return string The formatted list as an HTML string or comma-separated text.
function p.createList(input, options)
if not input or (type(input) == 'string' and input == '') or (type(input) == 'table' and #input == 0) then
return ''
end
-- Initialize options with defaults
options = options or {}
local mode = options.mode or 'bullet'
local bulletChar = options.bulletChar
local listClass = options.listClass
local itemHook = options.itemHook
-- If input is a string, split it. Otherwise, assume it's a pre-split table.
local items
if type(input) == 'string' then
items = NormalizationText.splitMultiValueString(input)
else
items = input
end
if #items == 0 then
return ''
end
-- Process items with the hook if provided, allowing for custom formatting
if type(itemHook) == 'function' then
local processedItems = {}
for i, item in ipairs(items) do
local processed = itemHook(item)
if processed then
table.insert(processedItems, processed)
end
end
items = processedItems
end
-- If there's only one item and no custom bullet, return it directly without list formatting
if #items == 1 and (mode ~= 'bullet_custom' or not bulletChar or bulletChar == '') then
local singleItem = items[1]
if type(singleItem) == 'table' then
return singleItem.content or ''
else
return singleItem
end
end
-- Handle comma-separated mode for simple text lists
if mode == 'comma' then
return table.concat(items, ', ')
end
-- Handle all HTML list-based modes
if mode == 'bullet' or mode == 'bullet_custom' or mode == 'invisible' then
local listItems = {}
local listStyle = ''
-- Handle custom bullet character via inline style
if mode == 'bullet_custom' and bulletChar and bulletChar ~= '' then
listStyle = string.format(' style="list-style-type: \'%s\';"', bulletChar)
end
-- Build the individual list items
for _, itemData in ipairs(items) do
local content = ''
local itemClass = ''
if type(itemData) == 'table' then
content = itemData.content or ''
if itemData.class and itemData.class ~= '' then
itemClass = string.format(' class="%s"', itemData.class)
end
elseif type(itemData) == 'string' then
content = itemData
end
if content ~= '' then
table.insert(listItems, string.format('<li%s>%s</li>', itemClass, content))
end
end
-- Build the final CSS class string for the <ul> element
local finalClass = 'template-list'
if mode == 'invisible' then
finalClass = finalClass .. ' list-style-none'
end
if listClass and listClass ~= '' then
finalClass = finalClass .. ' ' .. listClass
end
return string.format('<ul class="%s"%s>%s</ul>', finalClass, listStyle, table.concat(listItems, ''))
end
-- Fallback for a single item or an unknown mode
if #items == 1 then
return items[1]
end
-- Default fallback for multiple items with an unknown mode is a comma-separated list
return table.concat(items, ', ')
end
return p