Module:Alternating colored text
Jump to navigation
Jump to search
local p = {}
local getArgs = require('Module:Arguments').getArgs
function p.main(frame)
local args = getArgs(frame, {
trim = false,
removeBlanks = false
})
local style = args.style or ''
-- Determine color mode and extract colors
local color1, color2, color3
local startIndex
-- CASE 1: All named parameters
-- {{AC|color1=red|color2=blue|color3=green|text=...}}
if args.color1 and args.color1 ~= '' then
color1 = args.color1
color2 = args.color2 or ''
color3 = args.color3 or args.c or ''
startIndex = 1
if color2 == '' then
mw.addWarning('<code>color1</code> and <code>color2</code> must be used together!')
return ''
end
-- CASE 2: First two positional are colors, third must be named
-- {{AC|red|blue|c=green|...}} or {{AC|red|blue|...}}
-- IMPORTANT: Only 2 positional colors are allowed to avoid ambiguity
-- The third color (if needed) MUST use color3= or c=
elseif args[1] and args[1] ~= '' and args[2] and args[2] ~= '' then
color1 = args[1]
color2 = args[2]
color3 = args.color3 or args.c or ''
startIndex = 3
-- Warning: Detect if user might be trying to use 3 positional colors
-- Common color names that might indicate this
local arg3 = args[3]
if arg3 and arg3 ~= '' then
local commonColors = {
'red', 'blue', 'green', 'yellow', 'orange', 'purple', 'pink',
'white', 'black', 'gray', 'grey', 'brown', 'cyan', 'magenta',
'lime', 'navy', 'teal', 'maroon', 'olive', 'aqua', 'silver'
}
local arg3Lower = mw.ustring.lower(arg3)
for _, colorName in ipairs(commonColors) do
if arg3Lower == colorName then
mw.addWarning('The third parameter "' .. arg3 .. '" looks like a color name. If you want a third color, use <code>c=' .. arg3 .. '</code> or <code>color3=' .. arg3 .. '</code> instead of a positional parameter.')
break
end
end
-- Also check for hex colors
if arg3:match('^#[0-9A-Fa-f]+$') then
mw.addWarning('The third parameter "' .. arg3 .. '" looks like a hex color. If you want a third color, use <code>c=' .. arg3 .. '</code> or <code>color3=' .. arg3 .. '</code> instead of a positional parameter.')
end
-- Check for rgb/rgba
if arg3:match('^rgba?%s*%(') then
mw.addWarning('The third parameter looks like an RGB color. If you want a third color, use <code>c=...</code> or <code>color3=...</code> instead of a positional parameter.')
end
end
-- CASE 3: No valid colors found
else
mw.addWarning('Please specify <code>color1</code> and <code>color2</code>, or use positional parameters!')
return ''
end
local hasColor3 = color3 ~= '' and color3 ~= nil
local startOffset = startIndex - 1
-- Determine if we should use text mode
local textMode = false
local textContent = ''
-- Text mode triggers:
-- 1. Explicit text= parameter
-- 2. Any "letter" parameter is longer than 4 characters (auto-detect)
if args.text and args.text ~= '' then
textMode = true
textContent = args.text
else
-- Check if any parameter from startIndex onwards is > 4 chars
for i = startIndex, startIndex + 10 do -- Check first ~10 params
local param = args[i]
if param and param ~= '' then
if mw.ustring.len(param) > 4 then
textMode = true
-- Concatenate all remaining parameters into text
for j = startIndex, 99 do
local p = args[j]
if not p or p == '' then
break
end
textContent = textContent .. p
end
break
end
else
break
end
end
end
-- Pre-allocate output table
local out = {}
local outIndex = 1
-- Opening tag
out[outIndex] = '<span class="alternating-colored-text"'
outIndex = outIndex + 1
if style ~= '' then
out[outIndex] = ' style="'
out[outIndex + 1] = style
out[outIndex + 2] = '">'
outIndex = outIndex + 3
else
out[outIndex] = '>'
outIndex = outIndex + 1
end
-- TEXT MODE: Process as a string
if textMode then
-- Warn if user provided both text mode AND individual character parameters that will be ignored
if not args.text then
-- Auto-text mode was triggered
-- Check if there are additional short parameters after the long one that triggered it
local hasShortParamsAfter = false
for i = startIndex + 1, startIndex + 20 do
local p = args[i]
if p and p ~= '' and mw.ustring.len(p) <= 4 then
hasShortParamsAfter = true
break
elseif not p or p == '' then
break
end
end
if hasShortParamsAfter then
mw.addWarning('Text mode was auto-detected because a parameter exceeded 4 characters. All parameters from position ' .. startIndex .. ' onwards are being concatenated. If this is not intended, use individual single characters.')
end
else
-- Explicit text= was used
if args[startIndex] and args[startIndex] ~= '' then
mw.addWarning('Using <code>text=</code> parameter ignores individual character parameters (position ' .. startIndex .. ' onwards). Remove unused parameters or remove the <code>text=</code> parameter.')
end
end
-- Note: We do NOT strip wikitext formatting in text mode
-- This allows users to include <br>, <span>, and other HTML/wikitext
-- Templates are not expanded (handled by MediaWiki parser before this module runs)
-- Iterate through each character, but skip over HTML tags
local textLen = mw.ustring.len(textContent)
local i = 1
local pos = 0 -- Position counter for coloring (only counts non-tag characters)
while i <= textLen do
local char = mw.ustring.sub(textContent, i, i)
-- Check if we're at the start of an HTML tag
if char == '<' then
-- Find the end of the tag
local tagEnd = mw.ustring.find(textContent, '>', i + 1)
if tagEnd then
-- Extract the entire tag and add it uncolored
local tag = mw.ustring.sub(textContent, i, tagEnd)
out[outIndex] = tag
outIndex = outIndex + 1
i = tagEnd + 1
else
-- No closing >, treat < as regular character
pos = pos + 1
local colorVal
if hasColor3 and pos % 3 == 0 then
colorVal = color3
elseif pos % 2 == 0 then
colorVal = color2
else
colorVal = color1
end
out[outIndex] = '<span style="color:'
out[outIndex + 1] = colorVal
out[outIndex + 2] = '">'
out[outIndex + 3] = char
out[outIndex + 4] = '</span>'
outIndex = outIndex + 5
i = i + 1
end
else
-- Regular character, apply coloring
pos = pos + 1
local colorVal
if hasColor3 and pos % 3 == 0 then
colorVal = color3
elseif pos % 2 == 0 then
colorVal = color2
else
colorVal = color1
end
out[outIndex] = '<span style="color:'
out[outIndex + 1] = colorVal
out[outIndex + 2] = '">'
out[outIndex + 3] = char
out[outIndex + 4] = '</span>'
outIndex = outIndex + 5
i = i + 1
end
end
-- LEGACY MODE: Individual character parameters
else
for i = startIndex, 99 do
local letter = args[i]
if not letter or letter == '' then
break
end
local colorVal
local pos = i - startOffset
if hasColor3 and pos % 3 == 0 then
colorVal = color3
elseif pos % 2 == 0 then
colorVal = color2
else
colorVal = color1
end
out[outIndex] = '<span style="color:'
out[outIndex + 1] = colorVal
out[outIndex + 2] = '">'
out[outIndex + 3] = letter
out[outIndex + 4] = '</span>'
outIndex = outIndex + 5
end
end
out[outIndex] = '</span>'
return table.concat(out)
end
return p