Module:ListGeneration: Difference between revisions
// via Wikitext Extension for VSCode |
// via Wikitext Extension for VSCode |
||
| (11 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
-- | --[[ | ||
* Name: ListGeneration | |||
* Author: Mark W. Datysgeld | |||
* Description: Centralized and flexible module for generating various types of lists from delimited strings, designed to replace fragmented list generation logic | |||
* Notes: Handles semicolon-delimited strings automatically; supports multiple list modes (bullet, bullet_custom, invisible, comma); allows custom CSS classes on list container; provides itemHook for custom per-item processing and formatting; accepts both string input (auto-split) and pre-split table input | |||
]] | |||
- | |||
- | |||
local p = {} | local p = {} | ||
| Line 38: | Line 20: | ||
-- @return string The formatted list as an HTML string or comma-separated text. | -- @return string The formatted list as an HTML string or comma-separated text. | ||
function p.createList(input, options) | function p.createList(input, options) | ||
if not input or input == '' then | if not input or (type(input) == 'string' and input == '') or (type(input) == 'table' and #input == 0) then | ||
return '' | return '' | ||
end | end | ||
| Line 49: | Line 31: | ||
local itemHook = options.itemHook | 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 | |||
-- Default to splitting only by semicolon. This is a safer default than also splitting by "and", which can break up valid entity names. | |||
-- Callers that need more complex splitting logic should pre-split the string and pass a table instead. | |||
local semicolonOnlyPattern = {{pattern = ";%s*", replacement = ";"}} | |||
items = NormalizationText.splitMultiValueString(input, semicolonOnlyPattern) | |||
else | |||
items = input | |||
end | |||
if #items == 0 then | if #items == 0 then | ||
return '' | return '' | ||
| Line 60: | Line 51: | ||
for i, item in ipairs(items) do | for i, item in ipairs(items) do | ||
local processed = itemHook(item) | local processed = itemHook(item) | ||
if processed | if processed then | ||
table.insert(processedItems, processed) | table.insert(processedItems, processed) | ||
end | end | ||
end | end | ||
items = processedItems | items = processedItems | ||
end | |||
-- If there's only one item and no special formatting is needed, return it directly without list formatting | |||
if #items == 1 then | |||
local singleItem = items[1] | |||
local hasCustomBullet = (mode == 'bullet_custom' and bulletChar and bulletChar ~= '') | |||
local hasSpecialClass = (type(singleItem) == 'table' and singleItem.class and singleItem.class ~= '') | |||
-- Only bypass list formatting if there's no custom bullet AND no special class | |||
if not hasCustomBullet and not hasSpecialClass then | |||
if type(singleItem) == 'table' then | |||
return singleItem.content or '' | |||
else | |||
return singleItem | |||
end | |||
end | |||
-- If we have custom bullets or special classes, continue to list formatting below | |||
end | end | ||
| Line 83: | Line 91: | ||
-- Build the individual list items | -- Build the individual list items | ||
for _, | for _, itemData in ipairs(items) do | ||
table.insert(listItems, string.format('<li>%s</li>', | 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 | end | ||
| Line 90: | Line 111: | ||
local finalClass = 'template-list' | local finalClass = 'template-list' | ||
if mode == 'invisible' then | if mode == 'invisible' then | ||
finalClass = finalClass .. ' | finalClass = finalClass .. ' list-style-none' | ||
end | end | ||
if listClass and listClass ~= '' then | if listClass and listClass ~= '' then | ||