Module:Alternating colored text

From Uncyclopedia, the content-free encyclopedia
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